Skip to content

Latest commit

ย 

History

History
1372 lines (1018 loc) ยท 97.5 KB

schema_reference.md

File metadata and controls

1372 lines (1018 loc) ยท 97.5 KB

๐Ÿ“ CoreBank ๋ฏธ๋‹ˆ ์ฝ”์–ด๋ฑ…ํ‚น โ€” ํ…Œ์ด๋ธ” ์Šคํ‚ค๋งˆ ๋ ˆํผ๋Ÿฐ์Šค

DBMS: MySQL 8.4 ยท InnoDB ยท utf8mb4_0900_ai_ci ๋Œ€์ƒ: 39๊ฐœ ๋น„์ฆˆ๋‹ˆ์Šค ํ…Œ์ด๋ธ” + 8๊ฐœ ๋น„์ฆˆ๋‹ˆ์Šค ์™ธ ํ…Œ์ด๋ธ” (ledger_entry_id_sequence, batch_execution_lock, batch_execution_history, business_date_cutoff, cob_checkpoint, SPRING_SESSION, SPRING_SESSION_ATTRIBUTES, EVENT_PUBLICATION) ยท ํ…Œ์ด๋ธ” ๋ชฉ๋ก ๊ธฐ์ค€ 394๊ฐœ ์ปฌ๋Ÿผ ๊ทผ๊ฑฐ DDL: src/main/resources/db/migration/ ๋‚ด V ํŒŒ์ผ๋“ค

์ˆœ์ˆ˜ ์Šคํ‚ค๋งˆ ๋ ˆํผ๋Ÿฐ์Šค์ž…๋‹ˆ๋‹ค. ๊ฐœ์ • ์ด๋ ฅยท๊ฐ์ถ• ๊ทผ๊ฑฐยทํ™•์ธ ํ•„์š” ํ•ญ๋ชฉ์€ DB_ERD_v3.md์— ์žˆ์Šต๋‹ˆ๋‹ค.

ํ‘œ๊ธฐ ๊ทœ์•ฝ

ํ‘œ๊ธฐ ์˜๋ฏธ
PK ๊ธฐ๋ณธํ‚ค
FK ์™ธ๋ž˜ํ‚ค. Null ์—ด ์˜†์— ์ฐธ์กฐ ๋Œ€์ƒ์„ ์ ์—ˆ๋‹ค
UK ์œ ๋‹ˆํฌ ํ‚ค
Null = X NOT NULL
Null = O NULL ํ—ˆ์šฉ

๊ธˆ์•ก์€ ์ „๋ถ€ BIGINT(์› ๋‹จ์œ„ ์ •์ˆ˜), ๊ธˆ๋ฆฌ๋Š” DECIMAL(5,2)(์—ฐ %), ๊ณ„์ขŒ๋ฒˆํ˜ธ๋Š” CHAR(12), ๊ฑฐ๋ž˜๋ฒˆํ˜ธ๋Š” CHAR(20)์ž…๋‹ˆ๋‹ค.

์‹œ๊ฐ์€ DATETIME(6)์ž…๋‹ˆ๋‹ค. MySQL์˜ DATETIME์€ ์‹œ๊ฐ„๋Œ€ ์ •๋ณด๋ฅผ ๊ฐ–์ง€ ์•Š๋Š” ๋ฒฝ์‹œ๊ฐ(wall-clock) ๊ทธ๋Œ€๋กœ๋ฅผ ์ €์žฅํ•˜๋ฉฐ ์ž๋™ UTC ๋ณ€ํ™˜์ด ์—†์Šต๋‹ˆ๋‹ค โ€” KST๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜(Hibernate hibernate.jdbc.time_zone, JDBC connectionTimeZone, JpaAuditingConfig์˜ Clock)์ด ๊ฐ’์„ ์“ฐ๊ณ  ์ฝ์„ ๋•Œ ์ง€ํ‚ค๋Š” ์ €์žฅยทํ‘œ์‹œ ๊ณ„์•ฝ์ž…๋‹ˆ๋‹ค.


ํ…Œ์ด๋ธ” ๋ชฉ๋ก

# ํ…Œ์ด๋ธ” ์„ค๋ช… ๋‹ด๋‹น ์ปฌ๋Ÿผ
1 customer ๊ณ ๊ฐ P6 19
2 terms ์•ฝ๊ด€ P6 10
3 customer_terms_agreement ํšŒ์›๊ฐ€์ž… ์•ฝ๊ด€ ๋™์˜ P6 4
4 verification_request ์ธ์ฆ ์š”์ฒญ P6 13
5 notification ์•Œ๋ฆผ P1 9
6 product ์ƒํ’ˆ P3 25
7 product_rate_tier ์ƒํ’ˆ ๊ธฐ๊ฐ„๋ณ„ ๊ธˆ๋ฆฌ P3 3
8 product_preferential_rate ์ƒํ’ˆ ์šฐ๋Œ€๊ธˆ๋ฆฌ P3 4
9 product_terms ์ƒํ’ˆ-์•ฝ๊ด€ ์—ฐ๊ฒฐ P3 3
10 account ๊ณ„์ขŒ P2 23
11 account_number_sequence ๊ณ„์ขŒ๋ฒˆํ˜ธ ์ฑ„๋ฒˆ ๊ทœ์น™ P2 8
12 transaction_sequence ๊ฑฐ๋ž˜๋ฒˆํ˜ธ ์ผ๋ จ๋ฒˆํ˜ธ ์ฑ„๋ฒˆ P4 4
13 transfer ์ด์ฒด ๊ฑฐ๋ž˜ P4 26
14 ledger_entry ์›์žฅ P4 14
15 ledger_entry_id_sequence ์›์žฅ PK ์ „์šฉ ์ฑ„๋ฒˆ P4 1
16 favorite_account ์ž์ฃผ ์“ฐ๋Š” ๊ณ„์ขŒ P4 6
17 transfer_limit ์ด์ฒดํ•œ๋„ P1 5
18 transfer_limit_daily_usage ์ผ๋ณ„ ํ•œ๋„ ์‚ฌ์šฉ์•ก P1 5
19 transfer_limit_history ์ด์ฒดํ•œ๋„ ๋ณ€๊ฒฝ ์ด๋ ฅ P1 6
20 product_subscription ์ƒํ’ˆ๊ฐ€์ž… P3 19
21 subscription_terms_agreement ์ƒํ’ˆ ์•ฝ๊ด€ ๋™์˜ P3 5
22 scheduled_transfer ์˜ˆ์•ฝ์ด์ฒด P3 18
23 auto_transfer ์ž๋™์ด์ฒด ๋“ฑ๋ก P5 18
24 auto_transfer_execution ์ž๋™์ด์ฒด ํšŒ์ฐจ ์‹คํ–‰๊ฒฐ๊ณผ P5 8
25 idempotency_key ๋ฉฑ๋“ฑํ‚ค P5 9
26 audit_log ๊ฐ์‚ฌ ๋กœ๊ทธ P5 8
27 common_code ๊ณตํ†ต์ฝ”๋“œ P5 8
28 batch_execution_lock ๋ฐฐ์น˜ ์ค‘๋ณต ํŠธ๋ฆฌ๊ฑฐ ๋ฐฉ์ง€ ๋ฝ P5 3
29 gl_account ๊ณ„์ •๊ณผ๋ชฉ P3 6
30 gl_voucher ์ „ํ‘œ P3 6
31 gl_journal_entry ๋ถ„๊ฐœ P3 8
32 business_date ํ˜„์žฌ ์˜์—…์ผ P5 4
33 holiday ํœด์ผ ๋‹ฌ๋ ฅ P5 4
34 gl_voucher_sequence ์ „ํ‘œ๋ฒˆํ˜ธ ์ผ๋ จ๋ฒˆํ˜ธ ์ฑ„๋ฒˆ P3 4
35 auth_token ์ผํšŒ์„ฑ ์ธ์ฆ ํ† ํฐ P4 9
36 otp_issue_lock OTP ๋ฐœ๊ธ‰ ์ž ๊ธˆ P4 3
37 terms_view_history ์ƒํ’ˆ ์•ฝ๊ด€ ์—ด๋žŒ ์ด๋ ฅ P4 4
38 batch_execution_history ๋ฐฐ์น˜ ์Šคํ… ์‹คํ–‰ ๊ธฐ๋ก P5 8
39 ledger_reconciliation_mismatch ์›์žฅ-์ž”์•ก ๋Œ€์‚ฌ ๋ถˆ์ผ์น˜ ๋ชฉ๋ก P4 6
40 admin_permission ๊ด€๋ฆฌ์ž ๊ถŒํ•œ P1 3
41 account_status_history ๊ณ„์ขŒ ์ƒํƒœ ์ „์ด ์ด๋ ฅ P2 8
42 business_date_cutoff ์˜์—…์ผ ๋งˆ๊ฐ cutoff P5 4
43 interest_payment ์˜ˆ์ ๊ธˆ ์ด์ž ์ง€๊ธ‰ ์ด๋ ฅ P2 9
44 SPRING_SESSION ๊ณต์šฉ HTTP ์„ธ์…˜ P6 7
45 SPRING_SESSION_ATTRIBUTES ์ง๋ ฌํ™”๋œ ์„ธ์…˜ ์†์„ฑ P6 3
46 EVENT_PUBLICATION ์ด๋ฒคํŠธ ๋ฐœํ–‰ ๊ธฐ๋ก (Spring Modulith) P1 9
47 cob_checkpoint COB ์žฌ์‹œ์ž‘ ์ฒดํฌํฌ์ธํŠธ P5 5

1. ๊ณ ๊ฐ ยท ์ธ์ฆ โ€” P6 (admin_permission ยท notification์€ P1)

SPRING_SESSION / SPRING_SESSION_ATTRIBUTES (PH-49c)

Spring Session JDBC ํ‘œ์ค€ ์Šคํ‚ค๋งˆ. Flyway V202610221420์œผ๋กœ๋งŒ ์ƒ์„ฑํ•˜๋ฉฐ JPA ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. ์„ธ์…˜์˜ ์‹œ๊ฐ์€ ํ”„๋ ˆ์ž„์›Œํฌ ๊ณ„์•ฝ์— ๋”ฐ๋ผ UTC epoch ๋ฐ€๋ฆฌ์ดˆ BIGINT์ด๊ณ  ์—…๋ฌด ํ…Œ์ด๋ธ”์˜ KST DATETIME(6) ๊ทœ์•ฝ์˜ ์˜ˆ์™ธ๋‹ค.

ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ ํƒ€์ž… ํ‚คยทNULL ์˜๋ฏธ
SPRING_SESSION PRIMARY_ID CHAR(36) PK, NOT NULL ๋‚ด๋ถ€ ์„ธ์…˜ ํ–‰ UUID
SPRING_SESSION SESSION_ID CHAR(36) UK, NOT NULL ์ฟ ํ‚ค๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ์„ธ์…˜ ID
SPRING_SESSION CREATION_TIME BIGINT NOT NULL ์ƒ์„ฑ epoch ms
SPRING_SESSION LAST_ACCESS_TIME BIGINT NOT NULL ๋งˆ์ง€๋ง‰ ์ ‘๊ทผ epoch ms
SPRING_SESSION MAX_INACTIVE_INTERVAL INT NOT NULL ๋ฌด์กฐ์ž‘ ๋งŒ๋ฃŒ ์ดˆ: ๊ณ ๊ฐ 600, ๊ด€๋ฆฌ์ž 1800(PH-49a-โ‘ก ๋กœ๊ทธ์ธ ์ •์ฑ…)
SPRING_SESSION EXPIRY_TIME BIGINT INDEX, NOT NULL ๋งŒ๋ฃŒ epoch ms
SPRING_SESSION PRINCIPAL_NAME VARCHAR(100) INDEX, NULL ํ—ˆ์šฉ ์ธ์ฆ ๊ณ ๊ฐ PK ๋ฌธ์ž์—ด, ์ต๋ช… ์„ธ์…˜์€ NULL
SPRING_SESSION_ATTRIBUTES SESSION_PRIMARY_ID CHAR(36) ๋ณตํ•ฉ PKยทFK, NOT NULL PRIMARY_ID ์ฐธ์กฐ, ON DELETE CASCADE
SPRING_SESSION_ATTRIBUTES ATTRIBUTE_NAME VARCHAR(200) ๋ณตํ•ฉ PK, NOT NULL SPRING_SECURITY_CONTEXT ๋“ฑ ์†์„ฑ ์ด๋ฆ„
SPRING_SESSION_ATTRIBUTES ATTRIBUTE_BYTES BLOB NOT NULL ์ง๋ ฌํ™”ํ•œ ์†์„ฑ ๊ฐ’

์ธ๋ฑ์Šค: SPRING_SESSION_IX1(SESSION_ID) UNIQUE, SPRING_SESSION_IX2(EXPIRY_TIME), SPRING_SESSION_IX3(PRINCIPAL_NAME). PRINCIPAL_NAME์€ ๊ณ ๊ฐ FK๊ฐ€ ์•„๋‹Œ ํ”„๋ ˆ์ž„์›Œํฌ ๊ฒ€์ƒ‰ ์ธ๋ฑ์Šค๋‹ค. ๋กœ๊ทธ์•„์›ƒ์€ ํ•ด๋‹น ์„ธ์…˜๋งŒ ์‚ญ์ œํ•˜๊ณ  ๊ณ ๊ฐ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ์€ ๊ณ ๊ฐ PK๋กœ ๋ชจ๋“  ์„ธ์…˜์„ ์‚ญ์ œํ•œ๋‹ค. ์„ธ์…˜ ์‚ญ์ œ๋Š” ํ•ด๋‹น ์—…๋ฌด ํŠธ๋žœ์žญ์…˜์— ์ฐธ์—ฌํ•˜๋ฏ€๋กœ ์—…๋ฌด ๋กค๋ฐฑ ์‹œ ํ•จ๊ป˜ ๋กค๋ฐฑํ•œ๋‹ค. ๋งŒ๋ฃŒ ํ–‰ ์ •๋ฆฌ๋Š” ๋งค๋ถ„์ด๋ฉฐ ์ธ์ฆ ๋งŒ๋ฃŒ๋Š” ์ฆ‰์‹œ ์ ์šฉ๋œ๋‹ค.

customer

๊ณ ๊ฐ

์ ‘์† ์ด๋ ฅ(๊ตฌ login_history)์„ ํก์ˆ˜ํ–ˆ๋‹ค. ๋Œ€์‹œ๋ณด๋“œ๊ฐ€ ์“ฐ๋Š” ๊ฐ’์ด ์ง์ „ยทํ˜„์žฌ 2๊ฑด๋ฟ์ด๋ผ ๋ณ„๋„ ํ…Œ์ด๋ธ”์„ ๋‘์ง€ ์•Š๋Š”๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
customer_id BIGINT PK X ๊ณ ๊ฐ ๋‚ด๋ถ€ ์‹๋ณ„์ž. ๋ช…์„ธ์˜ customerId. ํด๋ผ์ด์–ธํŠธ์— ๋…ธ์ถœ๋˜๋Š” ์œ ์ผํ•œ ๊ณ ๊ฐ ํ‚ค
user_id VARCHAR(20) UK X ๊ณ ๊ฐ์ด ์ง์ ‘ ์ •ํ•œ ๋กœ๊ทธ์ธ ์•„์ด๋””. ๋‚ด๋ถ€ PK์ธ customer_id์™€ ๋‹ค๋ฅธ ํ™”๋ฉด ์ž…๋ ฅ๊ฐ’์ด๋‹ค
existing_bank_customer_id VARCHAR(100) UK O ์‹ค๋ช…๊ณ„์ขŒ ์ธ์ฆ์œผ๋กœ ํ™•์ธํ•œ ๊ธฐ์กด ์€ํ–‰ ์›์žฅ์˜ ๊ณ ๊ฐ ์‹๋ณ„์ž. ์žฌ๊ฐ€์ž… ํŒ์ • ๊ธฐ์ค€(ATH0303). ์‹ค์„œ๋น„์Šค์˜ CI ๋Œ€๋ฆฌ ํ‚ค์ด๋ฉฐ, ์›์žฅ ์ธ์ฆ ์—†์ด ๋งŒ๋“ค์–ด์ง„ ๊ธฐ์กด ํ–‰์€ NULL
password_hash CHAR(60) X ๋กœ๊ทธ์ธ ๋น„๋ฐ€๋ฒˆํ˜ธ์˜ BCrypt ํ•ด์‹œ. ํ‰๋ฌธยท๋ณตํ˜ธํ™” ๊ฐ€๋Šฅ ์•”ํ˜ธํ™” ๊ธˆ์ง€
user_name VARCHAR(50) X ๊ณ ๊ฐ ์‹ค๋ช…. ์‘๋‹ต ์‹œ ์ด๋ฆ„ ๊ธธ์ด๋ณ„ ๋งˆ์Šคํ‚น ์ ์šฉ (2์ž ์ด* / 3์ž ํ™*๋™ / 4์ž ์ด์ƒ ๋‚จ**์ˆ˜)
birth_date DATE X ์ƒ๋…„์›”์ผ. ์‹ค๋ช…๊ณ„์ขŒ ์ธ์ฆยท์•„์ด๋”” ์ฐพ๊ธฐ์˜ ๋Œ€์กฐ๊ฐ’. ๋กœ๊ทธ ํ‰๋ฌธ ๊ธฐ๋ก ๊ธˆ์ง€
email VARCHAR(100) UK X ์ด๋ฉ”์ผ ์ฃผ์†Œ. ์—ฐ๋ฝ์ฒ˜ ๊ฒธ ์ธ์ฆ ์ˆ˜๋‹จ. ์ค‘๋ณต ๊ฐ€์ž… ์‹œ๋„ ์‹œ ATH0302
phone_number VARCHAR(11) X ํœด๋Œ€ํฐ ๋ฒˆํ˜ธ. ํ•˜์ดํ”ˆ ์—†์ด ์ˆซ์ž๋งŒ ์ €์žฅํ•˜๊ณ  ์‘๋‹ต ์‹œ ์ค‘๊ฐ„ 4์ž๋ฆฌ๋ฅผ ๋งˆ์Šคํ‚นํ•œ๋‹ค
login_failure_count TINYINT X 0 ๋กœ๊ทธ์ธ ๋น„๋ฐ€๋ฒˆํ˜ธ ์—ฐ์† ์˜ค๋ฅ˜ ํšŸ์ˆ˜. 5ํšŒ ๋„๋‹ฌ ์‹œ account_locked๊ฐ€ TRUE๋กœ ๋ฐ”๋€๋‹ค (ATH0102)
account_locked BOOLEAN X FALSE ๊ณ„์ • ์ž ๊ธˆ ์—ฌ๋ถ€. login_failure_count 5ํšŒ ๋„๋‹ฌ ์‹œ TRUE, ๊ด€๋ฆฌ์ž ์ž ๊ธˆ ํ•ด์ œ๋กœ FALSE ๋ณต๊ท€
status VARCHAR(12) X ACTIVE ๊ณ„์ • ์ƒํƒœ. ACTIVE(์ •์ƒ) / SUSPENDED(์ด์šฉ์ •์ง€). ๊ด€๋ฆฌ์ž๋งŒ ๋ฐ”๊พผ๋‹ค. SUSPENDED๋ฉด ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋งž์•„๋„ ๋กœ๊ทธ์ธ์„ ๊ฑฐ๋ถ€ํ•œ๋‹ค(ATH0106). ๋น„๋ฐ€๋ฒˆํ˜ธ 5ํšŒ ์˜ค๋ฅ˜ ์ž ๊ธˆ(account_locked)๊ณผ ๋ณ„๊ฐœ์ด๋ฉฐ ๋‘˜์ด ๋™์‹œ์— ๊ฑธ๋ฆด ์ˆ˜ ์žˆ๋‹ค
role VARCHAR(12) X CUSTOMER ๊ณ„์ • ๊ตฌ๋ถ„. CUSTOMER(๊ณ ๊ฐ) / ADMIN(๊ด€๋ฆฌ์ž). ๊ด€๋ฆฌ์ž ๋กœ๊ทธ์ธ์€ /admin/auth/login์œผ๋กœ ๋ถ„๋ฆฌ๋˜๊ณ  ์ด ๊ฐ’์ด ADMIN์ธ ๊ณ„์ •๋งŒ ํ†ต๊ณผํ•œ๋‹ค
last_login_at DATETIME(6) O ๊ฐ€์žฅ ์ตœ๊ทผ ๋กœ๊ทธ์ธ ์‹œ๊ฐ. ๋Œ€์‹œ๋ณด๋“œ์˜ currentLoginAt
last_login_ip VARCHAR(45) O ๊ฐ€์žฅ ์ตœ๊ทผ ๋กœ๊ทธ์ธ IP. ๋Œ€์‹œ๋ณด๋“œ์˜ currentLoginIp
previous_login_at DATETIME(6) O ์ง์ „ ๋กœ๊ทธ์ธ ์‹œ๊ฐ. ๋Œ€์‹œ๋ณด๋“œ์˜ previousLoginAt. ๋ถ€์ • ์ ‘์†์„ ๊ณ ๊ฐ์ด ์•Œ์•„์ฑ„๋Š” ๋‹จ์„œ
password_changed_at DATETIME(6) O ๋กœ๊ทธ์ธ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ตœ์ข… ๋ณ€๊ฒฝ ์ผ์‹œ. ์ง์ „ ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์‚ฌ์šฉ ์ œํ•œ(ATH0003) ํŒ์ • ๋ณด์กฐ
joined_at DATETIME(6) X ํšŒ์›๊ฐ€์ž… ์™„๋ฃŒ ์ผ์‹œ. ๊ณ ๊ฐ์ •๋ณด ์กฐํšŒ์˜ joinedAt
created_at DATETIME(6) X ํ–‰ ์ƒ์„ฑ ์ผ์‹œ
updated_at DATETIME(6) X ํ–‰ ์ตœ์ข… ์ˆ˜์ • ์ผ์‹œ

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
UNIQUE uk_customer_user_id user_id
UNIQUE uk_customer_email email
UNIQUE uk_customer_existing_bank_customer_id existing_bank_customer_id

CHECK ์ œ์•ฝ

์ด๋ฆ„ ์กฐ๊ฑด ์„ค๋ช…
ck_customer_status status IN ('ACTIVE', 'SUSPENDED') ๊ณ„์ • ์ƒํƒœ๋Š” ์ •์ƒยท์ด์šฉ์ •์ง€ ์ค‘ ํ•˜๋‚˜์—ฌ์•ผ ํ•œ๋‹ค.
ck_customer_role role IN ('CUSTOMER', 'ADMIN') ๊ณ„์ • ๊ตฌ๋ถ„์€ ๊ณ ๊ฐยท๊ด€๋ฆฌ์ž ์ค‘ ํ•˜๋‚˜์—ฌ์•ผ ํ•œ๋‹ค.

admin_permission

