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,76 @@
|
||||
# BAT-010 Planning
|
||||
|
||||
- Status: confirmed
|
||||
- Batch: BAT-010
|
||||
- Profile: standard
|
||||
|
||||
## Included REQ
|
||||
- REQ-030: portfolio tag 적용/해제/조회 v1 라우트 (Interface, Medium)
|
||||
- REQ-031: portfolio comment CRUD v1 라우트 (Interface, Medium)
|
||||
- REQ-032: portfolio v1 baseline 문서 갱신 (Documentation, Medium)
|
||||
|
||||
## Delivery Plan
|
||||
|
||||
### 구현 범위 및 순서
|
||||
1. **REQ-030 기존 라우트 보강 + GET 신설**
|
||||
- 기존 `POST /v1/portfolios/{id}/tags`, `DELETE /v1/portfolios/{id}/tags/{tag_id}` 라우트 감사 결과:
|
||||
- ownership 검증 ✓, tag 정책 검증 ✓ (POST만)
|
||||
- disabled portfolio 보호 **누락** → AC-8 충족을 위해 추가 필요
|
||||
- `GET /v1/portfolios/{id}/tags` 신설: `portfolio.tag_ids` → `repo.get_tags_by_ids()` → `PortfolioTagListResponse`
|
||||
- schema 추가: `PortfolioTagListResponse(tags: list[TagItem], total: int)`
|
||||
|
||||
2. **REQ-031 comment CRUD 구현**
|
||||
- 신규 4개 라우트: `POST`, `GET`, `PATCH`, `DELETE /v1/portfolios/{id}/comments[/{comment_id}]`
|
||||
- 기존 repo 메서드 재사용: `create_comment`, `list_comments`, `update_comment`, `delete_comment`
|
||||
- schema 추가 (app/schemas/v1.py): `PortfolioCommentItem`, `PortfolioCommentRequest`, `PortfolioCommentUpdateRequest`, `PortfolioCommentListResponse`
|
||||
- ownership 검증: `_get_portfolio_or_404` 헬퍼 재사용 (BAT-009 패턴)
|
||||
- disabled 보호: POST/PATCH/DELETE → HTTP 409; GET → 허용
|
||||
- comment 작성자 ownership: portfolio ownership만 적용 (REQ-031 Notes 결정)
|
||||
|
||||
3. **테스트 작성**
|
||||
- `tests/test_v1_portfolios_tags_comments.py` 신규
|
||||
- REQ-030 AC-1~11, REQ-031 AC-1~11 커버
|
||||
- BAT-009의 `_with_repo` 패치 패턴 재사용
|
||||
|
||||
4. **REQ-032 baseline 문서 갱신**
|
||||
- `docs/interface-contract.md`: v1 portfolio CRUD 엔드포인트 섹션 추가 (REQ-025~028), GET /v1/portfolios/{id}/tags 엔드포인트 추가, comment CRUD 엔드포인트 추가; POST /v1/assets/{asset_id}/ledger/trades 섹션 "pending REQ-029" 마킹
|
||||
- `docs/runtime-flows.md`: portfolio mutation flow + GET /v1/portfolios 토큰 분기 + soft delete flow 추가
|
||||
- `docs/data-model.md`: Portfolio.status='disabled' 의미 + 의존 데이터 보존 정책 추가
|
||||
- `docs/project-structure.md`: app/api/v1_portfolios.py 책임 갱신 + app/schemas/v1.py schema 목록 갱신
|
||||
|
||||
### 선행 조건
|
||||
- BAT-009 Implemented (REQ-025~028) ✓ — `_get_portfolio_or_404`, `_require_write_token`, `_close_repo` 헬퍼 재사용
|
||||
- BAT-003 release-candidate (REQ-001/003): `portfolios.tag_ids UUID[]`, `repo.append_portfolio_tag_id/remove_portfolio_tag_id/get_tags_by_ids` ✓
|
||||
- BAT-004 release-candidate (REQ-004/005): POST/DELETE /v1/portfolios/{id}/tags 이미 구현 ✓
|
||||
- `app/repositories/portfolio_repository.py`: `create_comment`, `list_comments`, `update_comment`, `delete_comment` 추상 메서드 이미 정의 ✓
|
||||
- `app/domain/models.py`: `PortfolioComment(id, portfolio_id, content, created_at, updated_at)` ✓
|
||||
|
||||
## Dependencies
|
||||
- Internal:
|
||||
- BAT-009(REQ-025~028): `_get_portfolio_or_404`, `_require_write_token` 헬퍼, `PortfolioItem` 스키마 패턴
|
||||
- BAT-003(REQ-001~003): `portfolios.tag_ids`, `repo.get_tags_by_ids`
|
||||
- BAT-004(REQ-005): POST/DELETE tag 라우트 (보강 대상)
|
||||
- External:
|
||||
- 없음
|
||||
|
||||
## Design Gate
|
||||
- Design Required Before Implementation: yes
|
||||
- Reason:
|
||||
- REQ-031 comment 작성자 ownership 정책 확정: portfolio ownership만 적용 (결정 완료)
|
||||
- REQ-030 GET 응답 schema 확정: `PortfolioTagListResponse(tags: list[TagItem], total: int)` (결정 완료)
|
||||
- REQ-032 ledger path 마킹 방식 확정: "pending REQ-029" 주석 처리 (결정 완료)
|
||||
- 모든 설계 gate가 사전 해소됨 → design.md 확정 후 구현 착수 가능
|
||||
|
||||
## Milestones
|
||||
1. planning.md confirmed ✓ (현재 단계)
|
||||
2. design.md confirmed — key decisions 기록
|
||||
3. REQ-030 disabled 보호 보강 + GET 신설 + tests
|
||||
4. REQ-031 comment CRUD 4종 + tests
|
||||
5. REQ-032 baseline docs 4종 갱신
|
||||
6. 전체 테스트 스위트 통과
|
||||
7. verification.md 완성
|
||||
|
||||
## Risks
|
||||
- R-1 (Low): 기존 POST/DELETE tag 라우트에 disabled 보호 추가 시 `test_tags_http_api.py` 회귀 가능 → 기존 테스트가 disabled portfolio를 사용하지 않으면 영향 없음; 확인 후 보강
|
||||
- R-2 (Low): `repo.get_tags_by_ids(portfolio.tag_ids)` — tag_ids가 빈 배열일 경우 빈 dict 반환 → 빈 list 응답으로 정상 처리
|
||||
- R-3 (Low): `update_comment`/`delete_comment` postgres 구현에서 `portfolio_comments` 테이블 존재 여부 확인 필요
|
||||
Reference in New Issue
Block a user