Files
jarca-ledger-mcp/docs/data-model.md
T

19 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이고 loan principal은 outstanding principal이다.
  • 식별자: id
  • 생명 주기: insert-only; correction은 supersedes_id child

필드

필드 타입 필수 여부 기본값 허용 값·형식 단위·정밀도 민감정보
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 아니오

select_account_valuation 선택 규칙과 기존 인덱스 매핑

  • select_account_valuation은 account_id is mandatory인 단일 평가 선택 query다. currency and valuation_kind/purpose are optional filters이며, basis_date exact match or <= upper bound 조건을 지원한다.
  • 선택 결과는 verified leaf valuations only다. 즉 superseded parent가 아닌 leaf만 권위로 사용하며, future-dated and unverified valuations are excluded한다.
  • idx_account_valuations_account_date supports account/date selection; idx_account_valuations_status_date supports status/date selection. neither index covers account + currency + purpose이므로 해당 조합의 전체 선택 조건을 기존 인덱스가 대신 보장한다고 해석하지 않는다.
  • idempotency and single_correction indexes enforce write integrity, not selection이다. 이 인덱스들은 재기록 방지와 correction 단일 child 불변조건을 위한 것이며 select_account_valuation의 후보 검색 인덱스가 아니다.

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만 추가한다. loan cache writes without an explicit liability definition do not append an account_valuations candidate; current cache와 transaction import는 그대로 완료하며 정의를 추정하지 않는다. reconciliation은 calculated balance provenance와 VALUATION_MANAGED 상태를 보존하며 investment valuation 때문에 transaction을 생성하지 않는다. schema_meta.schema_version은 12다.

현재 계좌 잔액 캐시와 기준일

  • last_balance is 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_date is 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 from last_synced_at or a valuation row.
  • last_synced_at is 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; non-loan writes may also append a dated account_valuations candidate. loan cache writes without an explicit liability definition do not append historical evidence, and updating the cache does not rewrite historical rows.
  • account_valuations is 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.
  • Every valuation attached to a loan account has an explicit principal_only or principal_interest_fees representative_liability_definition. A non-loan to loan conversion with any undefined or invalid attached valuation is rejected without changing the account or history; conversion with no valuations is allowed.

관계와 불변조건

관계

출발 엔터티 관계 대상 엔터티 카디널리티 필수 여부 소유권 삭제 규칙
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_correction ensures 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_ref is 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-declared reported_principal_kind and reported_principal_label are physical fields.
  • only verified leaves are authority; unknown/future/unverified are excluded or warning evidence. last_balance is external current comparison, not opening evidence; missing balance_after/opening evidence is INCOMPLETE_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_id is a read-model alias of snapshot_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 - loan is 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 plus python -m pytest tests/test_account_valuations.py tests/test_asset_snapshots.py

settlement-drafts — 월정산 초안

Schema 13 adds two additive tables; init_db()/migrate_db() remain the only schema writers and schema 11→12 history is unchanged. No draft backfill is inferred. Exact migrated columns (from infrastructure/sqlite/migrations.py) are listed below; SCHEMA_SQL and migration DDL are the schema authority.

Table Columns (SQLite types; ? means nullable) Indexes / constraints
settlement_drafts id TEXT PK, month TEXT NOT NULL, basis_date TEXT NOT NULL, status TEXT NOT NULL, version INTEGER NOT NULL, created_by TEXT NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, memo TEXT DEFAULT '', create_key TEXT UNIQUE NOT NULL, correction_of_run_id TEXT DEFAULT '', correction_reason TEXT DEFAULT '', final_run_id TEXT DEFAULT '', final_response TEXT DEFAULT '', cancelled_by TEXT DEFAULT '', cancellation_reason TEXT DEFAULT '', cancelled_at TEXT DEFAULT '', approval_fingerprint TEXT DEFAULT '', approval_version INTEGER DEFAULT 0, approved_by TEXT DEFAULT '', approved_at TEXT DEFAULT '', approval_reason TEXT DEFAULT '', approval_reference TEXT DEFAULT '', approval_flags TEXT DEFAULT '{}', additive original_request_hash TEXT DEFAULT '' idx_settlement_drafts_active_month(month) WHERE status='active' unique; idx_settlement_drafts_month(month,created_at)
settlement_draft_items id TEXT PK, draft_id TEXT NOT NULL FK, source_type TEXT NOT NULL, source_id TEXT NOT NULL, valuation_id TEXT DEFAULT '', selection_mode TEXT DEFAULT 'exact', selection_reason TEXT DEFAULT '', included INTEGER DEFAULT 1, exclusion_reason TEXT DEFAULT '', version INTEGER DEFAULT 1, selected_by TEXT DEFAULT '', selected_at TEXT DEFAULT '', evidence_json TEXT DEFAULT '{}' UNIQUE(draft_id,source_type,source_id)

settlement_drafts therefore owns generated draft ID, YYYY-MM month, fixed month-end basis_date, active/completed/cancelled status, positive version, creator/timestamps/memo, create idempotency key+request fingerprint, correction parent/reason, approval actor/time/reason/reference/flags/fingerprint/version, final run ID and persisted response. The partial unique active-month constraint is shared by normal/correction drafts. settlement_draft_items owns stable target type/ID, inclusion/reason, selected valuation and selection mode/reason, item version/audit, frozen source evidence/hash and correction-child identity. Monetary authority is derived from eligible frozen evidence, not editable amount columns.

Modes are exact, carried_before, and manual_substitute. exact requires confirmed same-day evidence; carried_before requires a verified prior valuation and reason; manual_substitute requires explicit valuation ID, reason and review/approval even when valuation date is future. Preserve date_difference_days = valuation_date - basis_date; age_days retains its historical basis-minus-valuation meaning. Unverified candidates remain visible with candidate_amount but authority amount NULL. Missing is distinct from substitution/exclusion. Manual evidence freezes semantic fields and hash; only explicit refresh/reselection changes it.

Frozen/public evidence retains valuation_date, original recorded_at, derived date_difference_direction (after/before/same/unknown) and age_days; loan evidence retains representative_liability_definition. recorded_at may be later than month end while valuation_date is exactly month end. These names are preserved through finalized response, reports, timeseries and monthly coverage; date differences and semantic hashes are derived from frozen JSON rather than separate draft-item columns. Actor/version/timestamps of approval are cleared together on draft mutation.

Review fingerprint binds draft version, target/inclusion state, full valuation/manual semantic evidence, correction child, warnings, amounts/classification/date and prior run. Approved fingerprint/version become invalid on mutation or external drift. Finalize checks idempotency replay before active status, then validates version, approval, fingerprint, current evidence and correction parent, and inserts run+rows+draft completion/link in one BEGIN IMMEDIATE. Rollback on any SQLite failure; replay returns persisted response.

KRW only aggregation; non-KRW is warned/excluded, never converted. NULL is not zero; no targets yields provisional zero plus completeness and unregistered-liability warning, not a complete close. Existing snapshot rows preserve full frozen evidence, approval, date/mode/difference and actors; substitution, carried and approved-missing flags are orthogonal. monthly_source_snapshot_id remains a read-model alias, never a persistence field.