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>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
# 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 보존) 추가
|
||||
Reference in New Issue
Block a user