refactor(jarca-ledger): implement BAT-010 backend core layering
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
# BAT-010 Design
|
||||
|
||||
## Layering design
|
||||
|
||||
- `jarca_ledger_mcp/application/shared.py`
|
||||
- 공통 helper, validation, clock, dedupe, parser imports, shared policy를 보유한다.
|
||||
- `jarca_ledger_mcp/application/system_services.py`
|
||||
- health/status/backup/account create-list 등 system/persistence-adjacent service를 담당한다.
|
||||
- `jarca_ledger_mcp/application/asset_account_services.py`
|
||||
- account update, manual asset, snapshot, liquidity/net-worth read/write helper를 담당한다.
|
||||
- `jarca_ledger_mcp/application/transaction_report_services.py`
|
||||
- transaction CRUD, budgets, monthly/category/fixed-cost/reporting helper를 담당한다.
|
||||
- `jarca_ledger_mcp/application/import_transfer_services.py`
|
||||
- import preview/import, self-transfer/cancel reconciliation, cross-transfer matching을 담당한다.
|
||||
- `jarca_ledger_mcp/application/categorization_services.py`
|
||||
- category rules, preview/apply, uncategorized workbench, ledger categories를 담당한다.
|
||||
|
||||
## Persistence design
|
||||
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/connection.py`
|
||||
- DB path resolution, sqlite connect, `db()` context manager를 담당한다.
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/schema.py`
|
||||
- schema version, DDL, additive column maps를 보유한다.
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/migrations.py`
|
||||
- idempotent/additive migration과 `init_db()`를 담당한다.
|
||||
- top-level `jarca_ledger_mcp/db.py`는 compatibility shim으로 유지한다.
|
||||
|
||||
## Adapter / gateway design
|
||||
|
||||
- `jarca_ledger_mcp/adapters/mcp/server.py`
|
||||
- 실제 FastMCP registration 위치.
|
||||
- top-level `jarca_ledger_mcp/server.py`
|
||||
- CLI entrypoint shim.
|
||||
- `jarca_ledger_mcp/adapters/streamlit/service_gateway.py`
|
||||
- dashboard가 실제로 사용하는 service surface만 재노출한다.
|
||||
- `dashboard/app.py`
|
||||
- gateway import를 통해 backend core를 호출한다.
|
||||
|
||||
## Compatibility design
|
||||
|
||||
- top-level `service.py`는 public API를 그대로 재노출한다.
|
||||
- monkeypatch 관성을 위해 `service._current_kst_datetime` 변경이 shared/application modules에 전파되도록 module proxy를 유지한다.
|
||||
- 기존 tests/import callers는 `from jarca_ledger_mcp import service` / `from jarca_ledger_mcp.db import init_db` 경로를 그대로 쓴다.
|
||||
|
||||
## Verification design
|
||||
|
||||
- `python -m py_compile`로 새 package tree syntax check.
|
||||
- `pytest -q`로 full regression 및 AppTest 포함 회귀 검증.
|
||||
- `hermes mcp test jarca-ledger`로 MCP tool discovery/registration 확인.
|
||||
- Browser smoke로 synthetic fixture DB 기반 `요약`, `자산/마감` 렌더 및 console JS error 유무 확인.
|
||||
@@ -0,0 +1,61 @@
|
||||
# BAT-010 Implementation
|
||||
|
||||
## Plan summary
|
||||
|
||||
BAT-010 implements the confirmed dcy-010 Phase 0~3 scope by extracting application services, SQLite infrastructure, and thin MCP/Streamlit adapter seams while preserving legacy import paths and response contracts.
|
||||
|
||||
## Changed files
|
||||
|
||||
- `jarca_ledger_mcp/service.py`
|
||||
- `jarca_ledger_mcp/db.py`
|
||||
- `jarca_ledger_mcp/server.py`
|
||||
- `jarca_ledger_mcp/application/__init__.py`
|
||||
- `jarca_ledger_mcp/application/shared.py`
|
||||
- `jarca_ledger_mcp/application/system_services.py`
|
||||
- `jarca_ledger_mcp/application/asset_account_services.py`
|
||||
- `jarca_ledger_mcp/application/transaction_report_services.py`
|
||||
- `jarca_ledger_mcp/application/import_transfer_services.py`
|
||||
- `jarca_ledger_mcp/application/categorization_services.py`
|
||||
- `jarca_ledger_mcp/infrastructure/__init__.py`
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/__init__.py`
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/connection.py`
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/schema.py`
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/migrations.py`
|
||||
- `jarca_ledger_mcp/adapters/__init__.py`
|
||||
- `jarca_ledger_mcp/adapters/mcp/__init__.py`
|
||||
- `jarca_ledger_mcp/adapters/mcp/server.py`
|
||||
- `jarca_ledger_mcp/adapters/streamlit/__init__.py`
|
||||
- `jarca_ledger_mcp/adapters/streamlit/service_gateway.py`
|
||||
- `dashboard/app.py`
|
||||
- `docs/discovery/dcy-010_20260702_backend-core-layering-mcp-adapter-realignment.md`
|
||||
- `docs/project-structure.md`
|
||||
- `docs/runtime-flows.md`
|
||||
- `docs/srs/index.md`
|
||||
- `docs/srs/Non-Functional/req-013_backend-core-layering-sqlite-infrastructure-service-facade-compatibility.md`
|
||||
- `docs/srs/Interface/req-014_mcp-streamlit-adapter-seam-realignment-contract-preserving-gateway.md`
|
||||
- `docs/batches/index.md`
|
||||
- `docs/batches/bat-010_20260703_backend-core-layering-phase-0-3/index.md`
|
||||
- `docs/batches/bat-010_20260703_backend-core-layering-phase-0-3/planning.md`
|
||||
- `docs/batches/bat-010_20260703_backend-core-layering-phase-0-3/design.md`
|
||||
- `docs/batches/bat-010_20260703_backend-core-layering-phase-0-3/implementation.md`
|
||||
- `docs/batches/bat-010_20260703_backend-core-layering-phase-0-3/verification.md`
|
||||
|
||||
## Execution log
|
||||
|
||||
- 2026-07-03 00:15 KST: BAT-010 standard batch scaffold and REQ-013/REQ-014 문서를 생성하고 승인 상태로 정리했다.
|
||||
- 2026-07-03 00:17 KST: `service.py` giant implementation을 application modules로 분리하고 top-level facade compatibility / monkeypatch proxy를 추가했다.
|
||||
- 2026-07-03 00:17 KST: `db.py` responsibilities를 `infrastructure/sqlite`로 분리하고 기존 init/commit/rollback semantics를 유지하는 shim을 추가했다.
|
||||
- 2026-07-03 00:18 KST: MCP adapter package, Streamlit gateway, baseline docs를 반영하고 regression fixes(`SCHEMA_VERSION import`, `db()` init semantics, underscore helper imports, service monkeypatch proxy)를 정리했다.
|
||||
|
||||
## Validation
|
||||
|
||||
- `python -m py_compile jarca_ledger_mcp/*.py jarca_ledger_mcp/application/*.py jarca_ledger_mcp/infrastructure/sqlite/*.py jarca_ledger_mcp/adapters/mcp/*.py jarca_ledger_mcp/adapters/streamlit/*.py dashboard/app.py` → PASS
|
||||
- `pytest -q` → PASS (`42 passed, 4 skipped`)
|
||||
- `hermes mcp test jarca-ledger` → PASS (`Connected`, `Tools discovered: 56`)
|
||||
- Browser smoke: synthetic fixture DB(`/tmp/fixture.sqlite3`)로 Streamlit `요약`과 `자산/마감` 페이지 렌더 확인, console JS errors 없음.
|
||||
|
||||
## Remaining risks / follow-up notes
|
||||
|
||||
- Phase 4+ write/import/advanced workflow의 더 세밀한 domain/service 분리는 아직 TODO다.
|
||||
- Streamlit gateway는 현재 필요한 surface만 노출하지만, 후속 phase에서 page/domain 기준으로 더 세분화할 수 있다.
|
||||
- application modules는 여전히 큰 편이므로 후속 phase에서 deeper repository/use-case split이 필요하다.
|
||||
@@ -0,0 +1,37 @@
|
||||
# BAT-010 Backend core layering (Phase 0~3)
|
||||
|
||||
- Profile: standard
|
||||
- Status: release-candidate
|
||||
- Included REQ: REQ-013, REQ-014
|
||||
- Discovery: dcy-010
|
||||
- Owner: 렛저장인
|
||||
- Date (KST): 2026-07-03
|
||||
|
||||
## 목표
|
||||
|
||||
REQ-013/REQ-014에 따라 `service.py` giant implementation과 `db.py` persistence 집중을 application / infrastructure / adapter seam으로 분리한다. 동시에 top-level facade/shim 호환, MCP tool contract, Streamlit 핵심 화면, additive migration discipline을 유지해 Phase 4+ 분리의 안전한 기반을 만든다.
|
||||
|
||||
## 산출물
|
||||
|
||||
- `jarca_ledger_mcp/application/` phase-0~3 service modules + shared helpers
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/` connection/schema/migration split
|
||||
- `jarca_ledger_mcp/adapters/mcp/server.py` + top-level `server.py` shim
|
||||
- `jarca_ledger_mcp/adapters/streamlit/service_gateway.py` + dashboard import seam 정렬
|
||||
- `service.py` / `db.py` compatibility facade & shim
|
||||
- full pytest / MCP discovery / browser smoke evidence
|
||||
- `docs/project-structure.md`, `docs/runtime-flows.md` baseline updates
|
||||
- BAT-010 planning/design/implementation/verification documents
|
||||
|
||||
## 범위 제한
|
||||
|
||||
- Phase 4+ transactional write/import/advanced workflow 분리
|
||||
- 신규 HTTP adapter 추가
|
||||
- response envelope, tool names, dashboard IA 재설계
|
||||
- destructive DB migration
|
||||
|
||||
## 문서
|
||||
|
||||
- `planning.md`: Phase 0~3 delivery plan, risks, validation gate
|
||||
- `design.md`: layering/seam/shim design
|
||||
- `implementation.md`: changed files, execution log, validation commands
|
||||
- `verification.md`: AC mapping, PASS/FAIL, REQ Implemented decision
|
||||
@@ -0,0 +1,34 @@
|
||||
# BAT-010 Planning
|
||||
|
||||
## Scope
|
||||
|
||||
- Implement REQ-013: application/infrastructure split, SQLite persistence extraction, service/db compatibility facade.
|
||||
- Implement REQ-014: MCP adapter split, Streamlit service gateway, contract-preserving verification.
|
||||
- Update architecture baseline docs to reflect the new layering and remaining Phase 4+ TODOs.
|
||||
- Use synthetic/temp data only for verification evidence.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- dcy-010 confirmed Discovery and approved/implemented REQ-013/REQ-014.
|
||||
- Existing BAT-009 runtime behavior, response contract expectations, and Streamlit dashboard pages.
|
||||
- Additive/idempotent SQLite migration discipline from REQ-002.
|
||||
|
||||
## Work plan
|
||||
|
||||
1. Split `service.py` implementation into application modules and preserve top-level facade compatibility.
|
||||
2. Split `db.py` responsibilities into `infrastructure/sqlite` and preserve existing import paths.
|
||||
3. Introduce MCP adapter package and Streamlit service gateway.
|
||||
4. Update baseline docs (`docs/project-structure.md`, `docs/runtime-flows.md`).
|
||||
5. Run py_compile, full pytest, MCP discovery, and browser smoke against synthetic fixture DB.
|
||||
6. If evidence satisfies ACs, mark BAT-010 release-candidate and REQ-013/REQ-014 Implemented.
|
||||
|
||||
## Design Gate
|
||||
|
||||
- Result: standard batch 유지.
|
||||
- Reason: package boundary 변화, compatibility shim, MCP adapter seam, Streamlit browser verification, baseline docs가 함께 변경되므로 planning/design/verification depth가 필요하다.
|
||||
|
||||
## Risks and mitigations
|
||||
|
||||
- Hidden helper coupling after module split: mitigate by full pytest, monkeypatch compatibility, and targeted smoke on boundary-sensitive flows.
|
||||
- DB initialization drift after infrastructure split: mitigate by preserving init/commit/rollback semantics and verifying schema initialization through tests.
|
||||
- MCP/dashboard contract drift: mitigate by `hermes mcp test jarca-ledger`, Streamlit AppTest/full pytest, and browser smoke on key pages.
|
||||
@@ -0,0 +1,45 @@
|
||||
# BAT-010 Verification
|
||||
|
||||
## Verification summary
|
||||
|
||||
Status: PASS
|
||||
|
||||
Evidence was collected against synthetic/temp data only. No production ledger DB mutation or real financial files were used.
|
||||
|
||||
## Acceptance criteria mapping
|
||||
|
||||
### REQ-013
|
||||
|
||||
- AC-1: PASS — `jarca_ledger_mcp/application/` 아래 shared/system/asset-account/transaction-report/import-transfer/categorization modules가 생성됐다.
|
||||
- AC-2: PASS — `jarca_ledger_mcp/infrastructure/sqlite/` 아래 connection/schema/migrations split이 생성됐고 top-level `db.py` shim이 유지된다.
|
||||
- AC-3: PASS — `jarca_ledger_mcp/service.py`는 compatibility facade로 축소됐으며 현재 40 lines 수준이다(실질 구현은 application modules로 이동).
|
||||
- AC-4: PASS — `pytest -q` full regression PASS (`42 passed, 4 skipped`), 기존 `service`/`db` import paths 유지.
|
||||
- AC-5: PASS — `docs/project-structure.md`와 `docs/runtime-flows.md`가 새 계층 구조와 shim/gateway 흐름을 반영한다.
|
||||
|
||||
### REQ-014
|
||||
|
||||
- AC-1: PASS — `jarca_ledger_mcp/adapters/mcp/server.py` 도입 후 `hermes mcp test jarca-ledger` PASS, tools discovered 56.
|
||||
- AC-2: PASS — `jarca_ledger_mcp/adapters/streamlit/service_gateway.py` 도입 후 `dashboard/app.py`가 gateway import를 사용한다.
|
||||
- AC-3: PASS — full pytest PASS로 Streamlit AppTest / contract regression 포함 회귀가 유지된다.
|
||||
- AC-4: PASS — local browser smoke에서 `요약`과 `자산/마감` 페이지 렌더를 확인했고 console JS errors가 없었다.
|
||||
- AC-5: PASS — baseline docs와 BAT-010 implementation/verification 문서가 새 adapter seam을 반영한다.
|
||||
|
||||
## Requirement state decision
|
||||
|
||||
- REQ-013: Implemented.
|
||||
- REQ-014: Implemented.
|
||||
|
||||
## Validation evidence
|
||||
|
||||
- `python -m py_compile jarca_ledger_mcp/*.py jarca_ledger_mcp/application/*.py jarca_ledger_mcp/infrastructure/sqlite/*.py jarca_ledger_mcp/adapters/mcp/*.py jarca_ledger_mcp/adapters/streamlit/*.py dashboard/app.py` → PASS
|
||||
- `pytest -q` → PASS (`42 passed, 4 skipped`)
|
||||
- `hermes mcp test jarca-ledger` → PASS (`Connected`, `Tools discovered: 56`)
|
||||
- Browser smoke on Streamlit `요약` / `자산/마감` → PASS, JS errors 없음
|
||||
|
||||
## Remaining issues
|
||||
|
||||
### Hard blockers
|
||||
- None.
|
||||
|
||||
### Non-blocking follow-up
|
||||
- Phase 4+ transactional write services, import pipeline deeper split, advanced workflow separation, narrower adapter surfaces remain tracked as GitHub Project TODO items.
|
||||
@@ -17,3 +17,4 @@
|
||||
| BAT-007 | standard | release-candidate | REQ-007, REQ-008 | dcy-007 | [bat-007_20260630_mcp-response-contract-ci-versioning](bat-007_20260630_mcp-response-contract-ci-versioning/) |
|
||||
| BAT-008 | standard | release-candidate | REQ-009, REQ-010 | dcy-008 | [bat-008_20260630_asset-snapshots-manual-assets-read-mcp](bat-008_20260630_asset-snapshots-manual-assets-read-mcp/) |
|
||||
| BAT-009 | standard | release-candidate | REQ-011, REQ-012 | dcy-009 | [bat-009_20260701_manual-asset-crud-snapshot-close](bat-009_20260701_manual-asset-crud-snapshot-close/) |
|
||||
| BAT-010 | standard | release-candidate | REQ-013, REQ-014 | dcy-010 | [bat-010_20260703_backend-core-layering-phase-0-3](bat-010_20260703_backend-core-layering-phase-0-3/) |
|
||||
|
||||
+2
-2
@@ -5,9 +5,9 @@
|
||||
- 문서 ID: dcy-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow
|
||||
- 이슈명: Jarca Ledger 대시보드 운영 허브 사양 정립 (이번 달 현금흐름 + 자산 유동성 + 운영 미처리)
|
||||
- 작성 시각(KST): 2026-06-29 14:02 KST
|
||||
- 마지막 갱신 시각(KST): 2026-06-29 20:03 KST
|
||||
- 마지막 갱신 시각(KST): 2026-06-30 20:43 KST
|
||||
- 대체됨: 없음
|
||||
- 후속 Discovery 참조: 없음
|
||||
- 후속 Discovery 참조: docs/discovery/dcy-008_20260630_asset-snapshot-manual-valuation-system.md
|
||||
- 생성된 REQ 참조: REQ-005 (`docs/srs/Interface/req-005_dashboard-operations-hub-liquidity-monthly-cashflow.md`)
|
||||
|
||||
# 1. 계획 상태 요약
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
# 0. 문서 상태
|
||||
이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다.
|
||||
|
||||
- 상태: confirmed
|
||||
- 문서 ID: dcy-010_20260702_backend-core-layering-mcp-adapter-realignment
|
||||
- 이슈명: Jarca Ledger 백엔드 코어 분리 및 layered 아키텍처(application/domain/infrastructure/adapters) 재편, MCP adapter 재정렬
|
||||
- 작성 시각(KST): 2026-07-02 23:32
|
||||
- 마지막 갱신 시각(KST): 2026-07-02 23:56
|
||||
- 대체됨: 없음
|
||||
- 후속 Discovery 참조: 없음
|
||||
- 생성된 REQ 참조: `REQ-013`, `REQ-014`
|
||||
|
||||
# 1. 계획 상태 요약
|
||||
현재 Discovery가 어떤 배경에서 작성되고 있는지, 연계 문서가 있는지, 지금 시점의 해석이 무엇인지 짧게 요약한다.
|
||||
|
||||
- 연계 문서 현황:
|
||||
- 관련 blueprint: `.hermes/plans/2026-07-02_jarca-ledger-backend-refactor-blueprint.md` (근거 리팩터링 청사진)
|
||||
- 관련 baseline 문서: `docs/project-structure.md`, `docs/runtime-flows.md`
|
||||
- 해석:
|
||||
- `jarca_ledger_mcp/service.py`가 약 3,378줄로 비대해져 MCP/Streamlit/SQLite 접근/import/reporting/reconciliation/asset 워크플로우가 하나의 함수 네임스페이스에 과결합된 상태이며, 향후 HTTP 등 인터페이스 확장 전에 layered backend 경계 도입이 필요하다.
|
||||
- 이번 Discovery는 MCP를 제거하지 않고 adapter로 재정의하면서 application/domain/infrastructure/adapters 경계로 단계적(strangler-fig) 재편하는 구조 개선 주기를 신규로 시작할지 판정하고, baseline 문서(project-structure/runtime-flows) 갱신 요구까지 포함한 초안을 만든다.
|
||||
|
||||
# 2. 요구사항 판정 결과
|
||||
이번 요청이 기존 요구사항과 비교해 신규인지, 유사한지, 중복인지 판단하고 그 근거를 남긴다.
|
||||
|
||||
- 판정: 신규
|
||||
- 근거
|
||||
- 기존 dcy-001~009는 기능/운영 워크플로우(분류·환급, 백업·복구, 잔액대조, E2E evidence, 대시보드, CI, MCP 응답 계약, 자산 스냅샷/CRUD)를 다루며, service.py 분해와 layered backend 아키텍처 재편이라는 구조 리팩터링 주제를 다룬 Discovery는 없다.
|
||||
- dcy-007(MCP response contract)은 응답 계약의 안정성을 다루지만 내부 계층 구조 분해나 persistence 분리를 정의하지 않아 문제 정의·범위·성공 기준이 실질적으로 다르다.
|
||||
|
||||
> **판정이 `완전 중복`인 경우**: 이하 섹션 작성을 중단하고 `# 9. 파일 처리 결과`에 중복 판정 사유와 참조 문서 경로를 기록한 뒤 문서를 닫는다. REQ 초안 작성으로 넘기지 않는다.
|
||||
|
||||
# 3. 문제점의 요약
|
||||
문제의 현재 상태, 기대 상태, 관련 이해관계자, 제약사항을 정리한다. Discovery의 핵심 맥락을 가장 먼저 이해할 수 있어야 한다.
|
||||
|
||||
- 현재 상태
|
||||
- `jarca_ledger_mcp/service.py`(약 3,378줄, blueprint 기준 약 126 함수)가 사실상 애플리케이션 전체 역할을 하며 비즈니스 규칙·오케스트레이션·SQL·mutation 안전·import·reporting·cross-transfer가 한 모듈에 집중되어 있다.
|
||||
- `jarca_ledger_mcp/server.py`(약 296줄, 약 57개 MCP tool wrapper)와 `dashboard/app.py`(약 1,811줄)가 모두 `from jarca_ledger_mcp import service`로 동일한 넓은 함수 네임스페이스에 직접 결합되어 있다.
|
||||
- `jarca_ledger_mcp/db.py`(약 333줄)에 schema·connection·additive migration helper가 한 파일에 섞여 있어 persistence 경계가 비즈니스 규칙과 분리되어 있지 않다.
|
||||
- baseline 문서는 이미 존재한다(`docs/project-structure.md`, `docs/runtime-flows.md`). 다만 이번 구조 재편은 패키지 레이아웃과 런타임 호출 흐름을 크게 바꾸므로 두 baseline 문서의 갱신 갭이 발생한다.
|
||||
- 기대 상태
|
||||
- MCP는 유지하되 `adapters/mcp`로 위치를 재정의하고, Streamlit은 `adapters/streamlit` gateway를 통해 좁은 표면에만 의존하는 thin adapter가 된다.
|
||||
- domain/application/infrastructure/adapters 경계가 명시되고, service.py는 호환 facade로 축소되거나 호출부 이관 후 제거되며, 각 도메인 영역이 독립적으로 이해·테스트 가능해진다.
|
||||
- 이해관계자
|
||||
- 문서 작성자(AI agent) 및 리팩터링 실행 subagent
|
||||
- 리뷰어/승인자(Hermes 및 저장소 소유자)
|
||||
- MCP/Streamlit 사용자(마이그레이션 중 동작 유지가 보장되어야 하는 소비자)
|
||||
- 제약사항
|
||||
- 마이그레이션 전 구간에서 MCP tool 이름/주요 응답 필드/카테고리·현금흐름 의미/import 증빙 필드/additive-only migration/Streamlit 페이지 동작이 호환 계약으로 유지되어야 한다.
|
||||
- big-bang rewrite 금지, 금융 데이터 특성상 destructive migration은 승인 없이 금지하고 fixture/복사 DB만 사용한다.
|
||||
|
||||
## 주요 사용자 시나리오
|
||||
사용자 또는 운영자가 실제로 어떤 상황에서 이 변경을 필요로 하는지 대표 시나리오를 적는다.
|
||||
|
||||
- 개발자가 특정 도메인(예: 자산 스냅샷) 로직을 수정할 때 3,378줄 service.py 전체를 탐색하지 않고 해당 application service와 repository만 열어 변경·테스트하려는 상황.
|
||||
- 운영자가 DB I/O/integrity 장애를 진단할 때, persistence 계층이 분리되어 있어 문제를 전체 애플리케이션 경로가 아닌 infrastructure/sqlite 경계로 국소화하려는 상황.
|
||||
- 향후 HTTP/FastAPI adapter를 추가하려는 개발자가 비즈니스 로직을 다시 이동시키지 않고 `application/*` 위에 adapter 패키지만 추가하려는 상황.
|
||||
|
||||
# 4. 이번에 정의할 변경
|
||||
이번 Discovery에서 다루는 핵심 변경 항목을 목록으로 적는다. 기능, 구조, 규칙 변경을 함께 포함해도 된다.
|
||||
|
||||
- service.py 분해: 비즈니스 로직을 domain(types/invariants/validation), application(use case/orchestration), infrastructure(sqlite repo/parsers)로 이관하고 service.py는 임시 호환 facade로 축소한다.
|
||||
- persistence 분리: db.py의 schema/connection/migration을 `infrastructure/sqlite`로 분리하고 테이블/use-case별 repository를 도입한다.
|
||||
- MCP/Streamlit thin adapter화: MCP tool 등록을 `adapters/mcp/server.py`로 이동해 top-level server.py는 shim으로 남기고, Streamlit은 `adapters/streamlit/service_gateway.py`의 좁은 gateway 호출로 전환한다.
|
||||
- baseline 문서 갱신 요구: 새 패키지 레이아웃과 런타임 호출 경로 변화를 반영해 `docs/project-structure.md`와 `docs/runtime-flows.md`를 갱신한다.
|
||||
- 단계적 migration 원칙 확정: strangler-fig 순서(foundations → read-only/reporting → write CRUD → import → cross-transfer/reconciliation/assets → adapter narrowing)로 blast radius를 최소화한다.
|
||||
|
||||
## 영향 범위
|
||||
변경이 미칠 코드/문서/운영 범위를 명시해 REQ 정제와 batch planning에서 추정 누락을 줄인다.
|
||||
|
||||
- 코드 영향:
|
||||
- `jarca_ledger_mcp/service.py`, `db.py`, `server.py` 분해 및 호환 facade/shim화
|
||||
- 신규 패키지 `jarca_ledger_mcp/{domain,application,infrastructure,adapters}/*` 도입
|
||||
- `dashboard/app.py`의 `service.*` 광범위 의존을 gateway 호출로 축소, `pyproject.toml` 패키지 discovery/entrypoint 정합성 유지
|
||||
- 테스트를 repository/application-service/adapter 계층으로 재배치(Layer A/B/C)
|
||||
- 문서 영향:
|
||||
- `docs/project-structure.md`, `docs/runtime-flows.md` 갱신 요구
|
||||
- 신규 Discovery 및 `docs/discovery/index.md` 행 추가
|
||||
- 운영 영향:
|
||||
- 마이그레이션 중 MCP/Streamlit 동작 유지 필요, 배포 절차 자체 변경은 없음(entrypoint 호환 유지)
|
||||
- destructive migration 금지, DB 안전 정책(복사/fixture DB) 유지
|
||||
|
||||
# 5. 요구사항 목록
|
||||
실제로 구현과 검증으로 이어질 요구사항을 기능/비기능으로 나누어 정리하고, 범위 경계를 명확히 적는다.
|
||||
|
||||
## 기능 요구사항
|
||||
- FR-1: `jarca_ledger_mcp`에 domain/application/infrastructure/adapters 경계를 도입하고 service.py의 로직을 도메인별 application service와 repository로 이관하되, service.py는 호환 facade로 남겨 기존 호출부가 깨지지 않게 한다.
|
||||
- FR-2: db.py의 schema/connection/additive migration을 `infrastructure/sqlite`(connection/schema/migrations/row_mapping + 테이블별 repo)로 분리하고, db.py는 호환 shim으로 유지한다.
|
||||
- FR-3: MCP tool 등록을 `adapters/mcp`로 이동해 top-level `server.py`를 thin shim으로 만들고, Streamlit이 `adapters/streamlit/service_gateway.py`의 좁은 gateway에만 의존하도록 전환한다.
|
||||
- FR-4: 구조/런타임 baseline 갭을 해소하기 위해 `docs/project-structure.md`와 `docs/runtime-flows.md`에 신규 계층 구조와 호출 흐름 갱신 요구를 반영한다.
|
||||
|
||||
## 비기능 요구사항
|
||||
성능, 운영성, 일관성, 자동화 안정성 등 기능 외 요구사항을 적는다.
|
||||
|
||||
- NFR-1: 호환 계약 안정성 — MCP tool 이름, 주요 응답 필드(`success`, `count`, `items`, `error`, `validation`, `matched_count` 등), 카테고리·현금흐름 의미, import 증빙 필드(`raw_summary`/`counterparty`/`raw_payload`/`external_id`/`import_batch_id`), additive-only migration, Streamlit 페이지 동작/순서가 의도적 버전 변경·승인 없이 바뀌지 않는다.
|
||||
- NFR-2: 단계적 안전성 — 각 phase는 독립적으로 검증 가능해야 하고(pytest 회귀 + py_compile), 한 번에 하나의 도메인 슬라이스만 이관해 blast radius를 최소화한다.
|
||||
- NFR-3: DB 안전성 — 리팩터링 중 fixture/복사 DB만 사용하고 승인 없는 destructive migration을 수행하지 않는다.
|
||||
|
||||
## 범위 경계
|
||||
이번 반복에서 반드시 포함할 범위와 명시적으로 제외할 범위를 구분한다.
|
||||
|
||||
- In Scope
|
||||
- blueprint 기준 Phase 0~3 우선: behavioral baseline 고정 → 새 skeleton/compat seam 도입 → persistence 분리 → read-only application service 추출
|
||||
- baseline 문서(project-structure/runtime-flows) 갱신 요구
|
||||
- 단계적(strangler-fig) migration 원칙 정의
|
||||
- Out of Scope
|
||||
- 즉시 FastAPI/HTTP 전환(향후 adapter 준비만, 강제하지 않음)
|
||||
- Postgres/원격 DB 이관
|
||||
- 멀티유저/권한 체계 도입
|
||||
- 원격 운영(remote ops) 재설계
|
||||
- Phase 4 이후의 write/import/advanced workflow/adapter narrowing 구현(별도 후속 REQ·Batch·GitHub Project TODO로 추적)
|
||||
|
||||
# 6. 리스크/가정 목록
|
||||
불확실성과 전제 조건을 분리해서 적는다. 리스크는 영향과 완화 방안을, 가정은 현재 판단의 전제를 기록한다.
|
||||
|
||||
## 리스크
|
||||
- R-1 (High): service.py 내부 숨은 결합 — 공유 helper 이관 시 예상치 못한 호출부가 깨질 수 있다.
|
||||
- 완화 방안: 리팩터링 전에 characterization/contract 회귀 테스트를 먼저 추가하고, helper는 첫 소비자와 함께 이동한다.
|
||||
- R-2 (High): MCP/Streamlit 계약 drift — tool 응답 형태나 페이지 동작이 조용히 바뀔 수 있다.
|
||||
- 완화 방안: 리팩터링 전 응답 형태(shape) 테스트와 Streamlit 페이지/서비스 통합 테스트를 확보하고 adapter gateway로 페이지 단위 점진 이관한다.
|
||||
- R-3 (Medium): 신규 repository 간 SQL/row mapping 중복으로 유지보수성 저하.
|
||||
- 완화 방안: row mapping과 공통 predicate를 중앙화(`row_mapping.py`)하고 repository 규칙(메시지 포매팅 금지, dict/dataclass 반환)을 강제한다.
|
||||
|
||||
## 가정
|
||||
아직 확정되지 않았지만 현재 문서 작성의 기반이 되는 전제를 적는다.
|
||||
|
||||
- A-1: 기존 pytest 스위트(transaction/import/rules/dashboard 회귀 등)가 동작하며 baseline 고정과 회귀 검증의 기준으로 사용할 수 있다.
|
||||
- A-2: 현재 SQLite schema가 additive-oriented이므로 destructive 변경 없이 계층 분리를 진행할 수 있다.
|
||||
- A-3: MCP는 이미 spirit 상 adapter(server.py가 대부분 thin wrapper)이므로 adapter 재정렬이 큰 동작 변경 없이 가능하다.
|
||||
|
||||
## 오픈 질문
|
||||
답을 아직 모르는 항목을 적는다. 추정으로 덮지 말고 REQ 초안 작성 이전에 확인할 질문으로 남긴다.
|
||||
|
||||
- OQ-1: 이번 리팩터링을 전체 phase(1~7)를 한 주기로 다룰지, blueprint Batch A(Phase 0~3)만 첫 배치로 축소해 시작할지?
|
||||
- 상태: Answered
|
||||
- 처리 방안: 사용자 승인에 따라 Discovery 범위를 Phase 0~3 우선 배치로 고정하고, Phase 4+는 GitHub Project TODO와 후속 REQ/Batch로 분리 추적한다.
|
||||
- 종료 조건: `# 5. 요구사항 목록 > 범위 경계`에 1차 범위가 Phase 0~3으로 반영되었으므로 종료한다.
|
||||
- OQ-2: 마이그레이션 완료 판정 기준(service.py 목표 라인 수 ~400~600줄 축소 vs 완전 제거) 중 어느 것을 Definition of Done으로 채택할지?
|
||||
- 상태: Answered
|
||||
- 처리 방안: 사용자 승인에 따라 1차 완료 기준을 service.py 호환 facade 수준(~400~600줄) 축소로 채택하고, 완전 제거는 후속 단계 최적화로 남긴다.
|
||||
- 종료 조건: 성공 기준 S-2와 REQ handoff 기준에 facade 축소 DoD가 반영되었으므로 종료한다.
|
||||
|
||||
### 오픈 질문 처리 기준
|
||||
- `Open`: 아직 답이 없고 다음 단계 진행에 영향이 있는 상태다. 문서에 유지한다.
|
||||
- `Answered`: 답이 확정된 상태다. 관련 본문/요구사항에 반영한 뒤 오픈 질문 목록에서는 제거하거나 resolved 기록으로 이동한다.
|
||||
- `Deferred`: 지금 단계에서 결정하지 않고 다음 단계 또는 후속 이슈로 넘기는 상태다. 넘길 대상과 이유를 반드시 적는다.
|
||||
- `Dropped`: 더 이상 유효하지 않은 질문이다. 삭제 사유를 짧게 남기고 목록에서 제거한다.
|
||||
- 처리 원칙 1: 질문만 남기지 말고 반드시 `상태`, `처리 방안`, `종료 조건`을 함께 적는다.
|
||||
- 처리 원칙 2: 답이 나온 질문은 본문 반영 없이 단순 삭제하지 않는다. 반영 위치를 먼저 갱신한다.
|
||||
- 처리 원칙 3: High 영향 질문은 `Deferred` 처리 후 처리 방안에 REQ 인계 추적 방식을 명시한다.
|
||||
|
||||
# 7. 초기 성공 기준
|
||||
이 변경이 성공했다고 판단할 기준을 측정 가능하게 정의한다. 가능하면 데이터 출처까지 연결한다.
|
||||
|
||||
- S-1: 마이그레이션 전 구간에서 MCP와 Streamlit이 동작하며 기존/대체 회귀 테스트가 통과한다.
|
||||
- S-2: 1차 리팩터링 완료 시 service.py가 호환 glue/facade 수준(blueprint §11 기준 ~400~600줄)으로 축소되고, db.py는 shim 또는 얇은 compatibility entry로 축소된다.
|
||||
- S-3: 각 주요 도메인 영역이 자체 application service와 persistence 경계를 갖고, `docs/project-structure.md`·`docs/runtime-flows.md`가 신규 계층 구조를 반영하도록 갱신되어 이후 REQ/Batch 산출물이 baseline 문서를 참조할 수 있다.
|
||||
|
||||
## 측정 방식 및 데이터 출처
|
||||
각 성공 기준을 어떻게 측정할지와 어떤 데이터나 문서를 근거로 쓸지 적는다.
|
||||
|
||||
- S-1 측정 방식: 각 phase 종료 시 pytest 회귀 스위트 + MCP tool contract 테스트 전부 통과 확인 / 데이터 출처: `tests/` 실행 결과, `docs/discovery/dcy-007` 응답 계약
|
||||
- S-2 측정 방식: `wc -l jarca_ledger_mcp/service.py`, `db.py` 라인 수와 import 의존성 그래프를 확인하고 1차 목표를 facade 수준 축소로 검증 / 데이터 출처: 리팩터링 후 소스 파일, blueprint §11 DoD
|
||||
- S-3 측정 방식: 각 도메인 application service/repository 존재 여부 및 baseline 문서 diff 확인 / 데이터 출처: `jarca_ledger_mcp/{application,infrastructure}/*`, `docs/project-structure.md`, `docs/runtime-flows.md`
|
||||
|
||||
# 8. REQ로 넘기기 전 확인 체크
|
||||
REQ 초안 작성 단계로 넘기기 전에 무엇이 확정되어야 하는지 확인한다. 미완료 항목은 후속 결정이 필요함을 뜻한다.
|
||||
|
||||
- [x] 범위(In Scope/Out of Scope) 확정
|
||||
- 기준: 사용자 승인에 따라 Phase 0~3 우선 범위와 Out of Scope 항목이 문서에 반영되어 있으며, Phase 4+는 별도 TODO/후속 REQ로 추적한다.
|
||||
- [x] 성공 지표의 측정 방식/데이터 출처 확정
|
||||
- 기준: S-2의 1차 DoD를 service.py facade 수준 축소로 채택했고, 세부 baseline 테스트 목록은 REQ/Phase 0 planning에서 계측 대상으로 명시한다.
|
||||
- [x] High 영향 리스크 우선순위 및 해소 책임자 지정
|
||||
- 기준: R-1, R-2는 REQ/Batch planning 단계에서 characterization/contract 테스트 선행 책임자를 지정하는 비차단 항목으로 정리되었고, Discovery 범위·성공 기준·검증 시나리오 확정은 완료되었다.
|
||||
- [x] 모든 오픈 질문(OQ) `Open` 상태 없음 확인
|
||||
- 기준: OQ 목록의 항목이 모두 `Answered`이거나 `Deferred` 처리 완료
|
||||
- [x] Freeze 확정 담당자(CONFIRMED_BY) 지정
|
||||
- 기준: 사용자 승인에 따라 저장소 소유자 `진환 고`가 Confirmed By로 기록되었다.
|
||||
|
||||
# 9. 파일 처리 결과
|
||||
이 Discovery 문서 생성/갱신 결과와 참조 문서를 기록한다. 이후 추적과 리뷰 시 근거로 사용한다.
|
||||
|
||||
- 처리 결과: 갱신
|
||||
- 생성 경로: docs/discovery/dcy-010_20260702_backend-core-layering-mcp-adapter-realignment.md
|
||||
- 참조 문서:
|
||||
- .hermes/plans/2026-07-02_jarca-ledger-backend-refactor-blueprint.md (근거 blueprint)
|
||||
- stage-pilot/templates/project-structure.md (baseline 갱신 논리 템플릿 참조)
|
||||
- stage-pilot/templates/runtime-flows.md (baseline 갱신 논리 템플릿 참조)
|
||||
|
||||
# 10. 사용자 결정 필요 항목 요약
|
||||
사용자나 승인자가 결정해야 하는 항목만 모아 정리한다. 결정, 확인, 데이터 요청을 구분해서 적는다.
|
||||
|
||||
## DECIDE
|
||||
- 없음 — 이번 반복 범위는 blueprint 기준 Phase 0~3 우선으로 고정한다.
|
||||
- 없음 — 1차 완료 기준은 service.py를 ~400~600줄 호환 facade 수준으로 축소하는 것으로 채택한다.
|
||||
|
||||
## CONFIRM
|
||||
- 없음 — MCP tool 이름/주요 응답 필드/import 증빙 필드/Streamlit 페이지 동작은 이번 리팩터링 동안 호환 계약으로 동결한다.
|
||||
|
||||
## DATA
|
||||
- REQ 단계 계측: Phase 0 baseline 고정용 현재 통과 pytest 스위트 목록과 커버 대상 MCP tool 집합은 REQ/Phase 0 planning 산출물에서 명시한다.
|
||||
|
||||
# 11. Discovery Freeze
|
||||
REQ 초안 작성 인계 시점의 확정 플래그와 섹션 참조만 기록한다. 내용 재작성 없이 원본 섹션을 링크로 대신한다.
|
||||
|
||||
## 섹션 참조
|
||||
- 범위: [# 5. 요구사항 목록 > 범위 경계](#5-요구사항-목록)
|
||||
- 리스크/오픈 질문: [# 6. 리스크/가정 목록](#6-리스크가정-목록)
|
||||
- 성공 기준: [# 7. 초기 성공 기준](#7-초기-성공-기준)
|
||||
- 인계 전 확인: [# 8. REQ로 넘기기 전 확인 체크](#8-req로-넘기기-전-확인-체크)
|
||||
- 사용자 결정 필요: [# 10. 사용자 결정 필요 항목 요약](#10-사용자-결정-필요-항목-요약)
|
||||
|
||||
## Freeze 플래그
|
||||
- Handoff Decision: 승인
|
||||
- Handoff Rationale: 사용자 승인에 따라 1차 범위를 Phase 0~3으로 축소하고 1차 완료 기준을 service.py facade 수준 축소로 확정했다. 호환 계약 동결 정책도 반영되었고, 남은 baseline 테스트 상세 목록과 리스크 책임자 지정은 REQ/Phase 0 planning 단계 비차단 계측·할당 항목으로 정리되었다.
|
||||
- Ready for REQ Drafting: true
|
||||
- Confirmed By: 진환 고
|
||||
- Confirmed At (KST): 2026-07-02 23:56 KST
|
||||
|
||||
@@ -15,3 +15,4 @@
|
||||
| dcy-007_20260630_mcp-response-contract-ci-contract-versioning | 20260630 | MCP response contract / CI contract versioning 정립 | [Discovery](./dcy-007_20260630_mcp-response-contract-ci-contract-versioning.md) | confirmed |
|
||||
| dcy-008_20260630_asset-snapshot-manual-valuation-system | 20260630 | 자산 스냅샷/수기 자산 테이블/평가 체계 정립 | [Discovery](./dcy-008_20260630_asset-snapshot-manual-valuation-system.md) | confirmed |
|
||||
| dcy-009_20260701_manual-asset-crud-month-end-snapshot-close-workflow | 20260701 | 수기 자산 CRUD + 월말 스냅샷 생성/마감 운영 워크플로우 | [Discovery](./dcy-009_20260701_manual-asset-crud-month-end-snapshot-close-workflow.md) | confirmed |
|
||||
| dcy-010_20260702_backend-core-layering-mcp-adapter-realignment | 20260702 | Jarca Ledger 백엔드 코어 분리 및 layered 아키텍처 재편, MCP adapter 재정렬 | [Discovery](./dcy-010_20260702_backend-core-layering-mcp-adapter-realignment.md) | confirmed |
|
||||
|
||||
+75
-41
@@ -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 구조를 반영했다.
|
||||
|
||||
+53
-69
@@ -4,19 +4,19 @@
|
||||
- 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, BAT-008
|
||||
- Last Updated (KST): 2026-07-03
|
||||
- Source Discovery / Batch: bootstrap-baseline, BAT-006, BAT-007, BAT-008, BAT-010
|
||||
- Primary Runtime: mixed
|
||||
|
||||
## Project Summary
|
||||
- Jarca 가계부 전용 MCP 서버와 Streamlit 대시보드로 계좌/카드 거래, 예산, 분류 규칙, import, 현금흐름 분석을 SQLite에 저장하고 운영한다.
|
||||
- Jarca 가계부 전용 MCP 서버와 Streamlit 대시보드로 계좌/카드 거래, 예산, 분류 규칙, import, 현금흐름 분석, 자산/스냅샷 운영을 SQLite에 저장하고 제공한다.
|
||||
|
||||
## Purpose
|
||||
- This document is the current execution-flow baseline for the project.
|
||||
- It is a cross-cutting reference document for Discovery, REQ, Batch Design, Batch Verification, and implementation updates.
|
||||
|
||||
## Scope
|
||||
- Covers representative command, MCP, dashboard, import, and reconciliation flows.
|
||||
- Covers representative command, MCP, dashboard, import, reconciliation, snapshot, and verification flows.
|
||||
- Does not duplicate full acceptance criteria or low-level implementation details.
|
||||
|
||||
## Covered Entry Points
|
||||
@@ -27,56 +27,48 @@
|
||||
|
||||
## Shared Components
|
||||
- SQLite database at `~/.local/share/jarca/ledger.sqlite3` by default.
|
||||
- `jarca_ledger_mcp.service` as the central domain/service layer.
|
||||
- `jarca_ledger_mcp/service.py` compatibility facade over application modules.
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/*` for DB path resolution, schema, migration, and connection lifecycle.
|
||||
- `jarca_ledger_mcp/adapters/mcp/server.py` for MCP registration.
|
||||
- `jarca_ledger_mcp/adapters/streamlit/service_gateway.py` for dashboard-facing service calls.
|
||||
- Parser modules for KB/Toss/SeoulPay sources.
|
||||
- Category and `cashflow_kind` semantics shared by reports and UI.
|
||||
|
||||
## Flow: `MCP server tool call`
|
||||
1. Hermes MCP client invokes a tool exposed by `jarca_ledger_mcp.server`.
|
||||
2. `server.py` forwards arguments to the matching `service.py` function.
|
||||
3. `service.py` opens the SQLite database path from env/default, validates inputs, and performs the operation.
|
||||
4. Service returns a dictionary payload with success data or error information.
|
||||
5. Hermes surfaces the tool result to the user or uses it in a follow-up workflow.
|
||||
1. Hermes MCP client invokes a tool exposed by `jarca_ledger_mcp.server` / `jarca_ledger_mcp.adapters.mcp.server`.
|
||||
2. MCP adapter forwards arguments to the matching `jarca_ledger_mcp.service` facade function.
|
||||
3. Service facade routes into the relevant application module.
|
||||
4. Application code opens SQLite through `infrastructure/sqlite` helpers, validates inputs, and performs the operation.
|
||||
5. Application returns a dictionary payload with success data or error information.
|
||||
6. Hermes surfaces the tool result to the user or uses it in a follow-up workflow.
|
||||
|
||||
## Flow: `Streamlit dashboard operation`
|
||||
1. Operator starts `streamlit run dashboard/app.py --server.address 0.0.0.0 --server.port 8501`.
|
||||
2. Dashboard reads the configured/default SQLite database.
|
||||
3. User navigates to 요약, 거래내역, 확인필요 큐, 미분류, 분류 규칙, 카테고리, 계좌, or Import pages.
|
||||
4. UI calls service functions for reads, updates, imports, categorization, and manual linking.
|
||||
5. UI displays success/error status and refreshes visible tables.
|
||||
3. User navigates to 요약, 자산/마감, 거래내역, 확인필요 큐, 미분류, 분류 규칙, 카테고리, 계좌, or Import pages.
|
||||
4. UI calls `jarca_ledger_mcp.adapters.streamlit.service_gateway` rather than giant implementation modules directly.
|
||||
5. Gateway delegates to the service facade/application modules and returns data to the page.
|
||||
6. UI displays success/error status and refreshes visible tables.
|
||||
|
||||
## Flow: `Dashboard operations hub overview`
|
||||
1. Operator opens the `요약` page.
|
||||
2. Dashboard resolves the KST current month and calls `get_monthly_cashflow_report(month)` using `transactions.transaction_date` and `ledger_categories.cashflow_kind` semantics.
|
||||
2. Dashboard calls `get_monthly_cashflow_report(month)` using `transactions.transaction_date` and `ledger_categories.cashflow_kind` semantics.
|
||||
3. Dashboard calls `get_asset_liquidity_report`, which uses the shared valuation helper: account-backed assets from `accounts.last_balance` plus active `manual_assets` rows when present.
|
||||
4. If `manual_assets` and `asset_snapshots` are empty, the report keeps the REQ-005 account-only fallback and preserves existing totals/keys.
|
||||
5. Dashboard renders sections in REQ-005 priority order: this-month actual income/expense/net/savings rate, asset liquidity, asset composition, budget/spend, operational warnings.
|
||||
6. Missing `last_balance` or `manual_assets.valuation_amount` values are excluded from asset totals and surfaced as warnings; transaction sums are not used to estimate non-transaction assets.
|
||||
6. Missing `last_balance` or `manual_assets.valuation_amount` values are excluded from asset totals and surfaced as warnings.
|
||||
|
||||
## Flow: `CI validation gates`
|
||||
1. GitHub Actions starts `.github/workflows/ci.yml` on `pull_request`, `push` to `main`, or `workflow_dispatch`.
|
||||
2. `lint` installs dev dependencies and runs `ruff check .` with the conservative BAT-007 required rule set.
|
||||
3. `contract-regression` installs dev dependencies and runs `pytest tests/test_contract_regression.py`; the test uses synthetic pytest temp DBs and `tests/contract_snapshots/response_contract_v1_0.json` metadata for health/status, list, report, and mutation success envelope scopes.
|
||||
4. `pytest-regression` installs the project with dev/dashboard extras and runs `pytest --ignore=tests/test_dashboard_app.py` so service/parser/regression failures fail the workflow.
|
||||
5. `dashboard-app-test` runs `pytest tests/test_dashboard_app.py`; the AppTest test creates a synthetic fixture DB through `scripts/ci_fixture_db.py`, sets `JARCA_LEDGER_DB_PATH`, and asserts core dashboard pages render without Streamlit exceptions.
|
||||
6. `dashboard-http-smoke` runs `scripts/ci_dashboard_http_smoke.py`; the wrapper creates a temp fixture DB, starts Streamlit on loopback, polls for HTTP 200, then terminates the process.
|
||||
7. `db-safety-smoke` runs `scripts/ci_db_safety_smoke.py`; the wrapper creates temp source/backup/target DB files and invokes `scripts/ledger_restore_smoke.py` without touching the operating DB path.
|
||||
8. Any required job failure fails the workflow. Stable required-check job names are `pytest-regression`, `dashboard-app-test`, `dashboard-http-smoke`, `db-safety-smoke`, `contract-regression`, and `lint`; actual branch protection toggle enforcement is configured outside the repository.
|
||||
9. CI logs are status-oriented and synthetic-data-only; they must not contain real account identifiers, raw payloads, statement filenames, balances from the operating DB, or passwords.
|
||||
|
||||
## Flow: `Asset snapshot and net-worth read model`
|
||||
1. Month-end manual close records item-level rows in `asset_snapshots` from the live authority sources: account `last_balance` rows and `manual_assets` valuations. BAT-008 stores the schema and service helper but does not expose snapshot creation as an MCP mutation.
|
||||
2. `get_asset_snapshot_report(basis_date)` first checks for snapshot rows on the requested basis date.
|
||||
3. If snapshot rows exist, the report computes bucket totals, total assets, total liabilities, and net worth from the stored rows.
|
||||
4. If no snapshot rows exist, the report falls back to live authority sources (`accounts.last_balance` + active `manual_assets`) and marks `source='live_authority'`.
|
||||
5. `get_net_worth_timeseries(start_date, end_date, months)` reads distinct stored snapshot basis dates and applies the same asset-buckets-minus-loan formula to every point.
|
||||
6. `list_manual_assets` exposes current manual asset/liability rows for read-only MCP consumers. Manual asset CRUD and snapshot creation MCP tools remain future scope.
|
||||
## Flow: `Asset snapshot and net-worth workflow`
|
||||
1. Operator can open `자산/마감` in Streamlit or call snapshot tools through MCP.
|
||||
2. `preview_asset_snapshot_close(basis_date)` computes authority-source items from `accounts.last_balance` + active `manual_assets` without DB side effects.
|
||||
3. `close_asset_snapshot(basis_date, source_note, memo, correction_reason)` writes append-only snapshot rows with correction metadata when re-closing the same basis date.
|
||||
4. `get_asset_snapshot_report(basis_date)` first checks stored snapshot rows; if none exist, it falls back to live authority sources and marks `source='live_authority'`.
|
||||
5. `get_net_worth_timeseries(start_date, end_date, months)` reads stored snapshot basis dates and applies the same asset-buckets-minus-loan formula to every point.
|
||||
|
||||
## Flow: `Import preview and import`
|
||||
1. Operator chooses or supplies a supported source file: KB Bank PDF, Toss Bank PDF, Toss Securities PDF, SeoulPay XLSX, or CSV.
|
||||
1. Operator chooses a supported source file: KB Bank PDF, Toss Bank PDF, Toss Securities PDF, SeoulPay XLSX, or CSV.
|
||||
2. Preview function parses the file and reports counts, sample rows, duplicate status, and classification preview.
|
||||
3. On explicit import, service creates/fetches the target account, inserts non-duplicate transactions, writes raw provenance, and records an import batch.
|
||||
4. Reports and dashboard views read the inserted rows using category and cashflow semantics.
|
||||
3. On explicit import, application code creates/fetches the target account, inserts non-duplicate transactions, writes provenance, and records an import batch.
|
||||
4. Reports and dashboard views read the inserted rows using shared category/cashflow semantics.
|
||||
5. If an import is wrong, rollback uses import batch data and soft-deletes by default.
|
||||
|
||||
## Flow: `Categorization rule lifecycle`
|
||||
@@ -86,7 +78,7 @@
|
||||
4. Category `cashflow_kind` controls actual cashflow/report inclusion.
|
||||
|
||||
## Flow: `Cross-account and cancel/original reconciliation`
|
||||
1. Preview functions search candidate pairs by amount, date, direction, account/source compatibility, and text similarity.
|
||||
1. Preview helpers search candidate pairs by amount, date, direction, account/source compatibility, and text similarity.
|
||||
2. Operator reviews candidates in the dashboard or runs the automatic matcher where confidence rules are satisfied.
|
||||
3. Matched self-transfers become `이체 / 본인계좌이동`; investment movements become `이체 / 투자이동`; ambiguous rows remain `확인필요`.
|
||||
4. Cancel/refund rows can be linked to original expense rows; memo tags preserve manual link evidence.
|
||||
@@ -97,26 +89,23 @@
|
||||
3. Risky import, rollback, categorization apply, reconciliation, or migration work is tested first against a synthetic fixture DB or repo-external validation DB copy selected through `JARCA_LEDGER_DB_PATH`.
|
||||
4. Backup list/status/hash checks use `list_ledger_backups` and `get_ledger_backup_status`.
|
||||
5. Restore execution is not an MCP flow. Restore smoke uses `scripts/ledger_restore_smoke.py` or the runbook and requires explicit approval before overwriting an existing target DB.
|
||||
6. Verification evidence must not include full transaction dumps, full merchant/counterparty dumps, account identifiers, raw_payload, original financial file contents, or passwords.
|
||||
|
||||
## Flow: `Statement-unavailable manual balance reconciliation`
|
||||
1. Operator follows the dcy-002 safety standard first: capture DB status, create or confirm a recent backup, and run preview/reconcile on a validation DB before operating on the production DB.
|
||||
2. Operator marks accounts with `statement_status`: `manual_only` for statement-unavailable accounts, `partial_import` for accounts that require manual supplementation, or `import_supported` where normal statement import is sufficient.
|
||||
3. Operator records manual evidence transactions with `source='manual'`, positive amount, date, account, and non-sensitive memo/source context.
|
||||
4. Operator runs `get_balance_reconciliation_report` from MCP/service or the dashboard account page. If `baseline_at` is `YYYY-MM`, the snapshot time is that month end at 23:59 KST; ad-hoc reconciliation uses the user-supplied snapshot timestamp.
|
||||
5. The report compares `baseline_balance`/`last_balance` with the latest `balance_after` if available, otherwise with net signed account transactions. Absolute tolerance is 1,000 KRW; 0.1% of baseline is reference-only.
|
||||
6. `OK` rows need no immediate triage. `REVIEW_NEEDED` rows present manual decision candidates: `계좌이동`, `실지출`, `실수입`, `투자이동`, `분석제외`, `확인필요`.
|
||||
7. This flow does not run automatic scheduling, notifications, restore, or auto-confirming mutation.
|
||||
## Flow: `CI validation gates`
|
||||
1. GitHub Actions starts `.github/workflows/ci.yml` on `pull_request`, `push` to `main`, or `workflow_dispatch`.
|
||||
2. `lint` runs `ruff check .` with the conservative required rule set.
|
||||
3. `contract-regression` runs `pytest tests/test_contract_regression.py` with synthetic pytest temp DBs and committed contract snapshots.
|
||||
4. `pytest-regression` runs the non-dashboard regression suite.
|
||||
5. `dashboard-app-test` runs `pytest tests/test_dashboard_app.py` using `scripts/ci_fixture_db.py` synthetic DB setup.
|
||||
6. `dashboard-http-smoke` starts Streamlit against a synthetic DB and polls readiness.
|
||||
7. `db-safety-smoke` runs restore smoke through temp source/backup/target DB paths only.
|
||||
8. Any required job failure fails the workflow. Stable required-check job names remain `pytest-regression`, `dashboard-app-test`, `dashboard-http-smoke`, `db-safety-smoke`, `contract-regression`, and `lint`.
|
||||
|
||||
## Flow: `Streamlit browser evidence capture`
|
||||
1. Operator runs `scripts/streamlit_browser_evidence.py` from the repository root.
|
||||
2. The script creates a synthetic fixture DB under the evidence output directory and refuses to use the default operating DB path.
|
||||
3. Streamlit starts with `JARCA_LEDGER_DB_PATH=<fixture.sqlite3>` on a local loopback port.
|
||||
4. `/usr/bin/google-chrome-stable` runs in headless mode through Chrome DevTools Protocol and opens target dashboard pages such as `분류 규칙`, `확인필요 큐`, and `Import`.
|
||||
5. After page title text is rendered, the script stores PNG screenshots, DOM snapshots, and `manifest.json` in the evidence directory.
|
||||
6. UI/dashboard-impacting batches must attach browser screenshot/snapshot evidence. Non-UI batches may treat it as optional, and docs-only batches do not require browser evidence.
|
||||
7. If Chrome/browser capture is unavailable, AppTest + HTTP 200 fallback evidence is allowed only as `PASS_WITH_NOTES` with the environment failure and remaining browser-evidence item recorded.
|
||||
8. Browser screenshot/DOM evidence is not a required GitHub Actions gate in BAT-006. Run it locally for visual/layout-sensitive dashboard changes, while non-visual backend/CI changes can rely on pytest/AppTest/HTTP/DB safety gates.
|
||||
1. Operator runs `scripts/streamlit_browser_evidence.py` or starts Streamlit against a synthetic fixture DB.
|
||||
2. The script/flow refuses to use the default operating DB path for evidence capture.
|
||||
3. Browser smoke opens key pages such as `요약`, `자산/마감`, `분류 규칙`, `확인필요 큐`, and `Import`.
|
||||
4. Verification records rendered headings/content and browser console JS error absence.
|
||||
5. UI/dashboard-impacting batches must attach browser screenshot/DOM evidence or equivalent browser smoke notes.
|
||||
|
||||
## Flow Constraints
|
||||
- Preview before broad import or categorization mutation where supported.
|
||||
@@ -125,20 +114,14 @@
|
||||
- Avoid destructive migrations without a backup/approval plan.
|
||||
- Before broad DB mutation, capture DB status evidence and create or confirm a recent backup.
|
||||
- Restore execution is script/runbook only and must not be exposed as an MCP tool.
|
||||
- Manual balance reconciliation must remain preview/report-first unless a future REQ approves persistent review routing and confirmation mutation.
|
||||
- Streamlit browser evidence must use synthetic/validation DBs only and must not screenshot/log real account numbers, balances, source financial filenames, passwords, full merchant/counterparty dumps, or raw payloads.
|
||||
- CI gates must use synthetic/temp DBs only. The default operating DB path (`~/.local/share/jarca/ledger.sqlite3`) is forbidden for AppTest, HTTP smoke, and DB safety smoke wrappers.
|
||||
- Contract regression must use synthetic/temp DBs only and must not expose runtime contract-version fields in MCP success payloads unless a future approved REQ changes the policy.
|
||||
- Branch protection required-check drift should be audited against the six stable workflow job names documented in `docs/interface-contract.md`; changing a job name requires an explicit REQ/BAT note because it can break external repository settings.
|
||||
- Dashboard and MCP asset valuation reports must use the shared service valuation policy: `accounts.last_balance` plus `manual_assets`, asset buckets minus loan, and missing valuation exclusion.
|
||||
- Snapshot read tools are read-only in BAT-008. Snapshot creation and manual asset CRUD MCP mutation tools require a future REQ.
|
||||
- Sensitive passwords are runtime inputs and must not be committed.
|
||||
- Streamlit browser evidence must use synthetic/validation DBs only and must not screenshot/log real account numbers, source financial filenames, passwords, full merchant/counterparty dumps, or raw payloads.
|
||||
- CI gates must use synthetic/temp DBs only. The default operating DB path is forbidden for AppTest, HTTP smoke, and DB safety smoke wrappers.
|
||||
- Top-level `service.py`, `db.py`, and `server.py` import paths remain compatibility surfaces until a future approved REQ retires them.
|
||||
|
||||
## Current Gaps / Planned Changes
|
||||
- Browser-level evidence is available locally through `scripts/streamlit_browser_evidence.py`; it remains outside required CI gates by design.
|
||||
- Contract-regression and lint gates are now part of the required-check contract for CI; full MCP tool-surface snapshot coverage remains deferred beyond the representative health/status/list/report/mutation scope.
|
||||
- Dedicated reconciliation workbench and persistent review-decision queue are deferred beyond REQ-003.
|
||||
- Separate asset snapshot/manual asset tables and automatic market/real-estate valuation are deferred beyond REQ-005.
|
||||
- Browser-level evidence exists locally and remains outside required CI gates by design.
|
||||
- Phase 4+ write/import/advanced workflow service thinning and narrower adapters are deferred to GitHub Project TODO items.
|
||||
- HTTP adapter and remote ops re-architecture remain deferred.
|
||||
|
||||
## Update Triggers
|
||||
- Update this document when a command entry point changes.
|
||||
@@ -151,5 +134,6 @@
|
||||
- 2026-06-29 KST: REQ-003/BAT-003 기준으로 statement-unavailable 수동 잔액대조 flow 추가.
|
||||
- 2026-06-29 KST: REQ-004/BAT-004 기준으로 Streamlit browser evidence capture flow 및 UI evidence gate 기준 추가.
|
||||
- 2026-06-29 KST: REQ-005/BAT-005 기준으로 dashboard operations hub 및 `liquidity_bucket`/`last_balance` 자산 유동성 flow 추가.
|
||||
- 2026-06-30 KST: REQ-006/BAT-006 기준으로 GitHub Actions CI validation gates, synthetic fixture DB boundary, AppTest/HTTP/DB safety smoke flow, local browser evidence boundary 추가.
|
||||
- 2026-06-30 KST: REQ-007/REQ-008/BAT-007 기준으로 `contract-regression`/`lint` CI required-check flow, contract snapshot scope, branch protection drift boundary 추가.
|
||||
- 2026-06-30 KST: REQ-006/BAT-006 기준으로 GitHub Actions CI validation gates, synthetic fixture DB boundary, AppTest/HTTP/DB safety smoke flow 추가.
|
||||
- 2026-06-30 KST: REQ-007/REQ-008/BAT-007 기준으로 contract-regression/lint CI required-check flow 추가.
|
||||
- 2026-07-03 KST: REQ-013/REQ-014/BAT-010 기준으로 service facade → application, db shim → infrastructure/sqlite, MCP/Streamlit adapter seam flow를 반영했다.
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
# REQ-014 MCP/Streamlit adapter seam realignment and contract-preserving gateway
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Interface
|
||||
- Priority: High
|
||||
- Owner: 렛저장인
|
||||
- Source Discovery: `docs/discovery/dcy-010_20260702_backend-core-layering-mcp-adapter-realignment.md`
|
||||
- Batch: BAT-010
|
||||
- Created At (KST): 2026-07-03 00:15 KST
|
||||
- Approved At (KST): 2026-07-03 00:15 KST
|
||||
- Implemented At (KST): 2026-07-03 00:18 KST
|
||||
|
||||
## 1. 배경
|
||||
|
||||
`dcy-010`은 MCP server와 Streamlit dashboard가 giant service namespace에 직접 결합돼 있어 내부 구조 개선이 곧 external contract drift로 이어질 위험이 크다고 판단했다. Phase 0~3에서는 adapter를 얇게 만들되, tool names/response envelope/dashboard 핵심 페이지를 유지하는 것이 핵심이다.
|
||||
|
||||
## 2. Intent
|
||||
|
||||
이 REQ의 목적은 MCP와 Streamlit을 제거하는 것이 아니라, backend core 위에 얹힌 thin adapter로 재정렬하는 것이다. 즉 `server.py`와 `dashboard/app.py`가 더 좁은 seam을 통해 application core를 호출하면서도 기존 사용자의 운영 경험과 계약은 유지해야 한다.
|
||||
|
||||
## 3. 범위
|
||||
|
||||
### In Scope
|
||||
- `jarca_ledger_mcp/adapters/mcp/server.py`를 도입하고 top-level `server.py`를 compatibility shim으로 유지한다.
|
||||
- `jarca_ledger_mcp/adapters/streamlit/service_gateway.py`를 도입하고 dashboard가 이 gateway를 통해 service functions를 호출하도록 정렬한다.
|
||||
- MCP tool discovery 결과(56 tools)와 success envelope contract를 유지한다.
|
||||
- Streamlit 핵심 페이지(`요약`, `자산/마감` 포함)가 synthetic fixture DB에서 렌더링돼야 한다.
|
||||
- baseline docs와 batch verification evidence에 adapter seam을 반영한다.
|
||||
|
||||
### Out of Scope
|
||||
- 신규 MCP 도구 추가나 응답 schema 변경.
|
||||
- 새로운 Streamlit IA/디자인 재구성.
|
||||
- HTTP adapter/REST route 추가.
|
||||
|
||||
## 4. Requirement
|
||||
|
||||
### FR-1. MCP adapter thinness
|
||||
- 실제 FastMCP registration은 `jarca_ledger_mcp/adapters/mcp/server.py`에 위치해야 한다.
|
||||
- top-level `jarca_ledger_mcp/server.py`는 CLI/script entrypoint 호환을 위한 shim이어야 한다.
|
||||
- MCP 도구명/설명/인자 contract는 유지돼야 한다.
|
||||
|
||||
### FR-2. Streamlit gateway seam
|
||||
- `dashboard/app.py`는 giant service implementation이 아니라 명시적 gateway module을 통해 service functions를 사용해야 한다.
|
||||
- gateway는 dashboard가 실제로 필요한 surface만 노출해야 한다.
|
||||
- dashboard 렌더 결과는 synthetic fixture DB 기준 기존 핵심 페이지를 깨지 않아야 한다.
|
||||
|
||||
### FR-3. Contract-preserving verification
|
||||
- full pytest regression과 MCP tool discovery가 PASS 해야 한다.
|
||||
- browser-level smoke는 synthetic fixture DB에서 `요약`과 구조 변경 영향 페이지(`자산/마감`)를 렌더링해야 한다.
|
||||
- 브라우저 콘솔 JS 에러가 없어야 한다.
|
||||
|
||||
### FR-4. Documentation alignment
|
||||
- `docs/project-structure.md`와 `docs/runtime-flows.md`는 adapter/gateway seam과 compatibility shim 구조를 반영해야 한다.
|
||||
- BAT verification 문서는 synthetic-only evidence와 잔여 Phase 4+ TODO를 기록해야 한다.
|
||||
|
||||
## 5. Acceptance Criteria
|
||||
|
||||
- AC-1: `jarca_ledger_mcp/adapters/mcp/server.py`와 top-level `server.py` shim이 존재하고 `hermes mcp test jarca-ledger`가 PASS 한다.
|
||||
- AC-2: `jarca_ledger_mcp/adapters/streamlit/service_gateway.py`가 도입되고 `dashboard/app.py`가 이를 사용한다.
|
||||
- AC-3: full pytest가 PASS 하고 Streamlit AppTest smoke가 계속 PASS 한다.
|
||||
- AC-4: local browser smoke에서 `요약`과 `자산/마감` 페이지가 렌더링되고 console JS errors가 없다.
|
||||
- AC-5: baseline docs와 batch evidence 문서가 새 adapter seam을 반영한다.
|
||||
|
||||
## 6. Impacted Area
|
||||
|
||||
- `jarca_ledger_mcp/server.py`
|
||||
- `jarca_ledger_mcp/adapters/mcp/server.py`
|
||||
- `jarca_ledger_mcp/adapters/streamlit/service_gateway.py`
|
||||
- `dashboard/app.py`
|
||||
- `tests/test_dashboard_app.py`
|
||||
- `tests/test_contract_regression.py`
|
||||
- `docs/project-structure.md`
|
||||
- `docs/runtime-flows.md`
|
||||
|
||||
## 7. Notes
|
||||
|
||||
- 이 REQ는 MCP/Streamlit surface와 operator-facing 호출 경계를 다루므로 `Interface` 타입으로 관리한다.
|
||||
- gateway는 현재 dashboard가 사용하는 surface만 노출하며, Phase 4+에서 더 좁은 domain-specific gateway로 재분할할 수 있다.
|
||||
|
||||
## 8. Change Log
|
||||
|
||||
- 2026-07-03 00:15 KST: dcy-010 confirmed 범위를 바탕으로 Proposed 초안을 생성.
|
||||
- 2026-07-03 00:15 KST: 사용자 승인 방향(계약 동결, adapter thinness, Phase 0~3 우선)에 따라 Approved로 전환.
|
||||
- 2026-07-03 00:18 KST: MCP adapter split, Streamlit gateway 도입, browser smoke, MCP discovery, full pytest PASS를 근거로 Implemented로 전환.
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
# REQ-013 Backend core layering / SQLite infrastructure split and service facade compatibility
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Non-Functional
|
||||
- Priority: High
|
||||
- Owner: 렛저장인
|
||||
- Source Discovery: `docs/discovery/dcy-010_20260702_backend-core-layering-mcp-adapter-realignment.md`
|
||||
- Batch: BAT-010
|
||||
- Created At (KST): 2026-07-03 00:15 KST
|
||||
- Approved At (KST): 2026-07-03 00:15 KST
|
||||
- Implemented At (KST): 2026-07-03 00:18 KST
|
||||
|
||||
## 1. 배경
|
||||
|
||||
`dcy-010` confirmed Discovery는 `jarca_ledger_mcp/service.py`와 `jarca_ledger_mcp/db.py`에 과도하게 집중된 책임 때문에 MCP adapter, Streamlit dashboard, SQLite persistence가 하나의 giant module 집합에 강결합돼 있다고 판단했다. Phase 0~3 우선 범위에서는 기능 계약을 바꾸지 않고도 backend core의 최소 layering을 세워 이후 write/import/advanced workflow 분리를 안전하게 이어갈 수 있어야 한다.
|
||||
|
||||
## 2. Intent
|
||||
|
||||
이 REQ의 목적은 서비스/DB 코드를 한 번에 다시 쓰는 것이 아니라, 기존 동작을 유지한 채 `application` / `infrastructure/sqlite` / compatibility facade 경계를 도입해 코드 탐색성, 변경 안전성, 후속 분리 가능성을 확보하는 것이다.
|
||||
|
||||
## 3. 범위
|
||||
|
||||
### In Scope
|
||||
- `jarca_ledger_mcp/service.py`를 compatibility facade로 축소하고 실제 구현을 application 모듈로 분리한다.
|
||||
- 공통 helper/정책을 `jarca_ledger_mcp/application/shared.py`로 정리한다.
|
||||
- SQLite connection/schema/migration 책임을 `jarca_ledger_mcp/infrastructure/sqlite/`로 이동한다.
|
||||
- 기존 `jarca_ledger_mcp/db.py` import surface는 compatibility shim으로 유지한다.
|
||||
- additive/idempotent migration discipline과 기존 테스트 contract를 유지한다.
|
||||
- `docs/project-structure.md`, `docs/runtime-flows.md`에 새 경계를 반영한다.
|
||||
|
||||
### Out of Scope
|
||||
- FastAPI/HTTP adapter 추가.
|
||||
- write/import/advanced workflow의 본격적인 Phase 4+ domain 분리.
|
||||
- 데이터 모델 semantics 변경, 응답 envelope 변경, destructive migration.
|
||||
|
||||
## 4. Requirement
|
||||
|
||||
### FR-1. Application service decomposition
|
||||
- 기존 `service.py`의 기능 구현은 최소한 `system`, `asset/account`, `transaction/report`, `import/transfer`, `categorization` 성격의 application 모듈로 분리돼야 한다.
|
||||
- shared helper와 공통 정책(`cashflow_kind`, KST clock, dedupe, validation helpers)은 application shared module로 이동해야 한다.
|
||||
- 분리 후에도 기존 `from jarca_ledger_mcp import service` 사용자는 동일 함수명을 계속 사용할 수 있어야 한다.
|
||||
|
||||
### FR-2. SQLite infrastructure split
|
||||
- 기존 `db.py`의 connection/schema/migration 책임은 `jarca_ledger_mcp/infrastructure/sqlite/`로 이동해야 한다.
|
||||
- top-level `db.py`는 기존 import 경로를 유지하는 compatibility shim이어야 한다.
|
||||
- `db()` context manager는 기존처럼 초기화/commit/rollback semantics를 유지해야 한다.
|
||||
- 스키마 migration은 additive/idempotent 원칙을 유지해야 한다.
|
||||
|
||||
### FR-3. Service facade compatibility
|
||||
- `jarca_ledger_mcp/service.py`는 thin facade여야 하며 구현 디테일 대신 application 모듈을 재노출해야 한다.
|
||||
- 기존 pytest/service call sites와 monkeypatch 관성(`_current_kst_datetime`)은 깨지지 않아야 한다.
|
||||
- facade 축소 결과는 더 이상 giant implementation file이 아니어야 한다.
|
||||
|
||||
### FR-4. Baseline documentation alignment
|
||||
- `docs/project-structure.md`는 새 package tree와 책임 경계를 반영해야 한다.
|
||||
- `docs/runtime-flows.md`는 service facade, Streamlit gateway, MCP adapter, SQLite infrastructure flow를 반영해야 한다.
|
||||
- 문서는 Phase 4+가 GitHub Project TODO로 남아 있음을 드러내야 한다.
|
||||
|
||||
## 5. Acceptance Criteria
|
||||
|
||||
- AC-1: `jarca_ledger_mcp/application/` 아래에 phase-0~3 범위의 application service modules와 shared module이 생성된다.
|
||||
- AC-2: `jarca_ledger_mcp/infrastructure/sqlite/` 아래에 connection/schema/migration 분리가 생성되고 top-level `db.py` shim이 동작한다.
|
||||
- AC-3: `jarca_ledger_mcp/service.py`는 compatibility facade로 축소되고 600줄 이하를 유지한다.
|
||||
- AC-4: 전체 pytest regression이 PASS 하며 기존 service/db import surface가 유지된다.
|
||||
- AC-5: `docs/project-structure.md`, `docs/runtime-flows.md`가 새 계층 구조를 반영한다.
|
||||
|
||||
## 6. Impacted Area
|
||||
|
||||
- `jarca_ledger_mcp/service.py`
|
||||
- `jarca_ledger_mcp/db.py`
|
||||
- `jarca_ledger_mcp/application/*`
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/*`
|
||||
- `tests/test_service.py`
|
||||
- `tests/test_asset_snapshots.py`
|
||||
- `docs/project-structure.md`
|
||||
- `docs/runtime-flows.md`
|
||||
|
||||
## 7. Notes
|
||||
|
||||
- 이 REQ는 주로 maintainability/architecture boundary와 compatibility behavior를 다루므로 `Non-Functional`로 관리한다.
|
||||
- write/import/advanced workflow의 deeper split은 dcy-010에서 별도 Phase 4+ TODO로 남겼다.
|
||||
|
||||
## 8. Change Log
|
||||
|
||||
- 2026-07-03 00:15 KST: dcy-010 confirmed 범위를 바탕으로 Proposed 초안을 생성.
|
||||
- 2026-07-03 00:15 KST: 사용자 승인 방향(Phase 0~3 우선, facade 축소, 계약 동결)에 따라 Approved로 전환.
|
||||
- 2026-07-03 00:18 KST: application/infrastructure split, facade/shim compatibility, full pytest PASS, MCP tool discovery, browser smoke evidence를 근거로 Implemented로 전환.
|
||||
+6
-2
@@ -28,12 +28,12 @@
|
||||
| **Integration** | 외부 시스템 연동, 플러그인, 확장 | KB/토스/서울페이 import |
|
||||
| **Interface** | 사용자 상호작용 방식 | MCP tool, Streamlit UI |
|
||||
| **Migration** | 데이터 이전, 버전 업그레이드 | SQLite schema migration |
|
||||
| **Non-Functional** | 성능, 보안, 확장성, 호환성, 신뢰성 | 개인정보/금융정보 보호, UX 성능 |
|
||||
| **Non-Functional** | 성능, 보안, 확장성, 호환성, 신뢰성 | 개인정보/금융정보 보호, UX 성능, 아키텍처 유지보수성 |
|
||||
| **Testing** | 테스트 전략, QA 요구사항, 검증 방식 | parser regression, report validation |
|
||||
|
||||
## Next Requirement ID
|
||||
|
||||
- Current: `REQ-013`
|
||||
- Current: `REQ-015`
|
||||
- Rule: `Requirement Register`에 있는 가장 큰 REQ 번호보다 정확히 1 커야 한다.
|
||||
|
||||
## Requirement Register
|
||||
@@ -52,6 +52,8 @@
|
||||
| REQ-010 | Asset snapshot/net worth read MCP and dashboard alignment | Interface | Implemented | High | 렛저장인 | [req-010_asset-snapshot-net-worth-read-mcp-and-dashboard-alignment.md](Interface/req-010_asset-snapshot-net-worth-read-mcp-and-dashboard-alignment.md) |
|
||||
| REQ-011 | Manual asset CRUD / month-end snapshot write model | Data | Implemented | High | 렛저장인 | [req-011_manual-asset-crud-month-end-snapshot-write-model.md](Data/req-011_manual-asset-crud-month-end-snapshot-write-model.md) |
|
||||
| REQ-012 | Manual asset CRUD / snapshot close MCP and operator dashboard alignment | Interface | Implemented | High | 렛저장인 | [req-012_manual-asset-crud-snapshot-close-mcp-and-operator-dashboard-alignment.md](Interface/req-012_manual-asset-crud-snapshot-close-mcp-and-operator-dashboard-alignment.md) |
|
||||
| REQ-013 | Backend core layering / SQLite infrastructure split and service facade compatibility | Non-Functional | Implemented | High | 렛저장인 | [req-013_backend-core-layering-sqlite-infrastructure-service-facade-compatibility.md](Non-Functional/req-013_backend-core-layering-sqlite-infrastructure-service-facade-compatibility.md) |
|
||||
| REQ-014 | MCP/Streamlit adapter seam realignment and contract-preserving gateway | Interface | Implemented | High | 렛저장인 | [req-014_mcp-streamlit-adapter-seam-realignment-contract-preserving-gateway.md](Interface/req-014_mcp-streamlit-adapter-seam-realignment-contract-preserving-gateway.md) |
|
||||
|
||||
## Recent Change Log Summary
|
||||
|
||||
@@ -76,3 +78,5 @@
|
||||
- 2026-07-01 09:00 KST: dcy-009 confirmed 범위를 `REQ-011`(manual asset CRUD / month-end snapshot write model)과 `REQ-012`(manual asset CRUD / snapshot close MCP and operator dashboard alignment) Proposed 상태로 생성했다.
|
||||
- 2026-07-01 09:02 KST: `REQ-011`, `REQ-012`를 승인 게이트 재검토 후 Approved로 전환했다.
|
||||
- 2026-07-01 10:52 KST: BAT-009 구현·검증 evidence, full pytest PASS, MCP tool discovery, browser smoke를 근거로 `REQ-011`, `REQ-012`를 Implemented로 전환했다.
|
||||
- 2026-07-03 00:15 KST: dcy-010 confirmed 범위를 `REQ-013`, `REQ-014`로 생성하고 승인 상태를 정리했다.
|
||||
- 2026-07-03 00:18 KST: BAT-010 구현·검증 evidence, full pytest PASS, MCP tool discovery, browser smoke를 근거로 `REQ-013`, `REQ-014`를 Implemented로 전환했다.
|
||||
|
||||
Reference in New Issue
Block a user