feat(portfolios): expose ledger investment aggregates
Add reversal-aware grouped manual-ledger aggregates to portfolio list responses and align the single-portfolio return summary with the same semantics.\n\nRefs #23
This commit is contained in:
@@ -328,8 +328,14 @@
|
||||
- Branching by token type:
|
||||
- `service`: returns portfolios where `managed_by_daemon_id = token.daemon_id`; NULL daemon_id → HTTP 403
|
||||
- `user/admin`: returns owner's own portfolios; admin may override with `?user_id=<id>`
|
||||
- Response: HTTP 200 `PortfolioListResponse {"portfolios": [{"portfolio_id": "<uuid>", "asset_id": "<uuid>", "symbol": "<assets.symbol|null>", ...}], "total": <int>}`
|
||||
- Response: HTTP 200 `PortfolioListResponse {"portfolios": [{"portfolio_id": "<uuid>", "asset_id": "<uuid>", "symbol": "<assets.symbol|null>", "net_contributed_capital": <float>, "cumulative_profit_withdrawn": <float>, ...}], "total": <int>}`
|
||||
- Note: list items are serialized from the server-side `portfolios JOIN assets` result; `symbol` must equal the joined `assets.symbol` for each returned `asset_id`.
|
||||
- Ledger aggregate fields:
|
||||
- `net_contributed_capital` (**순투자현금**) = 유효 manual `INVEST` 합계 - 유효 manual `WITHDRAW` 합계.
|
||||
- `cumulative_profit_withdrawn` (**누적 수익 인출액**) = 유효 manual `PROFIT` 합계. 매매상 실현손익 전체가 아니다.
|
||||
- `REVERSAL.target_ledger_entry_id`로 참조된 `INVEST`, `WITHDRAW`, `PROFIT` 원거래는 유효 집계에서 제외하며 `REVERSAL` 자체는 금액 action으로 합산하지 않는다.
|
||||
- 목록에 반환될 portfolio ID 집합만 한 번의 grouped aggregate로 조회한다. 해당 유효 manual ledger가 없는 항목은 두 필드 모두 `0.0`이다.
|
||||
- 이 필드들은 portfolio-hub가 소유한 ledger 집계값이다. 소비자는 ledger event를 재해석하지 않는다.
|
||||
|
||||
### Endpoint: `GET /v1/portfolios/{portfolio_id}/tags`
|
||||
|
||||
|
||||
@@ -141,7 +141,12 @@
|
||||
2. `service` token: `auth.daemon_id is None` → HTTP 403. `repo.list_portfolios(managed_by_daemon_id=auth.daemon_id, ...)`.
|
||||
3. `user`/`admin` token: admin with `?user_id=<id>` → filter by that user; else filter by `auth.user_id`.
|
||||
4. `?include_disabled=false` (default) → `status="enabled"` filter applied. `?include_disabled=true` → no status filter.
|
||||
5. Returns HTTP 200 `PortfolioListResponse`.
|
||||
5. 필터링된 반환 대상 portfolio ID만 `repo.get_return_summaries(ids)`에 전달한다. repository는 한 번의 grouped query로 유효 manual ledger를 집계한다.
|
||||
6. `REVERSAL.target_ledger_entry_id`로 참조된 `INVEST`/`WITHDRAW`/`PROFIT`은 제외한다. `REVERSAL` 자체는 금액 action으로 합산하지 않는다.
|
||||
7. 각 `PortfolioItem`에 순투자현금(`net_contributed_capital`)과 누적 수익 인출액(`cumulative_profit_withdrawn`)을 결합한다. 집계 row가 없으면 두 값은 `0.0`이다.
|
||||
8. Returns HTTP 200 `PortfolioListResponse`.
|
||||
|
||||
단건 `GET /v1/portfolios/{portfolio_id}/returns/summary`도 같은 grouped aggregate 구현을 portfolio ID 하나로 호출하므로 목록과 유효 원장 의미가 일치한다.
|
||||
|
||||
## Flow: `v1 API — Soft Delete and Dependent Data Preservation`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user