feat: add portfolio item symbol to v1 responses

This commit is contained in:
2026-05-24 13:09:37 +09:00
parent 3a78e5c138
commit 136ae16885
17 changed files with 655 additions and 11 deletions
@@ -19,7 +19,8 @@
- `permission ∈ {read, trade-write}` → `owner_user_id = auth.user_id` 필터, 본인 portfolio만 반환.
- **`?market=<code>` 필터**: 모든 토큰 타입에서 지원. `<code> = ANY(assets.markets)`인 portfolio만 반환(catalog와 join).
- **`?include_disabled=true` 옵션** (dcy-003 R-2 완화): 기본 응답은 `status='disabled'`인 portfolio 제외. opt-in 시에만 포함.
- 응답 항목 schema: 신규 `PortfolioItem` (`portfolio_id`, `asset_id`, `owner_user_id`, `broker`, `status`, `cash_balance`, ..., `tag_ids`, `managed_by_daemon_id`, ...). `asset_id`는 catalog의 `assets.asset_id`(UUID) 참조.
- 응답 항목 schema: 신규 `PortfolioItem` (`portfolio_id`, `asset_id`, `symbol`, `owner_user_id`, `broker`, `status`, `cash_balance`, ..., `tag_ids`, `managed_by_daemon_id`, ...). `asset_id`는 catalog의 `assets.asset_id`(UUID) 참조.
- `GET /v1/portfolios` 의 각 item은 반드시 `portfolios JOIN assets` 결과를 기반으로 직렬화되어야 한다. 특히 `symbol` 은 linked asset row의 `assets.symbol` 을 그대로 노출해야 하며, 클라이언트 캐시나 후속 catalog lookup으로 복원하는 모델은 정식 응답 계약이 아니다.
- 응답: HTTP 200 + `PortfolioListResponse` (`portfolios: list[PortfolioItem]`, `total: int`).
## Acceptance Criteria
@@ -34,6 +35,7 @@
9. Given client token, When `GET /v1/portfolios`, Then HTTP 403 fail-closed.
10. Given Bearer token 없음, When `GET /v1/portfolios`, Then HTTP 401.
11. Given 응답 portfolio 항목, When `asset_id` 필드 확인, Then `assets.asset_id`(catalog UUID)를 참조한다.
12. Given `GET /v1/portfolios` 응답 item, When `symbol` 필드를 확인, Then 값은 같은 row의 `asset_id`가 가리키는 joined `assets.symbol` 과 일치한다.
## Impacted Area
- Docs:
@@ -57,6 +59,64 @@
## Change Log
### CHG-20260524-02
- Date: 2026-05-24
- Author: Hermes Agent
#### Change Summary
- Status: Approved → Implemented
#### Intent
- BAT-014 verification 완료. GET `/v1/portfolios` 응답이 `portfolios JOIN assets` 결과에서 `symbol` 을 직접 반환함이 코드/테스트/문서로 재검증되었다.
#### Acceptance Criteria Delta
- No change
#### Impacted Area Delta
- No change
#### Delivery Trace Delta
- Batches: BAT-014 (release-candidate); BAT-009 response-contract evidence superseded by BAT-014
- Releases: pending
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: promote-to-implemented
- Follow-up Action: release 단계에서 smoke 확인
### CHG-20260524-01
- Date: 2026-05-24
- Author: Hermes Agent
#### Change Summary
- `GET /v1/portfolios` 응답을 joined asset result 기반으로 명확히 고정하고 `PortfolioItem.symbol` 계약을 추가하기 위해 REQ-028을 augment. 상태를 Implemented → Approved로 되돌림.
#### Intent
- trex-orbit 자동매매 데몬은 `GET /v1/portfolios` 응답만으로 외부 시세 API 호출 대상 symbol을 바로 얻어야 한다. 기존 계약은 `asset_id`만 제공해 클라이언트 측 catalog cache를 강제했으므로, server-side asset join 결과(`assets.symbol`)를 직접 응답에 포함하도록 명시한다.
#### Acceptance Criteria Delta
- Added:
- AC-12: GET 응답 item의 `symbol` 은 joined `assets.symbol` 과 일치해야 함
#### Impacted Area Delta
- Docs: `docs/interface-contract.md` GET `/v1/portfolios` 예시/필드 정의에 `symbol` 및 join 기반 응답 설명 추가 필요 (REQ-032 후속)
- Modules: `app/schemas/v1.py`, `app/api/v1_portfolios.py` (`_portfolio_to_item`), `app/repositories/postgres.py` (`_SELECT_PORTFOLIO` join 결과를 응답까지 전달)
- Tests: `tests/test_v1_portfolios_list.py` 에 list 응답 `symbol` 검증 추가 필요
#### Delivery Trace Delta
- Batches: BAT-009 evidence partially superseded; follow-up BAT-014 예정
- Releases: REL-001 response-contract evidence 일부 재검토 필요
#### Revalidation Impact
- Reverification Needed: yes
- Existing Implementation Invalidated: yes (response schema evidence partial)
- Status Recommendation: revert-to-approved
- Follow-up Action: BAT-014에서 GET `/v1/portfolios` 응답이 asset join 결과를 직접 반환하는지 회귀 검증
#### Validation Plan
- `tests/test_v1_portfolios_list.py` 에서 각 item의 `symbol` 필드 존재와 `asset_id`가 가리키는 joined asset row의 `symbol` 일치 여부를 검증한다.
### CHG-20260521-01
- Date: 2026-05-21
- Author: Justin Ko