Files
jarca-ledger-mcp/docs/project-structure.md
T

227 lines
17 KiB
Markdown

# Project Structure — Dashboard 관리자 인증
## 목적과 경계
Issue #6 인증을 기존 Dashboard 구조에 배치하고 fail-closed 경계와 server-only secret binding을 유지한다.
- 포함 경계: `dashboard/` 인증 adapter/gate, tests, 운영 문서
- 제외 경계: MCP transport, 금융 schema, DB migration, external auth middleware
## 디렉터리 구조
### dashboard-source — Dashboard source
```text
dashboard/
├── server.py
├── auth_server.py
├── authentication.py
├── app.py
├── common.py
└── page_views/
```
| 경로 | 종류 | 책임 | 공개 진입점 | 내부 구현 경계 | 편집 정책 | 생성 주체 |
|---|---|---|---|---|---|---|
| `dashboard/server.py` | source | ASGI app 조립 | `app` | route wiring only | source review required | developer |
| `dashboard/auth_server.py` | source | login/cleanup/logout response | `create_auth_routes()` | no DB/page imports | source review required | developer |
| `dashboard/authentication.py` | source | config, constant-time compare, token verify, gate | `require_dashboard_authentication()` | server-only secret use | source review required | developer |
| `dashboard/app.py` | source | auth gate first, then DB path resolution, common shell/sidebar/refresh assembly, and target body renderer dispatch | `main()` | shell/background remain outside the replaceable body; no token signing details | source review required | developer |
| `dashboard/common.py` | source | shared Dashboard shell, menu/query transition, stable body container, loading/error/retry rendering, and app background/style | `render_sidebar_nav()`, `render_dashboard_body()`, `inject_app_css()` | no authentication transport or financial write orchestration | source review required | developer |
| `dashboard/page_views/` | source | financial UI pages | `page_*` functions | no auth transport calls | source review required | developer |
`dashboard/common.py` owns the shared visual theme through `JARCA_COLORS`, `JARCA_PLOTLY_TEMPLATE`, and `inject_app_css()`. Page renderers consume that theme but do not own or replace the authenticated shell/sidebar background.
### verification-tests — 인증 검증
```text
tests/
├── test_dashboard_authentication.py
├── test_dashboard_persistent_authentication.py
├── test_dashboard_auth_server.py
├── test_dashboard_menu_transition.py
├── test_streamlit_browser_evidence.py
└── test_dashboard_authentication_app.py
```
| 경로 | 종류 | 책임 | 공개 진입점 | 내부 구현 경계 | 편집 정책 | 생성 주체 |
|---|---|---|---|---|---|---|
| `tests/test_dashboard_authentication.py` | test | credential compare, delay, redaction | pytest tests | test-only settings | source change paired with test | developer |
| `tests/test_dashboard_persistent_authentication.py` | test | claims, TTL, tamper, rotation | pytest tests | no real secrets | source change paired with test | developer |
| `tests/test_dashboard_auth_server.py` | test | HTTP routes and cookie scope | pytest tests | synthetic test credentials | source change paired with test | developer |
| `tests/test_dashboard_menu_transition.py` | test | REQ-002 menu/query/body transition and cache-clear regression | pytest/AppTest | synthetic fixture DB; no real secrets | source change paired with test and browser evidence where required | developer |
| `tests/test_streamlit_browser_evidence.py` | test | transition evidence manifest, redaction, TLS fixture and fail-closed validation | pytest | generated synthetic values only; no captured credential values | evidence-harness change paired with test | developer |
| `tests/test_dashboard_authentication_app.py` | test | gate ordering and cleanup/UI | AppTest | fixture DB only | source change paired with test | developer |
### browser-evidence — 실제 전환 관찰
| 경로 | 종류 | 책임 | 공개 진입점 | 내부 구현 경계 | 편집 정책 | 생성 주체 |
|---|---|---|---|---|---|---|
| `scripts/streamlit_browser_evidence.py` | verification tool | synthetic DB와 runtime 생성 인증 설정으로 실제 HTTPS Dashboard 전환의 frame/DOM/document/shell 관찰을 수집하고 redacted manifest를 검증 | `--mode transition` | 운영 DB·credential 사용 금지; 성공 증거는 browser/server teardown 뒤에만 확정 | source review and focused test required | developer |
| `docs/evidence/issue-9-dashboard-menu-transition/` | evidence artifact | exact source hash에 결합한 authenticated browser frame, screenshot, runtime, validator 결과 | `manifest.json` | synthetic fixture only; credential/token/cookie 값 금지 | immutable after verification except complete regeneration | verification runner |
### deployment-docs — 운영 문서
```text
docs/requirements/req-001_dashboard-administrator-authentication.md
docs/requirements/req-002_dashboard-menu-transition.md
docs/evidence/issue-9-dashboard-menu-transition/
docs/interface-contract.md
docs/runtime-flow.md
README.md
deploy/k8s/README.md
```
| 경로 | 종류 | 책임 | 공개 진입점 | 내부 구현 경계 | 편집 정책 | 생성 주체 |
|---|---|---|---|---|---|---|
| `docs/requirements/req-001_dashboard-administrator-authentication.md` | requirement | approved REQ-001 revision 2.0 | REQ-001 | canonical traceability | update in place | developer |
| `docs/requirements/req-002_dashboard-menu-transition.md` | requirement | approved REQ-002 revision 1.0 | REQ-002 | canonical traceability | update in place | developer |
| `docs/interface-contract.md` | contract | HTTP/cookie/gate contracts | contract IDs | no implementation secrets | update with API changes | developer |
| `docs/runtime-flow.md` | design | runtime states/transitions | flow IDs | no secret values | update with flow changes | developer |
| `README.md` | operations | local/deployment constraints | operator commands | no secret values | operational review | developer |
| `deploy/k8s/README.md` | operations | k3s secret/TLS procedure | deployment procedure | no secret values | deployment review | developer |
## 의존 방향
| 출발 영역 | 대상 영역 | 허용 여부 | 규칙 | 공유 계약 위치 |
|---|---|---|---|---|
| `dashboard.server` | `dashboard.auth_server` | 허용 | compose ASGI routes only | `docs/interface-contract.md` |
| `dashboard.server` | `dashboard.app` | 허용 | app remains protected by gate | `docs/runtime-flow.md` |
| `dashboard.app` | `dashboard.authentication` | 허용 | gate precedes DB/page dispatch | `docs/interface-contract.md` |
| `dashboard.authentication` | `dashboard.page_views` | 금지 | auth module never imports financial pages | `docs/project-structure.md` |
| `dashboard.app` | `dashboard.common` | 허용 | menu/query/body transition helpers only after auth gate | `docs/interface-contract.md` |
| `dashboard.auth_server` | `jarca_ledger_mcp` DB | 금지 | login/cleanup/logout are DB-free | `docs/requirements/req-001_dashboard-administrator-authentication.md` |
## 변경 규칙
| 구분 | 규칙 |
|---|---|
| 새 모듈·파일 배치 | auth route/gate changes stay in `dashboard/`; menu transition stays in existing `dashboard.app`/`dashboard.common`; no DB session module |
| 이름·패키지 | use existing `dashboard` package and snake_case modules |
| 소스·테스트 대응 | auth source behavior requires focused pytest/AppTest coverage; REQ-002 transition behavior requires focused pytest/AppTest targets and real-browser evidence where specified |
| 생성 산출물 | evidence may be redacted; never commit credentials, secrets, tokens, or cookie values |
## 검증
- 구조 검사 명령:
```text
python -m compileall -q dashboard tests scripts
```
- 구조 검사 기대 결과: exit 0 and no generated source outside ignored bytecode locations
- 정적 분석 명령:
```text
uv run --extra dashboard --extra dev ruff check dashboard tests scripts
```
- 정적 분석 기대 결과: exit 0 with no diagnostics
- 문서와 실제 트리의 정합성: every listed source/test/document path exists; dependency table has no forbidden reverse edge; REQ-002 symbols resolve to `dashboard/app.py`, `dashboard/common.py`, and named tests
## REQ-003 additive structure
### ledger-application — shared valuation and snapshot services
```text
jarca_ledger_mcp/
├── application/account_valuation_service.py
├── application/assets_service.py
├── application/accounts_write_services.py
├── application/imports_service.py
├── application/reconciliation_service.py
├── infrastructure/sqlite/migrations.py
├── adapters/mcp/server.py
└── adapters/streamlit/{accounts_gateway.py,assets_gateway.py}
```
| 경로 | 종류 | 책임 | 공개 진입점 | 내부 구현 경계 | 편집 정책 | 생성 주체 |
|---|---|---|---|---|---|---|
| `jarca_ledger_mcp/application/account_valuation_service.py` | source | validation, selection, idempotency, correction | named valuation functions | SQLite through shared db | source review + focused tests | developer |
| `jarca_ledger_mcp/application/assets_service.py` | source | preview, formula, close/correction | `preview_asset_snapshot_close`, `close_asset_snapshot` | snapshot transaction | source review + focused tests | developer |
| `jarca_ledger_mcp/infrastructure/sqlite/migrations.py` | source | schema 12 additive migration | `init_db`, `migrate_db` | no UI/MCP imports | migration review | developer |
| `tests/test_account_valuations.py` | test | valuation contracts | pytest | synthetic DB | paired with source | developer |
| `tests/test_asset_snapshots.py` | test | preview/close/report contracts | pytest | synthetic DB | paired with source | developer |
| `docs/data-model.md` | canonical doc | entity/schema authority | document | no secrets | update with schema | developer |
### 의존 방향 추가
| 출발 영역 | 대상 영역 | 허용 여부 | 규칙 | 공유 계약 위치 |
|---|---|---|---|---|
| `dashboard.page_views` | `streamlit gateways` | 허용 | page → gateway only | `docs/interface-contract.md` |
| `streamlit gateways` | `application services` | 허용 | adapter delegates; no SQL | `docs/runtime-flow.md` |
| `MCP adapters` | `application services` | 허용 | tool delegates; no duplicate business logic | `docs/interface-contract.md` |
| `application services` | `infrastructure.sqlite` | 허용 | service → shared db/schema | `docs/data-model.md` |
| `application services` | `dashboard` | 금지 | no reverse UI dependency | `docs/project-structure.md` |
### 변경 규칙 추가
| 구분 | 규칙 |
|---|---|
| 새 모듈·파일 배치 | valuation/snapshot logic stays in application; adapters remain thin; no direct SQL in page/MCP |
| 이름·패키지 | existing snake_case modules and service re-exports |
| 소스·테스트 대응 | every valuation/snapshot change paired with named synthetic tests and docs validator |
| 생성 산출물 | only redacted synthetic evidence; no credentials, cookie, token or actual account data |
## REQ-003 preservation inventory
REQ-001 auth gate, cookie/cleanup/logout and auth-before-DB; REQ-002 menu labels/order, query sibling preservation, stable shell/background and browser evidence remain in the preceding sections. Missing semantic items: 0. Ambiguous semantic items: 0.
### REQ-003 canonical module ownership and regression map
| 경로 | 책임·실패 경계 |
|---|---|
| `jarca_ledger_mcp/application/account_valuation_service.py` | register/list/select/correct; principal mapping, source_ref identity, parent scope, idempotency and no-write conflicts |
| `jarca_ledger_mcp/application/assets_service.py` | preview/close/report; valuation_date/age/carry, approval, correction, warnings/exclusions and atomic run |
| `jarca_ledger_mcp/application/asset_account_services.py` | shared account/asset evidence and reconciliation boundary |
| `jarca_ledger_mcp/infrastructure/sqlite/connection.py` | `read_db()` mode=ro and `db_not_initialized` without mkdir/migrate/commit |
| `jarca_ledger_mcp/infrastructure/sqlite/migrations.py` | explicit `init_db()` and additive migration |
| `jarca_ledger_mcp/application/monthly_settlement_service.py` | monthly read model; `monthly_source_snapshot_id` alias only, never persistence |
Named transitions are `valuation-01`→`valuation-02`→`valuation-03`→`valuation-04`, `close-01`→`close-02`→`close-03`→`close-04`, `prop-01`→`prop-02`→`prop-03`, `db-init-01`, `db-read-01`, `db-read-02`, and `write-first-use-01`; named failures are `valuation-fail`, `close-fail`, `prop-fail`, `db_not_initialized`, `conditional_approval_required`, `idempotency_conflict`, and `correction_conflict`. `auth-before-DB` precedes all reads.
Regression tests are `test_valuation_round_trip_preserves_null_zero_and_physical_amount_mapping`, `test_source_ref_is_account_scoped_evidence_identity_without_explicit_key`, `test_direct_correction_requires_matching_existing_parent_and_reason`, `test_investment_without_verified_valuation_and_without_opening_balance_is_incomplete`, `test_timeseries_and_monthly_expose_canonical_asset_provenance`, and `test_read_queries_missing_nested_db_return_stable_error_without_creating_path`. D06 requires these names and actual paths/signatures, not marker prose.
## D01 preservation matrix
| item | source evidence | test evidence |
|---|---|---|
| schema 11 legacy rows | `infrastructure/sqlite/migrations.py`: additive schema 12 migration | `tests/test_issue_12_regressions.py::test_schema12_migration_preserves_legacy_rows_indexes_and_is_idempotent` |
| auth gate and cookie lifecycle | `dashboard/server.py`: login, cleanup, logout, auth-before-DB gate | `tests/test_dashboard_authentication.py`, `tests/test_dashboard_persistent_authentication.py` |
| REQ-002 menu labels/order | `dashboard/common.py`: canonical 10-option menu and query transition | `tests/test_dashboard_menu_transition.py` |
| MCP envelope and tools | `adapters/mcp/server.py`: shared success/error response envelope and named tools | `tests/test_contract_regression.py` |
| reconciliation and monthly read models | `application/reconciliation_service.py`, `application/monthly_settlement_service.py`: read-only propagation | `tests/test_issue_12_review59_reports.py`, `tests/test_service.py::test_monthly_settlement_summary_read_model_foundation` |
Each row is an independently reviewable preservation claim: the source column names the canonical implementation boundary and the test column names executable evidence. A prose inventory without both references is not evidence.
## D05 canonical ownership
| concern | owner | boundary |
|---|---|---|
| monthly settlement | `monthly_settlement_service.py` | read-only monthly read model; `monthly_source_snapshot_id` aliases `snapshot_run_id`, never persistence |
| reconciliation | `reconciliation_service.py` | computes completeness/status and provenance; never creates fake transactions |
| policy | `assets_service.py` | owns exact/as-of, approval, exclusion/carry, correction and drift policy decisions |
| read-only | `assets_service.py` preview/report path | preview is no write: no insert, migrate, mkdir, or commit; explicit close is the write boundary |
| redaction | adapters/report serializers | only redacted evidence crosses output boundary; no credential/token/cookie/raw account data |
The owner is the canonical decision or write boundary; consumers render or read its result and do not reimplement policy.
The Dashboard gateway is `jarca_ledger_mcp/adapters/streamlit/overview_gateway.py` (including `get_asset_snapshot_report` and reconciliation/monthly read delegates). It calls shared application read services after `auth-before-DB`; page rendering is not an alternate policy or persistence boundary. A missing DB has stable unavailable semantics (`db_not_initialized`) and no-create behavior. The missing DB stable unavailable contract is no-create. An initialized DB read failure is `db_error`; initialized read has no write, migration, mkdir, or commit. The initialized DB read failure is db_error and initialized read has no write.
Reconciliation ownership remains in `reconciliation_service.py`: opening evidence and transaction coverage are required inputs. Missing opening evidence or incomplete coverage produces `INCOMPLETE_CALCULATION`/`reconciliation unavailable` with provenance, never an inferred balance or fake transaction.
## Issue #15 settlement draft ownership
| Path | Ownership / boundary |
|---|---|
| `jarca_ledger_mcp/application/settlement_draft_service.py` | Shared business validation, frozen selection/review/approval/finalize; owns no UI or transport behavior. |
| `jarca_ledger_mcp/application/monthly_settlement_service.py` | Read-only monthly aggregate; never draft mutation or transaction readiness write. |
| `jarca_ledger_mcp/application/assets_service.py` | Existing close/report authority; draft finalization does not call live-select close as shortcut. |
| `jarca_ledger_mcp/infrastructure/sqlite/migrations.py` | Additive schema 12→13 migration; schema initializer and migration constraints agree. |
| `jarca_ledger_mcp/adapters/mcp/server.py` | Thin same-name/same-signature MCP tools; no duplicate business logic, no new auth claim. |
| `jarca_ledger_mcp/adapters/streamlit/` | Existing Dashboard gateway boundary; auth-before-DB, explicit user actions only. |
| `tests/test_monthly_settlement_drafts.py` | Synthetic DB lifecycle, failure injection, replay and no-write regressions. |
Never document invented `jarca_ledger_mcp.mcp` or `monthly.py` modules. `transaction readiness` is separate from asset completeness and monthly reads remain read-only.