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,33 @@
|
||||
# BAT-011 Verification
|
||||
|
||||
- Status: verified
|
||||
- Batch: BAT-011
|
||||
|
||||
## Acceptance Mapping
|
||||
- REQ-029:
|
||||
- AC-1 (`test_ledger_trade_new`): 신 path HTTP 201 + `status="new"` + `asset_id=_PORTFOLIO_ID` ✅
|
||||
- AC-2 (`test_ledger_trade_duplicate_same_payload`): 동일 key + 동일 payload → HTTP 200 + `status="duplicate"` ✅
|
||||
- AC-3 (`test_ledger_trade_conflict_different_payload`): 동일 key + 다른 quantity → HTTP 409 ✅
|
||||
- AC-4 (`test_ledger_trade_no_daemon_id`): service token `daemon_id IS NULL` → HTTP 403; `insert_ledger_trade` not called ✅
|
||||
- AC-5 (`test_ledger_trade_portfolio_unassigned`): `portfolio.managed_by_daemon_id IS NULL` → HTTP 403; `insert_ledger_trade` not called ✅
|
||||
- AC-6 (`test_ledger_trade_daemon_mismatch`): `managed_by_daemon_id="other-daemon"` vs `auth.daemon_id=_DAEMON_ID` → HTTP 403; `insert_ledger_trade` not called ✅
|
||||
- AC-7 (`test_ledger_trade_disabled_portfolio`): `status="disabled"` → HTTP 409; `insert_ledger_trade` not called ✅
|
||||
- AC-8 (`test_ledger_trade_portfolio_not_found`): `repo.get.side_effect=Exception` → HTTP 404 ✅
|
||||
- AC-9 (`test_old_ledger_path_returns_404`): `POST /v1/assets/{id}/ledger/trades` → HTTP 404 (라우트 제거) ✅
|
||||
- AC-10 (`test_ledger_trade_no_auth`): Bearer 없음 → HTTP 401 ✅
|
||||
- Regression (`test_daemon_assignment.py` 4건): daemon assignment 인가 3단계 신 path에서 동작 검증 ✅
|
||||
|
||||
## Evidence
|
||||
- Test:
|
||||
- `pytest tests/test_v1_portfolios_ledger.py -v`: **10/10 passed**
|
||||
- `pytest --tb=short -q` (full suite): **340 passed, 0 failed**, 2 warnings (non-blocking DeprecationWarning from anyio)
|
||||
- 이전 suite 대비 +10 tests (330 → 340)
|
||||
- Manual:
|
||||
- 해당 없음 — 자동화 검증으로 충분 (인터페이스 변경, UI 없음)
|
||||
- Logs:
|
||||
- 2 DeprecationWarnings: `anyio._backends._asyncio.py` `HTTP_422_UNPROCESSABLE_ENTITY` → `HTTP_422_UNPROCESSABLE_CONTENT`. 기존 suite에서도 동일 경고 존재. 비차단.
|
||||
|
||||
## Result
|
||||
- Ready for Release: true
|
||||
- Blocking Issues: 없음 (코드 구현 완료, 10/10 AC 검증)
|
||||
- Release Note: trex-basic 동시 배포 전제 — release 단계에서 배포 순서 잠금 필수. 신 path 단일 서빙, 별칭/redirect 없음.
|
||||
Reference in New Issue
Block a user