Files
portfolio-hub/docs/batches/bat-018_20260625_holdings-cost-basis-endpoint/planning.md
T
genichinandClaude Opus 4.8 d93c0bcaf5 feat(holdings): REQ-043 현재 보유 평단(WAC) read — GET /v1/portfolios/{id}/holdings/cost-basis (BAT-018, PR #14)
dcy-008(confirmed)/REQ-043(Approved)/BAT-018. trex-core dcy-034 FR-7 cold-start seed 의존. AC 11/11, QC PASS. worktree+PR 워크플로 첫 파일럿.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
2026-06-26 00:07:43 +09:00

61 lines
3.4 KiB
Markdown

# BAT-018 Planning
- Status: confirmed
- Batch: BAT-018
- Profile: batch-lite
## Included REQ
- REQ-043 (Interface, Approved) — GET /v1/portfolios/{id}/holdings/cost-basis 현재 보유 평단(WAC) read 엔드포인트 신설.
## Delivery Plan
### 구현 순서
1. **domain 함수 추가** (`app/domain/pnl.py`)
- `calculate_current_wac(rows)` 신규 함수 — 기존 `calculate_realized_pnl`의 running_wac 누적 로직 재사용, 매도 완료 후 잔여 running_wac/running_qty/cost_basis_from/data_completeness_warning 반환.
- 반환 타입: 새 `CurrentWacResult` dataclass (wac, quantity, cost_basis_from, data_completeness_warning).
2. **스키마 추가** (`app/schemas/v1.py`)
- `HoldingsCostBasisResponse` 스키마 신규 추가 (REQ-043 응답 필드 전체 포함).
3. **엔드포인트 추가** (`app/api/v1_portfolios.py`)
- `GET /{portfolio_id}/holdings/cost-basis` 핸들러 — `require_read` 의존성.
- 소유권 분기: service token → `daemon_id == managed_by_daemon_id` 일치 확인(불일치/null → 403). user token → admin 외 비소유자 403.
- `portfolio.asset_quantity`에서 current_quantity 직접 읽기.
- WAC: `get_all_trades_for_pnl` 재사용 → `calculate_current_wac` 호출.
4. **테스트** (`tests/test_v1_portfolios_holdings.py` 신규)
- AC-1~11 커버. MagicMock repo 주입 패턴(기존 test_v1_portfolios_pnl.py 참조).
### 파일 변경 목록
- **신규 생성**:
- `tests/test_v1_portfolios_holdings.py` — AC-1~11 테스트
- `docs/batches/bat-018_20260625_holdings-cost-basis-endpoint/` — batch 문서
- **수정**:
- `app/domain/pnl.py` — `CurrentWacResult` dataclass + `calculate_current_wac` 함수 추가
- `app/schemas/v1.py` — `HoldingsCostBasisResponse` 추가
- `app/api/v1_portfolios.py` — 엔드포인트 추가, import 갱신
- `docs/batches/index.md` — BAT-018 register 행 추가
## Dependencies
- `app/domain/pnl.py`의 `calculate_realized_pnl` running_wac 로직(REQ-041) — 이미 구현됨.
- `app/repositories/portfolio_repository.py`의 `get_all_trades_for_pnl` — 이미 구현됨.
- `require_read` 인증 의존성 — 변경 없음.
- `portfolio.asset_quantity` 컬럼 — 이미 존재.
## Design Gate
- Design Required Before Implementation: **no**
- Reason:
- 기존 `get_realized_pnl` 핸들러(L710)의 직계 변형. HTTP contract·schema·계층 경계 모두 기존 패턴 답습.
- WAC 함수: `calculate_realized_pnl`의 running_wac 추출 — 구조적 신규 설계 없음.
- 소유권 정책: REQ-029 선례(`_require_service_token` + `managed_by_daemon_id` 검사)를 read 엔드포인트에 적용, 분기만 추가.
## Milestones
1. domain 함수(`calculate_current_wac`) + 단위 테스트 작성
2. 스키마(`HoldingsCostBasisResponse`) 추가
3. 엔드포인트(`GET /holdings/cost-basis`) 추가
4. 통합 테스트(`test_v1_portfolios_holdings.py`) AC-1~11 작성
5. `pytest` 전체 실행 — 신규 + 기존 회귀 확인
## Risks
| Risk | 완화 |
| --- | --- |
| R-1 (Low): current_quantity와 WAC 수량 불일치 시 data_completeness_warning 조건 | `portfolio.asset_quantity`는 직접 읽고, WAC는 ledger replay 독립 계산. 불일치 시 warning 트리거 → REQ-043 Notes 항목 준수. |
| R-2 (Low): service token 인증 분기가 기존 user token 패턴과 충돌 | `_get_portfolio_or_404`는 user token 전용 소유권 검사. service token 분기는 핸들러 내 명시적 분기로 별도 처리. |