- add ledger consolidation migration and remove ledger_trades usage - return portfolio state after v1 ledger trade writes - deprecate legacy buy/sell endpoints with deprecation headers - add BAT-016, DCY-006, and REQ-036~038 documentation - update repository models and tests for unified ledger entries
4.3 KiB
4.3 KiB
BAT-016 Design
- Status: confirmed
- Batch: BAT-016
Architecture Summary
- 신 path(
POST /v1/portfolios/{id}/ledger/trades)를 portfolio 회계의 단일 권위 endpoint로 재정의하고, 두 ledger 테이블을 portfolio_ledger 단일 회계 원장으로 통합한다. ledger write가 portfolio 잔고를 단일 트랜잭션으로 갱신하고 응답에 거래 후 권위 상태를 포함한다. 마이그레이션(DB) + 도메인/repository 통합(app) + endpoint 동작 변경 + 레거시 deprecated 표기의 3 REQ 묶음.
Changed Areas
- Docs:
docs/data-model.md(portfolio_ledger 통합 스키마, ledger_trades entity 제거),docs/interface-contract.md(신 path 회계 동작+응답, 레거시 deprecated),docs/runtime-flows.md(ledger write flow 회계 단계) - Modules:
migrations/versions/(신규 revision),app/repositories/postgres.py(ensure_schema + insert 통합 + FOR UPDATE + ON CONFLICT partial),app/repositories/portfolio_repository.py,app/domain/models.py(LedgerEntry 통합),app/domain/services.py(음수 허용 회계 헬퍼),app/api/v1_portfolios.py(handler),app/schemas/v1.py(응답),app/api/portfolios.py(레거시 deprecated) - Interfaces:
POST /v1/portfolios/{id}/ledger/trades(응답 확장 + 회계),POST /portfolios/{id}/buy·/sell(deprecated 표기)
Key Decisions
- 마이그레이션 전략 (REQ-036): 단일 alembic revision(down_revision=
20260601_0024)에서 컬럼 추가 → backfill → partial UNIQUE index 생성 → 타입 변경 → action 컬럼 제거 → ledger_trades DROP 순. partial UNIQUE는 REQ-017 패턴(CREATE UNIQUE INDEX ... WHERE order_id IS NOT NULL). 타입 변경은ALTER COLUMN ... TYPE NUMERIC(20,8) USING ...::numeric. - order_id/execution_id NULL 허용 (OQ-7 (ii)): broker write만 partial UNIQUE로 idempotency. 레거시/수동 write는 NULL → append-only. ON CONFLICT inference:
ON CONFLICT (portfolio_id, order_id, execution_id) WHERE order_id IS NOT NULL DO NOTHING. - 도메인 모델 통합 (REQ-037 FR-13):
LedgerEntry를 단일 모델로 유지하고 broker 필드(ledger_entry_id, order_id, execution_id, side, executed_at)를 흡수.LedgerTradedataclass 삭제. 기존LedgerEntry(잔고 snapshot 필드)와LedgerTrade(broker 필드)의 합집합. - 회계 헬퍼 분리 (REQ-037 FR-6, R-8): 음수 검증을 제거한 ledger 전용 회계 함수를 추출. 기존
apply_buy/apply_sell(음수 거부)은 레거시 buy/sell 전용으로 보존. 공통 회계 공식(부호/fee/tax)은 가능한 한 공유 함수로 추출해 divergence 방지. - 단일 트랜잭션 + row lock (REQ-037 FR-6/FR-7):
SELECT ... FOR UPDATE로 portfolios row 잠금 → 회계 계산 → portfolio_ledger INSERT(ON CONFLICT) → portfolios UPDATE → COMMIT. duplicate(ON CONFLICT DO NOTHING으로 INSERT 0건)면 portfolios 현재 권위 상태 SELECT로 응답(OQ-4 (b)). - 레거시 deprecated (REQ-038): FastAPI route
deprecated=True+ 응답 헤더Deprecation: true. 동작 무변경. 레거시 write는 portfolio_ledger에 order_id/execution_id NULL append.
Edge Cases
- duplicate 호출(ON CONFLICT DO NOTHING): INSERT가 0건 → status="duplicate" + portfolios 현재 권위 상태 응답. portfolio_ledger row 재생성 없음.
- 음수 잔고: buy로 cash 음수 또는 sell로 quantity 음수 → 거부하지 않고 그대로 기록/응답(OQ-3).
- 레거시 write의 NULL order_id: partial UNIQUE 대상 외 → append-only(같은 buy 두 번 = row 2건).
- action 자유형식 값(예: 'manual'): 마이그레이션 backfill 시 side 매핑 규칙 외 → 개발 워크스페이스 분포 단순(확인 후 처리). prod는 release 이연.
- 도메인 모델 통합 시 광범위 참조(R-1): test_v1_portfolios_ledger / test_v1 / test_daemon_assignment 등 LedgerTrade/LedgerEntry 참조 전수 갱신.
Architecture Impact
- both (data-model + runtime-flows)
Reference Doc Update Plan
- project-structure.md: none (신규 모듈/디렉토리 없음, 기존 모듈 변경에 한정)
- runtime-flows.md: ledger write flow 섹션에 회계 적용(단일 트랜잭션 + FOR UPDATE + portfolio_ledger insert + portfolios UPDATE) + portfolio_ledger 단일 원장 + 레거시 deprecated 명문화
- data-model.md: portfolio_ledger entity에 신규 컬럼/제약/타입 추가 + ledger_trades entity 섹션 제거 (REQ-036 Impacted Area)