Files
portfolio-hub/docs/srs/Interface/req-025_v1-portfolios-create.md
T
genichinandClaude Sonnet 4.6 4bf6b554a7 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>
2026-05-21 07:25:39 +00:00

7.1 KiB

REQ-025: POST /v1/portfolios 신설 (토큰 분기 + catalog 검증)

  • Status: Implemented
  • Type: Interface
  • Priority: High
  • Owner: Justin Ko

Intent

  • v1 API에 portfolio 생성 경로(POST /v1/portfolios)를 신설해 user/admin이 HTTP로 본인 또는 타 user의 portfolio를 직접 프로비저닝할 수 있도록 한다.
  • dcy-001 FR-4의 catalog 검증(asset_id active)을 portfolio 생성 시점에 통합 적용해 dcy-001 asset catalog 모델 위에서만 portfolio가 생성되도록 강제한다.

Requirement

  • 신규 라우트 POST /v1/portfolios (Bearer 인증 필수).
  • 토큰 분기 규칙 (dcy-003 OQ-2 + OQ-5 결정, dcy-004 정책과 정합):
    • token_type ∈ {service, client} → HTTP 403 fail-closed (detail="service token cannot create portfolios" 또는 client 대응 메시지). service는 daemon-bound로 portfolio CRUD 주체가 아니며 client는 dcy-004 REQ-016에서 폐지 확정.
    • 그 외(token_type=session 또는 env token):
      • permission='admin' → admin 분기. body user_id non-null이면 해당 user의 portfolio로, null이면 인증 주체의 user_id로 생성.
      • permission ∈ {read, trade-write} → user 분기. 인증 주체의 user_id로 생성. body user_id 지정은 무시 또는 HTTP 422.
  • catalog 검증 (dcy-001 FR-4 통합): asset_id가 assets 테이블에 존재하고 status='active'인지 검증. 미등록/inactive면 dcy-001 FR-4와 일관된 응답 코드로 거부(HTTP 422 또는 403; REQ 단계 확정은 본 REQ 또는 후속 보강).
  • body 스키마 (PortfolioCreateRequest 신규):
    • 필수: asset_id, broker
    • 선택: name, cash_balance, asset_quantity, asset_price, profit_buffer, strategy_name, strategy_params, managed_by_daemon_id, user_id(admin 분기 전용)
  • 응답: HTTP 201 + 생성된 portfolio의 PortfolioItem(portfolio_id, asset_id, owner_user_id, ...).
  • catalog 검증 위치(서비스 계층 공통 진입점 vs v1 라우터 레이어 한정)는 본 REQ 구현 시점에 결정. dcy-003 R-5 트레이드오프 reference 참조.

Acceptance Criteria

  1. Given admin token + body {"asset_id": "<catalog-uuid>", "broker": "kiwoom", "user_id": "<target-user-uuid>"}, When POST /v1/portfolios, Then HTTP 201 + 생성된 portfolio의 owner_user_id == <target-user-uuid> 반환.
  2. Given session/env token with permission ∈ {read, trade-write} + body {"asset_id": ..., "broker": ...}, When POST /v1/portfolios, Then HTTP 201 + owner_user_id == auth.user_id 반환.
  3. Given service token, When POST /v1/portfolios, Then HTTP 403 fail-closed + detail="service token cannot create portfolios".
  4. Given client token(폐지 전 운영 단계), When POST /v1/portfolios, Then HTTP 403 fail-closed.
  5. Given body asset_id가 catalog에 미존재 또는 status='inactive', When POST /v1/portfolios, Then HTTP 422 또는 403로 거부되고 portfolio row가 생성되지 않는다.
  6. Given Bearer token 없음, When POST /v1/portfolios, Then HTTP 401.
  7. Given non-admin token + body user_id 지정, When POST /v1/portfolios, Then user_id는 무시되어 owner_user_id == auth.user_id로 생성되거나 HTTP 422.

