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>
2.9 KiB
2.9 KiB
BAT-011 Design
- Status: confirmed
- Batch: BAT-011
Architecture Summary
app/api/v1_portfolios.py에POST /{portfolio_id}/ledger/trades서브 라우트를 추가한다. 기존app/api/v1_ledger.py의 daemon 인가 3단계 + idempotency 로직을 신 path로 이식하고, disabled 차단을 daemon 인가 이전에 삽입한다.- 구 path는 파일 전체 제거(
app/api/v1_ledger.py삭제) +app/main.py에서 include 제거로 처리한다. 별칭/redirect 없음. - trex-basic 동시 배포 순서: trex-basic 사전 빌드 완료 확인 → portfolio-hub 배포 → trex-basic 배포. rollback 시 portfolio-hub + trex-basic 동반 rollback.
Changed Areas
- Docs:
docs/interface-contract.md— REQ-032에서 이미 "pending REQ-029" 마킹됨. 본 batch에서 실제 명세 반영.docs/runtime-flows.md— ledger trade path 이전 흐름 + daemon assignment 3단계 인가 갱신 (REQ-032 기반 기존 흐름 보강).
- Modules:
app/api/v1_portfolios.py— 신 path 라우트 추가app/api/v1_ledger.py— 제거 (구 path 라우트 삭제)app/main.py— 구 ledger 라우터 include 제거app/services/ledger_service.py— disabled 차단 검증 추가 (또는 라우터 계층에서 처리)
- Interfaces:
POST /v1/portfolios/{portfolio_id}/ledger/trades(신설)POST /v1/assets/{asset_id}/ledger/trades(제거 → HTTP 404)
Key Decisions
- 구
v1_ledger.py완전 제거: 라우트만 제거하는 대신 파일 전체를 삭제해 잔재 코드가 남지 않도록 한다.app/main.py에서 해당 라우터 include를 제거. - disabled 차단 위치: 라우터 계층에서
_get_portfolio_or_404직후, daemon 인가 3단계 이전에if portfolio.status == "disabled": raise HTTPException(409)삽입. 서비스 계층 변경 최소화. - 인가 순서: (0) Bearer 없음 → 401, (1) token
daemon_id IS NULL→ 403, (2) portfolio not found → 404, (3)portfolio.status == "disabled"→ 409, (4)portfolio.managed_by_daemon_id IS NULL→ 403, (5)portfolio.managed_by_daemon_id != auth.daemon_id→ 403, (6) idempotency 분기 → 201/200/409. - trex-basic 동시 배포: release plan에 배포 순서 잠금 명시. 한시적 별칭/redirect 없음.
Edge Cases
portfolio_id가 비존재 → HTTP 404 (daemon 인가보다 우선).status='disabled'portfolio → HTTP 409 (daemon 인가 체크 전에 차단하여 daemon 미배정 오류와 구분).- 동일
(portfolio_id, order_id, execution_id)+ 동일 payload 재호출 → HTTP 200 +status="duplicate". - 동일 key + 다른 payload → HTTP 409 (idempotency conflict).
- Bearer token 없음 → HTTP 401.
Architecture Impact
- runtime-flows
Reference Doc Update Plan
- project-structure.md:
v1_ledger.py제거 반영 - runtime-flows.md: ledger path 이전 흐름 + daemon 인가 3단계 + disabled 차단 순서 갱신