Implement BAT-009 manual asset CRUD and snapshot close

This commit is contained in:
Jarca
2026-07-01 10:55:34 +09:00
parent beddff7661
commit 02380a88ab
24 changed files with 1129 additions and 24 deletions
@@ -0,0 +1,99 @@
# REQ-011 Manual asset CRUD / month-end snapshot write model
- Status: Implemented
- Type: Data
- Priority: High
- Owner: 렛저장인
- Source Discovery: `docs/discovery/dcy-009_20260701_manual-asset-crud-month-end-snapshot-close-workflow.md`
- Batch: BAT-009
- Created At (KST): 2026-07-01 09:00 KST
- Approved At (KST): 2026-07-01 09:02 KST
- Implemented At (KST): 2026-07-01 10:52 KST
## 1. 배경
REQ-009/REQ-010은 `manual_assets`, `asset_snapshots`, 조회성 MCP, 대시보드 정렬까지 구현했지만 쓰기 경로는 의도적으로 제외했다. 현재는 read model과 평가 helper는 존재하지만, 수기 자산을 생성·수정·비활성 처리하거나 특정 기준일 자산 상태를 마감해 `asset_snapshots`에 확정하는 1급 운영 경로가 없다. dcy-009 confirmed Discovery에 따라 write model, 재마감 정책, 이력 보존 규칙을 구현 가능한 데이터/서비스 요구사항으로 고정해야 한다.
## 2. Intent
수기 자산 CRUD와 월말 마감 스냅샷 생성을 임시 수기 절차가 아니라 명시적 저장 계층/서비스 계층 기능으로 정립한다. 이 REQ의 목적은 `manual_assets` write lifecycle, preview 입력 모델, `asset_snapshots` append-only correction 정책, soft delete 원칙, 백업/승인 연계 안전장치를 구현 가능한 데이터 책임으로 고정하는 것이다.
## 3. 범위
### In Scope
- `manual_assets`의 생성/수정/비활성(soft delete) write model을 정의한다.
- 특정 `basis_date` 기준 live authority(`accounts.last_balance` + 활성 `manual_assets`)를 스냅샷 행으로 고정하는 month-end snapshot close write path를 정의한다.
- snapshot preview를 위한 집계/검증 데이터 모델과 warning shape를 정의한다.
- 동일 `basis_date` 재마감 시 `append-only + 정정 행 추가` 정책과 중복/정정 메타데이터 규칙을 정의한다.
- dcy-002 운영 안전장치와 정합한 백업/승인 연계 규칙을 정의한다.
- `docs/data-model.md`와 필요 baseline 문서에 write model 책임을 반영한다.
### Out of Scope
- 외부 시세/부동산 자동 평가 연동.
- 월말 자동 스케줄링/cron 생성.
- read-only MCP 응답 shape 자체의 상세 설계(별도 Interface REQ에서 다룸).
- 투자 조언/리밸런싱/세금/수익률 계산.
## 4. Requirement
### FR-1. Manual asset CRUD write lifecycle
- `manual_assets`는 create/update/deactivate 흐름을 지원해야 한다.
- 생성/수정 시 최소 필드 `name`, `valuation_amount`, `valuation_date`, `liquidity_bucket`, `source_note`를 검증해야 한다.
- 허용 `liquidity_bucket` 값은 `cash`, `investment`, `deposit`, `real_estate`, `loan`, `other`다.
- 삭제 기본 정책은 hard delete가 아니라 비활성/soft delete여야 한다.
- hard delete는 운영 복구가 불필요한 예외 정리 작업에 한해 별도 승인 하에서만 허용되어야 한다.
### FR-2. Snapshot preview data model
- snapshot close 실행 전 preview는 해당 `basis_date`에 스냅샷될 계좌/수기 자산 항목 목록, 평가값, `liquidity_bucket`, source type, 합계, 경고를 계산할 수 있어야 한다.
- preview는 write side effect 없이 동작해야 한다.
- preview는 미평가/제외 항목, stale valuation, 중복 위험을 warning 형태로 드러낼 수 있어야 한다.
### FR-3. Month-end snapshot close write path
- snapshot close는 특정 `basis_date`의 live authority를 항목 단위 `asset_snapshots` 행으로 고정해야 한다.
- close 시 각 행은 `source_type`, `source_id`, `display_name`, `valuation_amount`, `liquidity_bucket`, `basis_date`, close 근거 메모를 보존해야 한다.
- close 결과는 이후 read model이 동일 산식으로 재구성 가능한 형태여야 한다.
### FR-4. Append-only correction policy
- 동일 `basis_date` 재마감 기본 정책은 overwrite가 아니라 `append-only + 정정 행 추가`여야 한다.
- 정정 실행은 기존 마감 행을 지우지 않고 correction 메타데이터(정정 사유, 정정 실행 시각, 정정 대상 basis_date)를 남겨야 한다.
- 정정 실행 전에는 dcy-002 기준 백업/승인 절차를 선행할 수 있어야 한다.
- read side는 최신 유효 마감 집합을 결정할 수 있도록 정정 계보를 추적할 수 있어야 한다.
### FR-5. Valuation/rule consistency
- write path는 REQ-009/REQ-010이 확정한 권위 소스(`accounts.last_balance` + `manual_assets`)와 순자산 산식(자산성 버킷 합계 − `loan`, 미평가 제외)을 그대로 따라야 한다.
- write path가 생성한 snapshot과 read model의 보고 결과는 동일 `basis_date`에서 일치 검증 가능해야 한다.
### FR-6. Baseline documentation alignment
- `docs/data-model.md`는 manual asset write lifecycle, soft delete semantics, correction metadata, snapshot close policy를 반영해야 한다.
- 필요 시 `docs/runtime-flows.md`, `docs/project-structure.md`는 preview → close → corrected-close 흐름과 write/read 책임 경계를 반영해야 한다.
## 5. Acceptance Criteria
- AC-1: 신규/기존 DB 모두에서 manual asset create/update/deactivate에 필요한 필드와 상태가 additive/idempotent하게 저장된다.
- AC-2: snapshot preview가 side effect 없이 항목 목록, bucket totals, total assets, total liabilities, net worth, warnings를 반환할 수 있다.
- AC-3: month-end snapshot close가 특정 `basis_date`의 authority source를 `asset_snapshots`에 항목 단위로 고정 저장한다.
- AC-4: 동일 `basis_date` 재마감은 overwrite 없이 correction append 정책으로 처리되고, 원본/정정 이력이 모두 보존된다.
- AC-5: manual asset soft delete와 snapshot correction이 있어도 REQ-009/REQ-010 read model은 동일 산식으로 일관된 결과를 낸다.
- AC-6: `docs/data-model.md`와 필요 baseline 문서가 본 REQ 범위를 반영한다.
## 6. Impacted Area
- `jarca_ledger_mcp/db.py`
- `jarca_ledger_mcp/service.py`
- `tests/test_asset_snapshots.py`
- 필요 시 `tests/test_service.py`
- `docs/data-model.md`
- 필요 시 `docs/runtime-flows.md`
- 필요 시 `docs/project-structure.md`
## 7. Notes
- 이 REQ는 write model, correction policy, persistence semantics를 다루므로 `Data` 타입으로 관리한다.
- MCP mutation contract와 operator UX는 `REQ-012`에서 다룬다.
- 월말 자동 스케줄링은 Discovery 결정에 따라 후속 범위로 유지한다.
## 8. Change Log
- 2026-07-01 09:00 KST: dcy-009 confirmed 범위를 바탕으로 Proposed 초안을 생성.
- 2026-07-01 09:02 KST: dcy-009 confirmed 결정사항(append-only correction, soft delete 기본, auto scheduling 후속)을 반영해 Approved로 전환.
- 2026-07-01 10:52 KST: BAT-009 구현, full pytest PASS, MCP tool discovery, browser smoke evidence를 근거로 Implemented로 전환.
@@ -0,0 +1,96 @@
# REQ-012 Manual asset CRUD / snapshot close MCP and operator dashboard alignment
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: 렛저장인
- Source Discovery: `docs/discovery/dcy-009_20260701_manual-asset-crud-month-end-snapshot-close-workflow.md`
- Batch: BAT-009
- Created At (KST): 2026-07-01 09:00 KST
- Approved At (KST): 2026-07-01 09:02 KST
- Implemented At (KST): 2026-07-01 10:52 KST
## 1. 배경
BAT-008은 조회성 MCP와 대시보드 read alignment까지 구현했지만, 운영자가 수기 자산을 입력·수정·비활성 처리하거나 월말 snapshot preview/close를 실행할 인터페이스는 남겨 두었다. dcy-009 confirmed Discovery는 mutation MCP와 operator dashboard UX가 동일 source 표기 규칙과 dcy-007 contract envelope를 따르면서 month-end close workflow를 제공해야 한다고 결정했다.
## 2. Intent
수기 자산 CRUD와 month-end snapshot close를 운영자가 실제로 사용할 수 있는 MCP mutation 및 대시보드 인터페이스로 정렬한다. 이 REQ의 목적은 preview/close/operator messaging/source labeling/contract regression 범위를 구현 가능한 인터페이스 요구사항으로 고정하는 것이다.
## 3. 범위
### In Scope
- manual asset create/update/deactivate mutation MCP를 정의한다.
- snapshot preview/close mutation MCP를 정의한다.
- 대시보드에 manual asset 관리와 month-end snapshot preview/close operator UX를 정의한다.
- 모든 관련 응답/화면에 `source`와 `is_closed_snapshot` 표기를 정렬한다.
- dcy-007 response contract/contract regression 범위에 신규 mutation MCP를 포함한다.
- `docs/interface-contract.md`와 필요 baseline 문서를 갱신한다.
### Out of Scope
- 외부 자동 시세 연동 UI/MCP.
- 월말 자동 스케줄링 UI/MCP.
- 투자 조언/리밸런싱 추천 UX.
- production DB 실데이터를 이용한 수동 운영 evidence.
## 4. Requirement
### FR-1. Manual asset mutation MCP
- manual asset create/update/deactivate MCP 도구를 제공해야 한다.
- 응답은 dcy-007 contract envelope와 호환되어야 하며 성공/오류 시 일관된 top-level shape를 유지해야 한다.
- create/update 결과는 최소한 식별자, 현재 상태(active/deactivated), 최근 평가 기준일, `liquidity_bucket`, source note를 돌려줄 수 있어야 한다.
### FR-2. Snapshot preview/close MCP
- 특정 `basis_date`에 대한 snapshot preview MCP를 제공해야 한다.
- preview 응답은 side effect 없이 항목 목록, bucket totals, liabilities, net worth, warnings, `source='live_authority'`, `is_closed_snapshot=false`를 설명할 수 있어야 한다.
- snapshot close MCP는 close 완료 후 close metadata와 `source='snapshot'`, `is_closed_snapshot=true`를 포함한 결과를 반환해야 한다.
- correction close가 발생하면 overwrite가 아니라 correction run임을 응답에서 구분할 수 있어야 한다.
### FR-3. Operator dashboard UX
- 대시보드는 manual asset 추가/수정/비활성 입력 경로를 제공해야 한다.
- 대시보드는 month-end snapshot preview와 close 실행 경로를 제공해야 한다.
- 화면은 현재 값이 live authority 기반 추정인지, 닫힌 snapshot 기반인지 명시적으로 구분해야 한다.
- correction/재마감이 있었으면 운영자가 그 사실을 인지할 수 있는 상태 문구 또는 메타데이터를 노출해야 한다.
### FR-4. Dashboard/read alignment
- mutation 실행 후 대시보드와 read MCP는 동일 authority source와 동일 순자산 산식을 반영해야 한다.
- close 이전 preview와 close 이후 read report는 같은 `basis_date` 기준 동일 집계 규칙을 사용해야 한다.
- 신규 write model이 비어 있거나 미사용 상태여도 기존 REQ-005/REQ-010 경로는 안전 폴백을 유지해야 한다.
### FR-5. Contract regression and documentation alignment
- 신규 mutation MCP는 `tests/test_contract_regression.py` 또는 동등 회귀 검증 범위에서 discovery/shape drift를 검출할 수 있어야 한다.
- `docs/interface-contract.md`는 manual asset CRUD 및 snapshot preview/close의 request/response contract를 반영해야 한다.
- 필요 시 `docs/runtime-flows.md`, `docs/project-structure.md`는 operator workflow와 UI/service/server 책임 경계를 반영해야 한다.
## 5. Acceptance Criteria
- AC-1: manual asset create/update/deactivate MCP가 정의되고 dcy-007 envelope와 정합한 응답을 반환한다.
- AC-2: snapshot preview MCP가 side effect 없이 preview totals/warnings/source flags를 반환한다.
- AC-3: snapshot close MCP가 close metadata와 closed snapshot source flags를 반환하고 correction close를 구분한다.
- AC-4: 대시보드가 manual asset CRUD와 month-end snapshot preview/close operator UX를 제공한다.
- AC-5: 대시보드/read MCP/close 결과가 `source` 및 `is_closed_snapshot` 표기를 일관되게 유지한다.
- AC-6: contract regression과 baseline 문서가 본 REQ 범위를 반영한다.
## 6. Impacted Area
- `jarca_ledger_mcp/server.py`
- `jarca_ledger_mcp/service.py`
- `dashboard/app.py`
- `tests/test_contract_regression.py`
- 필요 시 `tests/test_asset_snapshots.py`
- `docs/interface-contract.md`
- 필요 시 `docs/runtime-flows.md`
- 필요 시 `docs/project-structure.md`
## 7. Notes
- 이 REQ는 MCP mutation contract와 operator-facing dashboard flow를 다루므로 `Interface` 타입으로 관리한다.
- persistence semantics와 correction storage model은 `REQ-011`을 선행 입력으로 사용한다.
- 실제 월말 운영 루틴 세부값(누가 언제 마감하는지)은 구현/운영 evidence 단계에서 수집한다.
## 8. Change Log
- 2026-07-01 09:00 KST: dcy-009 confirmed 범위를 바탕으로 Proposed 초안을 생성.
- 2026-07-01 09:02 KST: dcy-009 confirmed 결정사항(source/is_closed_snapshot 표기, mutation MCP contract 정합)을 반영해 Approved로 전환.
- 2026-07-01 10:52 KST: BAT-009 구현, full pytest PASS, MCP tool discovery, browser smoke evidence를 근거로 Implemented로 전환.
+6 -1
View File
@@ -33,7 +33,7 @@
## Next Requirement ID
- Current: `REQ-011`
- Current: `REQ-013`
- Rule: `Requirement Register`에 있는 가장 큰 REQ 번호보다 정확히 1 커야 한다.
## Requirement Register
@@ -50,6 +50,8 @@
| REQ-008 | CI contract regression and lint required checks | Testing | Implemented | High | 렛저장인 | [req-008_ci-contract-regression-and-lint-required-checks.md](Testing/req-008_ci-contract-regression-and-lint-required-checks.md) |
| REQ-009 | Asset snapshot/manual assets valuation model | Data | Implemented | High | 렛저장인 | [req-009_asset-snapshot-manual-assets-valuation-model.md](Data/req-009_asset-snapshot-manual-assets-valuation-model.md) |
| 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) |
## Recent Change Log Summary
@@ -71,3 +73,6 @@
- 2026-06-30 21:17 KST: dcy-008 confirmed 범위를 `REQ-009`(asset snapshot/manual assets valuation model)과 `REQ-010`(asset snapshot/net worth read MCP and dashboard alignment) Proposed 상태로 생성했다.
- 2026-06-30 21:24 KST: `REQ-009`, `REQ-010`을 승인 게이트 재검토 후 Approved로 전환했다.
- 2026-06-30 22:05 KST: BAT-008 구현·검증 evidence, fresh Streamlit browser smoke, jarcaledgerqc PASS gate를 근거로 `REQ-009`, `REQ-010`을 Implemented로 전환했다.
- 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로 전환했다.