refactor(jarca-ledger): implement BAT-010 backend core layering

This commit is contained in:
Jarca
2026-07-03 07:03:17 +09:00
parent 02380a88ab
commit 7ac25a6cf7
36 changed files with 4892 additions and 4113 deletions
+75 -41
View File
@@ -4,21 +4,21 @@
- Baseline Seed: `.stage-pilot/bootstrap/baseline.yaml`
- Status: draft
- Owner: Jarca / project maintainer
- Last Updated (KST): 2026-06-30
- Source Discovery / Batch: bootstrap-baseline, BAT-006, BAT-007
- Last Updated (KST): 2026-07-03
- Source Discovery / Batch: bootstrap-baseline, BAT-006, BAT-007, BAT-010
## Project Summary
- Jarca 가계부 전용 MCP 서버와 Streamlit 대시보드로 계좌/카드 거래, 예산, 분류 규칙, import, 현금흐름 분석을 SQLite에 저장하고 운영한다.
- Jarca 가계부 전용 MCP 서버와 Streamlit 대시보드로 계좌/카드 거래, 예산, 분류 규칙, import, 자산/스냅샷, 현금흐름 분석을 SQLite에 저장하고 운영한다.
## Primary Domain
- Korean household finance ledger and transaction reconciliation
- Korean household finance ledger, reconciliation, and household asset tracking
## Tech Stack
- Python >=3.11
- FastMCP / MCP server
- SQLite
- Streamlit dashboard
- pandas / plotly dashboard dependencies
- Streamlit
- pandas / plotly
- PyMuPDF, openpyxl, msoffcrypto-tool
- pytest
- ruff
@@ -53,9 +53,28 @@ jarca-ledger-mcp/
│ └── app.py
├── jarca_ledger_mcp/
│ ├── __init__.py
│ ├── db.py
│ ├── service.py
│ ├── server.py
│ ├── service.py # compatibility facade
│ ├── db.py # compatibility shim
│ ├── server.py # compatibility shim / CLI entrypoint
│ ├── application/
│ │ ├── __init__.py
│ │ ├── shared.py
│ │ ├── system_services.py
│ │ ├── asset_account_services.py
│ │ ├── transaction_report_services.py
│ │ ├── import_transfer_services.py
│ │ └── categorization_services.py
│ ├── infrastructure/
│ │ └── sqlite/
│ │ ├── __init__.py
│ │ ├── connection.py
│ │ ├── schema.py
│ │ └── migrations.py
│ ├── adapters/
│ │ ├── mcp/
│ │ │ └── server.py
│ │ └── streamlit/
│ │ └── service_gateway.py
│ ├── kb_bank_pdf.py
│ ├── toss_bank_pdf.py
│ ├── toss_securities_pdf.py
@@ -64,7 +83,9 @@ jarca-ledger-mcp/
│ ├── contract_snapshots/
│ │ └── response_contract_v1_0.json
│ ├── test_contract_regression.py
│ ├── test_dashboard_app.py
│ ├── test_service.py
│ ├── test_asset_snapshots.py
│ ├── test_categorization.py
│ ├── test_category_rule_filters.py
│ ├── test_cross_account_transfer_matching.py
@@ -93,60 +114,72 @@ jarca-ledger-mcp/
```
## Package / Module Responsibilities
- `jarca_ledger_mcp/db.py`
- SQLite connection, schema initialization, migrations, row conversion, and database path resolution.
- `jarca_ledger_mcp/service.py`
- Domain service layer for accounts, transactions, categories, category rules, imports, reports, asset liquidity/net-worth aggregation, transfer matching, and manual link operations.
- Legacy-compatible top-level service facade. Public call sites continue to import from here while implementation lives in application modules.
- `jarca_ledger_mcp/db.py`
- Legacy-compatible top-level DB shim. Public call sites continue to import `init_db`, `db`, `resolve_db_path` from here.
- `jarca_ledger_mcp/server.py`
- Legacy-compatible MCP entrypoint shim that delegates to `adapters.mcp.server`.
- `jarca_ledger_mcp/application/shared.py`
- Shared helpers, validation, KST clock, dedupe policy, parser imports, and cross-domain constants.
- `jarca_ledger_mcp/application/system_services.py`
- Health/status/backup/account create-list/update and persistence-adjacent service behavior.
- `jarca_ledger_mcp/application/asset_account_services.py`
- Account mutation, manual asset, asset snapshot, liquidity/net-worth logic.
- `jarca_ledger_mcp/application/transaction_report_services.py`
- Transaction CRUD, budgets, monthly/category/fixed-cost/investable cashflow reports.
- `jarca_ledger_mcp/application/import_transfer_services.py`
- Import preview/import, self-transfer/cancel matching, cross-account transfer workflow.
- `jarca_ledger_mcp/application/categorization_services.py`
- Category rules, categorization preview/apply, uncategorized workbench, ledger categories.
- `jarca_ledger_mcp/infrastructure/sqlite/connection.py`
- DB path resolution, sqlite connection setup, context manager semantics.
- `jarca_ledger_mcp/infrastructure/sqlite/schema.py`
- Schema version, DDL, additive column definitions.
- `jarca_ledger_mcp/infrastructure/sqlite/migrations.py`
- Additive/idempotent migration routines and DB initialization.
- `jarca_ledger_mcp/adapters/mcp/server.py`
- FastMCP tool registration layer that exposes service functions to Hermes/MCP clients.
- `jarca_ledger_mcp/kb_bank_pdf.py`
- KB 국민은행 encrypted PDF transaction parsing.
- `jarca_ledger_mcp/toss_bank_pdf.py`
- Toss Bank transaction-history PDF parsing.
- `jarca_ledger_mcp/toss_securities_pdf.py`
- Toss Securities transaction-history PDF parsing and transaction preview conversion.
- `jarca_ledger_mcp/seoulpay_xlsx.py`
- SeoulPay encrypted XLSX parsing and preview conversion.
- `jarca_ledger_mcp/adapters/streamlit/service_gateway.py`
- Narrow dashboard-facing service surface used by `dashboard/app.py`.
- Parser modules (`kb_bank_pdf.py`, `toss_bank_pdf.py`, `toss_securities_pdf.py`, `seoulpay_xlsx.py`)
- Source-file parsing and preview conversion only.
- `dashboard/app.py`
- Streamlit operator UI for the operations hub summary, transaction filtering, uncategorized triage, rule management, review queues, categories, accounts/liquidity bucket editing, and import operations.
- Streamlit operator UI for the operations hub summary, 자산/마감, 거래내역, 확인필요 큐, 미분류, 분류 규칙, 카테고리, 계좌, Import pages.
- `tests/`
- Regression tests for service behavior, parser behavior, categorization, category rules, cross-account transfer matching, ledger category semantics, MCP response contract compatibility, and Streamlit AppTest dashboard smoke.
- `tests/contract_snapshots/`
- Representative MCP response contract metadata/schemas. Version `1.0` is used by `tests/test_contract_regression.py` and intentionally asserts required subset/types so optional additive fields remain compatible.
- Regression tests for facade compatibility, service behavior, parser behavior, categorization, transfer matching, MCP contract compatibility, and Streamlit AppTest smoke.
- `.github/workflows/ci.yml`
- GitHub Actions workflow for `pull_request`, `push` to `main`, and `workflow_dispatch`; stable required gate jobs are `pytest-regression`, `dashboard-app-test`, `dashboard-http-smoke`, `db-safety-smoke`, `contract-regression`, and `lint`.
- `scripts/ci_fixture_db.py`
- Synthetic fixture DB builder for CI/AppTest/smoke checks. Refuses the default operating DB path and seeds only synthetic ledger data.
- Synthetic fixture DB builder for CI/AppTest/browser smoke.
- `scripts/ci_dashboard_http_smoke.py`
- CI HTTP smoke wrapper that creates a synthetic fixture DB, starts Streamlit on loopback, polls HTTP 200 readiness, and cleans up the process with status-only JSON output.
- Synthetic-db Streamlit readiness smoke wrapper.
- `scripts/ci_db_safety_smoke.py`
- CI DB safety wrapper that runs restore smoke through temp synthetic source/backup/target DB paths only and emits status-only JSON.
- Synthetic-db backup/restore safety smoke wrapper.
- `scripts/streamlit_browser_evidence.py`
- Local browser evidence helper that creates a synthetic fixture DB, starts Streamlit with that DB, and captures Chrome screenshot/DOM snapshot artifacts for QC.
- Local browser evidence helper using synthetic/validation DBs only.
- `scripts/ledger_restore_smoke.py`
- Script-only restore smoke helper for validation DBs; restore remains outside the MCP tool surface.
- Script-only restore smoke helper; restore remains outside the MCP tool surface.
## Dependency Rules
- `server.py` should remain a thin tool adapter and delegate business logic to `service.py`.
- `adapters/mcp/server.py` should remain a thin tool adapter and delegate business logic to `service.py` facade/application modules.
- `dashboard/app.py` should call `adapters/streamlit/service_gateway.py`, not giant implementation modules directly.
- `service.py` / `db.py` / `server.py` shims preserve public import paths while new implementation lives under `application/`, `infrastructure/`, `adapters/`.
- Parser modules should parse source documents into structured records and avoid direct UI responsibilities.
- `dashboard/app.py` may call service functions but should not duplicate core classification/report semantics.
- DB schema migrations should be additive and idempotent by default.
## Shared Boundaries
- `cashflow_kind` is the boundary between actual household income/expense and account movement/exclusion semantics.
- `liquidity_bucket` is the account-level boundary for asset liquidity/composition/debt/net-worth views; `dashboard/app.py` displays it and `service.py` computes it from `accounts.last_balance`.
- `liquidity_bucket` is the account/manual-asset boundary for liquidity/composition/debt/net-worth views.
- Import evidence fields (`source`, `external_id`, `raw_summary`, `raw_payload`, `counterparty`, `import_batch_id`) are audit boundaries and should be preserved.
- Manual reconciliation is represented through memo tags and narrow transaction updates, not broad rewrites.
- Browser evidence artifacts are generated from synthetic/validation DBs and should not embed real financial identifiers or raw source payloads.
- CI gate fixtures are generated at runtime under temp space by `scripts/ci_fixture_db.py`; CI and AppTest must not read the default operating DB path.
- MCP contract regression fixtures use pytest `tmp_path` synthetic DBs and committed schema metadata only; they must not read the operating DB or expose runtime `contract_version` fields.
- Branch protection required-check contract is documented in `docs/interface-contract.md` and represented by stable workflow job names. Applying branch protection remains an external GitHub repository setting.
- CI gate fixtures are generated at runtime under temp space by `scripts/ci_fixture_db.py`; CI/AppTest/browser smoke must not read the default operating DB path.
## Current Gaps / Planned Changes
- Local browser evidence capture exists for core Streamlit pages; browser screenshot/visual regression remains local evidence rather than a required CI gate.
- CI workflow now covers pytest/AppTest/HTTP smoke/DB safety smoke plus BAT-007 contract-regression/lint required-check jobs; branch protection enforcement remains a repository setting outside this codebase.
- Long-term policy for accounts without downloadable statements remains partially operational/documentation work.
- Separate automatic asset snapshots/manual asset tables are not present; BAT-005 uses account rows as the manual asset/liability source.
- Application modules are now separated by phase-0~3 domain seams, but deeper repository/use-case split remains future Phase 4+ work.
- Streamlit gateway is intentionally narrow for current pages; further page/domain-specific gateways may follow in later phases.
- HTTP adapter and remote ops re-architecture remain out of scope.
## Update Triggers
- Update this document when package boundaries change.
@@ -157,5 +190,6 @@ jarca-ledger-mcp/
- 2026-06-26 22:24 KST: Created by `bootstrap-baseline` from repository observation.
- 2026-06-29 KST: REQ-004/BAT-004 기준으로 `scripts/streamlit_browser_evidence.py` 및 browser evidence artifact 구조 추가.
- 2026-06-29 KST: REQ-005/BAT-005 기준으로 dashboard operations hub와 service asset liquidity aggregation 책임 추가.
- 2026-06-30 KST: REQ-006/BAT-006 기준으로 GitHub Actions CI workflow, synthetic fixture DB builder, AppTest/HTTP/DB safety smoke wrappers, CI-vs-local-browser evidence 경계 추가.
- 2026-06-30 KST: REQ-007/REQ-008/BAT-007 기준으로 MCP response contract snapshot/test 위치와 `contract-regression`/`lint` required-check job 계약 추가.
- 2026-06-30 KST: REQ-006/BAT-006 기준으로 GitHub Actions CI workflow, synthetic fixture DB builder, AppTest/HTTP/DB safety smoke wrappers 추가.
- 2026-06-30 KST: REQ-007/REQ-008/BAT-007 기준으로 MCP response contract snapshot/test 위치와 required-check job 계약 추가.
- 2026-07-03 KST: REQ-013/REQ-014/BAT-010 기준으로 application / infrastructure / adapter layering, compatibility facade/shim, Streamlit gateway 구조를 반영했다.