Files
portfolio-hub/docs/batches/bat-010_20260521_v1-portfolios-sub-resources/design.md
T
genichinandClaude Sonnet 4.6 4bf6b554a7 feat: v1 portfolio mutation, sub-resources, ledger path migration (BAT-008~011)
dcy-003/004 기반 v1 API surface 완성 및 BAT-008~011 구현·검증 완료:

- BAT-008 (REQ-019~021,024): 토큰 surface baseline 문서 갱신
- BAT-009 (REQ-025~028): POST/PATCH/DELETE/GET /v1/portfolios CRUD 신설
  - _require_write_token, _get_portfolio_or_404, soft delete, daemon-scoped list
- BAT-010 (REQ-030~032): portfolio tag/comment 서브 라우트 신설 + baseline 갱신
  - GET/POST/DELETE /v1/portfolios/{id}/tags
  - POST/GET/PATCH/DELETE /v1/portfolios/{id}/comments
- BAT-011 (REQ-029): ledger path migration
  - POST /v1/assets/{asset_id}/ledger/trades → /v1/portfolios/{portfolio_id}/ledger/trades
  - v1_ledger.py 제거, disabled 차단(409) 추가
  - test_v1.py / test_daemon_assignment.py 구 path 갱신
- 신규 tests: test_v1_portfolios_crud.py, test_v1_portfolios_list.py,
  test_v1_portfolios_tags_comments.py, test_v1_portfolios_ledger.py
- 전체 suite: 340 passed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 07:25:39 +00:00

3.9 KiB

BAT-010 Design

  • Status: confirmed
  • Batch: BAT-010

Architecture Summary

  • app/api/v1_portfolios.py에 portfolio 서브 리소스 라우트 7개(GET tags, POST/GET/PATCH/DELETE comments)를 추가하고 기존 POST/DELETE tag 라우트에 disabled 보호를 보강한다.
  • 신규 v1 schema 5종(PortfolioTagListResponse, PortfolioCommentItem, PortfolioCommentRequest, PortfolioCommentUpdateRequest, PortfolioCommentListResponse)을 app/schemas/v1.py에 추가한다.
  • docs/ baseline 4종을 v1 portfolio surface에 맞게 갱신한다.

Changed Areas

  • Docs:
    • docs/interface-contract.md — v1 portfolio CRUD + tag/comment 서브 라우트 섹션 추가; ledger path "pending REQ-029" 마킹
    • docs/runtime-flows.md — portfolio mutation flow + GET 토큰 분기 + soft delete flow 추가
    • docs/data-model.md — Portfolio.status='disabled' 의미 + 의존 데이터 보존 정책 추가
    • docs/project-structure.md — app/api/v1_portfolios.py, app/schemas/v1.py 책임 기술 갱신
  • Modules:
    • app/api/v1_portfolios.py — 7개 라우트 추가 + 기존 2개 보강
    • app/schemas/v1.py — 5개 schema 추가
  • Interfaces:
    • GET /v1/portfolios/{portfolio_id}/tags (신설)
    • POST /v1/portfolios/{portfolio_id}/comments (신설)
    • GET /v1/portfolios/{portfolio_id}/comments (신설)
    • PATCH /v1/portfolios/{portfolio_id}/comments/{comment_id} (신설)
    • DELETE /v1/portfolios/{portfolio_id}/comments/{comment_id} (신설)
    • POST /v1/portfolios/{portfolio_id}/tags disabled 보호 보강 (기존 route)
    • DELETE /v1/portfolios/{portfolio_id}/tags/{tag_id} disabled 보호 보강 (기존 route)

Key Decisions

  1. GET tags 응답 schema: PortfolioTagListResponse(tags: list[TagItem], total: int) — 기존 TagItem 재사용. portfolio.tag_ids → repo.get_tags_by_ids(tag_ids) → dict → TagItem list.
  2. Disabled 보호 위치: ownership 검증 직후, mutation 수행 직전. if portfolio.status == "disabled": raise HTTPException(409, "disabled portfolio"). GET은 차단 없음.
  3. Comment 작성자 ownership: portfolio ownership만 적용 (REQ-031 Notes 결정). _get_portfolio_or_404 헬퍼로 일괄 처리. PATCH/DELETE 시 comment 작성자 ID 별도 검증 없음 — portfolio owner이면 모든 comment 수정/삭제 가능.
  4. Comment schema: v1 전용 클래스 신설. PortfolioCommentItem.comment_id = PortfolioComment.id(domain) 매핑.
  5. Comment PATCH/DELETE 404: repo.update_comment / repo.delete_comment가 ValueError("댓글을 찾을 수 없습니다") 발생 시 HTTP 404로 변환.
  6. Auth guard: 기존 tag 라우트는 require_trade_write + token_source != "db" 패턴 유지. 신규 comment 라우트는 require_read + _require_write_token(auth) (write) / inline service·client 차단 (GET) 패턴 적용.
  7. Import 추가: PortfolioComment domain model import (v1_portfolios.py), schema 5종 import.

Edge Cases

  • portfolio.tag_ids = [] → get_tags_by_ids([]) → {} → PortfolioTagListResponse(tags=[], total=0) 정상
  • comment 404: portfolio_id가 존재하지만 comment_id가 해당 portfolio의 comment가 아닌 경우 → repo ValueError → HTTP 404
  • disabled portfolio + GET comment: 허용 (AC-8). disabled portfolio + GET tags: 허용 (별도 제한 없음)
  • _get_portfolio_or_404가 404를 발생시키는 경우(비존재 portfolio): service/client 차단 체크 이전에 발생 가능 → 기존 404 응답이 먼저 반환됨 (AC-11 충족)

Architecture Impact

  • both (project-structure + runtime-flows 갱신)

Reference Doc Update Plan

  • project-structure.md: app/api/v1_portfolios.py에 신규 라우트 기술 추가; app/schemas/v1.py schema 목록 갱신
  • runtime-flows.md: portfolio mutation flow (ownership + disabled 보호), GET /v1/portfolios 토큰 분기 flow, soft delete flow (status='disabled' + dependent data 보존) 추가