Impacted Area

  • Docs:
    • docs/interface-contract.md — POST /v1/portfolios 명세 추가 (REQ-032 baseline 작업)
    • docs/runtime-flows.md — portfolio create flow + catalog 검증 단계 (REQ-032)
  • Modules:
    • app/api/v1_portfolios.py (신규) — POST /v1/portfolios 라우트, 토큰 분기 인증 헬퍼(_require_portfolio_access)
    • app/main.py — v1_portfolios_router include
    • app/schemas/v1.py — PortfolioCreateRequest, PortfolioItem 신규
    • app/services/portfolio_service.py:create_portfolio — catalog 검증 통합(dcy-001 FR-4 정책)
    • app/repositories/portfolio_repository.py, app/repositories/postgres.py — get_asset_by_id(asset_id, only_active=True) 헬퍼(또는 직접 query) 추가
  • Tests:
    • 신규 tests/test_v1_portfolios_crud.py — AC-1~7 검증

Notes

  • 본 REQ는 dcy-003 FR-1(생성) + FR-2(catalog 검증)을 통합. 생성 시점에 catalog 검증이 자연 적용되므로 단일 REQ로 분리.
  • catalog 검증 위치: dcy-003 §5 FR-2 본문에 "REQ 작성 단계에서 결정" 위임. R-5(CLI 회귀) 완화 방안을 참조해 본 REQ 구현 시 결정.
  • 토큰 분기 게이트는 dcy-004 REQ-016 client 폐지 이후 client 분기가 자연 사라지나, 폐지 release 이전·이후 모두 정합하도록 게이트 자체는 유지(env token 침투 방어).
  • daemon이 portfolio를 직접 생성하지 못함(OQ-2). v1 API에서 daemon의 권한은 조회(REQ-028)와 ledger 기록(REQ-029)에 한정.
  • Source: dcy-003 FR-1, FR-2, OQ-2, OQ-5, NFR-1, NFR-3, NFR-4. dcy-001 FR-4 통합.

Change Log

CHG-20260521-01

  • Date: 2026-05-21
  • Author: Justin Ko

Change Summary

  • Status: Approved → Implemented

Intent

  • BAT-009 confirm-batch-verification 완료. tests/test_v1_portfolios_crud.py AC-1~7 전 케이스 pytest 통과 (2026-05-21, 298 PASSED).

Acceptance Criteria Delta

  • No change

Impacted Area Delta

  • No change

Delivery Trace Delta

  • Batches: BAT-009 (release-candidate)
  • Releases: TBD

Revalidation Impact

  • Reverification Needed: no
  • Existing Implementation Invalidated: no
  • Status Recommendation: promote-to-implemented
  • Follow-up Action: 없음

CHG-20260520-02

  • Date: 2026-05-20
  • Author: Justin Ko

Change Summary

  • Status: Proposed → Approved

Intent

  • 승인 게이트 통과: 필수 필드(Status/Type/Priority/Owner/Intent/Requirement/AC/Impacted Area/Change Log) 모두 충족, AC 구체성 확인 완료, blocker 없음

Acceptance Criteria Delta

  • No change

Impacted Area Delta

  • No change

Delivery Trace Delta

  • Batches: none (미정)
  • Releases: none (미정)

Revalidation Impact

  • Reverification Needed: no
  • Existing Implementation Invalidated: no
  • Status Recommendation: promote-to-approved
  • Follow-up Action: batch 계획 편입

CHG-20260520-01

  • Date: 2026-05-20
  • Author: Justin Ko

Change Summary

  • 최초 생성 — dcy-003 confirm-discovery 후 draft-req 실행. dcy-003 FR-1 + FR-2 통합 산출물.

Intent

  • v1 portfolio mutation의 핵심 진입점(생성) + dcy-001 catalog 검증 통합.

Acceptance Criteria Delta

  • Added:
    • AC-1~7 최초 작성

Impacted Area Delta

  • Docs: docs/interface-contract.md, docs/runtime-flows.md (REQ-032에서 처리)
  • Modules: app/api/v1_portfolios.py (신규), app/main.py, app/schemas/v1.py, app/services/portfolio_service.py, app/repositories/* — 최초 지정
  • Tests: tests/test_v1_portfolios_crud.py (신규) — 최초 지정

Delivery Trace Delta

  • Batches: none (미정)
  • Releases: none (미정)

Revalidation Impact

  • Reverification Needed: no
  • Existing Implementation Invalidated: no
  • Status Recommendation: keep-current
  • Follow-up Action: confirm-req 후 batch 계획 편입; dcy-001 REQ-009/011/012 선행 의존성 확인(assets 테이블 + portfolios asset_id FK)

Validation Plan

  • pytest TestClient로 AC-1~7 검증; 토큰 타입별·permission별 시나리오 + catalog hit/miss