๊ด€๋ฆฌ์ž ๊ถŒํ•œ (#561)

ํ–‰ ํ•˜๋‚˜๊ฐ€ ๊ถŒํ•œ ํ•˜๋‚˜๋‹ค. ๊ถŒํ•œ์ด ์—†๋Š” ๊ด€๋ฆฌ์ž๋Š” ํ–‰์ด 0๊ฐœ์ด๋ฉฐ, ๊ด€๋ฆฌ์ž์ธ์ง€ ์•„๋‹Œ์ง€๋Š” customer.role๋กœ ๊ฐ€๋ฆฐ๋‹ค. CSV ํ•œ ์นธ์— ๋‹ด์ง€ ์•Š๋Š” ์ด์œ ๋Š” ์˜คํƒ€๋ฅผ DB๊ฐ€ ๋ง‰์ง€ ๋ชปํ•˜๊ณ  common_code์˜ ํ‘œ์‹œ๋ช…๊ณผ ๊ฐ’์ด ์ด์–ด์ง€์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค(PR #572 ๋ฆฌ๋ทฐ). ๋ถ€์—ฌยทํšŒ์ˆ˜ API๋Š” PH-49b ๋ชซ์ด๊ณ  ์ด ์‹œ์ ์—๋Š” ์‹œ๋“œ๋กœ๋งŒ ๋„ฃ๋Š”๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค NULL ๊ธฐ๋ณธ๊ฐ’ ์„ค๋ช…
customer_id BIGINT PK, FK X ๊ถŒํ•œ์„ ๊ฐ€์ง„ ๊ด€๋ฆฌ์ž. customer.customer_id ์ฐธ์กฐ
permission VARCHAR(20) PK X ๊ถŒํ•œ ํ•˜๋‚˜. GL_READยทGL_WRITEยทCUSTOMER_READยทCUSTOMER_WRITEยทAUDIT_READ. common_code์˜ ADMIN_PERMISSION ๊ทธ๋ฃน๊ณผ ๊ฐ’์ด ๊ฐ™๋‹ค
granted_at DATETIME(6) X ๊ถŒํ•œ์„ ์ค€ ์‹œ๊ฐ. ํšŒ์ˆ˜๋Š” ํ–‰ ์‚ญ์ œ๋ผ ์ด๋ ฅ์€ audit_log๊ฐ€ ๋งก๋Š”๋‹ค

๊ธฐ๋ณธํ‚ค โ€” (customer_id, permission) ๋ณตํ•ฉ. ๊ฐ™์€ ๊ถŒํ•œ์ด ๋‘ ๋ฒˆ ๋“ค์–ด๊ฐ€์ง€ ์•Š๋Š”๋‹ค.

์™ธ๋ž˜ํ‚ค

์ด๋ฆ„ ์ปฌ๋Ÿผ ์ฐธ์กฐ
fk_admin_permission_customer customer_id customer(customer_id)

CHECK ์ œ์•ฝ

์ด๋ฆ„ ์กฐ๊ฑด ์„ค๋ช…
ck_admin_permission permission COLLATE utf8mb4_0900_as_cs IN ('GL_READ', 'GL_WRITE', 'CUSTOMER_READ', 'CUSTOMER_WRITE', 'AUDIT_READ') ๊ณ ์ • 5์ข…๋งŒ ํ—ˆ์šฉํ•œ๋‹ค. common_code๋Š” code_group์œผ๋กœ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜๋ฅผ ํ•จ๊ป˜ ๋‹ด์•„ FK๋ฅผ ๊ฑธ ์ˆ˜ ์—†์–ด CHECK๋กœ ๊ณ ์ •ํ•˜๊ณ , ๊ถŒํ•œ์ด ๋Š˜๋ฉด ๋‘˜์„ ํ•จ๊ป˜ ๋ฐ”๊พผ๋‹ค.

terms

์•ฝ๊ด€ (ํšŒ์›๊ฐ€์ž…ยท์ƒํ’ˆ ๊ณต์šฉ)

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
terms_id BIGINT PK X ์•ฝ๊ด€ ๋‚ด๋ถ€ ์‹๋ณ„์ž. ๋ฒ„์ „๋งˆ๋‹ค ๋ณ„๋„ ํ–‰์ด๋ฏ€๋กœ ๊ฐœ์ •ํ•˜๋ฉด ์ƒˆ ID๊ฐ€ ๋ฐœ๊ธ‰๋œ๋‹ค
terms_code VARCHAR(30) UK X ์•ฝ๊ด€ ์ข…๋ฅ˜ ์ฝ”๋“œ. ๋ฒ„์ „์ด ๋‹ฌ๋ผ๋„ ๋™์ผํ•œ ๊ฐ’ (์˜ˆ: TERMS_PRIVACY)
version VARCHAR(10) UK X ์•ฝ๊ด€ ๋ฒ„์ „ ๋ฌธ์ž์—ด. ์ƒํ’ˆ๊ฐ€์ž… ์‹œ ๋™์˜ ๋ฒ„์ „ ๋Œ€์กฐ(PRD0006)์˜ ๊ธฐ์ค€
terms_type VARCHAR(20) X ์•ฝ๊ด€ ์“ฐ์ž„์ƒˆ ๊ตฌ๋ถ„. SIGNUP(ํšŒ์›๊ฐ€์ž… ์•ฝ๊ด€) / PRODUCT(์ƒํ’ˆ ๊ฐ€์ž… ์•ฝ๊ด€)
title VARCHAR(200) X ์•ฝ๊ด€ ์ œ๋ชฉ. ๋ชฉ๋ก ํ™”๋ฉด ํ‘œ์‹œ์šฉ
content TEXT X ์•ฝ๊ด€ ์ „๋ฌธ. ์•ฝ๊ด€ ๋ณธ๋ฌธ ์กฐํšŒ ์‘๋‹ต์˜ content
is_required BOOLEAN X FALSE ํ•„์ˆ˜ ๋™์˜ ์—ฌ๋ถ€. FALSE๋ฉด ์„ ํƒ ์•ฝ๊ด€์ด๋ผ ๋ฏธ๋™์˜ํ•ด๋„ ๊ฐ€์ž…์ด ์ง„ํ–‰๋œ๋‹ค
view_required BOOLEAN X FALSE ์ „๋ฌธ ์—ด๋žŒ ๊ฐ•์ œ ์—ฌ๋ถ€. TRUE๋ฉด ๋™์˜ ์ „์— ๋ณธ๋ฌธ์„ ์—ด์–ด์•ผ ํ•˜๋ฉฐ ์ด๋ ฅ์ด ์—†์œผ๋ฉด PRD0005
created_at DATETIME(6) X ํ–‰ ์ƒ์„ฑ ์ผ์‹œ
updated_at DATETIME(6) X ํ–‰ ์ตœ์ข… ์ˆ˜์ • ์ผ์‹œ

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
UNIQUE uk_terms_code_version terms_code, version

customer_terms_agreement

ํšŒ์›๊ฐ€์ž… ์•ฝ๊ด€ ๋™์˜

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
agreement_id BIGINT PK X ๋™์˜ ์ด๋ ฅ ๋‚ด๋ถ€ ์‹๋ณ„์ž
customer_id BIGINT FK UK X ๋™์˜ํ•œ ๊ณ ๊ฐ โ†’ customer.customer_id
terms_id BIGINT FK UK X ๋™์˜ ๋Œ€์ƒ ์•ฝ๊ด€. ๋ฒ„์ „์ด ํฌํ•จ๋œ ํ–‰์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค โ†’ terms.terms_id
agreed_at DATETIME(6) X ๋™์˜ ์‹œ๊ฐ. ๋ถ„์Ÿ ์‹œ ์ฆ๊ฑฐ๊ฐ€ ๋˜๋ฏ€๋กœ ๊ฐฑ์‹ ํ•˜์ง€ ์•Š๊ณ  ํ–‰์„ ์ƒˆ๋กœ ์Œ“๋Š”๋‹ค

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
UNIQUE uk_cta customer_id, terms_id

verification_request

์ธ์ฆ ์š”์ฒญ (์ด๋ฉ”์ผยท๋น„๋ฐ€๋ฒˆํ˜ธ์žฌ์„ค์ •ยทOTP ํ†ตํ•ฉ). *AuthToken ์€ auth_token

์ด๋ฉ”์ผ ์ธ์ฆยท๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ •ยทOTP๋ฅผ ํ•˜๋‚˜๋กœ ํ•ฉ์ณค๋‹ค. ์…‹ ๋‹ค ์ฝ”๋“œ ๋ฐœ๊ธ‰ โ†’ ๊ฒ€์ฆ โ†’ ๋งŒ๋ฃŒ โ†’ 1ํšŒ์šฉ ๊ตฌ์กฐ๊ฐ€ ๊ฐ™๊ณ  ์‹๋ณ„์ž๊ฐ€ ๋ชจ๋‘ String์ด๋ผ ํ†ตํ•ฉ์ด ๊ฐ€๋Šฅํ–ˆ๋‹ค. ๊ฒ€์ฆ ๊ฒฐ๊ณผ๋กœ ๋ฐœ๊ธ‰๋˜๋Š” *AuthToken์€ ์ด ํ…Œ์ด๋ธ”์ด ์•„๋‹ˆ๋ผ auth_token์— ์žˆ๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
verification_request_id VARCHAR(64) PK X ์ธ์ฆ ์š”์ฒญ ์‹๋ณ„์ž. ์šฉ๋„๋ณ„ ์ ‘๋‘์–ด(EVF_ ์ด๋ฉ”์ผ / PRR_ ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • / OTP_REQ_ OTP) + CSPRNG ๋‚œ์ˆ˜. ๋ช…์„ธ์˜ emailVerificationIdยทpasswordResetRequestIdยทotpRequestId๊ฐ€ ๋ชจ๋‘ ์ด ์ปฌ๋Ÿผ์ด๋‹ค
purpose VARCHAR(24) X ์ธ์ฆ ์š”์ฒญ์˜ ์šฉ๋„. SIGN_UP / EMAIL_CHANGE / PASSWORD_RESET / OTP_TRANSACTION. ์„ธ ์š”์ฒญ์„ ํ•œ ํ…Œ์ด๋ธ”์— ํ•ฉ์นœ ๊ตฌ๋ถ„ ์ถ•
customer_id BIGINT FK O ์š”์ฒญ ๊ณ ๊ฐ. ํšŒ์›๊ฐ€์ž… ์ „ ์ด๋ฉ”์ผ ์ธ์ฆ์€ ๊ณ ๊ฐ์ด ์•„์ง ์—†์–ด NULL โ†’ customer.customer_id
target VARCHAR(100) O ์ธ์ฆ ๋Œ€์ƒ ๊ฐ’. ์ด๋ฉ”์ผ ์ธ์ฆ์€ ์ˆ˜์‹  ์ด๋ฉ”์ผ ์ฃผ์†Œ๊ฐ€ ๋“ค์–ด๊ฐ€๊ณ  OTP๋Š” ๋น„์–ด ์žˆ๋‹ค
code_hash CHAR(60) X ์ธ์ฆ๋ฒˆํ˜ธยทOTP 6์ž๋ฆฌ์˜ ๋‹จ๋ฐฉํ–ฅ ํ•ด์‹œ. ํ‰๋ฌธ ์ €์žฅยท๋กœ๊ทธ ๊ธฐ๋ก ๊ธˆ์ง€
transaction_type VARCHAR(32) O OTP ์ „์šฉ. ์–ด๋–ค ๊ฑฐ๋ž˜๋ฅผ ์Šน์ธํ•˜๋ ค๋Š” OTP์ธ์ง€ (IMMEDIATE_TRANSFER ๋“ฑ)
transaction_data JSON O OTP ์ „์šฉ. ์ถœ๊ธˆ๊ณ„์ขŒยท์ž…๊ธˆ๊ณ„์ขŒยท๊ธˆ์•ก ๋“ฑ ๊ฑฐ๋ž˜ ํ•ต์‹ฌ ์ •๋ณด. ์ตœ์ข… ๊ฑฐ๋ž˜ API๊ฐ€ ์š”์ฒญ ๋ณธ๋ฌธ๊ณผ ๋Œ€์กฐํ•ด ๋ณ€์กฐ๋ฅผ ์žก๋Š”๋‹ค (OTP0102)
error_count TINYINT X 0 ์ธ์ฆ๋ฒˆํ˜ธ ์—ฐ์† ์˜ค๋ฅ˜ ํšŸ์ˆ˜. 5ํšŒ์— ๋„๋‹ฌํ•˜๋ฉด locked๊ฐ€ TRUE๊ฐ€ ๋œ๋‹ค (OTP0103)
locked BOOLEAN X FALSE ์ž ๊ธˆ ์—ฌ๋ถ€. error_count๊ฐ€ 5์ด๋ฉด TRUE. ์žฌ๋ฐœ๊ธ‰ ์ „๊นŒ์ง€ ๊ฒ€์ฆ ๋ถˆ๊ฐ€ (OTP0103)
used BOOLEAN X FALSE ์‚ฌ์šฉ ์™„๋ฃŒ ์—ฌ๋ถ€. ๊ฒ€์ฆ ์„ฑ๊ณต ์‹œ TRUE๋กœ ๋ฐ”๊ฟ” ์žฌ์‚ฌ์šฉ์„ ๋ง‰๋Š”๋‹ค
verified_at DATETIME(6) O ๊ฒ€์ฆ ์„ฑ๊ณต ์‹œ๊ฐ. ๋ฏธ๊ฒ€์ฆ์ด๋ฉด NULL
expires_at DATETIME(6) X ์œ ํšจ์‹œ๊ฐ„ ๋งŒ๋ฃŒ ์‹œ๊ฐ. ๋ฐœ๊ธ‰ ์‹œ๊ฐ + 180์ดˆ
created_at DATETIME(6) X ๋ฐœ๊ธ‰ ์š”์ฒญ ์‹œ๊ฐ

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
INDEX ix_vr_customer customer_id, purpose, created_at DESC
INDEX ix_vr_target target, purpose, created_at DESC

์ด๋ฉ”์ผ ์ธ์ฆ๋ฒˆํ˜ธ ๋ฐœ๊ธ‰์€ target(์ด๋ฉ”์ผ) + purpose ๋‹จ์œ„๋กœ ์ง๋ ฌํ™”ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ™์€ ์กฐํ•ฉ์˜ ๋™์‹œ ์žฌ๋ฐœ๊ธ‰๋„ ๊ธฐ์กด ํ™œ์„ฑ ์š”์ฒญ ๋ฌดํšจํ™”์™€ ์‹ ๊ทœ ์š”์ฒญ ์ €์žฅ์„ ์ˆœ์„œ๋Œ€๋กœ ์ˆ˜ํ–‰ํ•˜์—ฌ, ๋งˆ์ง€๋ง‰์œผ๋กœ ์ฒ˜๋ฆฌ๋œ ์š”์ฒญ ํ•˜๋‚˜๋งŒ used = FALSE ์ƒํƒœ๋กœ ๋‚จ๊ฒจ์•ผ ํ•ฉ๋‹ˆ๋‹ค. SIGN_UP๊ณผ EMAIL_CHANGE์ฒ˜๋Ÿผ ๋ชฉ์ ์ด ๋‹ค๋ฅธ ์š”์ฒญ์€ ์„œ๋กœ ๋ฌดํšจํ™”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


notification

์•Œ๋ฆผ

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
notification_id BIGINT PK X ์•Œ๋ฆผ ๋‚ด๋ถ€ ์‹๋ณ„์ž. ์ฝ์Œ ์ฒ˜๋ฆฌ API์˜ ๊ฒฝ๋กœ ๋ณ€์ˆ˜
customer_id BIGINT FK X ์ˆ˜์‹  ๊ณ ๊ฐ โ†’ customer.customer_id
type VARCHAR(24) UK X ์•Œ๋ฆผ์„ ๋ฐœ์ƒ์‹œํ‚จ ์—…๋ฌด ๊ตฌ๋ถ„. TRANSFER(์ฆ‰์‹œ ยท ํƒ€ํ–‰์ด์ฒด) / SCHEDULED_TRANSFER(์˜ˆ์•ฝ์ด์ฒด) / AUTO_TRANSFER(์ž๋™์ด์ฒด) / PRODUCT_SUBSCRIPTION(์ƒํ’ˆ๊ฐ€์ž…)
ref_id BIGINT UK O ๋‹คํ˜• ์ฐธ์กฐ: TRANSFER->transfer.transfer_id / SCHEDULED_TRANSFER->scheduled_transfer_id / AUTO_TRANSFER->auto_transfer_execution.execution_id / PRODUCT_SUBSCRIPTION->subscription_id
title VARCHAR(100) X ์•Œ๋ฆผ ์ œ๋ชฉ. ๋ชฉ๋ก ํ™”๋ฉด์˜ ํ•œ ์ค„ ์š”์•ฝ
content VARCHAR(500) X ์•Œ๋ฆผ ๋ณธ๋ฌธ ๋ฌธ๊ตฌ
is_read BOOLEAN X FALSE ์ฝ์Œ ์—ฌ๋ถ€. ๋ฏธ์ฝ์Œ ๊ฑด์ˆ˜ ์กฐํšŒ์˜ ์ง‘๊ณ„ ๋Œ€์ƒ
read_at DATETIME(6) O ์ฝ์Œ ์ฒ˜๋ฆฌ ์‹œ๊ฐ. ๋ฏธ์ฝ์Œ์ด๋ฉด NULL
occurred_at DATETIME(6) X ์•Œ๋ฆผ ๋ฐœ์ƒ ์‹œ๊ฐ. ๋ชฉ๋ก ์ •๋ ฌ ๊ธฐ์ค€

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
INDEX ix_noti_customer customer_id, is_read, occurred_at DESC
UNIQUE uk_noti_type_ref type, ref_id โ€” ๊ตฌ๋…์ž๊ฐ€ ๊ฐ™์€ ์ด๋ฒคํŠธ๋ฅผ ๋‘ ๋ฒˆ ๋ฐ›์•„๋„ ์•Œ๋ฆผ์€ 1๊ฑด(#706)

2. ์ƒํ’ˆ โ€” P3

product

์ƒํ’ˆ

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
product_id BIGINT PK X ์ƒํ’ˆ ๋‚ด๋ถ€ ์‹๋ณ„์ž. ์ƒํ’ˆ ์ƒ์„ธยท๊ฐ€์ž… API์˜ productId
product_code VARCHAR(20) UK X ์ƒํ’ˆ ์—…๋ฌด ์ฝ”๋“œ. ํ™”๋ฉดยท์‹œ๋“œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ƒํ’ˆ์„ ์ง€์นญํ•˜๋Š” ์•ˆ์ •์  ํ‚ค
product_name VARCHAR(100) X ํ™”๋ฉด์— ๋…ธ์ถœํ•˜๋Š” ์ƒํ’ˆ๋ช…
product_group VARCHAR(12) X SAVINGS(์ •๊ธฐ์ ๊ธˆ) / DEPOSIT(์ •๊ธฐ์˜ˆ๊ธˆ)
deposit_type VARCHAR(20) X ๋‚ฉ์ž… ๋ฐฉ์‹. LUMP_SUM(ํ•œ ๋ฒˆ์— ์˜ˆ์น˜) / INSTALLMENT(๋งค์›” ๋‚ฉ์ž…)
summary VARCHAR(200) O ์ƒํ’ˆ ํ•œ ์ค„ ์š”์•ฝ. ๋ชฉ๋ก ํ™”๋ฉด์šฉ
description TEXT O ์ƒํ’ˆ ์ƒ์„ธ ์„ค๋ช…. ์ƒ์„ธ ํ™”๋ฉด์šฉ
eligibility TEXT O ๊ฐ€์ž… ์ž๊ฒฉ ์กฐ๊ฑด ์•ˆ๋‚ด ๋ฌธ๊ตฌ. ์ƒ์„ธ์กฐํšŒ data.eligibility
subscription_restrictions TEXT O ๊ฐ€์ž… ์ œํ•œ ์‚ฌํ•ญ ๋ชฉ๋ก(JSON ๋ฐฐ์—ด ๋ฌธ์ž์—ด). ์ƒ์„ธ์กฐํšŒ data.subscriptionRestrictions. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ StringListJsonConverter๊ฐ€ List<String>์œผ๋กœ ๋ณ€ํ™˜
notices TEXT O ์œ ์˜์‚ฌํ•ญ ๋ชฉ๋ก(JSON ๋ฐฐ์—ด ๋ฌธ์ž์—ด). ์ƒ์„ธ์กฐํšŒ data.notices. subscription_restrictions์™€ ๋™์ผํ•œ ์ปจ๋ฒ„ํ„ฐ ์‚ฌ์šฉ
base_rate DECIMAL(5,2) X ๊ธฐ๋ณธ๊ธˆ๋ฆฌ(์—ฐ %). ์šฐ๋Œ€๊ธˆ๋ฆฌ๋ฅผ ์ œ์™ธํ•œ ๊ธฐ์ค€๊ฐ’
max_rate DECIMAL(5,2) X ์ตœ๊ณ ๊ธˆ๋ฆฌ(์—ฐ %). ์šฐ๋Œ€ ์กฐ๊ฑด์„ ๋ชจ๋‘ ์ฑ„์› ์„ ๋•Œ์˜ ์ƒํ•œ. ๋ชฉ๋ก ํ™”๋ฉด ํ‘œ์‹œ์šฉ
min_amount BIGINT X ์ตœ์†Œ ๊ฐ€์ž…๊ธˆ์•ก. ๋ฏธ๋งŒ์ด๋ฉด PRD0001
max_amount BIGINT X ์ตœ๋Œ€ ๊ฐ€์ž…๊ธˆ์•ก. ์ดˆ๊ณผํ•˜๋ฉด PRD0001
amount_unit BIGINT X ๊ฐ€์ž…๊ธˆ์•ก ์ž…๋ ฅ ๋‹จ์œ„. ์ด ๊ฐ’์˜ ๋ฐฐ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ฉด PRD0004
min_term_months SMALLINT X ์ตœ์†Œ ๊ฐ€์ž…๊ธฐ๊ฐ„(๊ฐœ์›”). ๋ฏธ๋งŒ์ด๋ฉด PRD0002
max_term_months SMALLINT X ์ตœ๋Œ€ ๊ฐ€์ž…๊ธฐ๊ฐ„(๊ฐœ์›”). ์ดˆ๊ณผํ•˜๋ฉด PRD0002
interest_pay_type VARCHAR(20) X ์ด์ž ๊ณ„์‚ฐ ๋ฐฉ์‹. SIMPLE(๋‹จ๋ฆฌ) / COMPOUND(๋ณต๋ฆฌ)
sale_status VARCHAR(12) X ํŒ๋งค ์ƒํƒœ. ON_SALE(ํŒ๋งค์ค‘) / SUSPENDED(ํŒ๋งค์ค‘์ง€). ํŒ๋งค์ค‘์ง€ ์ƒํ’ˆ์€ ๋ชฉ๋ก ์กฐํšŒ์—์„œ๋Š” ๋น ์ง€์ง€๋งŒ ์ƒ์„ธ ์กฐํšŒ๋Š” 200์œผ๋กœ ์‘๋‹ตํ•œ๋‹ค(์ฆ๊ฒจ์ฐพ๊ธฐยท๊ณต์œ  ๋งํฌ ์ง„์ž… ์ง€์› ๋ชฉ์ , saleStatus๋กœ ํ”„๋ก ํŠธ๊ฐ€ ๊ตฌ๋ถ„)
sale_start_date DATE O ํŒ๋งค ์‹œ์ž‘์ผ
sale_end_date DATE O ํŒ๋งค ์ข…๋ฃŒ์ผ
new_flag BOOLEAN X FALSE ์‹ ์ƒํ’ˆ ๋ฑƒ์ง€ ํ‘œ์‹œ ์—ฌ๋ถ€
single_account_limit BOOLEAN X FALSE 1์ธ 1๊ณ„์ขŒ ์ œํ•œ ์ƒํ’ˆ์ธ์ง€. TRUE์ธ ์ƒํ’ˆ๋งŒ ์ค‘๋ณต ๊ฐ€์ž… ์‹œ PRD0301์„ ๋˜์ง„๋‹ค
created_at DATETIME(6) X ํ–‰ ์ƒ์„ฑ ์ผ์‹œ
updated_at DATETIME(6) X ํ–‰ ์ตœ์ข… ์ˆ˜์ • ์ผ์‹œ

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
UNIQUE uk_product_code product_code
INDEX ix_product_group_status product_group, sale_status

CHECK ์ œ์•ฝ

์ด๋ฆ„ ์กฐ๊ฑด
ck_product_amount min_amount <= max_amount AND min_amount > 0
ck_product_term min_term_months <= max_term_months AND min_term_months > 0
ck_product_rate base_rate <= max_rate AND base_rate >= 0

product_rate_tier

์ƒํ’ˆ ๊ธฐ๊ฐ„๋ณ„ ๊ธˆ๋ฆฌ

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
product_id BIGINT PK FK X ๋Œ€์ƒ ์ƒํ’ˆ โ†’ product.product_id
term_months SMALLINT PK X ๊ฐ€์ž…๊ธฐ๊ฐ„(๊ฐœ์›”). ์ด ๊ธฐ๊ฐ„์„ ๊ณจ๋ž์„ ๋•Œ ์ ์šฉ๋  ๊ธˆ๋ฆฌ๋ฅผ ์ •์˜ํ•œ๋‹ค
rate DECIMAL(5,2) X ํ•ด๋‹น ๊ธฐ๊ฐ„์— ์ ์šฉ๋˜๋Š” ๊ธฐ๋ณธ๊ธˆ๋ฆฌ(์—ฐ %)

product_preferential_rate

์ƒํ’ˆ ์šฐ๋Œ€๊ธˆ๋ฆฌ

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
product_id BIGINT PK FK X ๋Œ€์ƒ ์ƒํ’ˆ โ†’ product.product_id
condition_code VARCHAR(30) PK X ์šฐ๋Œ€ ์กฐ๊ฑด ์ฝ”๋“œ. ๊ธ‰์—ฌ์ด์ฒดยท์ž๋™์ด์ฒด ๋“ฑ๋ก ๋“ฑ ์กฐ๊ฑด์„ ์‹๋ณ„ํ•œ๋‹ค
condition_name VARCHAR(100) X ์šฐ๋Œ€ ์กฐ๊ฑด ์„ค๋ช…. ํ™”๋ฉด ํ‘œ์‹œ์šฉ
rate DECIMAL(5,2) X ์กฐ๊ฑด ์ถฉ์กฑ ์‹œ ๊ฐ€์‚ฐ๋˜๋Š” ๊ธˆ๋ฆฌ(์—ฐ %)

product_terms

์ƒํ’ˆ-์•ฝ๊ด€ ์—ฐ๊ฒฐ

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
product_id BIGINT PK FK X ๋Œ€์ƒ ์ƒํ’ˆ โ†’ product.product_id
terms_id BIGINT PK FK X ์—ฐ๊ฒฐ๋œ ์•ฝ๊ด€ (๋ฒ„์ „ ํฌํ•จ) โ†’ terms.terms_id
display_order SMALLINT X ์ƒํ’ˆ ์ƒ์„ธ์กฐํšŒ์—์„œ ์ด ์•ฝ๊ด€์„ ๋ณด์—ฌ์ค„ ์ˆœ์„œ(์˜ค๋ฆ„์ฐจ์ˆœ). โ€” terms ์ž์ฒด์˜ ์†์„ฑ์ด ์•„๋‹˜

ํ•„์ˆ˜ ๋™์˜ ์—ฌ๋ถ€๋Š” ์ƒํ’ˆ๋ณ„ ์˜ค๋ฒ„๋ผ์ด๋“œ ์—†์ด terms.is_required ๋‹จ์ผ ๊ธฐ์ค€์œผ๋กœ ํŒ๋‹จํ•œ๋‹ค.


3. ๊ณ„์ขŒ โ€” P2

account

๊ณ„์ขŒ (๋ณ„๋ช…ยทํ‘œ์‹œ์ˆœ์„œยท์ถœ๊ธˆ๋“ฑ๋ก ํก์ˆ˜)

๊ณ„์ขŒ๋ณ„๋ช…ยทํ‘œ์‹œ์ˆœ์„œ(๊ตฌ account_preference)์™€ ์ถœ๊ธˆ๊ณ„์ขŒ ๋“ฑ๋ก(๊ตฌ withdrawal_account)์„ ํก์ˆ˜ํ–ˆ๋‹ค. balance๋Š” ์กฐํšŒ์šฉ ์บ์‹œ์ด๋ฉฐ ์ง„์‹ค์˜ ์›์ฒœ์€ ledger_entry๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
account_id BIGINT PK X ๊ณ„์ขŒ ๋‚ด๋ถ€ ์‹๋ณ„์ž. ๋ณธ์ธ ๊ณ„์ขŒ์—๋งŒ ์‚ฌ์šฉํ•œ๋‹ค (ํƒ€ ๊ณ ๊ฐ ๊ณ„์ขŒ๋Š” ๋ฒˆํ˜ธ๋กœ ์ง€์นญ)
account_number CHAR(12) UK X ํ•˜์ดํ”ˆ ์—†๋Š” ์ˆซ์ž 12์ž๋ฆฌ
customer_id BIGINT FK X ์˜ˆ๊ธˆ์ฃผ โ†’ customer.customer_id
product_id BIGINT FK O ์ž…์ถœ๊ธˆ๊ณ„์ขŒ๋Š” NULL โ†’ product.product_id
account_type VARCHAR(24) X ๊ณ„์ขŒ ์ข…๋ฅ˜. DEMAND_DEPOSIT(์ž…์ถœ๊ธˆ) / TIME_DEPOSIT(์ •๊ธฐ์˜ˆ๊ธˆ) / INSTALLMENT_SAVINGS(์ •๊ธฐ์ ๊ธˆ)
balance BIGINT X 0 ํ˜„์žฌ ์ž”์•ก. ์กฐํšŒ ์„ฑ๋Šฅ์šฉ ์บ์‹œ์ด๋ฉฐ ์ง„์‹ค์˜ ์›์ฒœ์€ ledger_entry ํ•ฉ๊ณ„๋‹ค. ๋ฐฐ์น˜๋กœ ๋Œ€์‚ฌํ•œ๋‹ค
hold_amount BIGINT X 0 ์ง€๊ธ‰์ •์ง€ ๋ณด๋ฅ˜์•ก. ์ถœ๊ธˆ๊ฐ€๋Šฅ์•ก ๊ณ„์‚ฐ ์‹œ ์ž”์•ก์—์„œ ์ฐจ๊ฐํ•œ๋‹ค.
status VARCHAR(12) X ACTIVE ๊ณ„์ขŒ ์ƒํƒœ. ACTIVE(์ •์ƒ) / SUSPENDED(๊ฑฐ๋ž˜์ •์ง€) / MATURED(๋งŒ๊ธฐ ๋„๋‹ฌ) / CLOSED(ํ•ด์ง€) / DORMANT(ํœด๋ฉด)
password_hash CHAR(60) X ๊ณ„์ขŒ๋น„๋ฐ€๋ฒˆํ˜ธ 4์ž๋ฆฌ์˜ BCrypt ํ•ด์‹œ
password_failure_count TINYINT X 0 ๊ณ„์ขŒ๋น„๋ฐ€๋ฒˆํ˜ธ ์—ฐ์† ์˜ค๋ฅ˜ ํšŸ์ˆ˜. ๊ฒ€์ฆ ์‹คํŒจ ์‘๋‹ต์˜ errorCount
password_locked BOOLEAN X FALSE ๊ณ„์ขŒ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž ๊ธˆ ์—ฌ๋ถ€. 5ํšŒ ์˜ค๋ฅ˜ ์‹œ TRUE๊ฐ€ ๋˜์–ด ๊ฑฐ๋ž˜๊ฐ€ ์ •์ง€๋œ๋‹ค (APW0101)
alias VARCHAR(24) O ๊ณ ๊ฐ์ด ๋ถ™์ธ ๊ณ„์ขŒ๋ณ„๋ช…. ๊ณ„์ขŒ๋ช… ํ‘œ์‹œ ์‹œ ์ƒํ’ˆ๋ช…๋ณด๋‹ค ์šฐ์„ ํ•œ๋‹ค
display_order INT O ๊ณ ๊ฐ์ด ์ง€์ •ํ•œ ๊ณ„์ขŒ ๋ชฉ๋ก ํ‘œ์‹œ ์ˆœ์„œ
withdrawal_registered BOOLEAN X FALSE ์ถœ๊ธˆ๊ณ„์ขŒ๋กœ ๋“ฑ๋ก๋๋Š”์ง€. ์ด์ฒดยท์ƒํ’ˆ๊ฐ€์ž…์˜ ์ถœ๊ธˆ ์›์ฒœ์ด ๋  ์ˆ˜ ์žˆ๋Š”์ง€๋ฅผ ๊ฐ€๋ฅธ๋‹ค
withdrawal_registered_at DATETIME(6) O ์ถœ๊ธˆ๊ณ„์ขŒ ๋“ฑ๋ก ์‹œ๊ฐ. ๋ฏธ๋“ฑ๋ก์ด๋ฉด NULL
opened_date DATETIME(6) X ๊ณ„์ขŒ ๊ฐœ์„ค์ผ
maturity_date DATE O ๋งŒ๊ธฐ์ผ. ์˜ˆยท์ ๊ธˆ ๊ณ„์ขŒ๋งŒ ๊ฐ’์ด ์žˆ๋‹ค
closed_date DATETIME(6) O ํ•ด์ง€์ผ.
closed_trade_date DATE O ํ•ด์ง€ ๋…ผ๋ฆฌ ์˜์—…์ผ. ํ•ด์ง€ ํŠธ๋žœ์žญ์…˜์ด ์˜์—…์ผ gate(BusinessDateGate)๋กœ ์ฝ์€ ๊ฐ’(๊ธฐํ‘œ๋ฅผ ๋‹ค๋ฅธ ์„œ๋น„์Šค์— ๋งก๊ธฐ๋ฉด ๊ทธ ๊ฒฐ๊ณผ์˜ tradeDate)์ด๋ฉฐ today()๋กœ ๋”ฐ๋กœ ์ฝ์ง€ ์•Š๋Š”๋‹ค. ์ •๋ณด๊ณ„ CLOSE ์ด๋ฒคํŠธ ๊ธฐ์ค€์ผ์ด๋ฉฐ ํ•ด์ง€ ๊ตฌํ˜„(PH-15ยท16)์ด ์ฑ„์šด๋‹ค
last_transaction_at DATETIME(6) O ์ตœ๊ทผ ๊ฑฐ๋ž˜ ์ผ์‹œ. ์ „์ฒด ๊ณ„์ขŒ ์กฐํšŒ์˜ lastTransactionAt
version BIGINT X 0 ๋‚™๊ด€์  ๋ฝ ๋ฒ„์ „. ๋ฐฐ์น˜ยท์กฐํšŒ ๊ฒฝ๋กœ์˜ ๊ฐฑ์‹  ์ถฉ๋Œ์„ ์žก๋Š”๋‹ค (์ด์ฒด ์‹คํ–‰ ๊ฒฝ๋กœ๋Š” ๋น„๊ด€์  ๋ฝ)
created_at DATETIME(6) X ํ–‰ ์ƒ์„ฑ ์ผ์‹œ. JPA Auditing์ด KST ๊ธฐ์ค€์œผ๋กœ ์ž๋™ ์„ค์ •
updated_at DATETIME(6) X ํ–‰ ์ตœ์ข… ์ˆ˜์ • ์ผ์‹œ. JPA Auditing์ด KST ๊ธฐ์ค€์œผ๋กœ ์ž๋™ ์„ค์ •

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
UNIQUE uk_account_number account_number
INDEX ix_account_customer customer_id, status
INDEX ix_account_withdrawal customer_id, withdrawal_registered

CHECK ์ œ์•ฝ

์ด๋ฆ„ ์กฐ๊ฑด ์„ค๋ช…
ck_account_balance balance >= 0 ๊ณ„์ขŒ ์ž”์•ก์€ 0์› ์ด์ƒ์ด์–ด์•ผ ํ•œ๋‹ค.
ck_account_hold_amount hold_amount >= 0 AND hold_amount <= balance ๋ณด๋ฅ˜์•ก์€ 0์› ์ด์ƒ์ด๋ฉฐ ์›์žฅ์ž”์•ก์„ ์ดˆ๊ณผํ•˜์ง€ ์•Š๋Š”๋‹ค.
ck_account_number account_number REGEXP '^[0-9]{12}$' ๊ณ„์ขŒ๋ฒˆํ˜ธ๋Š” ํ•˜์ดํ”ˆ ์—†๋Š” ์ˆซ์ž 12์ž๋ฆฌ์—ฌ์•ผ ํ•œ๋‹ค.
ck_account_type account_type IN ('DEMAND_DEPOSIT', 'TIME_DEPOSIT', 'INSTALLMENT_SAVINGS') ๊ณ„์ขŒ ์œ ํ˜•์€ ์ž…์ถœ๊ธˆยท์ •๊ธฐ์˜ˆ๊ธˆยท์ •๊ธฐ์ ๊ธˆ ์ค‘ ํ•˜๋‚˜์—ฌ์•ผ ํ•œ๋‹ค.
ck_account_status status IN ('ACTIVE', 'SUSPENDED', 'MATURED', 'CLOSED', 'DORMANT') ๊ณ„์ขŒ ์ƒํƒœ๋Š” ์ •์ƒยท๊ฑฐ๋ž˜์ •์ง€ยท๋งŒ๊ธฐ ๋„๋‹ฌยทํ•ด์ง€ยทํœด๋ฉด ์ค‘ ํ•˜๋‚˜์—ฌ์•ผ ํ•œ๋‹ค.
ck_account_password_lock_state ์˜ค๋ฅ˜ ํšŸ์ˆ˜๊ฐ€ 0~4์ด๋ฉด password_locked = FALSE, ์˜ค๋ฅ˜ ํšŸ์ˆ˜๊ฐ€ 5์ด๋ฉด password_locked = TRUE ๊ณ„์ขŒ๋น„๋ฐ€๋ฒˆํ˜ธ ์—ฐ์† ์˜ค๋ฅ˜ ํšŸ์ˆ˜์™€ ์ž ๊ธˆ ์ƒํƒœ๊ฐ€ ํ•ญ์ƒ ์ผ์น˜ํ•ด์•ผ ํ•œ๋‹ค.
ck_account_withdrawal_registered withdrawal_registered IN (FALSE, TRUE) ์ถœ๊ธˆ๊ณ„์ขŒ ๋“ฑ๋ก ์—ฌ๋ถ€๋Š” Boolean ๊ฐ’์ด์–ด์•ผ ํ•œ๋‹ค.
ck_account_product DEMAND_DEPOSIT์ด๋ฉด product_id IS NULL
TIME_DEPOSIT ๋˜๋Š” INSTALLMENT_SAVINGS์ด๋ฉด product_id IS NOT NULL
์ž…์ถœ๊ธˆ๊ณ„์ขŒ์—๋Š” ์ƒํ’ˆ์ด ์—ฐ๊ฒฐ๋˜์ง€ ์•Š๊ณ , ์˜ˆยท์ ๊ธˆ๊ณ„์ขŒ์—๋Š” ์ƒํ’ˆ์ด ๋ฐ˜๋“œ์‹œ ์—ฐ๊ฒฐ๋˜์–ด์•ผ ํ•œ๋‹ค.
ck_account_maturity DEMAND_DEPOSIT์ด๋ฉด maturity_date IS NULL
TIME_DEPOSIT ๋˜๋Š” INSTALLMENT_SAVINGS์ด๋ฉด maturity_date IS NOT NULL AND maturity_date >= opened_date
์ž…์ถœ๊ธˆ๊ณ„์ขŒ์—๋Š” ๋งŒ๊ธฐ์ผ์ด ์—†๊ณ , ์˜ˆยท์ ๊ธˆ๊ณ„์ขŒ์˜ ๋งŒ๊ธฐ์ผ์€ ๊ฐœ์„ค์ผ ์ดํ›„์—ฌ์•ผ ํ•œ๋‹ค.
ck_account_withdrawal_type withdrawal_registered = FALSE OR account_type = 'DEMAND_DEPOSIT' ์ถœ๊ธˆ๊ณ„์ขŒ ๋“ฑ๋ก์€ ์ž…์ถœ๊ธˆ๊ณ„์ขŒ์—๋งŒ ํ—ˆ์šฉํ•œ๋‹ค.
ck_account_withdrawal_registered_at ๋ฏธ๋“ฑ๋ก์ด๋ฉด withdrawal_registered_at IS NULL
๋“ฑ๋ก์ด๋ฉด withdrawal_registered_at IS NOT NULL
์ถœ๊ธˆ๊ณ„์ขŒ ๋“ฑ๋ก ์—ฌ๋ถ€์™€ ๋“ฑ๋ก ์ผ์‹œ์˜ ์กด์žฌ ์—ฌ๋ถ€๊ฐ€ ์ผ์น˜ํ•ด์•ผ ํ•œ๋‹ค.
ck_account_closed_date CLOSED์ด๋ฉด closed_date IS NOT NULL AND closed_date >= opened_date
CLOSED๊ฐ€ ์•„๋‹ˆ๋ฉด closed_date IS NULL
ํ•ด์ง€ ๊ณ„์ขŒ์—๋Š” ๊ฐœ์„ค์ผ ์ดํ›„์˜ ํ•ด์ง€์ผ์ด ์žˆ์–ด์•ผ ํ•˜๋ฉฐ, ๋ฏธํ•ด์ง€ ๊ณ„์ขŒ์—๋Š” ํ•ด์ง€์ผ์ด ์—†์–ด์•ผ ํ•œ๋‹ค.

account_status_history

๊ณ„์ขŒ ์ƒํƒœ ์ „์ด ๊ฐ์‚ฌ ์ด๋ ฅ (PH-15, #671)

๊ณ„์ขŒ ์ƒํƒœ ๋ณ€๊ฒฝ ์‹œ ์ „์ด ์ „ยทํ›„ ์ƒํƒœ์™€ ์ฒ˜๋ฆฌ ์‹œ๊ฐ์„ ๊ธฐ๋กํ•˜๋Š” append-only ํ…Œ์ด๋ธ”์ด๋‹ค. COB์˜ ACTIVE โ†’ MATURED ์ „์ด์™€ ๊ณ ๊ฐ ์š”์ฒญ ๋งŒ๊ธฐํ•ด์ง€์˜ MATURED โ†’ CLOSED ์ „์ด๋ฅผ ๊ธฐ๋กํ•œ๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
history_id BIGINT PK X AUTO_INCREMENT ์ด๋ ฅ ์‹๋ณ„์ž
account_id BIGINT INDEX X ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋œ ๊ณ„์ขŒ ID
previous_status VARCHAR(12) X ๋ณ€๊ฒฝ ์ „ ๊ณ„์ขŒ ์ƒํƒœ. ๋งŒ๊ธฐ ์ „์ด๋Š” ACTIVE, ๋งŒ๊ธฐํ•ด์ง€๋Š” MATURED
new_status VARCHAR(12) X ๋ณ€๊ฒฝ ํ›„ ๊ณ„์ขŒ ์ƒํƒœ. ๋งŒ๊ธฐ ์ „์ด๋Š” MATURED, ๋งŒ๊ธฐํ•ด์ง€๋Š” CLOSED
maturity_date DATE O ๊ณ„์•ฝ ๋งŒ๊ธฐ์ผ
effective_business_date DATE O ๋งŒ๊ธฐ ์ „์ด๋Š” COB์—์„œ ๊ณ„์‚ฐํ•œ ๋งŒ๊ธฐ ์ „์ด ๊ธฐ์ค€์ผ, ๋งŒ๊ธฐํ•ด์ง€๋Š” MATURITY ์ถœ๊ธˆ ์›์žฅ์˜ ์‹ค์ œ ๊ฑฐ๋ž˜์ผ(tradeDate)
changed_at DATETIME(6) INDEX X ์‹ค์ œ ์ƒํƒœ ์ „์ด ์ฒ˜๋ฆฌ ์‹œ๊ฐ
trigger_type VARCHAR(20) X ์ „์ด ๋ฐœ์ƒ ์›์ธ. COB(๋ฐฐ์น˜ ๋งŒ๊ธฐ ์ „์ด) / CUSTOMER(๊ณ ๊ฐ ์š”์ฒญ ๋งŒ๊ธฐํ•ด์ง€)

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
PRIMARY PRIMARY history_id
INDEX ix_account_status_history_account_time account_id, changed_at

interest_payment

์˜ˆ์ ๊ธˆ ์ด์ž ์ง€๊ธ‰ ์ด๋ ฅ (PH-14, #687)

์˜ˆ์ ๊ธˆ ๋งŒ๊ธฐํ•ด์ง€ ๋˜๋Š” ์ค‘๋„ํ•ด์ง€ ์‹œ ๊ณ„์‚ฐ๋œ ์ด์ž์™€ ์›์ฒœ์„ธ, ์‹ค์ œ ์›์žฅ ๊ธฐํ‘œ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋กํ•œ๋‹ค.

ํ•œ ๊ณ„์ขŒ์— ๋Œ€ํ•ด ์ด์ž ์ง€๊ธ‰ ์ด๋ ฅ์€ ์ตœ๋Œ€ 1๊ฑด์ด๋‹ค. account_id์˜ UNIQUE ์ œ์•ฝ์œผ๋กœ ์ค‘๋ณต ์ง€๊ธ‰์„ ๋ฐฉ์ง€ํ•˜๋ฉฐ, ์›์žฅยทGLยท๊ณ„์ขŒ ํ•ด์ง€ ์ฒ˜๋ฆฌ์™€ ๋™์ผํ•œ ํŠธ๋žœ์žญ์…˜์—์„œ ์ €์žฅํ•œ๋‹ค.

์„ธํ›„์ด์ž๊ฐ€ 0์›์ด๋ฉด ์›์žฅ์„ ๊ธฐํ‘œํ•˜์ง€ ์•Š์ง€๋งŒ ์ง€๊ธ‰ ์ด๋ ฅ์€ ๋‚จ๊ธด๋‹ค. ์ด ๊ฒฝ์šฐ transaction_number์™€ trade_date๋Š” NULL์ด๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
interest_payment_id BIGINT PK X AUTO_INCREMENT ์ด์ž ์ง€๊ธ‰ ์ด๋ ฅ ์‹๋ณ„์ž
account_id BIGINT UK X ์ง€๊ธ‰ ๋Œ€์ƒ ์ƒํ’ˆ ๊ณ„์ขŒ ID. ๊ณ„์ขŒ๋‹น ์ด์ž ์ง€๊ธ‰ 1ํšŒ ๋ณด์žฅ. ๋ฌผ๋ฆฌ์  FK ์—†์Œ
payment_reason VARCHAR(12) X ์ง€๊ธ‰ ์‚ฌ์œ . MATURITY(๋งŒ๊ธฐํ•ด์ง€) / TERMINATION(์ค‘๋„ํ•ด์ง€)
gross_amount BIGINT X ์„ธ์ „์ด์ž. ์› ๋‹จ์œ„ ์ •์ˆ˜
tax_amount BIGINT X ์›์ฒœ์ง•์ˆ˜ ์„ธ๊ธˆ ํ•ฉ๊ณ„. ์› ๋‹จ์œ„ ์ •์ˆ˜
net_amount BIGINT X ์„ธํ›„์ด์ž. gross_amount - tax_amount
transaction_number CHAR(20) UK O INTEREST ์›์žฅ ๊ธฐํ‘œ ๊ฑฐ๋ž˜๋ฒˆํ˜ธ. ์ง€๊ธ‰์•ก 0์›์ด๋ฉด NULL
trade_date DATE O ์ด์ž ์›์žฅ ๊ฑฐ๋ž˜์ผ. LedgerDepositResult.tradeDate ์‚ฌ์šฉ. ์ง€๊ธ‰์•ก 0์›์ด๋ฉด NULL
paid_at DATETIME(6) X ์ด์ž ์ง€๊ธ‰ ์ฒ˜๋ฆฌ ์ผ์‹œ (KST)

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
PRIMARY PRIMARY interest_payment_id
UNIQUE uk_interest_payment_account account_id
UNIQUE uk_interest_payment_tx transaction_number

CHECK ์ œ์•ฝ

์ด๋ฆ„ ์กฐ๊ฑด ์„ค๋ช…
ck_interest_payment_amount gross_amount >= 0 AND tax_amount >= 0 AND tax_amount <= gross_amount AND net_amount = gross_amount - tax_amount ์„ธ์ „์ด์žยท์„ธ๊ธˆยท์„ธํ›„์ด์ž ์ •ํ•ฉ์„ฑ
ck_interest_payment_ledger net_amount = 0์ด๋ฉด ๊ฑฐ๋ž˜๋ฒˆํ˜ธยท๊ฑฐ๋ž˜์ผ ๋ชจ๋‘ NULL, net_amount > 0์ด๋ฉด ๋ชจ๋‘ NOT NULL ์‹ค์ œ ์›์žฅ ๊ธฐํ‘œ ์—ฌ๋ถ€์™€ ๊ฑฐ๋ž˜ ์‹๋ณ„์ž ์ผ์น˜

account_number_sequence

์€ํ–‰ยท์ƒํ’ˆ๋ณ„ ๊ณ„์ขŒ๋ฒˆํ˜ธ ์ฑ„๋ฒˆ

์€ํ–‰ยท๊ณ„์ขŒ ์œ ํ˜•ยท์ƒํ’ˆ๋ณ„ ๊ณ„์ขŒ๋ฒˆํ˜ธ ๋ฐœ๊ธ‰ ๊ทœ์น™๊ณผ ๋งˆ์ง€๋ง‰ ๋ฐœ๊ธ‰ ์ผ๋ จ๋ฒˆํ˜ธ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.

๊ณ„์ขŒ๋ฒˆํ˜ธ ๊ตฌ์„ฑ

์€ํ–‰์ฝ”๋“œ 3์ž๋ฆฌ + ์ƒํ’ˆ Prefix 2์ž๋ฆฌ + ์ผ๋ จ๋ฒˆํ˜ธ 7์ž๋ฆฌ
์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… NULL ํ—ˆ์šฉ ๊ธฐ๋ณธ๊ฐ’ ํ‚ค ์„ค๋ช…
sequence_id BIGINT X AUTO_INCREMENT PK ๊ณ„์ขŒ๋ฒˆํ˜ธ ์ฑ„๋ฒˆ ๊ทœ์น™ ์‹๋ณ„์ž
bank_code CHAR(3) X ์—†์Œ ๊ณ„์ขŒ๋ฒˆํ˜ธ ์•ž 3์ž๋ฆฌ์— ํฌํ•จ๋˜๋Š” ์€ํ–‰์ฝ”๋“œ
account_type VARCHAR(24) X ์—†์Œ ๊ณ„์ขŒ ์œ ํ˜• (DEMAND_DEPOSIT, TIME_DEPOSIT, INSTALLMENT_SAVINGS)
product_id BIGINT O NULL FK ์—ฐ๊ฒฐ ์ƒํ’ˆ ์‹๋ณ„์ž. ์ž…์ถœ๊ธˆ๊ณ„์ขŒ๋Š” NULL
product_prefix CHAR(2) X ์—†์Œ ๊ณ„์ขŒ๋ฒˆํ˜ธ์— ํฌํ•จ๋˜๋Š” ์ƒํ’ˆ๋ณ„ Prefix
last_sequence BIGINT X 0 ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ฐœ๊ธ‰ํ•œ 7์ž๋ฆฌ ์ผ๋ จ๋ฒˆํ˜ธ
created_at DATETIME(6) X ์—†์Œ ์ฑ„๋ฒˆ ๊ทœ์น™ ์ƒ์„ฑ ์ผ์‹œ
updated_at DATETIME(6) X ์—†์Œ ์ฑ„๋ฒˆ ๊ทœ์น™ ์ตœ์ข… ์ˆ˜์ • ์ผ์‹œ

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ ์šฉ๋„
PRIMARY PRIMARY sequence_id ์ฑ„๋ฒˆ ๊ทœ์น™ ์‹๋ณ„ ๋ฐ PK ์กฐํšŒ
UNIQUE uk_account_number_sequence_prefix bank_code, product_prefix ๊ฐ™์€ ์€ํ–‰ ๋‚ด Prefix ์ค‘๋ณต ๋ฐฉ์ง€
UNIQUE uk_account_number_sequence_rule bank_code, COALESCE(product_id, 0) ๊ฐ™์€ ์ž…์ถœ๊ธˆ, ์˜ˆยท์ ๊ธˆ ์ƒํ’ˆ์˜ ์ฑ„๋ฒˆ ๊ทœ์น™ ์ค‘๋ณต ๋ฐฉ์ง€
INDEX ix_account_number_sequence_lookup bank_code, account_type, product_id ๊ณ„์ขŒ๋ฒˆํ˜ธ ๋ฐœ๊ธ‰ ์‹œ ์ฑ„๋ฒˆ ํ–‰ ์กฐํšŒ ๋ฐ ๋น„๊ด€์  ๋ฝ ๋ฒ”์œ„ ์ตœ์†Œํ™”
INDEX ix_account_number_sequence_product product_id ์ƒํ’ˆ FK ๊ฒ€์‚ฌ ๋ฐ ์ƒํ’ˆ ๊ธฐ์ค€ ์กฐํšŒ ์ง€์›

CHECK ์ œ์•ฝ

์ด๋ฆ„ ์กฐ๊ฑด ์„ค๋ช…
PRIMARY sequence_id (PK) ํ–‰๋ณ„ ๊ณ ์œ ๊ฐ’ (์ฑ„๋ฒˆ ๊ทœ์น™ ํ–‰ ์‹๋ณ„)
fk_account_number_sequence_product product_id (FK -> product.product_id) ์กด์žฌํ•˜๋Š” ์ƒํ’ˆ๋งŒ ์ฑ„๋ฒˆ ๊ทœ์น™ ์—ฐ๊ฒฐ ๊ฐ€๋Šฅ
ck_account_number_sequence_bank_code bank_code REGEXP '^[0-9]{3}$' (CHECK) ์€ํ–‰์ฝ”๋“œ ํ˜•์‹ ๊ฒ€์ฆ (์ˆซ์ž 3์ž๋ฆฌ)
ck_account_number_sequence_prefix product_prefix REGEXP '^[0-9]{2}$' (CHECK) ์ƒํ’ˆ Prefix ํ˜•์‹ ๊ฒ€์ฆ (์ˆซ์ž 2์ž๋ฆฌ)
ck_account_number_sequence_type account_type IN ('DEMAND_DEPOSIT', 'TIME_DEPOSIT', 'INSTALLMENT_SAVINGS') (CHECK) ํ—ˆ์šฉ๋œ ๊ณ„์ขŒ ์œ ํ˜• ์ค‘ ํ•˜๋‚˜์ธ์ง€ ๊ฒ€์ฆ
ck_account_number_sequence_product DEMAND_DEPOSIT์ด๋ฉด product_id IS NULL, ์˜ˆยท์ ๊ธˆ์ด๋ฉด product_id IS NOT NULL (CHECK) ์ž…์ถœ๊ธˆ์€ ์ƒํ’ˆ ์—†์Œ, ์˜ˆยท์ ๊ธˆ์€ ์ƒํ’ˆ ํ•„์ˆ˜ (์ •ํ•ฉ์„ฑ ๋ณด์žฅ)
ck_account_number_sequence_value last_sequence BETWEEN 0 AND 9999999 (CHECK) ์ผ๋ จ๋ฒˆํ˜ธ๊ฐ€ 7์ž๋ฆฌ ๋ฒ”์œ„(0 ~ 9,999,999)๋ฅผ ์ดˆ๊ณผํ•˜์ง€ ์•Š๋„๋ก ์ œํ•œ

4. ์ด์ฒด ยท ์›์žฅ โ€” P4

transaction_sequence

๊ฑฐ๋ž˜๋ฒˆํ˜ธ ์ผ๋ จ๋ฒˆํ˜ธ ์ฑ„๋ฒˆ (๋น„๊ด€์  ๋ฝ ๋Œ€์ƒ 0์ˆœ์œ„)

๊ฑฐ๋ž˜๋ฒˆํ˜ธ ์ผ๋ จ 10์ž๋ฆฌ๋ฅผ ์ฑ„๋ฒˆํ•œ๋‹ค. ์ผ์žยท์ฑ„๋„๋ณ„๋กœ ๋งค์ผ 0๋ถ€ํ„ฐ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๋ฏ€๋กœ AUTO_INCREMENT๋กœ ๋งŒ๋“ค ์ˆ˜ ์—†๋‹ค. ์ „ ๊ณ ๊ฐ์ด ๊ฐ™์€ ํ–‰์„ ๋‘๊ณ  ๊ฒฝํ•ฉํ•˜๋Š” ์œ ์ผํ•œ ์ง€์ ์ด๋ผ ๋ฝ ๋ณด์œ  ์‹œ๊ฐ„์„ ์ตœ์†Œ๋กœ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
seq_date DATE PK X ์ฑ„๋ฒˆ ๊ธฐ์ค€ ์˜์—…์ผ. KST ๊ธฐ์ค€์ด๋ฉฐ ๊ฑฐ๋ž˜๋ฒˆํ˜ธ ์•ž 8์ž๋ฆฌ์™€ ๊ฐ™๋‹ค
channel CHAR(2) PK X ์ฑ„๋„ ์ฝ”๋“œ. WB(์ธํ„ฐ๋„ท๋ฑ…ํ‚น) / BT(๋ฐฐ์น˜ยท์˜ˆ์•ฝ์ด์ฒด). ๊ฑฐ๋ž˜๋ฒˆํ˜ธ 9~10๋ฒˆ์งธ ์ž๋ฆฌ
last_seq BIGINT X 0 ํ•ด๋‹น ์ผ์žยท์ฑ„๋„์—์„œ ๋งˆ์ง€๋ง‰์œผ๋กœ ๋‚˜๊ฐ„ ์ผ๋ จ๋ฒˆํ˜ธ. ๋‹ค์Œ ๊ฑฐ๋ž˜๋Š” ์ด ๊ฐ’ + 1์„ ๋ฐ›๋Š”๋‹ค
updated_at DATETIME(6) X ๋งˆ์ง€๋ง‰ ์ฑ„๋ฒˆ ์‹œ๊ฐ

CHECK ์ œ์•ฝ

์ด๋ฆ„ ์กฐ๊ฑด
ck_txseq_range last_seq BETWEEN 0 AND 9999999999

transfer

์ด์ฒด ๊ฑฐ๋ž˜ (์ฆ‰์‹œยท์˜ˆ์•ฝยท์ž๋™ 3์ข…์˜ ๋‹จ์ผ ์ˆ˜๋ ด์ )

์ฆ‰์‹œยท์˜ˆ์•ฝยท์ž๋™์ด์ฒด 3์ข…์ด ๋ชจ๋‘ ์ด ํ…Œ์ด๋ธ” 1ํ–‰์œผ๋กœ ์ˆ˜๋ ดํ•œ๋‹ค. ์˜ˆ์•ฝยท์ž๋™์€ source_typeยทsource_id๋กœ ์›๋ณธ์„ ์—ญ์ถ”์ ํ•œ๋‹ค. status = ERROR์ธ ํ–‰์€ ์›์žฅ ๊ธฐํ‘œ๊ฐ€ 0ํ–‰์ด๋‹ค. ์˜ˆ์•ฝยท์ž๋™์ด์ฒด๋Š” uk_transfer_source_execution_date(source_type, source_id, execution_date)๋กœ ๊ฐ™์€ ํšŒ์ฐจ์˜ ์ค‘๋ณต ์‹คํ–‰์„ ์ƒํƒœ(SUCCESS/ERROR)์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ DB ๋ ˆ๋ฒจ์—์„œ ๋ง‰๋Š”๋‹ค โ€” ์ฆ‰์‹œ์ด์ฒด๋Š” ์„ธ ์ปฌ๋Ÿผ ๋ชจ๋‘ NULL์ด๋ผ ์ด ์ œ์•ฝ์˜ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค(MySQL์€ NULL์„ ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ’์œผ๋กœ ์ทจ๊ธ‰).

ํƒ€ํ–‰์ด์ฒด(PH-33-โ‘ก)๋„ ์ด ํ…Œ์ด๋ธ”์— ๋‚จ๋Š”๋‹ค. payee_bank_code๊ฐ€ ์žˆ์œผ๋ฉด ํƒ€ํ–‰, NULL์ด๋ฉด ๋‹นํ–‰์ด๋‹ค. ํƒ€ํ–‰์€ ์ˆ˜์ทจ ๊ณ„์ขŒ๊ฐ€ ๋‹นํ–‰ account์— ์—†์–ด deposit_account_id๊ฐ€ NULL์ด๊ณ , ์˜ˆ๊ธˆ์ฃผ๋Š” ์ƒ๋Œ€ ์€ํ–‰ ์‘๋‹ต(SUCCESS)์œผ๋กœ๋งŒ ๋ฐ›์•„ ERRORยทTIMEOUT ๊ฑด์€ payee_name๋„ NULL์ด๋‹ค. ๋‹นํ–‰ ํ–‰์€ ck_transfer_payee_accountยทck_transfer_payee_name์ด ์ง€๊ธˆ์ฒ˜๋Ÿผ ๋‘ ๊ฐ’์„ ๊ฐ•์ œํ•œ๋‹ค. ํƒ€ํ–‰ ์˜ˆ์•ฝยท์ž๋™์ด์ฒด๋Š” ์—†๋‹ค(์ฆ‰์‹œ์ด์ฒด๋งŒ).

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
transfer_id BIGINT PK X ์ด์ฒด ๊ฑฐ๋ž˜ ๋‚ด๋ถ€ ์‹๋ณ„์ž. ๋Œ€์™ธ ์‹๋ณ„์ž๋Š” transaction_number
transaction_number CHAR(20) UK X ๋Œ€์™ธ ๊ฑฐ๋ž˜ ์‹๋ณ„์ž. YYYYMMDD(8) + ์ฑ„๋„(2) + ์ผ๋ จ(10) = 20์ž. ์ด์ฒด ์ƒ์„ธ ์กฐํšŒ์˜ ๊ฒฝ๋กœ ๋ณ€์ˆ˜์ด์ž ์›์žฅ 2ํ–‰์„ ์ž‡๋Š” ํ‚ค
withdrawal_account_id BIGINT FK X ์ถœ๊ธˆ๊ณ„์ขŒ โ†’ account.account_id
deposit_account_id BIGINT FK O ์ž…๊ธˆ๊ณ„์ขŒ. ์›์žฅ ์ž…๊ธˆ ํ–‰์˜ account_id ๊ทผ๊ฑฐ โ†’ account.account_id. ๋‹นํ–‰ ๊ฑฐ๋ž˜๋Š” ํ•ญ์ƒ ๊ฐ’์ด ์žˆ๊ณ , ํƒ€ํ–‰ ๊ฑฐ๋ž˜๋Š” NULL์ด๋‹ค(์ˆ˜์ทจ ๊ณ„์ขŒ๊ฐ€ ๋‹นํ–‰์— ์—†๋‹ค)
deposit_account_number VARCHAR(16) X ์ž…๊ธˆ ๊ณ„์ขŒ๋ฒˆํ˜ธ. ์ˆซ์ž๋งŒ. ๋‹นํ–‰ 12์ž๋ฆฌ, ํƒ€ํ–‰ 1~16์ž๋ฆฌ(์ „๋ฌธ ๊ณ„์ขŒ๋ฒˆํ˜ธ ์นธ, ์ „๋ฌธ ๊ทœ๊ฒฉ ยง2)
payee_bank_code CHAR(3) O ํƒ€ํ–‰ ์ž…๊ธˆ ์€ํ–‰์ฝ”๋“œ(common_code BANK_CODE, ์ „๋ฌธ ๊ธฐ๊ด€์ฝ”๋“œ). NULL์ด๋ฉด ๋‹นํ–‰ ๊ฑฐ๋ž˜๋‹ค
payee_name VARCHAR(50) O ์ž…๊ธˆ๊ณ„์ขŒ ์˜ˆ๊ธˆ์ฃผ๋ช…. ๊ฑฐ๋ž˜ ์‹œ์  ์Šค๋ƒ…์ƒท์ด๋ผ ์ดํ›„ ์ƒ๋Œ€ ์ •๋ณด๊ฐ€ ๋ฐ”๋€Œ์–ด๋„ ๋‚จ๋Š”๋‹ค. ๋‹นํ–‰์€ ํ•ญ์ƒ ์žˆ๊ณ , ํƒ€ํ–‰์€ SUCCESS ์‘๋‹ต์ด ๋Œ๋ ค์ค€ ์ด๋ฆ„์ด๋ฉฐ ERRORยทTIMEOUT์ด๋ฉด NULL์ด๋‹ค
amount BIGINT X ์ด์ฒด๊ธˆ์•ก
fee BIGINT X 0 ์ˆ˜์ˆ˜๋ฃŒ. ๋‹นํ–‰ ์ด์ฒด๋Š” 0์œผ๋กœ ๊ณ ์ •
transfer_type VARCHAR(12) X ์ด์ฒด ์ข…๋ฅ˜. IMMEDIATE(์ฆ‰์‹œ) / SCHEDULED(์˜ˆ์•ฝ) / AUTO(์ž๋™)
channel CHAR(2) X ๊ฑฐ๋ž˜ ์ฑ„๋„. WB(์ธํ„ฐ๋„ท๋ฑ…ํ‚น) / BT(๋ฐฐ์น˜). ๊ฑฐ๋ž˜๋ฒˆํ˜ธ์˜ ์ฑ„๋„ 2์ž๋ฆฌ์™€ ๊ฐ™์€ ๊ฐ’
status VARCHAR(12) X ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ. SUCCESS(์ •์ƒ) / ERROR(์˜ค๋ฅ˜) / TIMEOUT(์ฒ˜๋ฆฌ ๋ถˆ๋ช… โ€” ๋Œ€์™ธ ์ „๋ฌธ ๋ฌด์‘๋‹ต์œผ๋กœ ์ƒ๋Œ€ ์ฒ˜๋ฆฌ ์—ฌ๋ถ€๋ฅผ ๋ชจ๋ฅธ๋‹ค. ์‹คํŒจ๊ฐ€ ์•„๋‹ˆ๋ฉฐ ์กฐํšŒ๊ฑฐ๋ž˜๋กœ ํ™•์ •ํ•œ๋‹ค, PH-80). PROCESSING์€ INSERT ์งํ›„์˜ ํŠธ๋žœ์žญ์…˜ ๋‚ด๋ถ€ ์ƒํƒœ๋ผ ์ปค๋ฐ‹๋œ ํ–‰์—๋Š” ๋‚˜ํƒ€๋‚˜์ง€ ์•Š๋Š”๋‹ค (#377)
source_type VARCHAR(12) O ์ด ์ด์ฒด๋ฅผ ๋งŒ๋“  ์›๋ณธ ๊ตฌ๋ถ„. SCHEDULED(์˜ˆ์•ฝ์ด์ฒด) / AUTO(์ž๋™์ด์ฒด). ์ฆ‰์‹œ์ด์ฒด๋Š” NULL
source_id BIGINT O ์˜ˆ์•ฝยท์ž๋™์ด์ฒด ์›๋ณธ PK. source_type๊ณผ ํ•จ๊ป˜ ์—ญ์ถ”์ ์— ์“ด๋‹ค
execution_date DATE O source_id์™€ ํ•จ๊ป˜ ๋ฉฑ๋“ฑํ‚ค๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ํšŒ์ฐจ ์‹คํ–‰์ผ์ž. SCHEDULED/AUTO ์ „์šฉ(์ฆ‰์‹œ์ด์ฒด๋Š” NULL). ๋ฐฐ์น˜๊ฐ€ ์‹ค์ œ๋กœ ํ˜ธ์ถœ๋œ ๋‚ ์งœ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ทธ ํšŒ์ฐจ์˜ ๋…ผ๋ฆฌ์  ์‹คํ–‰์ผ(scheduled_transfer.scheduled_date / auto_transfer_execution.execution_date)์ด ๋“ค์–ด๊ฐ€์•ผ ํฌ๋ž˜์‹œ ํ›„ ์žฌ์‹œ๋„๊ฐ€ ๊ฐ™์€ ํšŒ์ฐจ๋กœ ์‹๋ณ„๋œ๋‹ค
my_passbook_memo VARCHAR(10) O ๋‚ด ํ†ต์žฅ์— ์ฐํžˆ๋Š” ๋ฌธ๊ตฌ. ์ตœ๋Œ€ 10์ž
recipient_passbook_memo VARCHAR(10) O ๋ฐ›๋Š” ๋ถ„ ํ†ต์žฅ์— ์ฐํžˆ๋Š” ๋ฌธ๊ตฌ
withdrawal_balance_after BIGINT O ์ถœ๊ธˆ ์งํ›„ ์ถœ๊ธˆ๊ณ„์ขŒ ์ž”์•ก. ์„ฑ๊ณต ์‹œ์—๋งŒ ๊ฐ’์ด ์žˆ๋‹ค
error_code VARCHAR(10) O ์‹คํŒจ ์‹œ ์˜ค๋ฅ˜์ฝ”๋“œ
error_message VARCHAR(200) O ์‹คํŒจ ์‹œ ์‚ฌ์œ  ๋ฌธ๊ตฌ
transferred_at DATETIME(6) X ์ด์ฒด ์ฒ˜๋ฆฌ ์ผ์‹œ
trade_date DATE O ๊ฑฐ๋ž˜์ผ โ€” ์ด ์ด์ฒด๊ฐ€ ๊ท€์†๋˜๋Š” ์˜์—…์ผ. ๊ฑฐ๋ž˜ ํŠธ๋žœ์žญ์…˜์ด ์˜์—…์ผ gate(BusinessDateGate)๋กœ ์ฝ์€ ๊ฐ’์ด๋‹ค. ํœด์ผ ๊ฑฐ๋ž˜๋Š” ๋‹ค์Œ ์˜์—…์ผ์ด ๋œ๋‹ค(glossary 7๋ฒˆ). ์˜์—…์ผ ์ „ํ™˜(COB) ์ „์— gate๋ฅผ ์žก์€ ๊ฑฐ๋ž˜๋Š” ์ „ํ™˜ ์ด์ „ ์˜์—…์ผ, ์ „ํ™˜ ๋’ค ๊ฑฐ๋ž˜๋Š” ๋‹ค์Œ ์˜์—…์ผ์ด๋‹ค โ€” ์ „ํ™˜์€ ์ง„ํ–‰ ์ค‘ ๊ฑฐ๋ž˜๊ฐ€ ๋๋‚œ ๋’ค์—๋งŒ ์ผ์–ด๋‚œ๋‹ค(ADR-0008). ์„ฑ๊ณตยท์‹คํŒจ(ERROR) ํ–‰ ๋ชจ๋‘ ์ฑ„์šด๋‹ค โ€” ์‹คํŒจ ํ–‰์€ ์›์žฅ ์—†์ด ์ด ํ…Œ์ด๋ธ”์—๋งŒ ๋‚จ๊ณ , ๊ฑฐ๋ž˜์ผ์€ ERROR ๊ธฐ๋ก ํŠธ๋žœ์žญ์…˜์ด gate๋กœ ์ฝ์€ ๊ฐ’์ด๋‹ค. ์ž๋™ยท์˜ˆ์•ฝ์ด์ฒด๋Š” ํœด์ผ์—๋„ ์ง€์ •์ผ์— ์‹คํ–‰๋˜๋ฏ€๋กœ(REQ-AUTO-001), ํœด์ผ์— ์‹คํ–‰๋œ ํšŒ์ฐจ์˜ ๊ฑฐ๋ž˜์ผ๋„ ๋‹ค์Œ ์˜์—…์ผ์ด๋‹ค โ€” ์‹คํ–‰์ผ(execution_date, ๋‹ฌ๋ ฅ ๋‚ ์งœ)๊ณผ ๊ฑฐ๋ž˜์ผ์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค. ์ •์ • ๊ฑฐ๋ž˜(์ทจ์†Œ์ •์ •ยท์ •์ƒ๊ฑฐ๋ž˜)๋Š” ์›๊ฑฐ๋ž˜์ผ์ด ์•„๋‹ˆ๋ผ ์ •์ •ํ•œ ๋‚ ์˜ ์˜์—…์ผ์ด๋‹ค. #516 ๋Œ€์ž… ์ „ ํ–‰์€ NULL์ด๋‹ค
invalidated_at DATETIME(6) O ์ •์ • ์ฒด์ธ์œผ๋กœ ๋ฌดํšจํ™”๋œ ์‹œ๊ฐ. NULL์ด๋ฉด ์œ ํšจํ•œ ๊ฑฐ๋ž˜๋‹ค. ๋ฌดํšจํ™”๋Š” status๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค โ€” status๋Š” ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ(์„ฑ๊ณตยท์‹คํŒจ)์ด๊ณ  ๋ฌดํšจํ™”๋Š” ๊ทธ ๋’ค์— ์ผ์–ด๋‚˜๋Š” ๋ณ„๊ฐœ์˜ ์‚ฌ๊ฑด์ด๋‹ค. SUCCESS์ธ ์›๊ฑฐ๋ž˜๋งŒ ๋ฌดํšจํ™”๋˜๋ฉฐ ํ•œ ๋ฒˆ ๋ฌดํšจํ™”๋˜๋ฉด ๋˜๋Œ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค(PH-80)
ref_transfer_id BIGINT FK O ์ •์ • ์ฒด์ธ์˜ ์›๊ฑฐ๋ž˜ โ†’ transfer.transfer_id. ์ทจ์†Œ์ •์ •ยท์ •์ƒ๊ฑฐ๋ž˜ ๋ชจ๋‘ ์›๊ฑฐ๋ž˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋ฏ€๋กœ ์›๊ฑฐ๋ž˜ ํ•˜๋‚˜๋กœ ์ฒด์ธ ์ „์ฒด๋ฅผ ์ฐพ๋Š”๋‹ค. ์ผ๋ฐ˜ ๊ฑฐ๋ž˜๋Š” NULL
correction_type VARCHAR(12) O ์ •์ • ์ฒด์ธ์—์„œ์˜ ์—ญํ• . REVERSAL(์ทจ์†Œ์ •์ • โ€” ์›๊ฑฐ๋ž˜์™€ ๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ) / REPOST(์ •์ƒ๊ฑฐ๋ž˜ โ€” ์›๋ž˜ ์˜๋„ํ•œ ๊ฑฐ๋ž˜). ์ผ๋ฐ˜ ๊ฑฐ๋ž˜๋Š” NULL. ref_transfer_id์™€ ํ•จ๊ป˜ ์žˆ๊ฑฐ๋‚˜ ํ•จ๊ป˜ ์—†๋‹ค
created_at DATETIME(6) X ํ–‰ ์ƒ์„ฑ ์ผ์‹œ

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
UNIQUE uk_transfer_txno transaction_number
INDEX ix_transfer_wacc withdrawal_account_id, transferred_at DESC
INDEX ix_transfer_status_created status, created_at โ€” ์กฐํšŒ๊ฑฐ๋ž˜ ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ 1๋ถ„๋งˆ๋‹ค ์ฒ˜๋ฆฌ ๋ถˆ๋ช…(TIMEOUT) ํƒ€ํ–‰ ๊ฑด์„ ์ฐพ๋Š”๋‹ค(PH-33-โ‘ก)
UNIQUE uk_transfer_source_execution_date source_type, source_id, execution_date โ€” ์˜ˆ์•ฝยท์ž๋™์ด์ฒด ์ฒ˜๋ฆฌ๊ฒฐ๊ณผ์˜ ๊ฑฐ๋ž˜์ผ ์กฐํšŒ(transfer.api.TransferTradeDateQuery, #679)๋„ ์ด ์ธ๋ฑ์Šค๋กœ ์ฝ๋Š”๋‹ค
UNIQUE uk_transfer_correction ref_transfer_id, correction_type โ€” ์›๊ฑฐ๋ž˜ ํ•˜๋‚˜์— ์ทจ์†Œ์ •์ •ยท์ •์ƒ๊ฑฐ๋ž˜๋Š” ๊ฐ๊ฐ 1๊ฑด. ๋™์‹œ ์ •์ •์„ DB๊ฐ€ ๋ง‰๋Š”๋‹ค

CHECK ์ œ์•ฝ

์ด๋ฆ„ ์กฐ๊ฑด
ck_transfer_amount amount > 0
ck_transfer_fee fee >= 0
ck_transfer_selfsend withdrawal_account_id <> deposit_account_id โ€” ํƒ€ํ–‰์€ deposit_account_id๊ฐ€ NULL์ด๋ผ ํ•ด๋‹น ์—†์Œ
ck_transfer_payee_account (payee_bank_code IS NULL) = (deposit_account_id IS NOT NULL) โ€” ๋‹นํ–‰์€ ์ž…๊ธˆ๊ณ„์ขŒ ID ํ•„์ˆ˜, ํƒ€ํ–‰์€ ์—†์Œ
ck_transfer_payee_name payee_bank_code IS NOT NULL OR payee_name IS NOT NULL โ€” ๋‹นํ–‰์€ ์˜ˆ๊ธˆ์ฃผ ํ•„์ˆ˜
ck_transfer_correction_type correction_type IN ('REVERSAL', 'REPOST')
ck_transfer_correction_ref (correction_type IS NULL) = (ref_transfer_id IS NULL) โ€” ๋ฐ˜์ชฝ ์ •์ • ๊ธˆ์ง€

ledger_entry

์›์žฅ (APPEND-ONLY. UPDATE/DELETE ๊ธˆ์ง€)

APPEND-ONLY. UPDATEยทDELETE๋ฅผ ๊ธˆ์ง€ํ•œ๋‹ค. ์ทจ์†Œ๋Š” ๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ ๊ธฐํ‘œ๋ฅผ ์ƒˆ๋กœ ์Œ“๋Š”๋‹ค. ์˜ˆ์™ธ๋Š” reversed ํ•˜๋‚˜๋‹ค โ€” ๋ฐ˜๋Œ€๊ธฐํ‘œ๋ฅผ ์Œ“์„ ๋•Œ ์›๊ฑฐ๋ž˜ ํ–‰์˜ ์ด ๊ฐ’๋งŒ FALSEโ†’TRUE๋กœ ํ•œ ๋ฒˆ ์„ธ์šด๋‹ค(์ •์ • ์ฒด์ธ, PH-80). ๊ธˆ์•กยท์ž”์•กยท์‹œ๊ฐ์€ ์–ด๋–ค ๊ฒฝ์šฐ์—๋„ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค. occurred_at ๊ธฐ์ค€ RANGE ํŒŒํ‹ฐ์…˜์ด๋ผ FK๋ฅผ ์„ ์–ธํ•  ์ˆ˜ ์—†๊ณ , ํŒŒํ‹ฐ์…˜ ํ‚ค๊ฐ€ PK์— ํฌํ•จ๋ผ์•ผ ํ•ด์„œ PK๊ฐ€ ๋ณตํ•ฉํ‚ค๋‹ค. ํŒŒํ‹ฐ์…˜ ๋ฒ”์œ„์™€ ์œ ์ง€๋ณด์ˆ˜ ์ ˆ์ฐจ๋Š” flyway_guide.md ยง5๋ฅผ ๋”ฐ๋ฅธ๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
ledger_entry_id BIGINT PK X ์›์žฅ ํ–‰ ์‹๋ณ„์ž. ๊ฑฐ๋ž˜๋‚ด์—ญ ์กฐํšŒ ์‘๋‹ต์˜ ledgerEntryId
account_id BIGINT X ๊ธฐํ‘œ ๋Œ€์ƒ ๊ณ„์ขŒ
transfer_id BIGINT O ์›๋ณธ ์ด์ฒด ๊ฑฐ๋ž˜. ์ƒํ’ˆ๊ฐ€์ž… ์ดˆ์ž…๊ธˆยท์ด์ž ์ง€๊ธ‰์ฒ˜๋Ÿผ ์ด์ฒด๊ฐ€ ์•„๋‹Œ ๊ธฐํ‘œ๋Š” NULL
transaction_number CHAR(20) X ์ด ๊ธฐํ‘œ๊ฐ€ ์†ํ•œ ๊ฑฐ๋ž˜๋ฒˆํ˜ธ. ์ถœ๊ธˆ ํ–‰๊ณผ ์ž…๊ธˆ ํ–‰์ด ๊ฐ™์€ ๊ฐ’์„ ๊ฐ–๋Š”๋‹ค. ์ง ์—†๋Š” 1ํ–‰(OPENINGยทINTEREST)์€ ์ด ๋ฒˆํ˜ธ๋ฅผ ํ˜ผ์ž ์“ด๋‹ค
direction VARCHAR(10) X ๊ธฐํ‘œ ๋ฐฉํ–ฅ. DEPOSIT(์ž…๊ธˆ) / WITHDRAWAL(์ถœ๊ธˆ). ๊ธˆ์•ก์€ ๋Š˜ ์–‘์ˆ˜๋ผ ๋ถ€ํ˜ธ ์—ญํ• ์„ ์ด ์ปฌ๋Ÿผ์ด ํ•œ๋‹ค
amount BIGINT X ๊ธฐํ‘œ ๊ธˆ์•ก. ํ•ญ์ƒ ์–‘์ˆ˜
balance_after BIGINT X ์ด ๊ธฐํ‘œ ์งํ›„์˜ ๊ณ„์ขŒ ์ž”์•ก ์Šค๋ƒ…์ƒท. ํ†ต์žฅ ํ˜•ํƒœ๋กœ ๋ณด์—ฌ์ค„ ๋•Œ ์“ด๋‹ค
transaction_type VARCHAR(32) X ๊ธฐํ‘œ๋ฅผ ์ผ์œผํ‚จ ์—…๋ฌด. OPENING(๊ฐœ์‹œ ์ž”์•ก, ์ง ์—†๋Š” 1ํ–‰์ด๋ฉฐ ์ƒ๋Œ€ํŽธ์€ GL ๊ฐœ์‹œ ์ „ํ‘œ) / IMMEDIATE_TRANSFER / SCHEDULED_TRANSFER / AUTO_TRANSFER / PRODUCT_SUBSCRIPTION(๊ฐ€์ž… ์ดˆ์ž…๊ธˆ) / INTEREST(์ด์ž, ์ง ์—†๋Š” 1ํ–‰์ด๋ฉฐ ์ƒ๋Œ€ํŽธ์€ GL ์ด์ž ์ „ํ‘œ) / MATURITY(๋งŒ๊ธฐํ•ด์ง€, ์ƒํ’ˆ ๊ณ„์ขŒ โ†’ ๊ณ ๊ฐ ๊ณ„์ขŒ 2ํ–‰) / TERMINATION(์ค‘๋„ํ•ด์ง€, ์ƒํ’ˆ ๊ณ„์ขŒ โ†’ ๊ณ ๊ฐ ๊ณ„์ขŒ 2ํ–‰) / REVERSAL(๋ฐ˜๋Œ€๊ธฐํ‘œ) / INTERBANK_TRANSFER(ํƒ€ํ–‰์ด์ฒด ์ถœ๊ธˆ, ์ง ์—†๋Š” 1ํ–‰์ด๋ฉฐ ์ƒ๋Œ€ํŽธ์€ GL ๋ฏธ๊ฒฐ์ œ ์ „ํ‘œ. ์‹คํŒจ๋กœ ํ™•์ •๋˜๋ฉด ๊ฐ™์€ ๊ฑฐ๋ž˜๋ฒˆํ˜ธ๋กœ reversal_id๊ฐ€ ์› ์ถœ๊ธˆ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋˜๋Œ๋ฆผ ์ž…๊ธˆ 1ํ–‰์ด ๋ถ™๊ณ  ์› ์ถœ๊ธˆ์€ reversed๊ฐ€ ์„ ๋‹ค). INTERESTยทMATURITYยทTERMINATION์€ ์ž…๊ธˆ ๊ณ„์•ฝ transfer.api.LedgerDepositUseCase(#595)๋งŒ ๋‚จ๊ธด๋‹ค
transaction_content VARCHAR(10) O ํ†ต์žฅ์— ์ฐํžˆ๋Š” ์ ์š”. ์ตœ๋Œ€ 10์ž
channel CHAR(2) X ๊ฑฐ๋ž˜ ์ฑ„๋„. WB / BT
reversed BOOLEAN X FALSE ๋ฐ˜๋Œ€๊ธฐํ‘œ๋กœ ์ทจ์†Œ๋œ ์›๊ฑฐ๋ž˜์ธ์ง€ ์—ฌ๋ถ€. ์›๋ณธ์„ ์ง€์šฐ์ง€ ์•Š๊ณ  ์ด ๊ฐ’๋งŒ ์„ธ์šด๋‹ค
reversal_id BIGINT O ๋ฐ˜๋Œ€๊ธฐํ‘œ ํ–‰์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ์›๊ฑฐ๋ž˜์˜ ledger_entry_id
occurred_at DATETIME(6) PK X ๊ธฐํ‘œ ๋ฐœ์ƒ ์ผ์‹œ. RANGE ํŒŒํ‹ฐ์…˜ ํ‚ค์ด๋ฉฐ ๊ฑฐ๋ž˜๋‚ด์—ญ ์กฐํšŒ์˜ ๊ธฐ๊ฐ„ ์กฐ๊ฑด์ด ์ด ์ปฌ๋Ÿผ์— ๊ฑธ๋ฆฐ๋‹ค. ์˜จ๋ผ์ธ ๊ฑฐ๋ž˜ ๊ฒฝ๋กœ(์ด์ฒดยท์ƒํ’ˆ๊ฐ€์ž… ์ž…๊ธˆ)๋Š” ๊ณ„์ขŒ ๋ฝ์„ ์ฅ” ๋’ค ์ด ์‹œ๊ฐ์„ ์ฐ์œผ๋ฏ€๋กœ, ์‹œ๊ณ„๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ํ๋ฅด๋Š” ๋™์•ˆ์—๋Š” ๊ฐ™์€ ๊ณ„์ขŒ์˜ ์ž”์•ก ๋ฐ˜์˜ ์ˆœ์„œ์™€ ๊ฐ™๋‹ค. ์ ์ˆ˜ยท๊ฑฐ๋ž˜๋‚ด์—ญ์€ occurred_at DESC, ledger_entry_id DESC ์ˆœ์œผ๋กœ ๋งˆ์ง€๋ง‰ ์ž”์•ก์„ ๊ณ ๋ฅธ๋‹ค. ๋ฝ์„ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  ์ง์ ‘ ์ ์žฌํ•˜๋Š” ์‹œ๋“œ(Phase2MinimumSeedServiceยทlocal-demo-data.sql)๋Š” ์ด ๊ณ„์•ฝ์˜ ๋Œ€์ƒ์ด ์•„๋‹ˆ๋‹ค(#545)
trade_date DATE O ๊ฑฐ๋ž˜์ผ โ€” ์ด ๊ธฐํ‘œ๊ฐ€ ๊ท€์†๋˜๋Š” ์˜์—…์ผ. occurred_at(๋ฐœ์ƒ ์‹œ๊ฐ)๊ณผ ๋‹ค๋ฅด๋‹ค. ๊ฐ’ ๊ทœ์น™์€ transfer.trade_date์™€ ๊ฐ™๋‹ค. ์›์žฅ์„ ์“ฐ๋Š” ๋ชจ๋“  ๊ฒฝ๋กœ(์ด์ฒดยท์ •์ •ยท์ƒํ’ˆ๊ฐ€์ž… ์ž…๊ธˆยท์˜ˆ์ ๊ธˆ ์ž…๊ธˆ ๊ณ„์•ฝ)๊ฐ€ ์ฑ„์šด๋‹ค. #516 ๋Œ€์ž… ์ „ ํ–‰์€ NULL์ด๋‹ค. P6 ์‹œ๋“œ(PH-60b)๋Š” GL๊ณผ ๊ฐ™์€ ๊ฑฐ๋ž˜์ผ์„ ๋„ฃ๋Š”๋‹ค

trade_date ๋Š” NULL ์„ ํ—ˆ์šฉํ•œ๋‹ค(Expand). NOT NULL ์ œ์•ฝ์€ ๊ฑธ์ง€ ์•Š๋Š”๋‹ค โ€” 300๋งŒ ํ–‰ ํŒŒํ‹ฐ์…˜ ํ…Œ์ด๋ธ” ์žฌ๊ตฌ์„ฑ์„ ํ”ผํ•˜๋ ค๊ณ , ์ƒˆ ํ–‰์˜ ํ•„์ˆ˜ ์—ฌ๋ถ€๋Š” ๋„๋ฉ”์ธ ํŒฉํ† ๋ฆฌ๊ฐ€ ๋ง‰๋Š”๋‹ค(#515 A์•ˆ). ๊ธฐ์กด ํ–‰ ์ฑ„์šฐ๊ธฐ๋Š” #515์—์„œ ํ•œ๋‹ค. ๊ฑฐ๋ž˜์ผ๋กœ ์กฐํšŒํ•˜๋Š” ๊ณณ์ด ์•„์ง ์—†์–ด ์ธ๋ฑ์Šค๋Š” ๋‘์ง€ ์•Š๋Š”๋‹ค. gl_journal_entry ๋Š” ์‹œ์‚ฐํ‘œ๊ฐ€ ๊ฑฐ๋ž˜์ผ๋กœ ์ง‘๊ณ„ํ•ด์„œ GL-IDX ์—์„œ ๊ฑฐ๋ž˜์ผ ์ธ๋ฑ์Šค๋ฅผ ๋ถ™์˜€๋‹ค.

trade_date ๋กœ ๊ฑฐ๋ฅผ ๋•Œ๋Š” occurred_at ๋ฒ”์œ„๋„ ๋„‰๋„‰ํžˆ ๊ฐ™์ด ๊ฑด๋‹ค. ํŒŒํ‹ฐ์…˜ ํ‚ค๊ฐ€ occurred_at ์ด๋ผ trade_date ์กฐ๊ฑด๋งŒ ๊ฑธ๋ฉด ๋ชจ๋“  ํŒŒํ‹ฐ์…˜์„ ์ฝ๋Š”๋‹ค. ๊ฑฐ๋ž˜์ผ๊ณผ ๋ฐœ์ƒ์ผ์˜ ๊ฐ„๊ฒฉ์€ ์ผ์ •ํ•˜์ง€ ์•Š๋‹ค โ€” ์—ฐํœด๋ฉด ๋ฉฐ์น  ๋’ค์ด๊ณ , COB ๊ฐ€ ๋Šฆ์–ด์ง€๋ฉด ํ•˜๋ฃจ ์•ž์„ค ์ˆ˜๋„ ์žˆ๋‹ค.

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
INDEX ix_le_account_time account_id, occurred_at DESC
INDEX ix_le_txno transaction_number
INDEX ix_le_account_dir account_id, direction, occurred_at

CHECK ์ œ์•ฝ

์ด๋ฆ„ ์กฐ๊ฑด
ck_le_amount amount > 0
ck_le_direction direction IN ('DEPOSIT','WITHDRAWAL')
ck_le_txno transaction_number REGEXP '^[0-9]{8}[A-Z]{2}[0-9]{10}$'

ledger_entry_id_sequence

ledger_entry.ledger_entry_id ์ „์šฉ ์ฑ„๋ฒˆ ์นด์šดํ„ฐ

ledger_entry๋Š” ํŒŒํ‹ฐ์…˜ ํ‚ค(occurred_at)๋ฅผ ํฌํ•จํ•œ ๋ณตํ•ฉ PK (ledger_entry_id, occurred_at)๋ฅผ ์“ฐ๋Š”๋ฐ, Hibernate๋Š” @IdClass ๋ณตํ•ฉํ‚ค ๊ตฌ์„ฑ ํ•„๋“œ์— IDENTITY ์ฑ„๋ฒˆ ์ „๋žต์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค(docs/flyway_guide.md 4-3์ ˆ ์ฐธ๊ณ ). ๊ทธ๋ž˜์„œ ledger_entry_id ์ปฌ๋Ÿผ ์ž์ฒด์˜ AUTO_INCREMENT๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ง์ ‘ ํ™œ์šฉํ•  ์ˆ˜ ์—†๊ณ , ์ด ์ „์šฉ ํ…Œ์ด๋ธ”์— ๋นˆ ํ–‰์„ ์ €์žฅํ•ด ์ƒ์„ฑ๋˜๋Š” AUTO_INCREMENT ๊ฐ’๋งŒ ์ทจํ•ด ledger_entry_id๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ๋‹ค๋ฅธ ์ปฌ๋Ÿผ์€ ๋‘์ง€ ์•Š๋Š”๋‹ค.

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… NULL ํ—ˆ์šฉ ๊ธฐ๋ณธ๊ฐ’ ํ‚ค ์„ค๋ช…
sequence_id BIGINT X AUTO_INCREMENT PK ์ƒ์„ฑ ์ฆ‰์‹œ ledger_entry.ledger_entry_id๋กœ ๊ทธ๋Œ€๋กœ ์“ฐ์ธ๋‹ค

ledger_reconciliation_mismatch

์›์žฅ-์ž”์•ก ๋Œ€์‚ฌ ๋ถˆ์ผ์น˜ ๋ชฉ๋ก (PH-38)

COB ๋Œ€์‚ฌ ์Šคํ…์ด ์›์žฅ ๋ˆ„์  ํ•ฉ๊ณ„์™€ account.balance๊ฐ€ ๋‹ค๋ฅธ ๊ณ„์ขŒ๋ฅผ ์˜์—…์ผ๋ณ„๋กœ ๋‚จ๊ธด๋‹ค. ๊ด€๋ฆฌ์ž ๋ชฉ๋ก API(FE ADM-04)๊ฐ€ ์ฝ๋Š”๋‹ค. ๊ฐ™์€ ์˜์—…์ผ์„ ๋‹ค์‹œ ๋Œ€์‚ฌํ•˜๋ฉด ๊ทธ๋‚  ํ–‰์„ ๋ชจ๋‘ ์ง€์šฐ๊ณ  ์ƒˆ ๊ฒฐ๊ณผ๋กœ ๋ฐ”๊พผ๋‹ค โ€” ์žฌ์‹คํ–‰ ์ด๋ ฅ์€ batch_execution_history๊ฐ€ ๋‚จ๊ธด๋‹ค. ๋Œ€์‚ฌ๋Š” ๋ณด๊ณ ๋งŒ ํ•˜๊ณ  ์ •์ •ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ฒ˜๋ฆฌ ์ƒํƒœ ์ปฌ๋Ÿผ์ด ์—†๋‹ค. ๊ฐ์‚ฌ์šฉ ๊ธฐ๋ก์ด๋ผ ๊ณ„์ขŒ๊ฐ€ ํ•ด์ง€ยท์ •๋ฆฌ๋ผ๋„ ๋‚จ๋„๋ก account์— FK๋ฅผ ๊ฑธ์ง€ ์•Š๋Š”๋‹ค. ์ฐจ์•ก(ledger_balance - account_balance)์€ ์ €์žฅํ•˜์ง€ ์•Š๊ณ  ์กฐํšŒํ•  ๋•Œ ๊ณ„์‚ฐํ•œ๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
ledger_reconciliation_mismatch_id BIGINT PK X AUTO_INCREMENT ๋ถˆ์ผ์น˜ ํ–‰ ์‹๋ณ„์ž
business_date DATE UK X ๋Œ€์‚ฌํ•œ COB์˜ ๋งˆ๊ฐ ๋Œ€์ƒ ์˜์—…์ผ(ADR-0004 COB_DATE). batch_execution_history.business_date์™€ ๊ฐ™์€ ๊ฐ’์ด๋‹ค
account_id BIGINT UK X ๋ถˆ์ผ์น˜ ๊ณ„์ขŒ
ledger_balance BIGINT X ์›์žฅ ๋ˆ„์  ํ•ฉ๊ณ„ SUM(DEPOSIT) - SUM(WITHDRAWAL). ์›์žฅ์ด ์—†๋Š” ๊ณ„์ขŒ๋Š” 0
account_balance BIGINT X ๋Œ€์‚ฌ ์‹œ์ ์˜ account.balance
detected_at DATETIME(6) X ๋Œ€์‚ฌ๊ฐ€ ๋ถˆ์ผ์น˜๋ฅผ ํ™•์ธํ•œ ์‹œ๊ฐ

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
UNIQUE uk_ledger_reconciliation_mismatch_date_account business_date, account_id โ€” ์˜์—…์ผ๋ณ„ ๋ชฉ๋ก ์กฐํšŒ์™€ ์ตœ๊ทผ ์˜์—…์ผ ์กฐํšŒ๋„ ์ด ์ธ๋ฑ์Šค๋ฅผ ์“ด๋‹ค

favorite_account

์ž์ฃผ ์“ฐ๋Š” ๊ณ„์ขŒ (์ตœ๋Œ€ 20๊ฑด์€ ์•ฑ ๊ฒ€์ฆ)

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
favorite_account_id BIGINT PK X ๋“ฑ๋ก ๊ฑด ๋‚ด๋ถ€ ์‹๋ณ„์ž. ๋ณ„์นญ ์ˆ˜์ •ยท์‚ญ์ œ API์˜ ๊ฒฝ๋กœ ๋ณ€์ˆ˜
customer_id BIGINT FK UK X ๋“ฑ๋กํ•œ ๊ณ ๊ฐ โ†’ customer.customer_id
deposit_account_number CHAR(12) UK X ๋“ฑ๋กํ•œ ์ž…๊ธˆ ๊ณ„์ขŒ๋ฒˆํ˜ธ
payee_name VARCHAR(50) X ๋“ฑ๋ก ์‹œ์  ์˜ˆ๊ธˆ์ฃผ ์Šค๋ƒ…์ƒท
alias VARCHAR(24) O ๋ฏธ์ง€์ • ์‹œ ์˜ˆ๊ธˆ์ฃผ๋ช… (FAV0001)
registered_at DATETIME(6) X ๋“ฑ๋ก ์ผ์‹œ

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
UNIQUE uk_fav customer_id, deposit_account_number

5. ์ด์ฒดํ•œ๋„ โ€” P1

transfer_limit

์ด์ฒดํ•œ๋„ (P1 ์†Œ์œ  ๊ฒฝ๊ณ„ ์œ ์ง€)

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
customer_id BIGINT PK FK X ๋Œ€์ƒ ๊ณ ๊ฐ. ๊ณ ๊ฐ๋‹น 1ํ–‰ โ†’ customer.customer_id
one_time_limit BIGINT X 1ํšŒ ์ด์ฒดํ•œ๋„. ์ดˆ๊ณผํ•˜๋ฉด LMT0002
daily_limit BIGINT X 1์ผ ์ด์ฒดํ•œ๋„. ์ดˆ๊ณผํ•˜๋ฉด LMT0003
created_at DATETIME(6) X ํ•œ๋„ ์ตœ์ดˆ ๋ถ€์—ฌ ์ผ์‹œ. REQ-TRSF-029๋กœ ๊ฐ€์ž… ์‹œ ์ƒ์„ฑ๋œ๋‹ค
updated_at DATETIME(6) X ํ–‰ ์ตœ์ข… ์ˆ˜์ • ์ผ์‹œ

CHECK ์ œ์•ฝ

์ด๋ฆ„ ์กฐ๊ฑด
ck_tl_order one_time_limit <= daily_limit
ck_tl_positive one_time_limit > 0 AND daily_limit > 0

๋‚™๊ด€์  ๋ฝ์„ ์“ฐ์ง€ ์•Š๋Š”๋‹ค

version ์ปฌ๋Ÿผ์€ V202608201115๋กœ ์ œ๊ฑฐํ–ˆ๋‹ค. ํ•œ๋„ ๋ณ€๊ฒฝ๊ณผ ์ด์ฒด ์‹คํ–‰ ๋ชจ๋‘ ๋น„๊ด€์  ๋ฝ(SELECT ... FOR UPDATE)์œผ๋กœ ๊ฐ„๋‹ค. ์ด์ฒด๋Š” ์ด ํ…Œ์ด๋ธ”์„ ์ฝ๊ธฐ๋งŒ ํ•˜๋ฏ€๋กœ ๋ฒ„์ „ ๊ฒ€์ฆ์„ ํ•˜๋ ค๋ฉด ์ปค๋ฐ‹ ์ง์ „์— ์˜๋ฏธ ์—†๋Š” UPDATE๋ฅผ ๋„ฃ์–ด์•ผ ํ•˜๊ณ , ๊ทธ๋Ÿฌ๋ฉด ๊ฐ™์€ ๊ณ ๊ฐ์˜ ๋™์‹œ ์ด์ฒด๊ฐ€ ์„œ๋กœ ์ถฉ๋Œํ•ด ์žฌ์‹œ๋„๊ฐ€ ์ƒ๊ธด๋‹ค.


transfer_limit_daily_usage

์ผ๋ณ„ ํ•œ๋„ ์‚ฌ์šฉ์•ก (๋น„๊ด€์  ๋ฝ ๋Œ€์ƒ 1์ˆœ์œ„)

์ด์ฒด ์‹คํ–‰ ์‹œ ๊ฐ€์žฅ ๋จผ์ € ์ž ๊ทธ๋Š” ์ž์› ์ค‘ ํ•˜๋‚˜๋‹ค. SUCCESS๋กœ ํ™•์ •๋œ ๊ฑด๋งŒ ํ•ฉ์‚ฐํ•˜๋ฉฐ ์˜ค๋ฅ˜ยท์ทจ์†Œยท๋ฏธ์‹คํ–‰ ์˜ˆ์•ฝ์€ ์ œ์™ธํ•œ๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
customer_id BIGINT PK FK X ๋Œ€์ƒ ๊ณ ๊ฐ โ†’ customer.customer_id
usage_date DATE PK X ์‚ฌ์šฉ์•ก ์ง‘๊ณ„ ๊ธฐ์ค€์ผ. KST ์˜์—…์ผ์ด๋ฉฐ ๋งค์ผ ์ƒˆ ํ–‰์ด ์ƒ๊ธด๋‹ค
used_amount BIGINT X 0 ํ•ด๋‹น ์ผ์ž์— SUCCESS๋กœ ํ™•์ •๋œ ์ด์ฒด๊ธˆ์•ก ๋ˆ„๊ณ„. ์˜ค๋ฅ˜ยท์ทจ์†Œยท๋ฏธ์‹คํ–‰ ์˜ˆ์•ฝ์€ ๋น ์ง„๋‹ค
created_at DATETIME(6) X ํ•ด๋‹น ์ผ์ž ์ฒซ ์ด์ฒด๋กœ ํ–‰์ด ์ƒ์„ฑ๋œ ์‹œ๊ฐ
updated_at DATETIME(6) X ๋งˆ์ง€๋ง‰ ์‚ฌ์šฉ์•ก ๊ฐฑ์‹  ์‹œ๊ฐ

CHECK ์ œ์•ฝ

์ด๋ฆ„ ์กฐ๊ฑด
ck_tldu_used used_amount >= 0

transfer_limit_history

์ด์ฒดํ•œ๋„ ๋ณ€๊ฒฝ ์ด๋ ฅ (P1 ์†Œ์œ  ๊ฒฝ๊ณ„ ์œ ์ง€)

REQ-TRSF-025์˜ "๋ณ€๊ฒฝ ์ด๋ ฅ์„ ์ €์žฅํ•œ๋‹ค"๋ฅผ ๋‹ด๋Š”๋‹ค. ํ•œ๋„ ๋ณ€๊ฒฝ 1๊ฑด๋‹น 1ํ–‰์ด ์Œ“์ด๋Š” append-only ํ…Œ์ด๋ธ”์ด๋‹ค. ๋ณ€๊ฒฝ์žยท์š”์ฒญ IP ๊ฐ™์€ ๊ฐ์‚ฌ ์ •๋ณด๋Š” audit_log์˜ ์ฑ…์ž„์ด๋ฏ€๋กœ ์—ฌ๊ธฐ์—๋Š” ๊ฐ’์˜ ๋ณ€ํ™”๋งŒ ๋‚จ๊ธด๋‹ค.

๋ณ€๊ฒฝ ํ›„ ๊ฐ’์€ ์ €์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด๋ ฅ N์˜ ๋ณ€๊ฒฝ ํ›„ ๊ฐ’์€ ์ด๋ ฅ N+1์˜ before_*์™€ ๊ฐ™๊ณ , ๋งˆ์ง€๋ง‰ ์ด๋ ฅ์˜ ๋ณ€๊ฒฝ ํ›„ ๊ฐ’์€ transfer_limit์˜ ํ˜„์žฌ๊ฐ’๊ณผ ๊ฐ™๋‹ค. ๊ฐ™์€ ๊ฐ’์„ ๋‘ ๊ตฐ๋ฐ ๋‘๋ฉด ์–ด๊ธ‹๋‚  ์—ฌ์ง€๋งŒ ์ƒ๊ธด๋‹ค. ์กฐํšŒํ•  ๋•Œ๋Š” ์›ํ•˜๋Š” ๊ฑด์ˆ˜๋ณด๋‹ค ํ•œ ๊ฑด ๋” ์ฝ์–ด ์ธ์ ‘ ํ–‰๋ผ๋ฆฌ ์ง์„ ๋งž์ถ”๊ณ , ๋งˆ์ง€๋ง‰ ํ–‰๋งŒ transfer_limit์„ ์ฝ์–ด ์ฑ„์šด๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
history_id BIGINT PK X AUTO_INCREMENT ์ด๋ ฅ ์‹๋ณ„์ž
customer_id BIGINT FK X ๋Œ€์ƒ ๊ณ ๊ฐ โ†’ customer.customer_id
before_one_time_limit BIGINT X ๋ณ€๊ฒฝ ์ง์ „ 1ํšŒ ์ด์ฒดํ•œ๋„
before_daily_limit BIGINT X ๋ณ€๊ฒฝ ์ง์ „ 1์ผ ์ด์ฒดํ•œ๋„
created_at DATETIME(6) X ๋ณ€๊ฒฝ์ด ์ผ์–ด๋‚œ ์‹œ๊ฐ
updated_at DATETIME(6) X ํ–‰ ์ตœ์ข… ์ˆ˜์ • ์ผ์‹œ. append-only๋ผ created_at๊ณผ ๊ฐ™์€ ๊ฐ’์ด ์œ ์ง€๋œ๋‹ค

์ œ์•ฝยท์ธ๋ฑ์Šค๋ฅผ ๋‘์ง€ ์•Š์€ ์ด์œ 

CHECK ์ œ์•ฝ์€ ๋‘์ง€ ์•Š๋Š”๋‹ค โ€” ์ ์žฌ๋˜๋Š” ๊ฐ’์€ transfer_limit์˜ ck_tl_positiveยทck_tl_order๋ฅผ ์ด๋ฏธ ํ†ต๊ณผํ•œ ๊ฐ’์ด๋‹ค. ๋ณ„๋„ ์ธ๋ฑ์Šค๋„ ๋‘์ง€ ์•Š๋Š”๋‹ค โ€” ์ด๋ ฅ ์กฐํšŒ ์š”๊ตฌ์‚ฌํ•ญ์ด ์•„์ง ์—†๊ณ , FK๊ฐ€ customer_id ์ธ๋ฑ์Šค๋ฅผ ์ž๋™ ์ƒ์„ฑํ•œ๋‹ค. ์กฐํšŒ API๊ฐ€ ์ƒ๊ธฐ๋ฉด ๊ทธ๋•Œ ์ถ”๊ฐ€ํ•œ๋‹ค.


6. ์ƒํ’ˆ๊ฐ€์ž… โ€” P3

product_subscription

์ƒํ’ˆ๊ฐ€์ž…

PRD0301(1์ธ 1๊ณ„์ขŒ ์ œํ•œ)์€ product.single_account_limit = TRUE์ธ ์ƒํ’ˆ์—๋งŒ ์ ์šฉ๋˜๋ฏ€๋กœ (customer_id, product_id)์— UNIQUE๋ฅผ ๊ฑธ์ง€ ์•Š๋Š”๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์กฐํšŒ ํ›„ ํŒ์ •ํ•œ๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
subscription_id BIGINT PK X ๊ฐ€์ž… ๊ฑด ๋‚ด๋ถ€ ์‹๋ณ„์ž. ๊ฐ€์ž… ๊ฒฐ๊ณผ ์กฐํšŒ์˜ ๊ฒฝ๋กœ ๋ณ€์ˆ˜
customer_id BIGINT FK X ๊ฐ€์ž… ๊ณ ๊ฐ โ†’ customer.customer_id
product_id BIGINT FK X ๊ฐ€์ž… ์ƒํ’ˆ โ†’ product.product_id
account_id BIGINT FK UK O ๊ฐ€์ž…์œผ๋กœ ์ƒˆ๋กœ ๊ฐœ์„ค๋œ ๊ณ„์ขŒ. ๊ฐ€์ž… ์‹คํŒจ ์‹œ NULL โ†’ account.account_id
withdrawal_account_id BIGINT FK X ์ดˆ์ž…๊ธˆ์„ ๋นผ๊ฐˆ ์ถœ๊ธˆ๊ณ„์ขŒ โ†’ account.account_id
subscription_amount BIGINT X ๊ฐ€์ž…๊ธˆ์•ก. ์ ๋ฆฝ์‹์€ ์›” ๋‚ฉ์ž…์•ก
term_months SMALLINT X ๊ฐ€์ž…๊ธฐ๊ฐ„(๊ฐœ์›”)
payment_day TINYINT O ๋งค์›” ์ž๋™ ๋‚ฉ์ž…์ผ. 1~28 ์‚ฌ์ด์ด๋ฉฐ ์ ๋ฆฝ์‹ ์ƒํ’ˆ๋งŒ ๊ฐ’์ด ์žˆ๋‹ค
base_rate DECIMAL(5,2) X ๊ฐ€์ž… ์‹œ์ ์˜ ๊ธฐ๋ณธ๊ธˆ๋ฆฌ ์Šค๋ƒ…์ƒท. ์ดํ›„ ์ƒํ’ˆ ๊ธˆ๋ฆฌ๊ฐ€ ๋ฐ”๋€Œ์–ด๋„ ์œ ์ง€๋œ๋‹ค
preferential_rate DECIMAL(5,2) X 0.00 ์ ์šฉ๋œ ์šฐ๋Œ€๊ธˆ๋ฆฌ ํ•ฉ๊ณ„
applied_rate DECIMAL(5,2) X ์ตœ์ข… ์ ์šฉ๊ธˆ๋ฆฌ = base_rate + preferential_rate
maturity_handling VARCHAR(12) X ๋งŒ๊ธฐ ์ฒ˜๋ฆฌ ๋ฐฉ์‹. TRANSFER(์ถœ๊ธˆ๊ณ„์ขŒ๋กœ ์ž…๊ธˆ) / RENEW(์žฌ์˜ˆ์น˜)
expected_maturity_amount BIGINT O ์˜ˆ์ƒ ๋งŒ๊ธฐ ์ˆ˜๋ น์•ก(์„ธ์ „)
status VARCHAR(12) X ๊ฐ€์ž… ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ. SUCCESS(์ •์ƒ) / ERROR(์˜ค๋ฅ˜) / PROCESSING(์ฒ˜๋ฆฌ์ค‘)
transaction_number CHAR(20) O ์ดˆ์ž…๊ธˆ ๊ธฐํ‘œ์˜ ๊ฑฐ๋ž˜๋ฒˆํ˜ธ. ์‹คํŒจ ์‹œ NULL
opened_date DATE O ๊ฐœ์„ค์ผ
maturity_date DATE O ๋งŒ๊ธฐ์ผ
subscribed_at DATETIME(6) X ๊ฐ€์ž… ์‹คํ–‰ ์ผ์‹œ
subscription_trade_date DATE O ๊ฐ€์ž… ๋…ผ๋ฆฌ ์˜์—…์ผ. ๊ฐ€์ž… ํŠธ๋žœ์žญ์…˜์ด ์˜์—…์ผ gate(BusinessDateGate)๋กœ ์ฝ์€ ๊ฐ’์ด๋‹ค. ์ •๋ณด๊ณ„ SUBSCRIBE ์ด๋ฒคํŠธ ๊ธฐ์ค€์ผ. ๊ธฐ์กด ํ–‰์€ ๊ฐ€์ž… ์‹œ๊ฐ์„ ์˜์—…์ผ๋กœ ์˜ฌ๋ ค ์ฑ„์› ๋‹ค

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
UNIQUE uk_sub_account account_id
INDEX ix_sub_customer_product customer_id, product_id, status

subscription_terms_agreement

์ƒํ’ˆ ์•ฝ๊ด€ ๋™์˜ (๋ฒ„์ „ยท์—ด๋žŒ ์ด๋ ฅ)

terms_version๊ณผ read_at์ด PRD0005(์ „๋ฌธ ์—ด๋žŒ)ยทPRD0006(๋ฒ„์ „ ๋ถˆ์ผ์น˜) ํŒ์ •์˜ ๋ฌผ๋ฆฌ์  ๊ทผ๊ฑฐ๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
subscription_id BIGINT PK FK X ๋Œ€์ƒ ๊ฐ€์ž… ๊ฑด โ†’ product_subscription.subscription_id
terms_id BIGINT PK FK X ๋™์˜ํ•œ ์•ฝ๊ด€ โ†’ terms.terms_id
terms_version VARCHAR(10) X ๋™์˜ ์‹œ์ ์˜ ์•ฝ๊ด€ ๋ฒ„์ „. ํ˜„์žฌ ๋ฒ„์ „๊ณผ ๋‹ค๋ฅด๋ฉด PRD0006
read_at DATETIME(6) O ์•ฝ๊ด€ ์ „๋ฌธ์„ ์—ฐ ์‹œ๊ฐ. view_required = TRUE ์•ฝ๊ด€์ธ๋ฐ NULL์ด๋ฉด PRD0005
agreed_at DATETIME(6) X ๋™์˜ ์‹œ๊ฐ

7. ์˜ˆ์•ฝ ยท ์ž๋™์ด์ฒด โ€” P3ยทP5

scheduled_transfer

์˜ˆ์•ฝ์ด์ฒด

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
scheduled_transfer_id BIGINT PK X ์˜ˆ์•ฝ ๊ฑด ๋‚ด๋ถ€ ์‹๋ณ„์ž. ์ƒ์„ธ ์กฐํšŒยท์ทจ์†Œ API์˜ ๊ฒฝ๋กœ ๋ณ€์ˆ˜
customer_id BIGINT FK X ์˜ˆ์•ฝํ•œ ๊ณ ๊ฐ โ†’ customer.customer_id
withdrawal_account_id BIGINT FK X ์ถœ๊ธˆ๊ณ„์ขŒ โ†’ account.account_id
payee_bank_code CHAR(3) X ์ž…๊ธˆ ์€ํ–‰ ์ฝ”๋“œ. 1์ฐจ๋Š” ๋‹นํ–‰ ์ „์šฉ์ด๋ผ ์ƒ์ˆ˜์ด๋ฉฐ ๋ณ„๋„ ์€ํ–‰ ํ…Œ์ด๋ธ”์„ ๋‘์ง€ ์•Š๋Š”๋‹ค
payee_account_number CHAR(12) X ์ž…๊ธˆ ๊ณ„์ขŒ๋ฒˆํ˜ธ
payee_name VARCHAR(50) X ์˜ˆ๊ธˆ์ฃผ๋ช…. ๋“ฑ๋ก ์‹œ์  ์Šค๋ƒ…์ƒท์ด๋ผ ์ดํ›„ ์ƒ๋Œ€ ๊ณ„์ขŒ๊ฐ€ ๋ฐ”๋€Œ์–ด๋„ ์œ ์ง€๋œ๋‹ค
amount BIGINT X ์ด์ฒด๊ธˆ์•ก
scheduled_date DATE X ์˜ˆ์•ฝ ์‹คํ–‰์ผ. ๋“ฑ๋ก์ผ ์ต์ผ๋ถ€ํ„ฐ 1๋…„ ์ด๋‚ด์—ฌ์•ผ ํ•œ๋‹ค (SCD0001)
my_passbook_memo VARCHAR(10) O ๋‚ด ํ†ต์žฅ์— ์ฐํžˆ๋Š” ๋ฌธ๊ตฌ
recipient_passbook_memo VARCHAR(10) O ๋ฐ›๋Š” ๋ถ„ ํ†ต์žฅ์— ์ฐํžˆ๋Š” ๋ฌธ๊ตฌ
status VARCHAR(12) X ์˜ˆ์•ฝ ๊ฑด ์ƒ๋ช…์ฃผ๊ธฐ ์ƒํƒœ. WAITING(๋Œ€๊ธฐ) / PROCESSING(์ฒ˜๋ฆฌ์ค‘) / SUCCESS(์ •์ƒ) / FAILED(์˜ค๋ฅ˜) / CANCELED(์ทจ์†Œ)
transaction_number CHAR(20) O ์‹คํ–‰ ์„ฑ๊ณต ์‹œ ์ƒ์„ฑ๋œ ๊ฑฐ๋ž˜๋ฒˆํ˜ธ. ๋Œ€๊ธฐยท์‹คํŒจ ๊ฑด์€ NULL
registered_at DATETIME(6) X ์˜ˆ์•ฝ ๋“ฑ๋ก ์ผ์‹œ
executed_at DATETIME(6) O ๋ฐฐ์น˜ ์‹คํ–‰ ์ผ์‹œ. ๋ฏธ์‹คํ–‰์ด๋ฉด NULL
canceled_at DATETIME(6) O ์ทจ์†Œ ์ผ์‹œ. ๋ฏธ์ทจ์†Œ๋ฉด NULL
failure_reason VARCHAR(200) O ์‹คํ–‰ ์‹คํŒจ ์‚ฌ์œ 
version BIGINT X 0 ๋‚™๊ด€์  ๋ฝ ๋ฒ„์ „. ๋‹ค๊ฑด ์ทจ์†Œ๊ฐ€ ์ฝ์–ด๋‘” ๊ฑด์„ ๋ฐฐ์น˜๊ฐ€ PROCESSING์œผ๋กœ ์„ ์ ํ•˜๋ฉด ์ทจ์†Œ ์ €์žฅ์ด CMN0303์œผ๋กœ ๊ฑธ๋ฆฐ๋‹ค
active_dup_key VARCHAR(80) GEN UK O ์ƒ์„ฑ ์ปฌ๋Ÿผ. WAITING์ผ ๋•Œ๋งŒ ๊ฐ’์ด ์ƒ๊ฒจ ์ค‘๋ณต ์˜ˆ์•ฝ์„ ๋ง‰๋Š”๋‹ค (SCD0301)

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
UNIQUE uk_sched_active_dup active_dup_key
INDEX ix_sched_batch status, scheduled_date

CHECK ์ œ์•ฝ

์ด๋ฆ„ ์กฐ๊ฑด
ck_sched_amount amount > 0

auto_transfer

์ž๋™์ด์ฒด ๋“ฑ๋ก

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
auto_transfer_id BIGINT PK X ์ž๋™์ด์ฒด ๋“ฑ๋ก ๊ฑด ๋‚ด๋ถ€ ์‹๋ณ„์ž. ๋ณ€๊ฒฝยทํ•ด์ง€ API์˜ ๊ฒฝ๋กœ ๋ณ€์ˆ˜
customer_id BIGINT FK X ๋“ฑ๋กํ•œ ๊ณ ๊ฐ โ†’ customer.customer_id
withdrawal_account_id BIGINT FK X ์ถœ๊ธˆ๊ณ„์ขŒ โ†’ account.account_id
deposit_account_number CHAR(12) X ์ž…๊ธˆ ๊ณ„์ขŒ๋ฒˆํ˜ธ. ์ƒ๋Œ€ ๊ณ„์ขŒ๋ผ ๋‚ด๋ถ€ PK๊ฐ€ ์•„๋‹Œ ๋ฒˆํ˜ธ๋กœ ์ง€์นญํ•œ๋‹ค
payee_name VARCHAR(50) X ์˜ˆ๊ธˆ์ฃผ๋ช…. ๋“ฑ๋ก ์‹œ์  ์Šค๋ƒ…์ƒท
amount BIGINT X ํšŒ์ฐจ๋งˆ๋‹ค ์ด์ฒดํ•  ๊ธˆ์•ก
cycle_months TINYINT X ์ด์ฒด ์ฃผ๊ธฐ(๊ฐœ์›”). 1 / 3 / 6 ์ค‘ ํ•˜๋‚˜
transfer_day TINYINT X ๋งค์›” ์ด์ฒด ์ง€์ •์ผ. 1~31 (AUT0001)
start_date DATE X ์ด์ฒด ์‹œ์ž‘์ผ
end_date DATE X ์ด์ฒด ์ข…๋ฃŒ์ผ. ์‹œ์ž‘์ผ ์ดํ›„ 60๊ฐœ์›” ์ด๋‚ด (AUT0002)
next_execution_date DATE X ๋‹ค์Œ ์‹คํ–‰ ์˜ˆ์ •์ผ. ๋ฐฐ์น˜๊ฐ€ ์ด ๊ฐ’์œผ๋กœ ๋Œ€์ƒ์„ ๊ณ ๋ฅธ๋‹ค
my_passbook_memo VARCHAR(10) O ๋‚ด ํ†ต์žฅ์— ์ฐํžˆ๋Š” ๋ฌธ๊ตฌ
recipient_passbook_memo VARCHAR(10) O ๋ฐ›๋Š” ๋ถ„ ํ†ต์žฅ์— ์ฐํžˆ๋Š” ๋ฌธ๊ตฌ
status VARCHAR(12) X ๋“ฑ๋ก ๊ฑด ์ƒ๋ช…์ฃผ๊ธฐ ์ƒํƒœ. NORMAL(์šด์šฉ ์ค‘) / EXPIRED(๊ธฐ๊ฐ„ ๋งŒ๋ฃŒ๋กœ ์‹œ์Šคํ…œ ์ž๋™ ์ข…๋ฃŒ) / TERMINATED(๊ณ ๊ฐ ์ง์ ‘ ํ•ด์ง€). ํšŒ์ฐจ ์‹คํ–‰๊ฒฐ๊ณผ์™€๋Š” ์ „ํ˜€ ๋‹ค๋ฅธ ๊ฐœ๋…์ด๋‹ค
registered_at DATETIME(6) X ๋“ฑ๋ก ์ผ์‹œ
terminated_at DATETIME(6) O ํ•ด์ง€ยท๋งŒ๋ฃŒ ์ „ํ™˜ ์‹œ๊ฐ
updated_at DATETIME(6) X ํ–‰ ์ตœ์ข… ์ˆ˜์ • ์ผ์‹œ
active_dup_key VARCHAR(64) GEN UK O ์ƒ์„ฑ ์ปฌ๋Ÿผ. NORMAL์ผ ๋•Œ๋งŒ ๊ฐ’์ด ์ƒ๊ฒจ ์ค‘๋ณต ๋“ฑ๋ก์„ ๋ง‰๋Š”๋‹ค (AUT0301)

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
UNIQUE uk_auto_active_dup active_dup_key
INDEX ix_auto_batch status, next_execution_date

CHECK ์ œ์•ฝ

์ด๋ฆ„ ์กฐ๊ฑด
ck_auto_cycle cycle_months IN (1, 3, 6)
ck_auto_day transfer_day BETWEEN 1 AND 31
ck_auto_period end_date >= start_date
ck_auto_amount amount > 0

auto_transfer_execution

์ž๋™์ด์ฒด ํšŒ์ฐจ ์‹คํ–‰๊ฒฐ๊ณผ

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
execution_id BIGINT PK X ํšŒ์ฐจ ๋‚ด๋ถ€ ์‹๋ณ„์ž
auto_transfer_id BIGINT FK UK X ์ƒ์œ„ ์ž๋™์ด์ฒด ๋“ฑ๋ก ๊ฑด โ†’ auto_transfer.auto_transfer_id
execution_date DATE UK X ํšŒ์ฐจ ์‹คํ–‰ ์˜ˆ์ •์ผ. ๋“ฑ๋ก ๊ฑด์˜ transfer_day๋กœ ๊ณ„์‚ฐ๋œ๋‹ค
amount BIGINT X ํšŒ์ฐจ ์ด์ฒด๊ธˆ์•ก. ๋“ฑ๋ก ๊ฑด ๊ธˆ์•ก์ด ๋‚˜์ค‘์— ๋ฐ”๋€Œ์–ด๋„ ์‹คํ–‰ ์‹œ์  ๊ฐ’์„ ๋‚จ๊ธด๋‹ค
status VARCHAR(12) X ํšŒ์ฐจ ์‹คํ–‰๊ฒฐ๊ณผ. SUCCESS(์ •์ƒ) / ERROR(์˜ค๋ฅ˜) / PROCESSING(์ฒ˜๋ฆฌ์ค‘). ๋“ฑ๋ก ๊ฑด ์ƒํƒœ์™€ ๋ณ„๊ฐœ Enum์ด๋‹ค
transaction_number CHAR(20) O ์„ฑ๊ณต ์‹œ ์ƒ์„ฑ๋œ ๊ฑฐ๋ž˜๋ฒˆํ˜ธ. ์‹คํŒจ ๊ฑด์€ NULL
failure_reason VARCHAR(200) O ์‹คํŒจ ์‚ฌ์œ 
executed_at DATETIME(6) X ์‹ค์ œ ์‹คํ–‰ ์ผ์‹œ

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
UNIQUE uk_ate_dup auto_transfer_id, execution_date

8. ๊ณตํ†ต ์ธํ”„๋ผ โ€” P5

idempotency_key

๋ฉฑ๋“ฑํ‚ค (common_rev 7-2)

request_hash ๊ณ„์‚ฐ ์‹œ *AuthToken์œผ๋กœ ๋๋‚˜๋Š” ํ•„๋“œ๋Š” ์ œ์™ธํ•œ๋‹ค. ๋„คํŠธ์›Œํฌ ์ง€์—ฐ ์žฌ์š”์ฒญ์—์„œ ํ† ํฐ๋งŒ ๊ฐฑ์‹ ๋ผ ๋‹ค๋ฅธ ์š”์ฒญ์œผ๋กœ ์˜คํƒ์ง€๋˜๋Š” ๊ฒƒ์„ ๋ง‰๋Š”๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
idempotency_key CHAR(36) PK X ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ธ Idempotency-Key ํ—ค๋”๊ฐ’(UUID v4). ๊ฐ™์€ ์š”์ฒญ์˜ ์ค‘๋ณต ์‹คํ–‰์„ ๋ง‰๋Š” ๊ธฐ์ค€
customer_id BIGINT FK O ์š”์ฒญ ๊ณ ๊ฐ โ†’ customer.customer_id. ๊ณ ๊ฐ ์ƒ์„ฑ ์ „ ํšŒ์›๊ฐ€์ž… ์™„๋ฃŒ ๋ฉฑ๋“ฑํ‚ค ์˜ˆ์•ฝ์€ NULL
endpoint VARCHAR(120) X ์š”์ฒญ ๋Œ€์ƒ ์—”๋“œํฌ์ธํŠธ. ๊ฐ™์€ ํ‚ค๊ฐ€ ๋‹ค๋ฅธ API์— ์žฌ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์„ ๊ฑธ๋Ÿฌ๋‚ธ๋‹ค
request_hash CHAR(64) X ์š”์ฒญ ๋ณธ๋ฌธ์˜ SHA-256 ํ•ด์‹œ. ๊ฐ™์€ ํ‚ค์ธ๋ฐ ๊ฐ’์ด ๋‹ค๋ฅด๋ฉด CMN0302
state VARCHAR(12) X ์ฒ˜๋ฆฌ ์ƒํƒœ. PROCESSING(์ฒ˜๋ฆฌ ์ค‘) / COMPLETED(์™„๋ฃŒ). ์žฌ์š”์ฒญ ์‹œ CMN0301๊ณผ 200 ๋ฐ˜ํ™˜์„ ๊ฐ€๋ฅด๋Š” ๊ธฐ์ค€
http_status SMALLINT O ์ €์žฅ๋œ ์‘๋‹ต์˜ HTTP ์ƒํƒœ์ฝ”๋“œ
response_snapshot JSON O ์ €์žฅ๋œ ์‘๋‹ต ๋ณธ๋ฌธ. ์žฌ์š”์ฒญ ์‹œ ๊ทธ๋Œ€๋กœ ๋˜๋Œ๋ ค์ค€๋‹ค
created_at DATETIME(6) X ์ตœ์ดˆ ์š”์ฒญ ์ˆ˜์‹  ์‹œ๊ฐ
expires_at DATETIME(6) X ๋งŒ๋ฃŒ ์‹œ๊ฐ. 24์‹œ๊ฐ„ ๊ฒฝ๊ณผ ๊ฑด์€ ๋ฐฐ์น˜๊ฐ€ ์ง€์šด๋‹ค

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
INDEX ix_idem_expires expires_at

audit_log

๊ฐ์‚ฌ ๋กœ๊ทธ (REQ-NFR-010). ์กฐํšŒ API ์—†์œผ๋‚˜ ๊ทœ์ œ ๊ทผ๊ฑฐ๋กœ ์œ ์ง€

์กฐํšŒ API๋Š” ์—†์ง€๋งŒ REQ-NFR-010์ด ๊ธฐ๋ก ํ•ญ๋ชฉ์„ ํŠน์ •ํ•˜๊ณ  ์žˆ์–ด ์ •ํ˜• ํ…Œ์ด๋ธ”๋กœ ์œ ์ง€ํ•œ๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
audit_log_id BIGINT PK X ๊ฐ์‚ฌ ๋กœ๊ทธ ๋‚ด๋ถ€ ์‹๋ณ„์ž
customer_id BIGINT O ํ–‰์œ„ ๊ณ ๊ฐ. ๋น„๋กœ๊ทธ์ธ ์‹œ๋„๋Š” NULL
transaction_number CHAR(20) O ์›์žฅ ๋ณ€๊ฒฝ ๊ฑฐ๋ž˜์˜ ๊ฑฐ๋ž˜๋ฒˆํ˜ธ. ๊ฑฐ๋ž˜์™€ ๋กœ๊ทธ๋ฅผ ์ž‡๋Š” ํ‚ค
event_type VARCHAR(40) X ๊ฐ์‚ฌ ์ด๋ฒคํŠธ ์ข…๋ฅ˜. ์ด์ฒด ์‹คํ–‰ยทํ•œ๋„ ๋ณ€๊ฒฝ ๋“ฑ ์›์žฅ์— ์˜ํ–ฅ์„ ์ค€ ํ–‰์œ„๋ฅผ ๊ตฌ๋ถ„ํ•œ๋‹ค
request_ip VARCHAR(45) X ์š”์ฒญ ํด๋ผ์ด์–ธํŠธ IP. IPv6๊นŒ์ง€ ๋‹ด๊ธฐ๋„๋ก 45์ž
result VARCHAR(12) X ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ. SUCCESS / FAILURE
detail JSON O ๋ถ€๊ฐ€ ์ •๋ณด. ๋น„๋ฐ€๋ฒˆํ˜ธยท์ „์ฒด ๊ณ„์ขŒ๋ฒˆํ˜ธ ๋“ฑ์€ ๋งˆ์Šคํ‚น ํ›„ ์ €์žฅํ•œ๋‹ค
requested_at DATETIME(6) X ์š”์ฒญ ์ผ์‹œ

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
INDEX ix_audit_customer customer_id, requested_at DESC
INDEX ix_audit_txno transaction_number

common_code

๊ณตํ†ต์ฝ”๋“œ (REQ-CMN-023). ์ฝ”๋“œ๊ฐ’ โ†’ ํ™”๋ฉด ํ‘œ์‹œ๋ช… ๋งคํ•‘

code ๊ฐ’์€ ์„œ๋ฒ„ Enum ๊ฐ’๊ณผ ๋ฌธ์ž์—ด์ด ์ •ํ™•ํžˆ ์ผ์น˜ํ•ด์•ผ ํ•œ๋‹ค. Enum์—๋Š” ์žˆ๋Š”๋ฐ ์ด ํ…Œ์ด๋ธ”์— ํ–‰์ด ์—†์œผ๋ฉด ํ”„๋ก ํŠธ๊ฐ€ ํ‘œ์‹œ๋ช… ๋งคํ•‘์— ์‹คํŒจํ•œ๋‹ค. P5 ํ…Œ์ด๋ธ” ์ค‘ ์œ ์ผํ•˜๊ฒŒ created_at/updated_at์„ ๋ชจ๋‘ ๊ฐ€์ ธ BaseEntity๋ฅผ ์ƒ์†ํ•œ๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
code_group VARCHAR(50) PK X ์ฝ”๋“œ ๊ทธ๋ฃน๋ช…. ์˜ˆ: ACCOUNT_STATUS
code VARCHAR(50) PK X ์ฝ”๋“œ๊ฐ’. ์„œ๋ฒ„ Enum ๊ฐ’๊ณผ ์ผ์น˜. ์˜ˆ: ACTIVE
code_name VARCHAR(100) X ํ™”๋ฉด ํ‘œ์‹œ ํ•œ๊ธ€๋ช…. ์˜ˆ: ์ •์ƒ
sort_order INT X ๋“œ๋กญ๋‹ค์šด ํ‘œ์‹œ ์ˆœ์„œ
use_yn CHAR(1) X Y ์‚ฌ์šฉ ์—ฌ๋ถ€. Y/N. ๋ฌผ๋ฆฌ ์‚ญ์ œ ๋Œ€์‹  ์‚ฌ์šฉ
description VARCHAR(200) O ๊ด€๋ฆฌ์ž์šฉ ์„ค๋ช…
created_at DATETIME(6) X JPA Auditing
updated_at DATETIME(6) X JPA Auditing

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
INDEX ix_common_code_group code_group, use_yn, sort_order

batch_execution_lock

๋ฐฐ์น˜ ์ค‘๋ณต ํŠธ๋ฆฌ๊ฑฐ ๋ฐฉ์ง€ ๋ฝ (#189). Apache Fineract SchedulerTriggerListener.vetoJobExecution() ํŒจํ„ด ์ฐธ๊ณ 

๋‹ค์ค‘ ์ธ์Šคํ„ด์Šค ๋ฐฐํฌ ์‹œ ๊ฐ™์€ ๋ฐฐ์น˜(์˜ˆ: DailyTransferBatchScheduler.runDailyBatch())๊ฐ€ ๋™์‹œ์— ๋‘ ๋ฒˆ ํŠธ๋ฆฌ๊ฑฐ๋˜๋Š” ๊ฑธ ๋ง‰๋Š”๋‹ค. SELECT ... FOR UPDATE๋กœ ํ–‰์„ ์ž ๊ทธ๊ณ  ํ”Œ๋ž˜๊ทธ๋งŒ ํ™•์ธยท๊ฐฑ์‹ ํ•œ ๋’ค ์ฆ‰์‹œ ์ปค๋ฐ‹ํ•˜๋Š” ์งง์€ ํŠธ๋žœ์žญ์…˜์ด๋ผ, ๋ฐฐ์น˜ ์‹คํ–‰ ์ „์ฒด ๋™์•ˆ ์ด ํ…Œ์ด๋ธ”์„ ์ž ๊ทธ์ง€ ์•Š๋Š”๋‹ค. currently_running=TRUE์ธ ์ฑ„๋กœ updated_at์ด stale ์ž„๊ณ„๊ฐ’(6์‹œ๊ฐ„)๋ณด๋‹ค ์˜ค๋ž˜๋˜๋ฉด ์„œ๋ฒ„ ํฌ๋ž˜์‹œ๋กœ ๋ฝ ํ•ด์ œ๊ฐ€ ๋ชป ๋ถˆ๋ฆฐ ๊ฒƒ์œผ๋กœ ๋ณด๊ณ  ๊ฐ•์ œ๋กœ ์žฌํš๋“ํ•œ๋‹ค. ๋ฐฐ์น˜ ์ข…๋ฅ˜๋งˆ๋‹ค job_name์„ ํ•˜๋‚˜์”ฉ ๋“ฑ๋กํ•ด ์žฌ์‚ฌ์šฉํ•œ๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
job_name VARCHAR(50) PK X ๋ฐฐ์น˜ ์žก ์‹๋ณ„์ž. DAILY_TRANSFER_BATCH, IDEMPOTENCY_KEY_CLEANUP, LEDGER_RECONCILIATION_BATCH, AUTH_TOKEN_CLEANUP, TERMS_VIEW_HISTORY_CLEANUP, AUTO_TRANSFER_RECONCILE, SCHEDULED_TRANSFER_RECONCILE, COB 8ํ–‰
currently_running BOOLEAN X FALSE ์ด ๋ฐฐ์น˜๊ฐ€ ์ง€๊ธˆ ์‹คํ–‰ ์ค‘์ธ์ง€. ํŠธ๋ฆฌ๊ฑฐ ์‹œ์ž‘ ์‹œ TRUE, ์ข…๋ฃŒ ์‹œ(์„ฑ๊ณต/์‹คํŒจ ๋ฌด๊ด€) FALSE๋กœ ๋˜๋Œ๋ฆผ
updated_at DATETIME(6) X ๋งˆ์ง€๋ง‰ ์ƒํƒœ ๋ณ€๊ฒฝ ์‹œ๊ฐ. stale(ํฌ๋ž˜์‹œ๋กœ ๋ฐฉ์น˜๋จ) ํŒ๋‹จ ๊ธฐ์ค€

batch_execution_history

COB ๋“ฑ ๋ฐฐ์น˜๊ฐ€ ์Šคํ…์„ ์‹คํ–‰ํ•œ ๊ธฐ๋ก (#603)

CobRunnerService๊ฐ€ ์Šคํ…(CobStep)์„ ํ•˜๋‚˜ ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ๊ฒฐ๊ณผ๋ฅผ 1ํ–‰ ์ถ”๊ฐ€ํ•œ๋‹ค(append-only, UPDATEยทDELETE ์—†์Œ). ์Šคํ…์ด ์‹œ์ž‘ํ•˜๊ธฐ ์ „์—๋Š” ํ–‰์ด ์—†๊ณ , ๋๋‚œ ๋’ค(์„ฑ๊ณตยท์‹คํŒจยท์ค‘๋‹จ ์ค‘ ํ•˜๋‚˜๋กœ ํ™•์ •๋œ ๋’ค) ํ•œ ๋ฒˆ๋งŒ INSERTํ•œ๋‹ค. ๊ด€๋ฆฌ์ž ์กฐํšŒ API๋Š” ์•„์ง ์—†๋‹ค(#603 ๋ฒ”์œ„ ๋ฐ–).

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
batch_execution_history_id BIGINT PK X ๋‚ด๋ถ€ ์‹๋ณ„์ž (AUTO_INCREMENT)
job_name VARCHAR(50) X ๋ฐฐ์น˜ ์‹๋ณ„์ž. ์˜ˆ: COB
step_name VARCHAR(100) X CobStep.name()
business_date DATE X ์Šคํ…์ด ์ฒ˜๋ฆฌํ•œ ์˜์—…์ผ(COB_DATE)
started_at DATETIME(6) X ์Šคํ… ์‹œ์ž‘ ์‹œ๊ฐ
ended_at DATETIME(6) X ์Šคํ… ์ข…๋ฃŒ(์„ฑ๊ณต/์‹คํŒจ/์ค‘๋‹จ ํ™•์ •) ์‹œ๊ฐ
status VARCHAR(10) X SUCCESS / FAILURE / HALTED(CobStepHaltException, #600)
failure_reason TEXT O ์‹คํŒจยท์ค‘๋‹จ ์‹œ ์˜ˆ์™ธ ๋ฉ”์‹œ์ง€. SUCCESS๋ฉด NULL

auth_token

์ผํšŒ์„ฑ ์ธ์ฆ ํ† ํฐ (#580). Redis์— ์žˆ๋˜ ํ† ํฐ 7์ข…์„ ์˜ฎ๊ฒผ๋‹ค

์•ฝ๊ด€ ๋™์˜ ยท ์•„์ด๋”” ํ™•์ธ ยท ์ด๋ฉ”์ผ ์ธ์ฆ ยท ๊ณ„์ขŒ ์ธ์ฆ ยท ์ž„์‹œ๊ฐ€์ž…(ํšŒ์›๊ฐ€์ž… 5์ข…)๊ณผ OTP ์ธ์ฆ ยท ๊ณ„์ขŒ๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฆ ํ† ํฐ์„ ํ•œ ํ…Œ์ด๋ธ”์— ๋‘”๋‹ค. ํ† ํฐ ์›๋ฌธ์€ ์ €์žฅํ•˜์ง€ ์•Š๊ณ  SHA-256 ํ•ด์‹œ๋กœ ์ฐพ๋Š”๋‹ค. ์†Œ๋น„๋Š” consumed_at IS NULL AND claim_id IS NULL AND expires_at > now ์กฐ๊ฑด๋ถ€ UPDATE ํ•œ ๋ฒˆ์ด๊ณ , ์˜ํ–ฅ๋ฐ›์€ ํ–‰์ด 1์ผ ๋•Œ๋งŒ ์„ฑ๊ณต์ด๋‹ค. ์ž„์‹œ๊ฐ€์ž… ํ† ํฐ๋งŒ ์˜ˆ์™ธ๋กœ, ์„ ์ ํ•œ ๊ฐ€์ž… ์™„๋ฃŒ ์š”์ฒญ์ด claim_id = ์ž๊ธฐ ์š”์ฒญ ID ์กฐ๊ฑด์œผ๋กœ ์†Œ๋น„ํ•œ๋‹ค. ์ €์žฅยท์†Œ๋น„ ๋ชจ๋‘ ํ˜ธ์ถœ์ž ํŠธ๋žœ์žญ์…˜์— ์ฐธ์—ฌํ•˜๋ฏ€๋กœ ์—…๋ฌด๊ฐ€ ๋กค๋ฐฑ๋˜๋ฉด ์†Œ๋น„๋„ ๋กค๋ฐฑ๋œ๋‹ค(#498).

์œ ํšจ์„ฑ์€ ํ•ญ์ƒ expires_at์œผ๋กœ ํŒ์ •ํ•œ๋‹ค. AUTH_TOKEN_CLEANUP ๋ฐฐ์น˜๋Š” ๋งŒ๋ฃŒ ํ–‰์„ ์ง€์›Œ ๊ณต๊ฐ„์„ ํšŒ์ˆ˜ํ•  ๋ฟ์ด๋‹ค. ๊ธธ์–ด์•ผ 30๋ถ„ ์‚ฌ๋Š” ๋ฐ์ดํ„ฐ๋ผ customer์— FK๋ฅผ ๊ฑธ์ง€ ์•Š๋Š”๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
auth_token_id BIGINT PK X ๋‚ด๋ถ€ ์‹๋ณ„์ž (AUTO_INCREMENT)
purpose VARCHAR(30) UK X ํ† ํฐ ์ข…๋ฅ˜. TERMS_AUTH / USER_ID_CHECK / EMAIL_VERIFICATION / ACCOUNT_AUTH / TEMP_SIGNUP / OTP_AUTH / ACCOUNT_PASSWORD_AUTH
token_hash CHAR(64) UK X ํ† ํฐ ์›๋ฌธ์˜ SHA-256 16์ง„์ˆ˜
customer_id BIGINT O ๋กœ๊ทธ์ธ ๊ณ ๊ฐ ํ† ํฐ์˜ ๊ณ ๊ฐ. ํšŒ์›๊ฐ€์ž… ํ† ํฐ์€ NULL
payload TEXT X ํ† ํฐ์— ๋ฌถ์ธ ๊ฐ’(JSON ๋ฌธ์ž์—ด). utf8mb4_bin์ด๋ผ ๊ฐ’ ์ผ์น˜ ์†Œ๋น„๊ฐ€ ๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ๋น„๊ต๋œ๋‹ค
claim_id CHAR(36) O ์ž„์‹œ๊ฐ€์ž… ํ† ํฐ์„ ์„ ์ ํ•œ ๊ฐ€์ž… ์™„๋ฃŒ ์š”์ฒญ ID. ์„ ์  ์ „ยท๋ณต๊ตฌ ํ›„๋Š” NULL
created_at DATETIME(6) X ๋ฐœ๊ธ‰ ์‹œ๊ฐ
expires_at DATETIME(6) X ๋งŒ๋ฃŒ ์‹œ๊ฐ. ์ด ์‹œ๊ฐ์ด ์ง€๋‚˜๋ฉด ์กฐํšŒยท์†Œ๋น„๋˜์ง€ ์•Š๋Š”๋‹ค
consumed_at DATETIME(6) O ์†Œ๋น„ ์‹œ๊ฐ. NULL์ด๋ฉด ์•„์ง ์“ฐ์ง€ ์•Š์€ ํ† ํฐ

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
UNIQUE uk_auth_token_hash_purpose token_hash, purpose
INDEX ix_auth_token_expires expires_at

otp_issue_lock

๊ณ ๊ฐ๋ณ„ OTP ๋ฐœ๊ธ‰ ์ž ๊ธˆ (#580). Redis SET NX ์ž ๊ธˆ์„ ์˜ฎ๊ฒผ๋‹ค

๊ฐ™์€ ๊ณ ๊ฐ์˜ OTP ๋ฐœ๊ธ‰ ์š”์ฒญ์„ ์—ฌ๋Ÿฌ ์ธ์Šคํ„ด์Šค์—์„œ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜๋งŒ ํ†ต๊ณผ์‹œํ‚จ๋‹ค. ์ž ๊ธˆ์€ ๋ฐœ๊ธ‰ ํŠธ๋žœ์žญ์…˜์— ์ฐธ์—ฌํ•˜์ง€ ์•Š๊ณ (NOT_SUPPORTED) ๋ฌธ์žฅ๋งˆ๋‹ค ๋ฐ”๋กœ ์ปค๋ฐ‹ํ•ด ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค์— ์ฆ‰์‹œ ๋ณด์ด๊ฒŒ ํ•œ๋‹ค. ํš๋“(INSERT IGNORE โ†’ ๋งŒ๋ฃŒ ์ž ๊ธˆ UPDATE)์„ ํ•œ ํŠธ๋žœ์žญ์…˜์— ๋ฌถ์œผ๋ฉด ๊ต์ฐฉ์ด ๋‚  ์ˆ˜ ์žˆ์–ด์„œ๋‹ค. ๋งŒ๋ฃŒ๋œ ์ž ๊ธˆ์€ ๋‹ค๋ฅธ ์š”์ฒญ์ด ๋‹ค์‹œ ์žก์„ ์ˆ˜ ์žˆ๊ณ , ํ•ด์ œ๋Š” owner_id๊ฐ€ ๊ฐ™์„ ๋•Œ๋งŒ ๋œ๋‹ค. ๊ณ ๊ฐ๋‹น 1ํ–‰์ด๋ผ ์ •๋ฆฌ ๋ฐฐ์น˜๊ฐ€ ์—†๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
customer_id BIGINT PK X ์ž ๊ธˆ ๋Œ€์ƒ ๊ณ ๊ฐ
owner_id CHAR(36) X ์ž ๊ธˆ์„ ์žก์€ ๋ฐœ๊ธ‰ ์š”์ฒญ ID(UUID)
expires_at DATETIME(6) X ์ž ๊ธˆ ๋งŒ๋ฃŒ ์‹œ๊ฐ

terms_view_history

์ƒํ’ˆ ์•ฝ๊ด€ ์—ด๋žŒ ์ด๋ ฅ (#580). Redis TTL 30๋ถ„ ํ‚ค๋ฅผ ์˜ฎ๊ฒผ๋‹ค

์ƒํ’ˆ๊ฐ€์ž… ์ „ ์•ฝ๊ด€์„ ์—ด๋žŒํ–ˆ๋Š”์ง€ 30๋ถ„ ๋™์•ˆ ์ธ์ •ํ•œ๋‹ค. ๋‹ค์‹œ ์—ด๋žŒํ•˜๋ฉด ๊ฐ™์€ ํ–‰์˜ viewed_atยทexpires_at์„ ๋ฎ์–ด์“ด๋‹ค. ์œ ํšจ์„ฑ์€ expires_at์œผ๋กœ ํŒ์ •ํ•˜๋ฏ€๋กœ ๋งŒ๋ฃŒ ์ฆ‰์‹œ ์—ด๋žŒ์œผ๋กœ ์ธ์ •๋˜์ง€ ์•Š๋Š”๋‹ค. ํ–‰ ์‚ญ์ œ๋Š” ๋งค์‹œ 45๋ถ„์— ๋„๋Š” TERMS_VIEW_HISTORY_CLEANUP ๋ฐฐ์น˜๊ฐ€ ๋งก์•„์„œ, ๋งŒ๋ฃŒ๋œ ํ–‰์ด ์ตœ๋Œ€ ์•ฝ 1์‹œ๊ฐ„(์—ด๋žŒ ์‹œ์ ๋ถ€ํ„ฐ ์•ฝ 90๋ถ„) DB์— ๋‚จ์„ ์ˆ˜ ์žˆ๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
customer_id BIGINT PK X ์—ด๋žŒ ๊ณ ๊ฐ
terms_id BIGINT PK X ์—ด๋žŒํ•œ ์•ฝ๊ด€
viewed_at DATETIME(6) X ๋งˆ์ง€๋ง‰ ์—ด๋žŒ ์‹œ๊ฐ
expires_at DATETIME(6) X ์—ด๋žŒ ์ธ์ • ๋งŒ๋ฃŒ ์‹œ๊ฐ (์—ด๋žŒ ํ›„ 30๋ถ„)

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
INDEX ix_terms_view_history_expires expires_at

EVENT_PUBLICATION

์ด๋ฒคํŠธ ๋ฐœํ–‰ ๊ธฐ๋ก โ€” ์•„์›ƒ๋ฐ•์Šค (PH-96, #437). Spring Modulith Event Publication Registry๊ฐ€ ์†Œ์œ ํ•œ๋‹ค

์—…๋ฌด ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ๋ฐœํ–‰๋œ ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›์„ AFTER_COMMIT ๋ฆฌ์Šค๋„ˆ๋งˆ๋‹ค 1ํ–‰์„ ๊ฐ™์€ ์ปค๋ฐ‹์œผ๋กœ ๋‚จ๊ธด๋‹ค. ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์„ฑ๊ณตํ•˜๋ฉด ํ–‰์„ ์ง€์šด๋‹ค(spring.modulith.events.completion-mode=delete). ๊ทธ๋ž˜์„œ ๋‚จ์•„ ์žˆ๋Š” ํ–‰์ด ๊ณง ์•„์ง ์ „๋‹ฌ๋˜์ง€ ์•Š์€ ์ด๋ฒคํŠธ๋‹ค. ์ปค๋ฐ‹ ์งํ›„ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์‹คํŒจํ•˜๊ฑฐ๋‚˜ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ฃฝ์–ด๋„ ํ–‰์ด ๋‚จ์•„ ๋‹ค์‹œ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

DDL์€ spring-modulith-events-jdbc 2.0.8์˜ schemas/v2/schema-mysql.sql์„ ๊ทธ๋Œ€๋กœ ์˜ฎ๊ฒผ๋‹ค. ํ…Œ์ด๋ธ”ยท์ปฌ๋Ÿผ๋ช…์ด ๋Œ€๋ฌธ์ž์ธ ๊ฒƒ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ด ์ด๋ฆ„์œผ๋กœ ์กฐํšŒํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๊ณ , ์‹œ๊ฐ์ด TIMESTAMP(6)(2038-01-19๊นŒ์ง€)์ธ ๊ฒƒ์€ ์›๋ณธ DDL์„ ๋ฐ”๊พธ์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค(ADR-0010). ํ–‰์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ง์ ‘ ์“ฐ์ง€ ์•Š๊ณ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋งŒ ์“ด๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
ID VARCHAR(36) PK X ๋ฐœํ–‰ ๊ธฐ๋ก ์‹๋ณ„์ž (UUID)
LISTENER_ID VARCHAR(512) X ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›์„ ๋ฆฌ์Šค๋„ˆ ๋ฉ”์„œ๋“œ ์‹๋ณ„์ž
EVENT_TYPE VARCHAR(512) X ์ด๋ฒคํŠธ ํด๋ž˜์Šค ์ „์ฒด ์ด๋ฆ„
SERIALIZED_EVENT VARCHAR(4000) X Jackson์œผ๋กœ ์ง๋ ฌํ™”ํ•œ ์ด๋ฒคํŠธ JSON
PUBLICATION_DATE TIMESTAMP(6) X ๋ฐœํ–‰ ์‹œ๊ฐ
COMPLETION_DATE TIMESTAMP(6) O NULL ์™„๋ฃŒ ์‹œ๊ฐ. delete ๋ชจ๋“œ์—์„œ๋Š” ์™„๋ฃŒ ์‹œ ํ–‰์ด ์ง€์›Œ์ ธ ์“ฐ์ด์ง€ ์•Š๋Š”๋‹ค
STATUS VARCHAR(20) O PUBLISHED / PROCESSING / COMPLETED / FAILED / RESUBMITTED
COMPLETION_ATTEMPTS INT O ์ „๋‹ฌ ์‹œ๋„ ํšŸ์ˆ˜
LAST_RESUBMISSION_DATE TIMESTAMP(6) O NULL ๋งˆ์ง€๋ง‰ ์žฌ์ œ์ถœ ์‹œ๊ฐ

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
INDEX EVENT_PUBLICATION_BY_COMPLETION_DATE_IDX COMPLETION_DATE

9. ํšŒ๊ณ„ ์›์žฅ โ€” P3

2์ฐจ์— ์‹ ์„ค(PH-20, #451). ์ด์ž ์ง€๊ธ‰(P2)๊ณผ ํƒ€ํ–‰ ์ด์ฒด(P4)๊ฐ€ ๋“ค์–ด์˜ค๋ฉด์„œ ์˜ˆ์ˆ˜๊ธˆ ์•ˆ์˜ ์ด๋™๋งŒ ์žˆ๋˜ ์ „์ œ๊ฐ€ ๊นจ์ ธ ํšŒ๊ณ„ ์›์žฅ์ด ํ•„์š”ํ•ด์กŒ๋‹ค.

Apache Fineract ์˜ acc_gl_accountยทacc_gl_journal_entry ๋ฅผ ๋Œ€์กฐ ๊ธฐ์ค€์œผ๋กœ ์‚ผ๋˜ ๋‘ ๊ฐ€์ง€๋Š” ๋‹ค๋ฅด๋‹ค. ๊ธˆ์•ก์„ BIGINT ์› ๋‹จ์œ„ ์ •์ˆ˜๋กœ ๋‘”๋‹ค(Fineract ๋Š” DECIMAL(19,6), ์ ˆ๋Œ€๊ทœ์น™ 5). ์ „ํ‘œ๋ฅผ ๋ณ„๋„ ํ…Œ์ด๋ธ”๋กœ ๋บ€๋‹ค(Fineract ๋Š” transaction_id ๋ฅผ ๊ณต์œ ํ•˜๋Š” ๋ถ„๊ฐœ ๋ฌถ์Œ์ด ์ „ํ‘œ ์—ญํ• ) โ€” ์ „ํ‘œ ๋‹จ์œ„๋กœ ์ฐจ๋Œ€๋ณ€์„ ๊ฒ€์ฆํ•˜๊ณ  ์ฑ„๋ฒˆ ๊ทœ์น™์„ ๋‘˜ ์ž๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์ฐจ๋Œ€๋ณ€ ๊ฒ€์ฆ ์ž์ฒด๋Š” Fineract ์™€ ๊ฐ™์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋งŒ ํ•œ๋‹ค(gl_journal_patterns.md ยง2).

gl_account

๊ณ„์ •๊ณผ๋ชฉ

์ฝ”๋“œ ์ฒด๊ณ„๋Š” ๋Œ€๋ถ„๋ฅ˜1 + ์ค‘๋ถ„๋ฅ˜2 + ์„ธ๋ถ„๋ฅ˜2 = 5์ž๋ฆฌ์ด๊ณ  ์ฒซ ์ž๋ฆฌ๊ฐ€ ๋ถ„๋ฅ˜์™€ 1:1 ๋กœ ๋Œ€์‘ํ•œ๋‹ค(1 ์ž์‚ฐ / 2 ๋ถ€์ฑ„ / 3 ์ž๋ณธ / 4 ์ˆ˜์ต / 5 ๋น„์šฉ). ์‹œ๋“œ 15๊ฐœ๋Š” R__seed_gl_account.sql ์ด ๋„ฃ๋Š”๋‹ค โ€” ๋งˆ์Šคํ„ฐ์„ฑ ๋ฐ์ดํ„ฐ๋ผ V__ ๊ฐ€ ์•„๋‹ˆ๋ผ R__ ๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
account_code CHAR(5) PK X ๊ณ„์ •๊ณผ๋ชฉ ์ฝ”๋“œ. ๋Œ€1+์ค‘2+์„ธ2. ์ฒซ ์ž๋ฆฌ๊ฐ€ ๋ถ„๋ฅ˜
account_name VARCHAR(50) X ๊ณ„์ •๊ณผ๋ชฉ๋ช…. ์‹œ์‚ฐํ‘œ ํ™”๋ฉด์— ๊ทธ๋Œ€๋กœ ํ‘œ์‹œ๋œ๋‹ค
account_class VARCHAR(12) X ASSET / LIABILITY / EQUITY / REVENUE / EXPENSE
normal_balance VARCHAR(6) X ์ •์ƒ์ž”์•ก ๋ฐฉํ–ฅ. DEBIT / CREDIT. ์ž์‚ฐยท๋น„์šฉ์€ ์ฐจ๋ณ€, ๋ถ€์ฑ„ยท์ž๋ณธยท์ˆ˜์ต์€ ๋Œ€๋ณ€
created_at DATETIME(6) X CURRENT_TIMESTAMP(6)
updated_at DATETIME(6) X CURRENT_TIMESTAMP(6)

์ œ์•ฝ

์ด๋ฆ„ ๋‚ด์šฉ ์ด์œ 
ck_gl_account_code account_code REGEXP '^[1-5][0-9]{4}$' ์ฝ”๋“œ ์ฒด๊ณ„๊ฐ€ ๋ฌธ์„œ์—๋งŒ ์žˆ์œผ๋ฉด ๊นจ์ง„๋‹ค. ck_account_number ์™€ ๊ฐ™์€ ๋ฐฉ์‹
ck_gl_account_class_code ์ฝ”๋“œ ์ฒซ ์ž๋ฆฌ ยท account_class ยท normal_balance ๋‹ค์„ฏ ์กฐํ•ฉ ์ค‘ ํ•˜๋‚˜ ์—ด๋งˆ๋‹ค ๋”ฐ๋กœ ์ œํ•œํ•˜๋ฉด 10100+LIABILITY ๋‚˜ ASSET+CREDIT ์ด ํ†ต๊ณผํ•œ๋‹ค. ์ด CHECK ๊ฐ€ ๋‘ ์—ด์˜ ํ—ˆ์šฉ๊ฐ’ ๊ฒ€์‚ฌ๊นŒ์ง€ ํฌํ•จํ•œ๋‹ค. contra ๊ณ„์ •(์ž์‚ฐ์ธ๋ฐ ์ •์ƒ์ž”์•ก ๋Œ€๋ณ€)์€ 2์ฐจ์— ์—†๊ณ , ํ•„์š”ํ•ด์ง€๋ฉด ์ƒˆ V ํŒŒ์ผ์—์„œ ๋„“ํžŒ๋‹ค

gl_voucher

์ „ํ‘œ โ€” ๋ถ„๊ฐœ๋ฅผ ๋‹ด๋Š” ๋‹จ์œ„

๊ฑฐ๋ž˜ 1๊ฑด์ด ์žฅ๋ถ€์— ๋‚จ๊ธด ๊ธฐํ‘œ ๋‹จ์œ„๋‹ค. ๋ถ„๊ฐœ ์—ฌ๋Ÿฌ ์ค„์„ ๋‹ด๊ณ  ์ „ํ‘œ ํ•˜๋‚˜ ์•ˆ์—์„œ ์ฐจ๋ณ€ ํ•ฉ๊ณ„์™€ ๋Œ€๋ณ€ ํ•ฉ๊ณ„๊ฐ€ ๊ฐ™์•„์•ผ ํ•œ๋‹ค. ์ด ๊ฒ€์ฆ์€ ๋„๋ฉ”์ธ(gl.domain.Voucher)์—์„œ๋งŒ ํ•˜๊ณ  DB ์ œ์•ฝ์€ ๊ฑธ์ง€ ์•Š๋Š”๋‹ค โ€” ๊ทผ๊ฑฐ๋Š” gl_journal_patterns.md ยง2. ์ „ํ‘œ๋ฒˆํ˜ธ yyyyMMdd-TTT-NNNNNN ์€ gl_voucher_sequence ๊ฐ€ ์ฑ„๋ฒˆํ•œ๋‹ค.

updated_at ์ด ์—†๋‹ค. ์ „ํ‘œ๋Š” ์ˆ˜์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ํ‹€๋ฆฌ๋ฉด ์ง€์šฐ๊ฑฐ๋‚˜ ๊ณ ์น˜์ง€ ์•Š๊ณ  ์ •์ • ์ „ํ‘œ๋ฅผ ์ƒˆ๋กœ ์„ธ์šด๋‹ค(์šฉ์–ดํ‘œ "์ •์ • ์ฒด์ธ"). ์ˆ˜์ • ์‹œ๊ฐ ์นธ์ด ์žˆ์œผ๋ฉด ๊ณ ์ณ๋„ ๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ฝํžŒ๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
voucher_no VARCHAR(20) PK X ์ „ํ‘œ๋ฒˆํ˜ธ. ์˜์—…์ผ + ์œ ํ˜• + ์ผ๋ จ
trade_date DATE X ์ด ์ „ํ‘œ๊ฐ€ ๊ท€์†๋˜๋Š” ์˜์—…์ผ
tx_type VARCHAR(24) X OPENING / TRANSFER / PRODUCT_SUBSCRIPTION / INTEREST / REVERSAL / INTERBANK_TRANSFER(ํƒ€ํ–‰ ์†ก์‹  ์š”์ฒญ) / INTERBANK_SETTLEMENT(ํƒ€ํ–‰ ํ™•์ • ํ•ด์†Œ) / MATURITY(๋งŒ๊ธฐํ•ด์ง€ ์›๋ฆฌ๊ธˆ ์ด์ฒด) / TERMINATION(์ค‘๋„ํ•ด์ง€ ์›๋ฆฌ๊ธˆ ์ด์ฒด)
reference_key VARCHAR(40) X ์› ๊ฑฐ๋ž˜๋ฒˆํ˜ธ. ์›์žฅ transaction_number ์™€ ๊ฐ™์€ ๊ฐ’์ด๊ณ  ๊ฐœ์‹œ ์ „ํ‘œ๋Š” OPENING-{yyyyMMdd}. ์›์žฅ๊ณผ ์ „ํ‘œ๋ฅผ 1:1 ๋กœ ์ž‡๋Š”๋‹ค(PH-24). ํƒ€ํ–‰์ด์ฒด๋งŒ ํ•œ ๊ฑฐ๋ž˜๋ฒˆํ˜ธ์— INTERBANK_TRANSFERยทINTERBANK_SETTLEMENT ๋‘ ์ „ํ‘œ๊ฐ€ ๋ถ™๋Š”๋‹ค(gl_journal_patterns.md ยง3-5)
description VARCHAR(200) O ์ ์š”
created_at DATETIME(6) X CURRENT_TIMESTAMP(6)

์ œ์•ฝ

์ด๋ฆ„ ๋‚ด์šฉ ์ด์œ 
ck_gl_voucher_tx_type 9๊ฐœ ์œ ํ˜• ์ค‘ ํ•˜๋‚˜ REVERSAL ์€ ์ •์ • ์ฒด์ธ ์ทจ์†Œ์ •์ •(PH-24). INTERBANK_TRANSFERยทINTERBANK_SETTLEMENT ๋Š” ํƒ€ํ–‰ ๋ฏธ๊ฒฐ์ œ 2ํŒจํ„ด(๋ถ„๊ฐœ ํŒจํ„ดํ‘œ ยง3-5, PH-33-โ‘ก). ๋‘ ์ „ํ‘œ๋Š” ๊ฐ™์€ ์› ๊ฑฐ๋ž˜๋ฒˆํ˜ธ๋ฅผ ์ฐธ์กฐ ํ‚ค๋กœ ์“ด๋‹ค. MATURITYยทTERMINATION ์€ ์˜ˆ์ ๊ธˆ ์›๋ฆฌ๊ธˆ ์ด์ฒด(๋ถ„๊ฐœ ํŒจํ„ดํ‘œ ยง3-7, #713)

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
UNIQUE uk_gl_voucher_no_trade_date voucher_no, trade_date
UNIQUE uk_gl_voucher_tx_type_reference_key tx_type, reference_key

voucher_no ๊ฐ€ ์ด๋ฏธ PK ๋ผ uk_gl_voucher_no_trade_date ๋Š” ํ–‰์„ ๋” ์ œํ•œํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋ถ„๊ฐœ๊ฐ€ ๋ณต์ œํ•ด ๊ฐ€๋Š” trade_date ๋ฅผ ๋ณตํ•ฉ FK ๋กœ ๋ฌถ๊ธฐ ์œ„ํ•œ ์ฐธ์กฐ ๋Œ€์ƒ์ด๋‹ค.

uk_gl_voucher_tx_type_reference_key ๋Š” ๊ฐ™์€ ๊ฑฐ๋ž˜๋ฅผ ๋‘ ๋ฒˆ ๊ธฐํ‘œํ•˜๋Š” ๊ฒƒ์„ ๋ง‰๋Š”๋‹ค. ๋‘ ๋ฒˆ์งธ ๊ธฐํ‘œ๋Š” ์˜ˆ์™ธ๊ฐ€ ๋˜์–ด ์›์žฅ๊นŒ์ง€ ๋กค๋ฐฑ๋œ๋‹ค โ€” ์กฐ์šฉํžˆ ๋„˜๊ธฐ๋ฉด ์›์žฅ๋งŒ ๋‘ ๋ฒˆ ๊ธฐํ‘œ๋œ ์ƒํƒœ๊ฐ€ ๊ฐ€๋ ค์ง„๋‹ค.


gl_journal_entry

๋ถ„๊ฐœ โ€” ์ „ํ‘œ ์•ˆ์˜ ํ•œ ์ค„

๊ณ„์ •๊ณผ๋ชฉ ํ•˜๋‚˜์™€ ์ฐจ๋ณ€ ๋˜๋Š” ๋Œ€๋ณ€ ํ•œ์ชฝ์˜ ๊ธˆ์•ก์„ ๊ฐ€์ง„๋‹ค. Fineract acc_gl_journal_entry.type_enum + amount ์™€ ๊ฐ™์€ ํ˜•ํƒœ๋‹ค.

trade_date ๋ฅผ ์ „ํ‘œ์—์„œ ํ•œ ๋ฒˆ ๋” ๋“ค๊ณ  ๊ฐ„๋‹ค. 600๋งŒ ์ค„์„ ๊ธฐ๊ฐ„์œผ๋กœ ๊ฑฐ๋ฅผ ๋•Œ ์ „ํ‘œ ์กฐ์ธ์„ ์—†์• ๊ธฐ ์œ„ํ•ด์„œ๋‹ค โ€” Fineract ๋„ entry_date ๋ฅผ ๊ฐ™์€ ์ž๋ฆฌ์— ๋‘”๋‹ค. ๋ถ„๊ฐœ๋Š” ์ „ํ‘œ์™€ ํ•จ๊ป˜ ํ•œ ๋ฒˆ๋งŒ ์“ฐ์ด๊ณ  ์ˆ˜์ •๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋‘ ๊ฐ’์ด ์–ด๊ธ‹๋‚  ๊ฒฝ๋กœ๊ฐ€ ์—†๋‹ค.

์‹œ์‚ฐํ‘œ ์ง‘๊ณ„์šฉ ์ธ๋ฑ์Šค๋Š” ๊ฑฐ๋ž˜์ผ์ด ๋จผ์ €๋‹ค(GL-IDX). ix_gl_journal_entry_trade_date (trade_date, account_code, dr_cr, amount) ๋Š” ์กฐํšŒ ๊ธฐ๊ฐ„๋งŒ ๋ฒ”์œ„๋กœ ์ฝ๊ณ , ์ง‘๊ณ„ SQL ์ด ์“ฐ๋Š” ์ปฌ๋Ÿผ์„ ๋ชจ๋‘ ๋‹ด์•„ ๋ณธ ํ…Œ์ด๋ธ”์„ ์ฝ์ง€ ์•Š๋Š”๋‹ค. ์ธ๋ฑ์Šค๊ฐ€ ์—†์„ ๋•Œ๋Š” ๊ธฐ๊ฐ„๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ๋ถ„๊ฐœ ์ „์ฒด๋ฅผ fk_gl_journal_entry_account ์ˆœ์„œ๋กœ ์ฝ์—ˆ๋‹ค(์šด์˜ 647๋งŒ ํ–‰ ์ „ ๊ตฌ๊ฐ„ ํ‰๊ท  26.8์ดˆ, ph28_baseline_results.md). account_code ๋กœ ์‹œ์ž‘ํ•˜๋Š” ์ธ๋ฑ์Šค๋Š” ๋„ฃ์ง€ ์•Š๋Š”๋‹ค. (account_code, trade_date) ๋Š” ๊ธฐ๊ฐ„์œผ๋กœ ์ขํžˆ์ง€ ๋ชปํ•ด ์˜คํžˆ๋ ค ๋А๋ ธ๊ณ , fk_gl_journal_entry_account ๋Š” FK ๊ฐ€ ์ž๋™์œผ๋กœ ๋งŒ๋“  ์ธ๋ฑ์Šค๋ผ ๊ฐ™์€ FK ๋ฅผ ๋ฐ›์น  ์ˆ˜ ์žˆ๋Š” ์ธ๋ฑ์Šค๊ฐ€ ์ƒ๊ธฐ๋ฉด MySQL ์ด ์กฐ์šฉํžˆ ์ง€์šด๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
journal_entry_id BIGINT PK X AUTO_INCREMENT
voucher_no VARCHAR(20) FK โ†’ gl_voucher X ์ด ์ค„์ด ์†ํ•œ ์ „ํ‘œ
line_no SMALLINT X ์ „ํ‘œ ์•ˆ์˜ ์ค„ ๋ฒˆํ˜ธ. 1๋ถ€ํ„ฐ
account_code CHAR(5) FK โ†’ gl_account X ๊ณ„์ •๊ณผ๋ชฉ
dr_cr VARCHAR(6) X DEBIT / CREDIT. ๊ธˆ์•ก์˜ ๋ฐฉํ–ฅ์„ ์ด ์นธ์ด ๋งํ•œ๋‹ค
amount BIGINT X ์› ๋‹จ์œ„ ์ •์ˆ˜. ํ•œ ์ค„์€ ํ•œ์ชฝ ๊ธˆ์•ก๋งŒ ๊ฐ€์ง€๋ฏ€๋กœ ํ•ญ์ƒ ์–‘์ˆ˜
trade_date DATE X ์ „ํ‘œ trade_date ๋ณต์ œ๋ณธ. ์‹œ์‚ฐํ‘œ ์ง‘๊ณ„ ๊ธฐ์ค€์ผ
created_at DATETIME(6) X CURRENT_TIMESTAMP(6)

์ธ๋ฑ์Šค

์ข…๋ฅ˜ ์ด๋ฆ„ ์ปฌ๋Ÿผ
UNIQUE uk_gl_journal_entry_line voucher_no, line_no
FK fk_gl_journal_entry_voucher voucher_no, trade_date โ†’ gl_voucher
FK fk_gl_journal_entry_account account_code โ†’ gl_account
INDEX ix_gl_journal_entry_trade_date trade_date, account_code, dr_cr, amount

์ œ์•ฝ

์ด๋ฆ„ ๋‚ด์šฉ ์ด์œ 
ck_gl_journal_entry_dr_cr DEBIT ๋˜๋Š” CREDIT
ck_gl_journal_entry_amount amount > 0 0์› ๋ถ„๊ฐœ์™€ ์Œ์ˆ˜ ๊ธˆ์•ก์„ ๋ง‰๋Š”๋‹ค. ๋ฐฉํ–ฅ์€ dr_cr ์ด ๋งํ•œ๋‹ค
ck_gl_journal_entry_line_no line_no > 0 ์ค„ ๋ฒˆํ˜ธ๋Š” 1๋ถ€ํ„ฐ๋‹ค. NOT NULLยทUNIQUE ๋งŒ์œผ๋กœ๋Š” 0 ๊ณผ ์Œ์ˆ˜๊ฐ€ ํ†ต๊ณผํ•œ๋‹ค

์ „ํ‘œ FK ๊ฐ€ ๋ณตํ•ฉ์ธ ์ด์œ . voucher_no ๋งŒ ์ฐธ์กฐํ•˜๋ฉด ์ „ํ‘œ์™€ ๋‹ค๋ฅธ trade_date ๋ฅผ ๊ฐ€์ง„ ๋ถ„๊ฐœ๊ฐ€ ์ €์žฅ๋˜๊ณ , ๊ทธ๋Œ€๋กœ ๋‚ ์งœ๋ณ„ ์‹œ์‚ฐํ‘œ ์ง‘๊ณ„๊ฐ€ ํ‹€์–ด์ง„๋‹ค. ๋ณต์ œ๋ณธ์ด ์›๋ณธ๊ณผ ๊ฐ™๋„๋ก DB ๊ฐ€ ๊ฐ•์ œํ•œ๋‹ค โ€” ํŠนํžˆ P6 ์‹œ๋“œ ์ƒ์„ฑ๊ธฐ(PH-60b)๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  600๋งŒ ๊ฑด์„ ์ง์ ‘ INSERT ํ•˜๋ฏ€๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ทœ์•ฝ์œผ๋กœ๋Š” ๋ง‰์„ ์ˆ˜ ์—†๋‹ค.


gl_voucher_sequence

์ „ํ‘œ๋ฒˆํ˜ธ ์ผ๋ จ๋ฒˆํ˜ธ ์ฑ„๋ฒˆ (PH-21)

์ „ํ‘œ๋ฒˆํ˜ธ ๋ 6์ž๋ฆฌ๋ฅผ (๊ฑฐ๋ž˜์ผ, ์œ ํ˜•)๋งˆ๋‹ค 1๋ถ€ํ„ฐ ์ฑ„๋ฒˆํ•œ๋‹ค. ๊ตฌ์กฐ๋Š” transaction_sequence ์™€ ๊ฐ™๋‹ค. ์นด์šดํ„ฐ๋Š” ๊ธฐํ‘œ ํŠธ๋žœ์žญ์…˜๊ณผ ๋ณ„๋„๋กœ ์ปค๋ฐ‹ํ•œ๋‹ค โ€” ๊ฐ™์€ ํŠธ๋žœ์žญ์…˜์ด๋ฉด ์ด์ฒด๊ฐ€ ์ปค๋ฐ‹๋  ๋•Œ๊นŒ์ง€ ํ–‰ ๋ฝ์„ ์žก์•„ ๊ฐ™์€ ๋‚  ๊ฐ™์€ ์œ ํ˜•์˜ ๊ธฐํ‘œ๊ฐ€ ์ง๋ ฌํ™”๋œ๋‹ค. ๋Œ€๊ฐ€๋กœ ๊ธฐํ‘œ๊ฐ€ ๋กค๋ฐฑ๋˜๋ฉด ๊ฒฐ๋ฒˆ์ด ์ƒ๊ธด๋‹ค.

๊ทธ๋‚  ํ–‰์ด ์—†์œผ๋ฉด gl_voucher ์— ์ด๋ฏธ ์žˆ๋Š” ๊ฐ€์žฅ ํฐ ๋ฒˆํ˜ธ ๋‹ค์Œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•œ๋‹ค. ์‹œ๋“œ(PH-60b)๋Š” ์ด ์นด์šดํ„ฐ๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  ์ „ํ‘œ๋ฅผ ์ง์ ‘ ๋„ฃ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
trade_date DATE PK X ์ „ํ‘œ์˜ ๊ฑฐ๋ž˜์ผ. ์ „ํ‘œ๋ฒˆํ˜ธ ์•ž 8์ž๋ฆฌ์™€ ๊ฐ™๋‹ค
tx_type VARCHAR(24) PK X gl_voucher.tx_type ๊ณผ ๊ฐ™์€ ๊ฐ’
last_seq INT X ํ•ด๋‹น ๊ฑฐ๋ž˜์ผยท์œ ํ˜•์—์„œ ๋งˆ์ง€๋ง‰์œผ๋กœ ๋‚˜๊ฐ„ ์ผ๋ จ๋ฒˆํ˜ธ
updated_at DATETIME(6) X ๋งˆ์ง€๋ง‰ ์ฑ„๋ฒˆ ์‹œ๊ฐ

CHECK ์ œ์•ฝ

์ด๋ฆ„ ์กฐ๊ฑด
ck_gl_voucher_sequence_range last_seq BETWEEN 1 AND 999999

10. ์˜์—…์ผ โ€” P5

2์ฐจ์— ์‹ ์„ค(PH-40, #471). ์˜์—…์ผ์€ ์‹œ์Šคํ…œ ์‹œ๊ฐ๊ณผ ๋ถ„๋ฆฌ๋œ ๋…ผ๋ฆฌ ์—…๋ฌด์ผ์ž์ด๊ณ  business.api.BusinessDateProvider ๊ฐ€ ์œ ์ผํ•œ ์ถœ์ฒ˜๋‹ค(glossary 6๋ฒˆ).

Apache Fineract ์˜ m_business_date ์ฒ˜๋Ÿผ ์‹œ๊ณ„๊ฐ€ ์•„๋‹ˆ๋ผ DB ์— ์ €์žฅ๋œ ๊ฐ’์„ ์˜์—…์ผ๋กœ ์“ด๋‹ค. ํ…Œ์ด๋ธ”์€ ๋‘˜๋กœ ๋‚˜๋ˆˆ๋‹ค โ€” ๋งค์ผ ๋ฐ”๋€Œ๋Š” ๊ฐ’ 1๊ฐœ(business_date)์™€ ํ•œ ๋ฒˆ ๋„ฃ๊ณ  ๊ฑฐ์˜ ์•ˆ ๋ฐ”๋€Œ๋Š” ๋ชฉ๋ก(holiday)์€ ์„ฑ๊ฒฉ์ด ๋‹ค๋ฅด๋‹ค. Fineract ์™€ ๋‹ฌ๋ฆฌ ์˜์—…์ผ์„ ๋„˜๊ธธ ๋•Œ ํœด์ผ์„ ๊ฑด๋„ˆ๋›ด๋‹ค(Fineract ๋Š” plusDays(1) ์ด๊ณ  ํœด์ผ์€ ๋ณ„๋„ ๊ฐœ๋…).

business_date

ํ˜„์žฌ ์˜์—…์ผ

date_type ๋ณ„๋กœ ํ•œ ํ–‰์ด๋‹ค. 2์ฐจ์—๋Š” BUSINESS_DATE ํ•œ ํ–‰๋ฟ์ด๊ณ , ๋งˆ๊ฐ ๋Œ€์ƒ์ผ(COB_DATE) ๊ฐ™์€ ์ข…๋ฅ˜๊ฐ€ ํ•„์š”ํ•ด์ง€๋ฉด ํ…Œ์ด๋ธ”์„ ๋ฐ”๊พธ์ง€ ์•Š๊ณ  ํ–‰์„ ๋”ํ•œ๋‹ค(Fineract BusinessDateType ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ).

์ดˆ๊ธฐ๊ฐ’ 2026-01-01 ์€ ์˜๋ฏธ ์—†๋Š” ๊ณผ๊ฑฐ ๋‚ ์งœ๋‹ค โ€” ์„œ๋ฒ„๊ฐ€ ๋œฐ ๋•Œ ์˜ค๋Š˜ ๋‹ฌ๋ ฅ์— ๋งž์ถ˜๋‹ค(์˜ค๋Š˜์ด ์˜์—…์ผ์ด๋ฉด ์˜ค๋Š˜, ์•„๋‹ˆ๋ฉด ๋‹ค์Œ ์˜์—…์ผ. ์ €์žฅ๊ฐ’์ด ๊ทธ๋ณด๋‹ค ์ด์ „์ผ ๋•Œ๋งŒ ๋ฐ”๊พผ๋‹ค). V ํŒŒ์ผ์ด ์‹คํ–‰๋˜๋Š” ๋‚ ์€ ํ™˜๊ฒฝ๋งˆ๋‹ค(ํŒ€์› ๋กœ์ปฌยทCIยท๋ฐฐํฌ) ๋‹ฌ๋ผ์„œ ํŠน์ • ๋‚ ์งœ๋ฅผ ๋ฐ•์œผ๋ฉด ๋ฏธ๋ž˜๋‚˜ ๊ณผ๊ฑฐ๋กœ ์–ด๊ธ‹๋‚œ๋‹ค. NOW()ยทCURRENT_DATE ๋Š” RDS ๊ฐ€ UTC ๋ผ ์“ฐ์ง€ ์•Š๋Š”๋‹ค. ์ดํ›„ ์˜์—…์ผ์€ ๋งค์ผ ์ž์ •(KST) ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋งž์ถ”๊ณ , PH-43 ์ดํ›„์—๋Š” COB ๋งˆ์ง€๋ง‰ ์Šคํ…์ด ๋‹ค์Œ ์˜์—…์ผ๋กœ ๋„˜๊ธด๋‹ค. ๊ธฐ๋™ ์‹œ ๋งž์ถ”๊ธฐ๋Š” PH-43 ์ดํ›„์—๋„ ๋‚จ๋Š”๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
date_type VARCHAR(20) PK X ์˜์—…์ผ ์ข…๋ฅ˜. 2์ฐจ๋Š” BUSINESS_DATE 1ํ–‰
business_date DATE X ํ˜„์žฌ ์˜์—…์ผ
created_at DATETIME(6) X CURRENT_TIMESTAMP(6)
updated_at DATETIME(6) X CURRENT_TIMESTAMP(6) ๋งˆ์ง€๋ง‰ ์˜์—…์ผ ์ „ํ™˜ ์‹œ๊ฐ

business_date_cutoff

์˜์—…์ผ ๋งˆ๊ฐ cutoff (#556)

COB์˜ ์˜์—…์ผ ์ „ํ™˜(advanceFrom)๊ณผ ๋‹ฌ๋ ฅ ๋”ฐ๋ผ์žก๊ธฐ(catchUpTo)๊ฐ€ BUSINESS_DATE๋ฅผ ๋‹ค์Œ ์˜์—…์ผ๋กœ ๋„˜๊ธธ ๋•Œ ๋– ๋‚˜๋Š” ์˜์—…์ผ D์˜ ํ–‰์„ ๊ฐ™์€ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋‚จ๊ธด๋‹ค. ์ „ํ™˜ UPDATE๊ฐ€ BUSINESS_DATE ํ–‰์— ๋ฐฐํƒ€ ๋ฝ์„ ์žก์œผ๋ฏ€๋กœ, D๋ฅผ ์ฝ์€ ๊ฑฐ๋ž˜๊ฐ€ ๋ชจ๋‘ commit/rollback๋œ ๋’ค์—๋งŒ ์ด ํ–‰์ด ์ปค๋ฐ‹๋œ๋‹ค. ๋ ˆํ”Œ๋ฆฌ์นด์—์„œ status = 'CLOSED'์ธ D๊ฐ€ ๋ณด์ด๋ฉด D ๊ฑฐ๋ž˜์ผ ์›์žฅ์ด ๋”๋Š” ์ถ”๊ฐ€๋˜์ง€ ์•Š๋Š”๋‹ค(info_mart.md ยง3-0). batch_execution_history๋Š” ์ด ์‹ ํ˜ธ๋กœ ์“ฐ์ง€ ์•Š๋Š”๋‹ค. ๊ธฐ์ค€์ผ๋งˆ๋‹ค CLOSED ํ–‰์€ ํ•˜๋‚˜์ด๊ณ , ์žฌ์‹คํ–‰์€ ๋ฉฑ๋“ฑ INSERT๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค. ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”๊ณผ FK๋Š” ์—†๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
business_date_cutoff_id BIGINT PK X ๋‚ด๋ถ€ ์‹๋ณ„์ž (AUTO_INCREMENT)
base_date DATE UK X ๋งˆ๊ฐ๋œ ์˜์—…์ผ
status VARCHAR(10) UK X CLOSED
closed_at DATETIME(6) X ๋งˆ๊ฐ ์‹œ๊ฐ(KST, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ฑ„์›€)
๊ตฌ๋ถ„ ์ธ๋ฑ์Šค ์ปฌ๋Ÿผ
UNIQUE uk_business_date_cutoff_date_status base_date, status

cob_checkpoint

COB ์žฌ์‹œ์ž‘ ์ฒดํฌํฌ์ธํŠธ (#663)

CobRunnerService๊ฐ€ ์ƒˆ COB๋ฅผ ์‹œ์ž‘ํ•  ๋•Œ, ์˜์—…์ผ์„ ๋„˜๊ธฐ๊ธฐ ์ „์— ๋งˆ๊ฐ ๋Œ€์ƒ ์˜์—…์ผ(COB_DATE)์˜ ์˜์—…์ผ ์ „ํ™˜ ํ–‰๊ณผ ๋“ฑ๋ก๋œ ์Šคํ… ํ–‰์„ ๋ชจ๋‘ PENDING์œผ๋กœ ๋‚จ๊ธฐ๊ณ , ์ „ํ™˜๊ณผ ์Šคํ…์ด ๋๋‚  ๋•Œ๋งˆ๋‹ค SUCCESS๋กœ ๋ฐ”๊พผ๋‹ค. PENDING์ด ๋‚จ์€ cob_date๊ฐ€ ์žˆ์œผ๋ฉด ๋‹ค์Œ run()์ด ์˜ค๋ž˜๋œ ๋‚ ์งœ๋ถ€ํ„ฐ ๊ทธ ๋‚ ์งœ์˜ PENDING ์Šคํ…๋งŒ ์ด์–ด์„œ ์‹คํ–‰ํ•œ๋‹ค. ํ–‰์ด ์—†๋Š” ์Šคํ…(์ดˆ๊ธฐํ™” ์‹คํŒจ ๋“ฑ)์€ ์žฌ๊ฐœ ๋Œ€์ƒ์ด ์•„๋‹ˆ๋‹ค. batch_execution_history๋Š” ๊ด€์ธก์šฉ์ด๋ผ ์žฌ์‹œ์ž‘ ๊ทผ๊ฑฐ๋กœ ์“ฐ์ง€ ์•Š๊ณ , business_date_cutoff๋Š” ๋‹ฌ๋ ฅ ๋”ฐ๋ผ์žก๊ธฐ๋„ ๊ธฐ๋กํ•˜๋ฏ€๋กœ COB_DATE์˜ ๊ทผ๊ฑฐ๊ฐ€ ์•„๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”๊ณผ FK๋Š” ์—†๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
cob_checkpoint_id BIGINT PK X ๋‚ด๋ถ€ ์‹๋ณ„์ž (AUTO_INCREMENT)
cob_date DATE UK X ๋งˆ๊ฐ ๋Œ€์ƒ ์˜์—…์ผ(ADR-0004 COB_DATE)
step_name VARCHAR(100) UK X CobStep.name(). ์˜์—…์ผ ์ „ํ™˜์€ business-date-advance
status VARCHAR(10) X PENDING / SUCCESS
updated_at DATETIME(6) X ๋งˆ์ง€๋ง‰ ์ƒํƒœ ๋ณ€๊ฒฝ ์‹œ๊ฐ(KST, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ฑ„์›€)
๊ตฌ๋ถ„ ์ธ๋ฑ์Šค ์ปฌ๋Ÿผ
UNIQUE uk_cob_checkpoint_date_step cob_date, step_name

holiday

ํœด์ผ ๋‹ฌ๋ ฅ โ€” ์ฃผ๋ง์„ ์ œ์™ธํ•œ ๊ณตํœด์ผ

์ฃผ๋ง์€ ๋„ฃ์ง€ ์•Š๋Š”๋‹ค โ€” ํ† ยท์ผ์€ ์š”์ผ๋กœ ํŒ์ •ํ•œ๋‹ค. ์˜์—…์ผ = ์ฃผ๋ง๋„ ์•„๋‹ˆ๊ณ  ์ด ํ…Œ์ด๋ธ”์—๋„ ์—†๋Š” ๋‚ . ์‹œ๋“œ๋Š” R__seed_holiday.sql ์ด ๋„ฃ๋Š”๋‹ค โ€” ์šด์˜์—๋„ ์žˆ์–ด์•ผ ํ•˜๊ณ  ๋Œ€์ฒด๊ณตํœด์ผยท์ž„์‹œ๊ณตํœด์ผ์ด ์ถ”๊ฐ€๋  ์ˆ˜ ์žˆ๋Š” ๋งˆ์Šคํ„ฐ์„ฑ ๋ฐ์ดํ„ฐ๋ผ V__ ๊ฐ€ ์•„๋‹ˆ๋ผ R__ ๋‹ค. ๋“ฑ๋ก API ๋Š” 2์ฐจ ๋ฒ”์œ„ ๋ฐ–์ด๋‹ค.

์ปฌ๋Ÿผ ํƒ€์ž… ํ‚ค Null ๊ธฐ๋ณธ๊ฐ’ ๋‹ด๊ธฐ๋Š” ์ •๋ณด
holiday_date DATE PK X ํœด์ผ ๋‚ ์งœ
holiday_name VARCHAR(50) X ์˜ˆ: ๊ฐœ์ฒœ์ ˆ, ๋Œ€์ฒด๊ณตํœด์ผ(์ถ”์„)
created_at DATETIME(6) X CURRENT_TIMESTAMP(6)
updated_at DATETIME(6) X CURRENT_TIMESTAMP(6)