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

3.4 KiB

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 분기는 핸들러 내 명시적 분기로 별도 처리.