# Jarca Ledger MCP Project Structure - Baseline Mode: observed - Baseline Seed: `.stage-pilot/bootstrap/baseline.yaml` - Status: draft - Owner: Jarca / project maintainer - Last Updated (KST): 2026-07-09 - Source Discovery / Batch: bootstrap-baseline, BAT-006, BAT-007, BAT-010, BAT-012, BAT-013, BAT-014, dcy-013/BAT-015, dcy-012/REQ-020/BAT-016, REQ-021/BAT-017 ## Project Summary - Jarca 가계부 전용 MCP 서버와 Streamlit 대시보드로 계좌/카드 거래, 예산, 분류 규칙, import, 자산/스냅샷, 현금흐름 분석을 SQLite에 저장하고 운영한다. ## Primary Domain - Korean household finance ledger, reconciliation, and household asset tracking ## Tech Stack - Python >=3.11 - FastMCP / MCP server (stdio and streamable-http) - SQLite - Streamlit - pandas / plotly - PyMuPDF, openpyxl, msoffcrypto-tool - pytest - ruff ## Primary Runtime - Type: mixed - Planned Entry Points: - `jarca-ledger-mcp` :: MCP stdio server for local Hermes Agent tools and streamable-http server when configured by env. - `jarca-ledger` Docker container :: independent Streamable HTTP MCP service on `:8000/mcp`. - `dashboard/app.py` :: Streamlit dashboard for local ledger operations. - `pytest` :: Regression test entry point. ## Purpose - This document is the current repository and package structure baseline. - It is a cross-cutting reference document for Discovery, REQ, Batch Design, Batch Verification, and implementation updates. ## Scope - Covers top-level repository layout and package/module boundaries. - Does not duplicate detailed business rules, acceptance criteria, or implementation-only function signatures. ## Top-Level Structure ```text jarca-ledger-mcp/ ├── README.md ├── Dockerfile ├── docker-compose.yml ├── .dockerignore ├── pyproject.toml ├── uv.lock ├── .env.example ├── .github/ │ └── workflows/ │ └── ci.yml ├── dashboard/ │ └── app.py ├── jarca_ledger_mcp/ │ ├── __init__.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 │ │ ├── assets_service.py │ │ ├── transaction_report_services.py │ │ ├── import_transfer_services.py │ │ ├── imports_service.py │ │ ├── cross_transfer_service.py │ │ ├── reconciliation_service.py │ │ ├── review_decision_service.py │ │ ├── categorization_services.py │ │ └── uncategorized_workbench_service.py │ ├── infrastructure/ │ │ ├── parsers/ │ │ │ ├── __init__.py │ │ │ ├── kb_bank_pdf.py │ │ │ ├── toss_bank_pdf.py │ │ │ ├── toss_securities_pdf.py │ │ │ └── seoulpay_xlsx.py │ │ └── sqlite/ │ │ ├── __init__.py │ │ ├── connection.py │ │ ├── schema.py │ │ └── migrations.py │ ├── adapters/ │ │ ├── mcp/ │ │ │ ├── tool_contracts.py │ │ │ └── server.py │ │ └── streamlit/ │ │ ├── __init__.py │ │ ├── overview_gateway.py │ │ ├── assets_gateway.py │ │ ├── transactions_gateway.py │ │ ├── categorization_gateway.py │ │ ├── transfers_gateway.py │ │ ├── imports_gateway.py │ │ ├── accounts_gateway.py │ │ ├── reconciliation_gateway.py │ │ └── service_gateway.py │ ├── kb_bank_pdf.py │ ├── toss_bank_pdf.py │ ├── toss_securities_pdf.py │ └── seoulpay_xlsx.py ├── tests/ │ ├── contract_snapshots/ │ │ └── response_contract_v1_0.json │ ├── test_contract_regression.py │ ├── test_mcp_http_runtime.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 │ ├── test_kb_bank_pdf.py │ ├── test_toss_securities_pdf.py │ ├── test_seoulpay_xlsx.py │ └── test_ledger_categories.py ├── scripts/ │ ├── ci_fixture_db.py │ ├── ci_dashboard_http_smoke.py │ ├── ci_db_safety_smoke.py │ ├── ledger_restore_smoke.py │ └── streamlit_browser_evidence.py ├── docs/ │ ├── discovery/ │ ├── srs/ │ ├── batches/ │ ├── runbooks/ │ │ └── docker-network-mcp-deploy.md │ ├── releases/ │ ├── project-structure.md │ ├── runtime-flows.md │ ├── interface-contract.md │ └── data-model.md └── .stage-pilot/ └── bootstrap/baseline.yaml ``` ## Package / Module Responsibilities - `jarca_ledger_mcp/service.py` - 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 seam 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` - Legacy-compatible asset/account facade that preserves older import paths while delegating asset ownership to `assets_service.py` and account mutation to write services. - `jarca_ledger_mcp/application/assets_service.py` - Manual asset CRUD, snapshot close/report, liquidity, and net-worth workflow ownership. - `jarca_ledger_mcp/application/transaction_report_services.py` - Transaction CRUD, budgets, monthly/category/fixed-cost/investable cashflow reports, with reconciliation delegated to `reconciliation_service.py`. - `jarca_ledger_mcp/application/import_transfer_services.py` - Legacy-compatible import/transfer facade that preserves prior import paths while delegating to `imports_service.py` and `cross_transfer_service.py`. - `jarca_ledger_mcp/application/imports_service.py` - Import preview/import/rollback orchestration and import batch workflow ownership. - `jarca_ledger_mcp/application/cross_transfer_service.py` - Cross-account/self-transfer/cancel-original matching workflow ownership. - `jarca_ledger_mcp/application/reconciliation_service.py` - Manual/partial-import balance reconciliation preview ownership. - `jarca_ledger_mcp/application/review_decision_service.py` - Persistent review-decision and reconciliation-session workflow ownership. Provides safe non-destructive create/update/hold/recheck/release/close helpers shared by Streamlit and MCP adapters. - `jarca_ledger_mcp/application/categorization_services.py` - Category rules, categorization preview/apply, ledger categories, and compatibility delegation to `uncategorized_workbench_service.py`. - `jarca_ledger_mcp/application/uncategorized_workbench_service.py` - Uncategorized inbox/workbench queries and recommendation-apply workflow ownership. - `jarca_ledger_mcp/infrastructure/parsers/*` - Import parser seam that keeps file-source parsing under infrastructure while preserving legacy top-level parser modules. - `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/tool_contracts.py` - Narrow MCP adapter contract surface that re-exports only the public tool callables consumed by the FastMCP server. - `jarca_ledger_mcp/adapters/mcp/server.py` - FastMCP tool registration layer that depends on `tool_contracts.py` instead of broad direct service imports. Runtime transport is configurable: stdio by default, or streamable-http through `JARCA_MCP_TRANSPORT=streamable-http` with host/port/path env settings. - `jarca_ledger_mcp/adapters/streamlit/service_gateway.py` - Compatibility aggregator over page/domain gateway modules. - `jarca_ledger_mcp/adapters/streamlit/*_gateway.py` - Page/domain-sized dashboard service surfaces (`overview`, `assets`, `transactions`, `categorization`, `transfers`, `imports`, `accounts`, `reconciliation`). - 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, 자산/마감, 거래내역, 확인필요 큐, 미분류, 분류 규칙, 카테고리, 계좌, Import pages, wired through page/domain gateways instead of a flat broad service namespace. - 월정산 페이지는 `자산 / 순자산 마감 상태` 이후 읽기 전용 Evidence 및 다음 액션 체크리스트 영역을 렌더링한다. - `tests/` - 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/browser smoke. - `scripts/ci_dashboard_http_smoke.py` - Synthetic-db Streamlit readiness smoke wrapper. - `scripts/ci_db_safety_smoke.py` - Synthetic-db backup/restore safety smoke wrapper. - `scripts/streamlit_browser_evidence.py` - Local browser evidence helper using synthetic/validation DBs only. - `scripts/ledger_restore_smoke.py` - Script-only restore smoke helper; restore remains outside the MCP tool surface. - `Dockerfile` / `docker-compose.yml` - Build and run the independent `jarca-ledger` Docker service. Compose fixes `container_name=jarca-ledger`, `restart=unless-stopped`, port `8000:8000`, and bind mount `/volume1/docker/jarca-ledger/data:/data`. - `docs/runbooks/docker-network-mcp-deploy.md` - Operator runbook for building, starting, and verifying the Docker Streamable HTTP MCP deployment and DB path. ## Dependency Rules - `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. - 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/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, but BAT-017 constrains new persistence/response behavior to normalized provenance plus source-specific minimized payload allowlists. - `import_batches.filename` is an operator-correlation field, not a raw path cache: new writes must use masked basename plus source-hash prefix, and read surfaces must expose provenance at `minimal` by default unless an explicit operator/debug path is invoked. - 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/AppTest/browser smoke must not read the default operating DB path. ## Current Gaps / Planned Changes - Application modules are now separated by phase-0~3 domain seams, but deeper repository/use-case split remains future Phase 4+ work. - Streamlit now uses page/domain gateways; deeper presenter/view-model extraction remains future work. - Network MCP over FastMCP streamable-http is now available for internal Synology operation; broader HTTP/REST business API, external exposure, reverse proxy/TLS/auth, and remote ops re-architecture remain future work. ## Update Triggers - Update this document when package boundaries change. - Update this document when new top-level runtime or domain modules are added. - Update this document when a batch changes the approved structure baseline. ## Change Log - 2026-07-12 KST: REQ-025/BAT-020 기준으로 월정산 페이지 Read-only Evidence / 다음 액션 하드닝과 테스트 검증 항목을 반영. - 2026-07-09 KST: REQ-021/BAT-017 기준으로 import provenance sanitizer 경계, masked filename persistence, explicit debug gate wiring, and baseline doc ownership을 반영. - 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 추가. - 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 구조를 반영했다. - 2026-07-03 KST: REQ-016/REQ-017/REQ-018 및 BAT-012/BAT-013/BAT-014 기준으로 import/advanced owning services, parser seam, MCP contract helper, page/domain Streamlit gateways를 반영했다. - 2026-07-07 KST: REQ-019/BAT-015 기준으로 Dockerfile/compose, `jarca-ledger` independent container, streamable-http MCP endpoint, Synology volume `/volume1/docker/jarca-ledger/data`, and Docker deployment runbook을 반영했다. - 2026-07-08 KST: REQ-020/BAT-016 기준으로 review decision service, schema version 11, MCP/Streamlit review workflow integration을 반영했다.