12 KiB
12 KiB
계좌 평가 이력과 자산 마감 데이터 모델
목적과 범위
계좌 평가 증거, 수동 자산, append-only 자산 마감과 기존 ledger entities의 실제 SQLite 정본을 기록한다.
- 포함 범위:
accounts,transactions,manual_assets,account_valuations,asset_snapshots,asset_snapshot_runs,reconciliation_sessions,review_decisions,import_batches,schema_meta - 제외 범위: auth cookie/session, external price/FX store, inferred transactions, actual credentials/data
정본 엔터티
accounts — 기존 계좌
- 책임: 계좌 identity/current display balance와 account type/liquidity metadata
- 식별자:
id - 생명 주기: 기존 CRUD; valuation history는 별도 append-only
필드
| 필드 | 타입 | 필수 여부 | 기본값 | 허용 값·형식 | 단위·정밀도 | 민감정보 |
|---|---|---|---|---|---|---|
id |
TEXT | 필수 | 없음 | generated account id | 식별자 | 아니오 |
name |
TEXT | 필수 | 없음 | non-empty | 없음 | 아니오 |
type |
TEXT | 필수 | bank |
bank/card/cash/investment/loan/other | enum | 아니오 |
currency |
TEXT | 필수 | KRW |
supported currency | ISO code | 아니오 |
last_balance |
INTEGER | 선택 | NULL | exact integer | currency unit | 아니오 |
last_balance_basis_date |
TEXT | 선택 | '' |
YYYY-MM-DD or unknown | date of the evidence represented by last_balance; empty/unknown is explicit |
아니오 |
last_synced_at |
TEXT | 선택 | '' |
ISO date/time | timestamp | 아니오 |
statement_status |
TEXT | 필수 | unknown |
existing status enum | 없음 | 아니오 |
liquidity_bucket |
TEXT | 필수 | other |
cash/deposit/investment/real_estate/other/loan | enum | 아니오 |
account_number_masked |
TEXT | 필수 | '' |
masked only | redacted | 민감 가능 |
account-valuations — 기준일 계좌 평가
- 책임: 날짜가 지정된 평가 evidence와 선택/correction provenance. investment
principal은 reported principal amount이고 loanprincipal은 outstanding principal이다. - 식별자:
id - 생명 주기: insert-only; correction은
supersedes_idchild
필드
| 필드 | 타입 | 필수 여부 | 기본값 | 허용 값·형식 | 단위·정밀도 | 민감정보 |
|---|---|---|---|---|---|---|
id |
TEXT | 필수 | 없음 | generated valuation id | 식별자 | 아니오 |
account_id |
TEXT FK | 필수 | 없음 | accounts.id | 관계 | 아니오 |
basis_date |
TEXT | 필수 | 없음 | YYYY-MM-DD | date | 아니오 |
amount |
INTEGER | 필수 | 없음 | exact signed integer | currency unit | 아니오 |
currency |
TEXT | 필수 | KRW | supported currency | ISO code | 아니오 |
valuation_kind |
TEXT | 필수 | balance | balance/cash_balance/total_value/loan/loan_balance | purpose | 아니오 |
source_type |
TEXT | 필수 | manual | manual/import/account_write/reconciliation/snapshot | enum | 아니오 |
source_ref |
TEXT | 필수 | '' |
source/hash/reference | opaque | 민감 가능 |
verification_status |
TEXT | 필수 | unverified | verified/unverified/rejected | enum | 아니오 |
recorded_at |
TEXT | 필수 | 없음 | ISO timestamp | timestamp | 아니오 |
memo |
TEXT | 필수 | '' |
operator note | 없음 | synthetic only |
idempotency_key |
TEXT | 필수 | '' |
caller key | opaque | 아니오 |
supersedes_id |
TEXT FK | 선택 | NULL | parent valuation | one child | 아니오 |
correction_reason |
TEXT | 필수 | '' |
required for correction | 없음 | 아니오 |
as_of_at/timezone |
TEXT | 함께 선택 | NULL | timezone-aware ISO + IANA | timestamp/zone | 아니오 |
cost_basis,net_contributed,profit,principal,interest,fee |
INTEGER | 선택 | NULL | exact integer; NULL distinct from 0 | currency unit | 아니오 |
reported_principal_kind,reported_principal_label,return_basis |
TEXT | 선택 | NULL | source-declared | 없음 | 아니오 |
return_rate |
REAL | 선택 | NULL | finite number | ratio | 아니오 |
representative_liability_definition |
TEXT | loan 필수 | NULL | principal_only/principal_interest_fees | enum | 아니오 |
manual-assets — 수동 자산/부채
- 책임: transaction이 아닌 평가 source
- 식별자:
id - 생명 주기: update/deactivate; closed snapshot은 별도 immutable copy
필드
| 필드 | 타입 | 필수 여부 | 기본값 | 허용 값·형식 | 단위·정밀도 | 민감정보 |
|---|---|---|---|---|---|---|
id |
TEXT | 필수 | 없음 | generated asset id | 식별자 | 아니오 |
name |
TEXT | 필수 | 없음 | non-empty | 없음 | 아니오 |
liquidity_bucket |
TEXT | 필수 | other | normalized bucket | enum | 아니오 |
valuation_amount |
INTEGER | 선택 | NULL | exact integer; NULL unvalued | currency unit | 아니오 |
valuation_date |
TEXT | 필수 | '' |
YYYY-MM-DD | date | 아니오 |
currency |
TEXT | 필수 | KRW | supported currency | ISO code | 아니오 |
source_note,memo |
TEXT | 필수 | '' |
synthetic/redacted note | 없음 | 민감 가능 |
active |
INTEGER | 필수 | 1 | 0/1 | boolean | 아니오 |
asset-snapshots — closed snapshot rows
- 책임: basis-date historical immutable item copy
- 식별자:
id - 생명 주기: insert-only; correction run creates new rows
필드
| 필드 | 타입 | 필수 여부 | 기본값 | 허용 값·형식 | 단위·정밀도 | 민감정보 |
|---|---|---|---|---|---|---|
id,basis_date,source_type,name,created_at |
TEXT | 필수 | 없음 | generated/date/account/manual_asset | identity/date | 아니오 |
source_id,currency,liquidity_bucket,valuation_source,source_note,memo |
TEXT | 필수 | ''/KRW/other |
source metadata | 없음 | 가능 |
amount |
INTEGER | 선택 | NULL | exact integer | currency unit | 아니오 |
snapshot_run_id |
TEXT | 필수 | '' |
asset_snapshot_runs.id | relation | 아니오 |
correction_of_run_id,correction_reason |
TEXT | 필수 | '' |
prior run/reason | provenance | 아니오 |
is_correction |
INTEGER | 필수 | 0 | 0/1 | boolean | 아니오 |
closed_at |
TEXT | 필수 | '' |
ISO timestamp | timestamp | 아니오 |
valuation_id,selection_policy,verification_status,evidence_kind,exclusion_reason |
TEXT | additive | empty/exact/unverified/applied/empty | provenance enum | 없음 | 아니오 |
asset-snapshot-runs — close 실행 증거
- 책임: approval, selection, applied/excluded/carried evidence와 run identity
- 식별자:
id - 생명 주기: insert-only; correction points to prior run
필드
| 필드 | 타입 | 필수 여부 | 기본값 | 허용 값·형식 | 단위·정밀도 | 민감정보 |
|---|---|---|---|---|---|---|
id,basis_date,close_status |
TEXT | 필수 | 없음 | complete_exact/incomplete_draft/conditional | identity/date/status | 아니오 |
selection_policy |
TEXT | 필수 | exact | exact/as_of | enum | 아니오 |
idempotency_key |
TEXT | 필수 | '' |
unique when non-empty | opaque | 아니오 |
approved_by,approved_at,approval_reason,approval_reference |
TEXT | 필수 | empty | explicit approval metadata | provenance | 아니오 |
correction_of_run_id,correction_reason |
TEXT | 필수 | empty | prior run/reason | provenance | 아니오 |
applied_evidence,excluded_evidence,carried_evidence |
TEXT JSON | 필수 | [] |
redacted evidence arrays | JSON | 가능 |
created_at |
TEXT | 필수 | 없음 | ISO timestamp | timestamp | 아니오 |
transactions, import-batches, reconciliation-sessions, review-decisions, schema-meta — 기존 entities
기존 필드와 관계를 보존한다. import는 거래를 기록할 수 있지만 balance valuation candidate는 dated unverified row만 추가한다. reconciliation은 calculated balance provenance와 VALUATION_MANAGED 상태를 보존하며 investment valuation 때문에 transaction을 생성하지 않는다. schema_meta.schema_version은 12다.
현재 계좌 잔액 캐시와 기준일
last_balanceis the current cache value: it is the latest current balance observed by an import or account write, not a historical valuation and not opening evidence.last_balance_basis_dateis the basis field for the evidence represented by that cache. It is a date when known; legacy or date-less writes store unknown/NULL and must not be inferred fromlast_synced_ator a valuation row.last_synced_atis the execution/sync timestamp: when the import or account write advanced the cache, not the evidence basis date.- imports and account writes advance the account cache; they may also append a dated
account_valuationscandidate, but updating the cache does not rewrite historical rows. account_valuationsis the historical authority. A dated valuation remains append-only evidence even when it is older than the current cache; older evidence never rolls back the current cache.
관계와 불변조건
관계
| 출발 엔터티 | 관계 | 대상 엔터티 | 카디널리티 | 필수 여부 | 소유권 | 삭제 규칙 |
|---|---|---|---|---|---|---|
accounts |
has valuations | account-valuations |
1:N | required | account service | no cascade/history preserved |
account-valuations |
supersedes | account-valuations |
0..1 child | optional | valuation service | append-only |
asset-snapshot-runs |
contains | asset-snapshots |
1:N/possibly zero | required | snapshot service | no delete |
account-valuations |
evidence for | asset-snapshots |
0..N | optional | snapshot run | copy only |
import-batches |
produces candidate | account-valuations |
0..N | optional | import service | candidate preserved |
accounts |
has reconciliation | reconciliation-sessions |
1:N | optional | reconciliation service | no valuation side effect |
불변조건
idx_account_valuations_single_correctionensures one direct child; correction parent scope is same account/date/currency/purpose. Cyclic or self parent, second child, missing reason, and conflict are no-write failures.source_refis account-scoped evidence identity even when an explicit key is supplied; key/source mismatch conflicts. This is evidence idempotency. There is no generic label; only source-declaredreported_principal_kindandreported_principal_labelare physical fields.- only verified leaves are authority; unknown/future/unverified are excluded or warning evidence.
last_balanceis external current comparison, not opening evidence; missing balance_after/opening evidence isINCOMPLETE_CALCULATION. - preview does not insert; close inserts run and rows atomically; latest run is report authority. Reports expose actual valuation_date, age, carry, verification, run, approval, correction, warnings, and exclusions across close response, live, closed, timeseries, and monthly.
monthly_source_snapshot_idis a read-model alias ofsnapshot_run_id, not a persistence field. Investment unavailable and unavailable investment, loan purpose/definition/ambiguity, and reconciliation completeness remain explicit; no fake writes.asset_buckets - loanis the net-worth formula; representative loan only, no fake transactions.
저장과 마이그레이션
- 저장 위치: resolved SQLite path from
jarca_ledger_mcp.infrastructure.sqlite.connection - 직렬화 형식: SQLite tables; evidence arrays JSON UTF-8
- 스키마 버전: schema 11 → schema 12 additive
- 기존 데이터 처리:
migrate_db()creates missing tables/columns/indexes; this is an additive migration with no guessed migration or deletion. legacy rows with unknown basis remain unknown; no inference is permitted. - 하위 호환성: existing ledger/auth/menu/MCP contracts and legacy rows remain readable
- 롤백 조건: pre-migration backup restore boundary; do not down-migrate or delete valuation history in application code
검증
- 정상 데이터:
tests/test_account_valuations.py,tests/test_asset_snapshots.py - 경계 데이터: NULL/0, stale carry-forward, correction, empty snapshot tables
- 오류 데이터: invalid currency/kind, missing loan definition, idempotency/correction conflict
- 저장 후 재조회: service list/select/report and contract regression tests
- 마이그레이션:
test_*schema*tests pluspython -m pytest tests/test_account_valuations.py tests/test_asset_snapshots.py