chore: restructure SRS for asset catalog and tag model redesign (dcy-001/002, REQ-001~008)
Architecture Redesign (May 19, 2026): - Separate admin-managed asset catalog from user portfolios - Eliminate portfolio as asset definition; clarify portfolio as user position - Introduce new asset_catalog + portfolio structure Discovery Documents: - dcy-001: asset-catalog-and-user-portfolio-model — admin asset management and user portfolio separation - dcy-002: tag-ownership-and-applicability-policy — tag model implementation strategy New Requirements (REQ-001~008): - REQ-001: tags master table introduction (Data, Proposed) - REQ-002: assets.tag_ids UUID[] column addition (Data, Proposed) - REQ-003: portfolios.tag_ids and portfolio_tags removal (Data, Proposed) - REQ-004: tags master HTTP API (Interface, Proposed) - REQ-005: tag apply/remove HTTP API (Interface, Proposed) - REQ-006: portfolio_tags data migration (Migration, Proposed) - REQ-007: pfhub tag CLI commands (Interface, Proposed) - REQ-008: tag model baseline docs update (Documentation, Proposed) Cleanup: - Remove archived SRS documents (REQ-001~029 old structure) - Remove archived batch documentation (BAT-001~010) - Remove archived discovery documents (dcy-001~006 old structure) - Remove archived release documentation (REL-001~006) Data Model Updates: - Add Deployment category to SRS structure - Add Data category for new data model requirements - Update app/cli/core/utils.py for new tag handling Documentation: - Create new SRS index with consolidated requirement structure - Update docs/discovery/index.md with new discovery references - Migrate from requirement-centric to domain-model-centric organization Rationale: - Existing single-portfolio model lacks admin catalog governance - New asset catalog enables central management of tradeable symbols - Tag system supports user-driven asset organization and discovery - Cleaner separation of concerns between admin operations and user trading
This commit is contained in:
@@ -1,124 +0,0 @@
|
||||
# req-004: GET /health 응답 스키마 확장
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Interface
|
||||
- Priority: High
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- trex-basic Consumer-Driven Contract는 GET /health가 status, service, version, checked_at을 반환할 것을 요구한다.
|
||||
- 현재 구현은 `{"status": "ok"}`만 반환하므로 계약 스키마를 충족하도록 응답을 확장한다.
|
||||
|
||||
## Requirement
|
||||
- GET /health 엔드포인트는 status, service(고정값 "portfolio-hub"), version(앱 버전), checked_at(ISO 8601 KST) 필드를 포함한 JSON을 반환해야 한다.
|
||||
- status 허용값은 ok, degraded, failed이며 정상 응답은 ok를 반환해야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given 서비스가 정상 동작 중일 때, When GET /health를 요청하면, Then 응답 JSON에 status, service, version, checked_at 필드가 모두 존재해야 한다.
|
||||
2. Given GET /health 응답을 받을 때, When status 값을 확인하면, Then "ok", "degraded", "failed" 중 하나여야 한다.
|
||||
3. Given GET /health 응답을 받을 때, When checked_at 형식을 검증하면, Then ISO 8601 형식을 만족해야 한다.
|
||||
4. Given GET /health 응답을 받을 때, When service 필드를 확인하면, Then 고정값 "portfolio-hub"여야 한다.
|
||||
5. Given 인증 없이 GET /health를 요청해도, Then 200 응답이 반환되어야 한다(비인증 엔드포인트).
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/interface-contract.md (REQ-011에서 갱신 예정), docs/runtime-flows.md
|
||||
- Modules: app/api/health.py, app/schemas/ (HealthResponse 스키마 추가)
|
||||
- Tests: tests/test_health.py (신규) 또는 tests/test_app.py 확장
|
||||
|
||||
## Notes
|
||||
- degraded 상태를 반환하는 트리거 조건은 이번 반복에서 정의하지 않는다(OQ-2 Answered). 스키마에 허용값으로만 포함한다.
|
||||
- 앱 버전은 pyproject.toml의 version 필드 또는 settings에서 읽어 반환한다. 설계 단계에서 구체적 방법을 확정한다.
|
||||
- Source Discovery: dcy-002 (FR-1)
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260511-01
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Implemented 전환 — BAT-001 re-verified verification passed, confirm-req-implemented 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- BAT-001 verification.md (re-verified, 2026-05-03) AC-1~5 모두 PASS. Blocking Issues 없음. AC2(degraded/failed 경로)는 REQ Notes에서 이번 반복 OOS로 명시 — 릴리스 블로커 아님.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: BAT-001 (release-candidate)
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: implemented
|
||||
- Follow-up Action: draft-release (BAT-001 기반 release 편성 검토)
|
||||
|
||||
#### Validation Plan
|
||||
- BAT-001 verification.md (re-verified) AC-1~5 evidence 연결 확인 완료
|
||||
|
||||
### CHG-20260502-02
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-004 confirm-req 승인 전환 (Status: Proposed → Approved)
|
||||
|
||||
#### Intent
|
||||
- 필수 필드(Status, Type, Priority, Owner, Intent, Requirement, Acceptance Criteria 5개, Impacted Area, Change Log) 모두 충족 확인 후 승인
|
||||
|
||||
#### 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: keep-current
|
||||
- Follow-up Action: suggest-batch-reqs → draft-batch
|
||||
|
||||
### CHG-20260502-01
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-004 최초 생성 (source Discovery: dcy-002 FR-1)
|
||||
|
||||
#### Intent
|
||||
- trex-basic Consumer-Driven Contract의 GET /health 응답 스키마 요구사항을 REQ backlog로 정규화
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- 전체 Acceptance Criteria 신규 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/interface-contract.md (REQ-011 에서 갱신 예정)
|
||||
- Modules:
|
||||
- app/api/health.py
|
||||
- Tests:
|
||||
- tests/test_health.py 신규
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- none (batch 미생성 상태)
|
||||
- Releases:
|
||||
- none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: confirm-req 후 batch 배정
|
||||
@@ -0,0 +1,83 @@
|
||||
# REQ-004: tags 마스터 HTTP API
|
||||
|
||||
- Status: Proposed
|
||||
- Type: Interface
|
||||
- Priority: High
|
||||
- Owner: Justin Ko
|
||||
|
||||
## Intent
|
||||
- tags 마스터 테이블에 대한 HTTP API를 제공하여 태그 생성, 목록 조회, 비활성화 기능을 권한 기반으로 제어한다.
|
||||
- 태그 이름은 저장 전 소문자로 정규화하여 대소문자 변형 중복을 방지한다.
|
||||
- admin 토큰으로 생성된 태그는 is_admin_tag=TRUE로 기록되며, 이는 asset 태그 적용 정책의 핵심 조건이 된다.
|
||||
|
||||
## Requirement
|
||||
- `POST /v1/tags` — 태그 생성; trade-write 이상 권한 필요; name을 str.lower()로 정규화 후 저장; 중복 name(정규화 후) 시 HTTP 409 반환
|
||||
- `GET /v1/tags` — 태그 목록 조회; read 이상 권한 필요; `?is_active=true|false` 필터 지원
|
||||
- `PATCH /v1/tags/{tag_id}/deactivate` — 태그 비활성화; admin 또는 태그 생성자 본인만 가능; 이미 비활성화된 태그에 멱등 처리(재요청 시 200 반환); 존재하지 않는 tag_id는 HTTP 404
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given trade-write 토큰, When `POST /v1/tags {"name": "TestTag"}`, Then HTTP 201, name="testtag"(소문자 정규화)로 저장된다.
|
||||
2. Given admin 토큰, When `POST /v1/tags {"name": "adminTag"}`, Then HTTP 201, is_admin_tag=TRUE인 태그가 생성된다.
|
||||
3. Given non-admin trade-write 토큰, When `POST /v1/tags {"name": "userTag"}`, Then HTTP 201, is_admin_tag=FALSE인 태그가 생성된다.
|
||||
4. Given "testtag" 태그가 이미 존재, When `POST /v1/tags {"name": "TestTag"}` (대소문자 변형), Then HTTP 409 Conflict가 반환된다.
|
||||
5. Given read 토큰, When `GET /v1/tags`, Then HTTP 200과 활성 태그 목록이 반환된다.
|
||||
6. Given read 토큰, When `GET /v1/tags?is_active=false`, Then 비활성 태그만 반환된다.
|
||||
7. Given admin 토큰, When `PATCH /v1/tags/{tag_id}/deactivate` (본인 생성 또는 타인 생성 무관), Then HTTP 200, is_active=FALSE로 설정된다.
|
||||
8. Given 태그 생성자(non-admin) 토큰, When `PATCH /v1/tags/{tag_id}/deactivate` (본인 생성 태그), Then HTTP 200 반환된다.
|
||||
9. Given non-admin 비생성자 토큰, When `PATCH /v1/tags/{tag_id}/deactivate`, Then HTTP 403 Forbidden이 반환된다.
|
||||
10. Given 존재하지 않는 tag_id, When `PATCH /v1/tags/{tag_id}/deactivate`, Then HTTP 404가 반환된다.
|
||||
11. Given 이미 is_active=FALSE인 태그, When `PATCH /v1/tags/{tag_id}/deactivate` 재요청, Then HTTP 200 반환(멱등).
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/interface-contract.md (/v1/tags 엔드포인트 명세 추가)
|
||||
- Modules:
|
||||
- app/api/ — v1_tags.py 라우터 추가 (또는 기존 라우터에 통합)
|
||||
- app/schemas/v1.py — TagItem, TagCreateRequest, TagListResponse 스키마 추가
|
||||
- app/services/ — 태그 생성/조회/비활성화 서비스 로직
|
||||
- app/repositories/portfolio_repository.py — insert_tag, get_tags, deactivate_tag 프로토콜
|
||||
- app/repositories/postgres.py — 태그 CRUD SQL 구현
|
||||
- app/core/auth.py — permission 검증 (기존 require_read, require_trade_write, require_admin 재사용)
|
||||
- Tests: 엔드포인트별 permission 검증, 소문자 정규화, 중복 거부, 비활성화 멱등성
|
||||
|
||||
## Notes
|
||||
- NFR-1 흡수: name 정규화는 서비스/라우터 레이어에서 str.lower() 호출, DB는 TEXT UNIQUE 그대로.
|
||||
- NFR-3 흡수: 권한 미충족 시 HTTP 403은 기존 permission_dependency 패턴 재사용.
|
||||
- `POST /v1/tags` 권한: trade-write 이상이면 일반 사용자도 태그 생성 가능하며 is_admin_tag는 admin 여부에 따라 자동 결정.
|
||||
- `GET /v1/tags` 기본 필터: is_active=true (활성 태그만). ?is_active=false로 비활성 태그 조회 가능.
|
||||
- Source: dcy-002 FR-4(CRUD 부분), NFR-1, NFR-3
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260519-01
|
||||
- Date: 2026-05-19
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- 최초 생성 — dcy-002 confirm-discovery 후 REQ 초안 작성
|
||||
|
||||
#### Intent
|
||||
- dcy-002 FR-4의 tags 마스터 CRUD API를 Interface REQ로 분리
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~11 최초 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/interface-contract.md — /v1/tags 명세 추가
|
||||
- Modules:
|
||||
- app/api/, app/schemas/v1.py, app/services/, app/repositories/ — 최초 지정
|
||||
- Tests:
|
||||
- 최초 지정
|
||||
|
||||
#### 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 계획 편입; REQ-001 선행 의존성 확인
|
||||
@@ -1,215 +0,0 @@
|
||||
# req-005: service-token 발급 시 runtime_id 동시 생성
|
||||
|
||||
- Status: Approved
|
||||
- Type: Interface
|
||||
- Priority: High
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- trex-basic 계열 consumer는 `runtime_id`를 런타임 세대 식별자로 사용하되, asset assignment와 운영 provenance는 stable `daemon_id`를 기준으로 추적해야 한다.
|
||||
- service-token 발급 시 runtime_id를 새로 생성하면서도, 토큰은 기존 daemon registry에 존재하는 `daemon_id`에 바인딩되어 저장되어야 한다.
|
||||
- CLI(`pfhub service-token issue`)와 API 엔드포인트 양쪽에서 발급 결과에 `runtime_id`와 `daemon_id`가 함께 포함되어야 한다.
|
||||
|
||||
## Requirement
|
||||
- pfhub service-token issue CLI 커맨드와 대응 API 엔드포인트(`POST /auth/service-tokens`)는 service-token 발급 시 고유 `runtime_id`를 생성하고, 기존 daemon registry에 존재하는 `daemon_id`에 토큰을 바인딩해 auth_tokens에 함께 저장한 뒤 발급 결과(`token`, `runtime_id`, `daemon_id`)를 반환해야 한다.
|
||||
- 발급 경로는 unknown daemon 자동 생성 또는 upsert를 허용하면 안 되며, binding 대상은 사전에 생성된 daemon registry entry여야 한다.
|
||||
- `runtime_id`는 발급마다 새로 생성되는 런타임 식별자이고, `daemon_id`는 rotate/재기동과 무관하게 유지되는 stable logical identity다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given `pfhub service-token issue <name> --user <username> --daemon-id <daemon_id>` 실행 시, When 발급이 성공하면, Then 출력에 token 문자열, `runtime_id`, `daemon_id`가 모두 포함되어야 한다.
|
||||
2. Given API 엔드포인트(`POST /auth/service-tokens`)로 existing `daemon_id`를 지정해 service-token 발급 시, When 성공 응답을 받으면, Then 응답 JSON에 token, `runtime_id`, `daemon_id`가 포함되어야 한다.
|
||||
3. Given `runtime_id`와 `daemon_id`가 발급된 service-token으로 `GET /v1/user_info`를 호출하면, Then 응답의 `runtime_id`, `daemon_id`가 발급 시 저장된 값과 동일해야 한다.
|
||||
4. Given 동일 daemon에 대해 두 번의 service-token 발급을 수행하면, Then 각각 다른 `runtime_id`가 반환되어야 하고 `daemon_id`는 요청한 binding 값을 유지해야 한다.
|
||||
5. Given auth_tokens 테이블을 직접 조회하면, Then 발급된 service-token 행에 `runtime_id`와 `daemon_id` 값이 모두 저장되어 있어야 한다.
|
||||
6. Given 존재하지 않는 `daemon_id`로 service-token 발급을 요청하면, Then 명시적 validation 오류가 반환되어야 하고 auth_tokens 행은 생성되지 않아야 한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/runtime-flows.md, docs/interface-contract.md (REQ-011에서 갱신 예정), README.md token provenance 절차 (REQ-021에서 갱신 예정)
|
||||
- Modules: app/cli/commands/service_tokens.py, app/schemas/auth.py, app/api/auth_routes.py, app/domain/models.py, app/services/auth_service.py, app/repositories/portfolio_repository.py, app/repositories/postgres.py
|
||||
- Tests: tests/test_auth.py, tests/test_cli.py, tests/test_v1.py
|
||||
|
||||
## Notes
|
||||
- runtime_id 포맷은 UUID v4를 권장한다. 설계 단계에서 확정한다.
|
||||
- auth_tokens 테이블의 `runtime_id`, `daemon_id` 컬럼 및 daemon registry 스키마는 REQ-009 migration에서 처리한다.
|
||||
- daemon provisioning(create/update)은 별도 관리 경로에서 수행하며, issue 경로는 binding만 담당한다.
|
||||
- 기존 daemon-less service-token은 transition 구간에서 `daemon_id = NULL`로 남을 수 있고, daemon-scoped API에서는 fail-closed로 처리한다.
|
||||
- Source Discovery: dcy-002 (FR-2, A-2), dcy-006 (FR-1, FR-5, NFR-1)
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260513-01
|
||||
- Date: 2026-05-13
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- runtime_id-only service-token 발급 요구사항을 existing daemon binding + `daemon_id` diagnostics 포함 구조로 확장하고, 기존 Implemented 상태를 Approved로 되돌림
|
||||
|
||||
#### Intent
|
||||
- dcy-006에서 `runtime_id`는 runtime identity, `daemon_id`는 stable logical identity로 역할이 분리됐다. 현재 BAT-001/REL-001 구현은 runtime_id만 저장·노출하므로 revised issuance contract와 daemon-scoped authorization 전제를 충족하지 못한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-6: unknown `daemon_id` 발급 요청 거부
|
||||
- Updated:
|
||||
- AC-1~5: CLI/API issue, `/v1/user_info`, DB persistence 기준을 `daemon_id` binding 포함으로 재정의
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- `docs/runtime-flows.md`, `docs/interface-contract.md` — issue flow와 response contract에 `daemon_id` 추가 필요
|
||||
- `README.md` — daemon-aware provenance 절차 반영 필요
|
||||
- Modules:
|
||||
- `app/cli/commands/service_tokens.py`, `app/schemas/auth.py`, `app/api/auth_routes.py`, `app/services/auth_service.py`, `app/repositories/portfolio_repository.py`, `app/repositories/postgres.py`
|
||||
- Tests:
|
||||
- `tests/test_auth.py`, `tests/test_cli.py`, `tests/test_v1.py`
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-001 (release-candidate; REL-001 released input) — runtime_id-only issuance evidence는 daemon binding 요구사항 기준으로 재설계 및 재검증 필요
|
||||
- Releases:
|
||||
- REL-001 (released) — service-token issuance release evidence가 revised REQ를 충족하지 않으므로 후속 app-service release가 필요
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: yes
|
||||
- Existing Implementation Invalidated: yes
|
||||
- Status Recommendation: rollback-to-approved
|
||||
- Follow-up Action: dcy-006 후속 batch에서 daemon registry binding, issue API/CLI contract, `/v1/user_info` diagnostics를 함께 구현하고 재검증한다.
|
||||
|
||||
#### Validation Plan
|
||||
- dcy-006 FR-1/FR-5와 `app/services/auth_service.py`, `app/api/auth_routes.py`, `app/cli/commands/service_tokens.py`의 현재 구현 차이를 코드 리뷰로 대조한다.
|
||||
- 구현 후 `tests/test_auth.py`, `tests/test_cli.py`, `tests/test_v1.py`에 daemon-bound issuance/user_info 케이스를 추가해 targeted validation을 수행한다.
|
||||
|
||||
### CHG-20260511-02
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-005 AC-2의 API 경로를 실제 구현 경로인 `POST /auth/service-tokens`로 명확화
|
||||
|
||||
#### Intent
|
||||
- CONFLICT-4 분석 결과를 반영해 "POST /auth/tokens 또는 동등 경로"라는 모호한 표현을 제거하고, BAT-001 verification과 runtime flow에 이미 반영된 실제 엔드포인트로 REQ를 정렬한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- none
|
||||
- Updated:
|
||||
- AC-2: API 발급 경로를 `POST /auth/service-tokens`로 구체화
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- `docs/srs/Interface/req-005_service-token-runtime-id-issuance.md`: AC-2 경로 문구 명확화
|
||||
- Modules:
|
||||
- none
|
||||
- Tests:
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-001 (release-candidate) — verification evidence는 이미 `POST /auth/service-tokens` 기준으로 정렬되어 있어 추가 재검증은 불필요
|
||||
- Releases:
|
||||
- REL-001 (draft) — release scope 문서도 동일 경로를 사용 중이라 추가 수정 없음
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: none
|
||||
|
||||
#### Validation Plan
|
||||
- REQ-005 AC-2, BAT-001 verification evidence, runtime-flows.md의 API 경로가 모두 `POST /auth/service-tokens`로 일치하는지 코드 리뷰로 확인
|
||||
|
||||
### CHG-20260511-01
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Implemented 전환 — BAT-001 re-verified verification passed, confirm-req-implemented 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- BAT-001 verification.md (re-verified, 2026-05-03) AC-1~5 모두 PASS. Blocking Issues 없음. AC5 DB 미확인은 REQ-009와 동일 제약으로 non-blocker 처리.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: BAT-001 (release-candidate)
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: implemented
|
||||
- Follow-up Action: draft-release (BAT-001)
|
||||
|
||||
#### Validation Plan
|
||||
- BAT-001 verification.md (re-verified) AC-1~5 evidence 연결 확인 완료
|
||||
|
||||
### CHG-20260502-02
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-005 confirm-req 승인 전환 (Status: Proposed → Approved)
|
||||
|
||||
#### Intent
|
||||
- 필수 필드(Status, Type, Priority, Owner, Intent, Requirement, Acceptance Criteria 5개, Impacted Area, Change Log) 모두 충족 확인 후 승인
|
||||
|
||||
#### 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: keep-current
|
||||
- Follow-up Action: suggest-batch-reqs → draft-batch
|
||||
|
||||
### CHG-20260502-01
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-005 최초 생성 (source Discovery: dcy-002 FR-2)
|
||||
|
||||
#### Intent
|
||||
- service-token 발급 시 runtime_id 동시 생성 요구사항을 REQ backlog로 정규화
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- 전체 Acceptance Criteria 신규 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/runtime-flows.md (REQ-011에서 갱신 예정)
|
||||
- Modules:
|
||||
- app/cli/commands/service_tokens.py
|
||||
- app/api/auth_routes.py
|
||||
- app/domain/models.py
|
||||
- Tests:
|
||||
- tests/test_auth.py 확장 또는 tests/test_service_tokens.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 배정. REQ-009 migration과 함께 delivery 단위 구성 권장.
|
||||
@@ -0,0 +1,83 @@
|
||||
# REQ-005: 태그 적용·해제 HTTP API
|
||||
|
||||
- Status: Proposed
|
||||
- Type: Interface
|
||||
- Priority: High
|
||||
- Owner: Justin Ko
|
||||
|
||||
## Intent
|
||||
- asset(portfolios)과 portfolio에 태그를 적용하고 해제하는 HTTP API를 제공하며, asset에는 admin 생성 태그만, portfolio에는 admin 또는 소유자 생성 태그만 적용 가능하도록 정책을 적용한다.
|
||||
- 정책 위반 시 HTTP 403을 반환하여 명확한 오류 피드백을 제공한다.
|
||||
- 존재하지 않는 tag_id 적용 시도는 HTTP 404로 처리한다.
|
||||
|
||||
## Requirement
|
||||
- `POST /v1/assets/{asset_id}/tags {"tag_id": "..."}` — asset에 태그 적용; admin 권한 필요; 적용 조건: tags.is_admin_tag=TRUE AND tags.is_active=TRUE; 조건 불만족 시 HTTP 403; 존재하지 않는 tag_id 시 HTTP 404
|
||||
- `DELETE /v1/assets/{asset_id}/tags/{tag_id}` — asset에서 태그 해제; admin 권한 필요
|
||||
- `POST /v1/portfolios/{portfolio_id}/tags {"tag_id": "..."}` — portfolio에 태그 적용; trade-write 이상 권한 필요; 적용 조건: tags.is_active=TRUE AND (tags.is_admin_tag=TRUE OR tags.created_by_user_id = portfolio 소유자); 조건 불만족 시 HTTP 403; 존재하지 않는 tag_id 시 HTTP 404
|
||||
- `DELETE /v1/portfolios/{portfolio_id}/tags/{tag_id}` — portfolio에서 태그 해제; trade-write 이상, 소유자 본인 또는 admin
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given admin 토큰, admin이 생성한 활성 tag_id, When `POST /v1/assets/{asset_id}/tags`, Then HTTP 200, 해당 tag_id가 asset의 tag_ids 배열에 추가된다.
|
||||
2. Given admin 토큰, is_admin_tag=FALSE인 tag_id, When `POST /v1/assets/{asset_id}/tags`, Then HTTP 403 Forbidden이 반환된다.
|
||||
3. Given admin 토큰, is_active=FALSE인 tag_id, When `POST /v1/assets/{asset_id}/tags`, Then HTTP 403 Forbidden이 반환된다.
|
||||
4. Given non-admin 토큰, When `POST /v1/assets/{asset_id}/tags`, Then HTTP 403 Forbidden이 반환된다.
|
||||
5. Given admin 토큰, When `DELETE /v1/assets/{asset_id}/tags/{tag_id}`, Then HTTP 200, tag_id가 asset의 tag_ids 배열에서 제거된다.
|
||||
6. Given trade-write 토큰(portfolio 소유자), 소유자 본인이 생성한 tag_id (is_admin_tag=FALSE, is_active=TRUE), When `POST /v1/portfolios/{portfolio_id}/tags`, Then HTTP 200, 태그가 portfolio의 tag_ids에 추가된다.
|
||||
7. Given trade-write 토큰(portfolio 소유자), admin이 생성한 활성 tag_id, When `POST /v1/portfolios/{portfolio_id}/tags`, Then HTTP 200, 태그가 추가된다.
|
||||
8. Given trade-write 토큰(user A, 소유자), 다른 user B가 생성한 non-admin tag_id, When `POST /v1/portfolios/{portfolio_id}/tags`, Then HTTP 403 Forbidden이 반환된다.
|
||||
9. Given 소유자 또는 admin 토큰, When `DELETE /v1/portfolios/{portfolio_id}/tags/{tag_id}`, Then HTTP 200, tag_id가 portfolio의 tag_ids에서 제거된다.
|
||||
10. Given 유효한 권한, 존재하지 않는 tag_id, When 적용 요청, Then HTTP 404 Not Found가 반환된다.
|
||||
11. Given 존재하지 않는 asset_id 또는 portfolio_id, When 태그 적용 요청, Then HTTP 404가 반환된다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/interface-contract.md (/v1/assets/{id}/tags, /v1/portfolios/{id}/tags 엔드포인트 명세 추가)
|
||||
- Modules:
|
||||
- app/api/v1_assets.py — POST/DELETE /v1/assets/{asset_id}/tags 라우트 추가
|
||||
- app/api/portfolios.py — POST/DELETE /v1/portfolios/{portfolio_id}/tags 라우트 추가 (또는 별도 파일)
|
||||
- app/schemas/v1.py — TagApplyRequest 스키마 추가
|
||||
- app/services/ — 태그 적용/해제 서비스 로직, 정책 검증
|
||||
- app/repositories/postgres.py — tag_ids 배열 append/remove SQL (array_append, array_remove 또는 동등)
|
||||
- Tests: 정책 위반 시 403, 존재하지 않는 tag_id 시 404, admin/non-admin 구분 검증
|
||||
|
||||
## Notes
|
||||
- NFR-3 흡수: 정책 위반 시 HTTP 403은 이 REQ의 핵심 동작.
|
||||
- REQ-001(tags 테이블), REQ-002(assets.tag_ids), REQ-003(portfolios.tag_ids)이 선행되어야 한다.
|
||||
- asset에 태그 적용 권한이 admin 전용인 이유: assets는 admin 관리 카탈로그이며 asset 태그에는 is_admin_tag=TRUE만 허용 (dcy-002 FR-2).
|
||||
- portfolio 소유자 확인: portfolios.owner_user_id = auth_context.user_id 비교.
|
||||
- Source: dcy-002 FR-2, FR-3, FR-4(apply/remove 부분), NFR-3
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260519-01
|
||||
- Date: 2026-05-19
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- 최초 생성 — dcy-002 confirm-discovery 후 REQ 초안 작성
|
||||
|
||||
#### Intent
|
||||
- dcy-002 FR-4의 태그 적용·해제 엔드포인트와 FR-2/FR-3의 정책 검증을 Interface REQ로 분리
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~11 최초 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/interface-contract.md — apply/remove 엔드포인트 추가
|
||||
- Modules:
|
||||
- app/api/v1_assets.py, app/api/portfolios.py, app/schemas/v1.py, app/services/, app/repositories/postgres.py — 최초 지정
|
||||
- Tests:
|
||||
- 최초 지정
|
||||
|
||||
#### 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 계획 편입; REQ-001, REQ-002, REQ-003 선행 의존성 확인
|
||||
@@ -1,260 +0,0 @@
|
||||
# req-006: GET /v1/assets 엔드포인트 구현
|
||||
|
||||
- Status: Approved
|
||||
- Type: Interface
|
||||
- Priority: High
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- trex-basic 데몬이 자신에게 배정된 자산 목록과 전략 파라미터만 조회할 수 있도록 portfolio 데이터를 daemon-scoped asset 뷰로 제공한다.
|
||||
- 동일 owner user 아래 여러 daemon이 존재해도, 다른 daemon에 배정된 asset은 응답에 섞이면 안 된다.
|
||||
|
||||
## Requirement
|
||||
- GET /v1/assets는 service-token bearer 인증으로 토큰 소유 user 범위 안에서, 인증된 token의 `daemon_id`에 배정된 portfolio 목록만 `asset_id`, `symbol`, `market`, `status`, `cash`, `quantity`, `broker_type`, `strategy_id`, `strategy_type`, `strategy_params`, `updated_at` 필드로 반환해야 한다. 다른 사용자 소유 portfolio와 다른 daemon에 배정된 portfolio는 응답에 포함되면 안 된다.
|
||||
- `status=active` 쿼리 파라미터는 daemon-scoped 결과 집합 위에서 필터링되어야 한다.
|
||||
- strategy_params는 해당 portfolio의 active_strategy_id로 조회한 StrategySet.config에서 파생한다. strategy_id는 허용값 검증 없이 그대로 반환한다(OQ-1 Answered).
|
||||
- strategy_type은 해당 portfolio의 active_strategy_id로 조회한 StrategySet.name을 반환한다. active_strategy_id가 없거나 StrategySet 조회 실패 시 null을 반환한다.
|
||||
- `daemon_id`가 없는 legacy service-token은 transition 구간 동안 `GET /v1/assets`에서 fail-closed(`403 Forbidden`)로 처리되어야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given 유효한 daemon-bound service-token bearer 인증으로 `GET /v1/assets` 요청 시, When 토큰이 유효하면, Then HTTP 200과 해당 daemon에 배정된 portfolio 목록만 반환되어야 하며 다른 사용자 소유 portfolio나 다른 daemon에 배정된 portfolio는 포함되면 안 된다.
|
||||
2. Given `GET /v1/assets?status=active` 요청 시, Then status가 active인 항목만 daemon-scoped 결과 안에서 반환되어야 한다.
|
||||
3. Given 응답의 각 항목을 확인하면, Then asset_id, symbol, market, status, cash, quantity, broker_type, strategy_id, strategy_type, strategy_params, updated_at 필드가 모두 포함되어야 한다.
|
||||
4. Given portfolio에 연결된 StrategySet이 있을 때, When strategy_params를 확인하면, Then StrategySet.config 값에서 파생된 JSON 객체여야 한다.
|
||||
5. Given StrategySet config가 없거나 파싱 실패 시, Then strategy_params는 빈 객체({})를 반환하고 에러가 전파되지 않아야 한다.
|
||||
6. Given portfolios.market이 NULL인 경우, Then 응답의 market 필드도 null로 반환되어야 한다(DECIDE_MARKET_DEFAULT Answered).
|
||||
7. Given 인증 없이 GET /v1/assets 요청 시, Then HTTP 401이 반환되어야 한다.
|
||||
8. Given portfolio에 active_strategy_id로 연결된 StrategySet이 있을 때, Then strategy_type은 해당 StrategySet.name 값을 반환해야 한다.
|
||||
9. Given portfolio에 active_strategy_id가 없거나 StrategySet 조회 실패 시, Then strategy_type은 null을 반환해야 한다.
|
||||
10. Given `daemon_id`가 없는 legacy service-token으로 `GET /v1/assets` 요청 시, Then HTTP 403이 반환되어야 하고 daemon-scoped asset 목록은 비노출이어야 한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/interface-contract.md (REQ-011에서 갱신 예정), docs/project-structure.md (신규 라우터 파일 반영 필요)
|
||||
- Modules: app/api/v1_assets.py, app/schemas/v1.py, app/repositories/portfolio_repository.py, app/repositories/postgres.py, app/core/auth.py, app/main.py
|
||||
- Tests: tests/test_v1.py, tests/test_portfolio_ownership.py 또는 신규 daemon assignment 회귀 테스트
|
||||
|
||||
## Notes
|
||||
- broker_type은 portfolios.broker 컬럼을 그대로 매핑한다(m-2 finding 반영).
|
||||
- strategy_id는 portfolios.active_strategy_id를 그대로 반환한다.
|
||||
- `GET /v1/assets`의 최종 authorization 스코프는 service-token 소유자 범위 위에 `managed_by_daemon_id = auth.daemon_id` 조건을 추가한 daemon scope다.
|
||||
- exact-one asset assignment는 `portfolios.managed_by_daemon_id`를 통해 표현되며 스키마 제약은 REQ-009 change-req에서 다룬다.
|
||||
- Source Discovery: dcy-002 (FR-3, A-3, OQ-1), dcy-006 (FR-2, FR-3, NFR-2)
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260513-01
|
||||
- Date: 2026-05-13
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- owner-user scope 기반 `/v1/assets` 요구사항을 daemon-scoped asset visibility와 fail-closed legacy token 규칙으로 갱신하고, Implemented 상태를 Approved로 되돌림
|
||||
|
||||
#### Intent
|
||||
- dcy-006에서 각 asset은 정확히 1개 daemon에 배정되고, `GET /v1/assets`는 owner user 전체가 아니라 인증 daemon 범위만 반환해야 한다. 현재 구현은 `owner_user_id=auth.user_id`만 사용하므로 revised authorization model과 맞지 않는다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-10: daemon-less legacy token fail-closed(403)
|
||||
- Updated:
|
||||
- AC-1, AC-2: owner scope를 daemon scope 기준으로 재정의
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- `docs/interface-contract.md`, `docs/runtime-flows.md` — daemon-scoped asset list contract 반영 필요
|
||||
- Modules:
|
||||
- `app/api/v1_assets.py`, `app/schemas/v1.py`, `app/repositories/portfolio_repository.py`, `app/repositories/postgres.py`, `app/core/auth.py`
|
||||
- Tests:
|
||||
- `tests/test_v1.py`, daemon assignment 관련 신규 회귀 테스트
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-001 (release-candidate; REL-001 released input) — owner-user scope verification evidence는 daemon-scoped visibility 기준으로 전면 재검증 필요
|
||||
- Releases:
|
||||
- REL-001 (released) — released contract는 owner-user scope 기준이라 revised REQ와 불일치
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: yes
|
||||
- Existing Implementation Invalidated: yes
|
||||
- Status Recommendation: rollback-to-approved
|
||||
- Follow-up Action: dcy-006 후속 batch에서 daemon assignment query, 403 fail-closed path, daemon-scoped regression test를 구현한다.
|
||||
|
||||
#### Validation Plan
|
||||
- `app/api/v1_assets.py`가 현재 `owner_user_id=auth.user_id`만 적용하는지 확인하고, daemon-aware query 설계를 REQ-009와 함께 정리한다.
|
||||
- 구현 후 daemon A/B 분리 시나리오와 daemon-less token 403 시나리오를 targeted pytest로 검증한다.
|
||||
|
||||
### CHG-20260511-02
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- owner scope 회귀 수정 반영 — GET /v1/assets는 service-token 소유자의 portfolio만 반환함을 REQ와 verification evidence에 명시
|
||||
|
||||
#### Intent
|
||||
- CONFLICT-1 분석 결과와 2026-05-11 사용자 결정에 따라 trex-basic은 전체 사용자의 portfolio를 조회하면 안 되며, 서비스 토큰 소유자 범위로만 조회되어야 한다는 설계를 REQ 본문과 검증 기준에 명확히 남긴다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- none
|
||||
- Updated:
|
||||
- AC1: 반환 범위를 "해당 사용자 소유 portfolio 목록만"으로 명확화하고, 다른 사용자 소유 portfolio 비포함 조건을 추가
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/batches/bat-001_20260502_trex-basic-v1-api-contract/verification.md: REQ-006 AC1 evidence를 owner scope 기준으로 재정렬
|
||||
- Modules:
|
||||
- app/api/v1_assets.py: `owner_user_id=auth.user_id` 적용으로 owner scope 강제
|
||||
- Tests:
|
||||
- tests/test_v1.py: `test_v1_assets_returns_asset_list`에 `owner_user_id="user-1"` 전달 assert 추가
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-001 (release-candidate) — REQ-006 targeted re-verification 필요 및 evidence 갱신
|
||||
- Releases:
|
||||
- REL-001 (draft) — release 입력 전 owner scope 기준 반영 여부 재확인 필요
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: yes
|
||||
- Existing Implementation Invalidated: yes
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: owner scope 수정 코드와 targeted pytest 재실행 결과를 BAT-001 verification에 반영하고 Implemented 상태 유지
|
||||
|
||||
#### Validation Plan
|
||||
- `app/api/v1_assets.py`에서 `owner_user_id=auth.user_id` 적용 여부 확인
|
||||
- `tests/test_v1.py -k 'v1_assets'` 재실행으로 GET /v1/assets 회귀 테스트 PASS 확인
|
||||
- BAT-001 verification.md의 REQ-006 AC1 evidence를 최신 테스트와 맞춤
|
||||
|
||||
### CHG-20260511-01
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Implemented 전환 — BAT-001 re-verified verification passed, confirm-req-implemented 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- BAT-001 verification.md (re-verified, 2026-05-03, CHG-20260503-01 strategy_type 재검증 포함) AC-1~9 모두 PASS. Blocking Issues 없음.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: BAT-001 (release-candidate)
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: implemented
|
||||
- Follow-up Action: draft-release (BAT-001)
|
||||
|
||||
#### Validation Plan
|
||||
- BAT-001 verification.md (re-verified) AC-1~9 evidence 연결 확인 완료 (strategy_type 필드 재검증 포함)
|
||||
|
||||
### CHG-20260503-01
|
||||
- Date: 2026-05-03
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- GET /v1/assets 응답 필드에 `strategy_type` 추가 — StrategySet.name 값을 반환
|
||||
|
||||
#### Intent
|
||||
- trex-basic 데몬이 asset 뷰에서 전략 이름(StrategySet.name)을 직접 확인할 수 있도록 `strategy_type` 필드를 응답에 추가한다.
|
||||
- DB 변경 없이 기존 StrategySet.name 컬럼을 활용하는 순수 응답 스키마 확장이다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-8: Given portfolio에 active_strategy_id로 연결된 StrategySet이 있을 때, Then strategy_type은 StrategySet.name 값을 반환해야 한다.
|
||||
- AC-9: Given portfolio에 active_strategy_id가 없거나 StrategySet 조회 실패 시, Then strategy_type은 null을 반환해야 한다.
|
||||
- Modified:
|
||||
- AC-3: `strategy_type` 필드를 필수 응답 필드 목록에 추가
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Modules:
|
||||
- app/schemas/v1.py: AssetItem에 strategy_type 필드 추가
|
||||
- app/api/v1_assets.py: strategy_type 매핑 로직 추가 (StrategySet.name 조회)
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-001 (release-candidate) — REQ-006 포함, strategy_type 추가로 재검증 필요
|
||||
- Releases:
|
||||
- 없음 (아직 draft-release 미수행)
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: yes
|
||||
- Existing Implementation Invalidated: yes (BAT-001 verification은 strategy_type 없이 수행됨)
|
||||
- Status Recommendation: keep-current (Approved 유지 — 구현 전 단계이므로 상태 되돌림 불필요)
|
||||
- Follow-up Action: 구현 후 BAT-001 verification 재수행 또는 BAT-006 신규 생성 결정 필요
|
||||
|
||||
#### Validation Plan
|
||||
- app/schemas/v1.py AssetItem에 strategy_type 필드 추가
|
||||
- app/api/v1_assets.py에서 portfolio.active_strategy_id로 StrategySet.name 조회 후 매핑
|
||||
- tests/test_v1_assets.py 또는 test_app.py에서 strategy_type 필드 존재 및 null 케이스 검증
|
||||
|
||||
### CHG-20260502-02
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-006 confirm-req 승인 전환 (Status: Proposed → Approved)
|
||||
|
||||
#### Intent
|
||||
- 필수 필드(Status, Type, Priority, Owner, Intent, Requirement, Acceptance Criteria 7개, Impacted Area, Change Log) 모두 충족 확인 후 승인
|
||||
|
||||
#### 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: keep-current
|
||||
- Follow-up Action: suggest-batch-reqs → draft-batch
|
||||
|
||||
### CHG-20260502-01
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-006 최초 생성 (source Discovery: dcy-002 FR-3)
|
||||
|
||||
#### Intent
|
||||
- trex-basic Consumer-Driven Contract의 GET /v1/assets 요구사항을 REQ backlog로 정규화
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- 전체 Acceptance Criteria 신규 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/interface-contract.md (REQ-011에서 갱신 예정)
|
||||
- Modules:
|
||||
- app/api/v1_assets.py 신규
|
||||
- app/main.py (/v1 라우터 등록)
|
||||
- Tests:
|
||||
- tests/test_v1_assets.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 배정. REQ-009 migration(market 컬럼 추가)과 함께 delivery 단위 구성 권장.
|
||||
@@ -0,0 +1,82 @@
|
||||
# REQ-007: pfhub tag CLI 명령어
|
||||
|
||||
- Status: Proposed
|
||||
- Type: Interface
|
||||
- Priority: Medium
|
||||
- Owner: Justin Ko
|
||||
|
||||
## Intent
|
||||
- tags 마스터 테이블 기반의 태그 관리 CLI 명령어를 `pfhub tag` 최상위 서브커맨드로 추가하여 운영자·사용자가 터미널에서 태그 생성, 조회, 비활성화, 적용, 해제를 수행할 수 있도록 한다.
|
||||
- 기존 `pfhub portfolio tag add/list/remove` 명령어(portfolio_tags 자유 문자열 기반)는 이 REQ 구현과 함께 제거한다.
|
||||
|
||||
## Requirement
|
||||
- `pfhub tag create <name>` — 태그 생성 (trade-write 이상 권한)
|
||||
- `pfhub tag list [--inactive]` — 태그 목록; --inactive 없으면 활성 태그만, --inactive 플래그 시 비활성 태그 포함 전체 조회
|
||||
- `pfhub tag deactivate <tag_id>` — 태그 비활성화; `--force` 확인 필요 (admin 또는 생성자 본인)
|
||||
- `pfhub tag apply asset <asset_id> <tag_id>` — asset에 태그 적용 (admin 권한)
|
||||
- `pfhub tag apply portfolio <portfolio_id> <tag_id>` — portfolio에 태그 적용 (trade-write 이상, 소유자 또는 admin)
|
||||
- `pfhub tag remove asset <asset_id> <tag_id>` — asset에서 태그 해제; `--force` 확인 필요 (admin)
|
||||
- `pfhub tag remove portfolio <portfolio_id> <tag_id>` — portfolio에서 태그 해제; `--force` 확인 필요 (소유자 또는 admin)
|
||||
- 기존 `pfhub portfolio tag add`, `pfhub portfolio tag list`, `pfhub portfolio tag remove` 명령어를 제거해야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given trade-write 토큰, When `pfhub tag create "코스피200"`, Then 태그가 생성되고 `pfhub tag list`에 나타난다.
|
||||
2. Given 활성 태그 존재, When `pfhub tag list`, Then 활성 태그 목록이 출력된다.
|
||||
3. Given 활성·비활성 태그 모두 존재, When `pfhub tag list --inactive`, Then 비활성 태그가 포함된 전체 목록이 출력된다.
|
||||
4. Given admin 또는 생성자 토큰, When `pfhub tag deactivate <tag_id> --force`, Then 태그가 비활성화되고 `pfhub tag list --inactive`에서 비활성 상태로 확인된다.
|
||||
5. Given admin 토큰, admin 생성 활성 tag_id, When `pfhub tag apply asset <asset_id> <tag_id>`, Then asset에 태그가 적용된다.
|
||||
6. Given trade-write 토큰(소유자 또는 admin), When `pfhub tag apply portfolio <portfolio_id> <tag_id>` (정책 충족 태그), Then portfolio에 태그가 적용된다.
|
||||
7. Given admin 토큰, When `pfhub tag remove asset <asset_id> <tag_id> --force`, Then asset에서 태그가 제거된다.
|
||||
8. Given 소유자 또는 admin 토큰, When `pfhub tag remove portfolio <portfolio_id> <tag_id> --force`, Then portfolio에서 태그가 제거된다.
|
||||
9. Given 기존 CLI 실행 환경, When `pfhub portfolio tag add/list/remove`를 실행, Then 명령어가 존재하지 않는다(Typer error 또는 명령 없음).
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/project-structure.md (pfhub tag 커맨드 그룹 추가, pfhub portfolio tag 제거), docs/runtime-flows.md (tag CLI flow 추가)
|
||||
- Modules:
|
||||
- app/cli/commands/ — tag.py 신규 파일 (pfhub tag 커맨드 그룹)
|
||||
- app/cli/main.py — app.add_typer(tag_app, name="tag") 추가
|
||||
- app/cli/commands/portfolio.py — tag_app, tag_add, tag_list, tag_remove 제거
|
||||
- app/services/ — 태그 CLI 서비스 메서드 (create, list, deactivate, apply, remove) 추가
|
||||
- Tests: pfhub tag 커맨드 각 AC 기능 테스트, pfhub portfolio tag 제거 확인
|
||||
|
||||
## Notes
|
||||
- runtime-flows.md의 CLI 흐름 제약 준수: AppContext 통해 settings와 repository 주입.
|
||||
- `pfhub tag apply`/`remove`는 REST API(REQ-005)를 통해 정책 검증이 이루어지므로 CLI는 HTTP 오류를 그대로 사용자에게 표시.
|
||||
- REQ-004, REQ-005가 선행 구현되어야 한다.
|
||||
- Source: dcy-002 FR-6
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260519-01
|
||||
- Date: 2026-05-19
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- 최초 생성 — dcy-002 confirm-discovery 후 REQ 초안 작성
|
||||
|
||||
#### Intent
|
||||
- dcy-002 FR-6를 Interface REQ로 분리; 기존 pfhub portfolio tag 명령어 교체 명시
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~9 최초 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/project-structure.md, docs/runtime-flows.md — 최초 지정
|
||||
- Modules:
|
||||
- app/cli/commands/tag.py (신규), app/cli/main.py, app/cli/commands/portfolio.py, app/services/ — 최초 지정
|
||||
- Tests:
|
||||
- 최초 지정
|
||||
|
||||
#### 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 계획 편입; REQ-004, REQ-005 선행 의존성 확인
|
||||
@@ -1,177 +0,0 @@
|
||||
# req-007: GET /v1/user_info 엔드포인트 구현
|
||||
|
||||
- Status: Approved
|
||||
- Type: Interface
|
||||
- Priority: High
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- trex-basic 데몬이 사용자 거래 가능 여부와 브로커 인증 정보를 조회할 수 있도록 한다.
|
||||
- `runtime_id`는 인증 service-token의 런타임 세대 식별자이고, `daemon_id`는 stable logical identity로 함께 반환되어야 한다.
|
||||
- credential_payload는 DB에서 Fernet 복호화 후 반환한다(NFR-3/REQ-010 의존).
|
||||
|
||||
## Requirement
|
||||
- GET /v1/user_info는 service-token bearer 인증으로 `runtime_id`, `daemon_id`, `trading_enabled`(users.is_active 매핑), `disabled_reason`, `brokers[]`(broker, account_ref, credential_payload, credential_version, last_rotated_at)를 반환해야 한다.
|
||||
- environment 필드를 응답에 포함하지 않는다.
|
||||
- credential_payload는 Fernet으로 복호화된 JSON을 반환한다.
|
||||
- transition 구간의 legacy token은 `daemon_id = null`을 진단용으로 반환할 수 있어야 하며, `runtime_id`가 없는 구형 token 처리 규칙은 기존 v1 contract를 유지한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given `runtime_id`가 연결된 service-token으로 `GET /v1/user_info` 호출 시, Then HTTP 200과 응답 JSON에 `runtime_id`, `daemon_id`, `trading_enabled`, `brokers[]` 필드가 포함되어야 한다.
|
||||
2. Given GET /v1/user_info 응답을 확인하면, Then environment 필드가 존재하지 않아야 한다.
|
||||
3. Given users.is_active가 true인 사용자의 service-token으로 호출 시, Then 응답의 trading_enabled가 true여야 한다.
|
||||
4. Given users.is_active가 false인 사용자의 service-token으로 호출 시, Then 응답의 trading_enabled가 false여야 한다.
|
||||
5. Given broker_credentials에 KIS credential이 저장된 사용자의 토큰으로 호출 시, When 응답의 brokers[] 항목을 확인하면, Then credential_payload가 복호화된 JSON({app_key, app_secret})으로 반환되어야 한다.
|
||||
6. Given runtime_id가 없는 구형 service-token으로 호출 시, Then 설계 단계에서 확정된 오류 응답이 반환되어야 한다(R-4, 404 또는 즉시 runtime_id 생성 중 선택).
|
||||
7. Given 인증 없이 요청 시, Then HTTP 401이 반환되어야 한다.
|
||||
8. Given `daemon_id = NULL`로 backfill된 legacy service-token으로 호출 시, Then HTTP 200 응답이 유지되고 `daemon_id` 필드는 `null`로 노출되어야 한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/interface-contract.md (REQ-011에서 갱신 예정), docs/data-model.md (REQ-011에서 갱신 예정)
|
||||
- Modules: app/api/v1_user_info.py, app/schemas/v1.py, app/core/auth.py, app/domain/models.py, app/services/, app/repositories/postgres.py, app/main.py
|
||||
- Tests: tests/test_v1.py, tests/test_auth.py
|
||||
|
||||
## Notes
|
||||
- trading_enabled는 users.is_active 단순 매핑이다(A-4 Confirmed). 별도 trading 전용 상태 필드는 이번 반복 Out of Scope.
|
||||
- disabled_reason: trading_enabled가 false일 때 이유 문자열. 이번 반복에서는 is_active가 false인 경우 "account_inactive" 고정값을 사용하는 방안을 설계 단계에서 확정한다.
|
||||
- `daemon_id = NULL` legacy token은 transition diagnostics 대상으로 허용되지만, daemon-scoped read/write endpoint에서는 fail-closed가 적용된다.
|
||||
- R-4(기존 service-token에 runtime_id 없는 경우 처리): 404 또는 즉시 생성 중 설계 단계에서 결정. 이 REQ의 Acceptance Criteria 6번은 runtime_id 부재 처리 규칙에 한해 유지한다.
|
||||
- Fernet 복호화는 REQ-010에서 정의한 암호화 유틸리티를 사용한다.
|
||||
- Source Discovery: dcy-002 (FR-4, NFR-1, A-4), dcy-006 (FR-1, FR-5, NFR-1)
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260513-01
|
||||
- Date: 2026-05-13
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- `/v1/user_info` 응답 요구사항에 stable `daemon_id` diagnostics를 추가하고, runtime_id-only 구현 증거를 무효화하여 Status를 Approved로 되돌림
|
||||
|
||||
#### Intent
|
||||
- dcy-006은 `/v1/user_info`를 runtime 세대 식별과 daemon binding diagnostics를 함께 제공하는 endpoint로 재정의한다. 현재 구현/verification은 `runtime_id`만 기준으로 삼아 revised contract를 충족하지 못한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-8: legacy token의 `daemon_id = null` diagnostics
|
||||
- Updated:
|
||||
- AC-1: 응답 필수 필드에 `daemon_id` 추가
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- `docs/interface-contract.md`, `docs/data-model.md`, `docs/runtime-flows.md`
|
||||
- Modules:
|
||||
- `app/api/v1_user_info.py`, `app/schemas/v1.py`, `app/core/auth.py`, `app/repositories/postgres.py`
|
||||
- Tests:
|
||||
- `tests/test_v1.py`, `tests/test_auth.py`
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-001 (release-candidate; REL-001 released input) — `/v1/user_info` evidence를 daemon diagnostics 기준으로 재검증해야 함
|
||||
- Releases:
|
||||
- REL-001 (released) — released smoke는 `runtime_id`만 확인했으므로 revised REQ 충족 증거로 재사용 불가
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: yes
|
||||
- Existing Implementation Invalidated: yes
|
||||
- Status Recommendation: rollback-to-approved
|
||||
- Follow-up Action: dcy-006 후속 batch에서 `daemon_id` schema/API contract와 legacy diagnostic behavior를 구현한다.
|
||||
|
||||
#### Validation Plan
|
||||
- `app/api/v1_user_info.py`, `app/schemas/v1.py` 현재 구현에 `daemon_id`가 없는지 코드 리뷰로 확인한다.
|
||||
- 구현 후 daemon-bound token, legacy daemon-less token, runtime_id-missing token 시나리오를 분리해 targeted pytest를 추가한다.
|
||||
|
||||
### CHG-20260511-01
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Implemented 전환 — BAT-001 re-verified verification passed, confirm-req-implemented 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- BAT-001 verification.md (re-verified, 2026-05-03) AC-1~7 모두 PASS. Blocking Issues 없음.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: BAT-001 (release-candidate)
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: implemented
|
||||
- Follow-up Action: draft-release (BAT-001)
|
||||
|
||||
#### Validation Plan
|
||||
- BAT-001 verification.md (re-verified) AC-1~7 evidence 연결 확인 완료
|
||||
|
||||
### CHG-20260502-02
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-007 confirm-req 승인 전환 (Status: Proposed → Approved)
|
||||
|
||||
#### Intent
|
||||
- 필수 필드(Status, Type, Priority, Owner, Intent, Requirement, Acceptance Criteria 7개, Impacted Area, Change Log) 모두 충족 확인 후 승인
|
||||
- 설계 의존성 주의: AC #6(runtime_id 없는 구형 토큰 R-4 처리: 404 또는 즉시 생성)은 설계 단계에서 확정 필요. 핵심 Requirement가 명확하고 Notes에 명시적으로 deferred 처리됨 — 승인 게이트 통과 판단.
|
||||
|
||||
#### 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: keep-current
|
||||
- Follow-up Action: suggest-batch-reqs → draft-batch. 설계 단계에서 R-4 처리 방식 확정 후 AC #6 구체화.
|
||||
|
||||
### CHG-20260502-01
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-007 최초 생성 (source Discovery: dcy-002 FR-4)
|
||||
|
||||
#### Intent
|
||||
- trex-basic Consumer-Driven Contract의 GET /v1/user_info 요구사항을 REQ backlog로 정규화
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- 전체 Acceptance Criteria 신규 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/interface-contract.md (REQ-011에서 갱신 예정)
|
||||
- Modules:
|
||||
- app/api/v1_user_info.py 신규
|
||||
- app/domain/models.py BrokerCredential 추가
|
||||
- Tests:
|
||||
- tests/test_v1_user_info.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 배정. REQ-009(broker_credentials 테이블), REQ-010(Fernet 암호화), REQ-005(runtime_id)와 함께 delivery 단위 구성 권장.
|
||||
@@ -1,213 +0,0 @@
|
||||
# req-008: POST /v1/assets/{asset_id}/ledger/trades 엔드포인트 구현
|
||||
|
||||
- Status: Approved
|
||||
- Type: Interface
|
||||
- Priority: High
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- trex-basic이 체결 내역을 portfolio-hub에 idempotent하게 전송할 수 있도록 한다.
|
||||
- 동일 (asset_id, order_id, execution_id) 조합의 중복 수신은 DB unique constraint로 감지하고 status=duplicate를 반환한다(NFR-2).
|
||||
- 동일 키에 다른 payload가 오면 충돌로 처리하며, daemon assignment mismatch 또는 미배정 asset write는 저장 전에 거부한다.
|
||||
|
||||
## Requirement
|
||||
- POST /v1/assets/{asset_id}/ledger/trades는 service-token bearer 인증으로, 인증된 token의 `daemon_id`에 배정된 asset에 대해서만 체결 내역(execution_id, order_id, side, quantity, price, fee_amount, tax_amount, executed_at)을 ledger_trades 테이블에 저장하고 HTTP 201을 반환해야 한다.
|
||||
- 동일 (asset_id, order_id, execution_id) 재수신은 신규 행 생성 없이 status=duplicate와 기존 ledger_entry_id를 HTTP 200으로 반환해야 한다.
|
||||
- 동일 키에 payload가 다른 경우 HTTP 409를 반환해야 한다.
|
||||
- idempotency는 DB unique constraint로 보장하며, 애플리케이션 로직만으로 보장하지 않는다.
|
||||
- daemon assignment mismatch, 미배정 asset, `daemon_id = NULL` legacy token은 모두 HTTP 403으로 fail-closed 처리해야 하며 ledger row가 생성되면 안 된다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given 유효한 daemon-bound service-token과 해당 daemon에 배정된 asset의 신규 체결 데이터로 POST /v1/assets/{asset_id}/ledger/trades 요청 시, Then HTTP 201과 생성된 ledger_entry_id가 반환되어야 한다.
|
||||
2. Given 동일 (asset_id, order_id, execution_id)와 동일 payload로 두 번째 요청 시, Then HTTP 200과 status="duplicate", 기존 ledger_entry_id가 반환되어야 하며 DB에 단일 행만 존재해야 한다.
|
||||
3. Given 동일 (asset_id, order_id, execution_id)에 다른 payload로 요청 시, Then HTTP 409가 반환되어야 한다.
|
||||
4. Given asset_id가 존재하지 않는 portfolio_id인 경우, Then HTTP 404가 반환되어야 한다.
|
||||
5. Given 인증 없이 요청 시, Then HTTP 401이 반환되어야 한다.
|
||||
6. Given asset이 다른 daemon에 배정되어 있는 경우, When 요청 daemon이 asset owner daemon과 다르면, Then HTTP 403이 반환되어야 하고 ledger row는 생성되지 않아야 한다.
|
||||
7. Given asset이 아직 daemon에 배정되지 않았거나 토큰의 `daemon_id`가 NULL인 경우, Then HTTP 403이 반환되어야 하고 ledger row는 생성되지 않아야 한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/interface-contract.md (REQ-011에서 갱신 예정), docs/data-model.md (REQ-011에서 갱신 예정)
|
||||
- Modules: app/api/v1_ledger.py, app/domain/models.py, app/services/, app/schemas/, app/repositories/portfolio_repository.py, app/repositories/postgres.py, app/main.py
|
||||
- Tests: tests/test_v1.py 또는 신규 daemon assignment / ledger authorization 회귀 테스트
|
||||
|
||||
## Notes
|
||||
- NFR-2(idempotency DB unique constraint): (asset_id, order_id, execution_id) unique constraint는 REQ-009 migration에서 정의한다.
|
||||
- ledger_trades 테이블과 기존 portfolio_ledger 테이블은 별개다. portfolio_ledger는 내부 원장이고 ledger_trades는 trex-basic이 외부에서 기록하는 체결 내역이다.
|
||||
- 중복 감지 구현: DB unique constraint 위반(psycopg UniqueViolation) 캐치 → 기존 행 조회 → payload 동일 여부 비교 → duplicate 또는 409 응답.
|
||||
- daemon authorization은 기존 permission(`trade-write`) 위에 추가되는 두 번째 authorization 축이다.
|
||||
- Source Discovery: dcy-002 (FR-5, NFR-2), dcy-006 (FR-2, FR-4, NFR-2)
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260518-01
|
||||
- Date: 2026-05-18
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- `insert_ledger_trade()` 미구현 결함 수정 — PostgresPortfolioRepository에 메서드가 존재하지 않아 모든 POST /v1/assets/{asset_id}/ledger/trades 요청이 HTTP 500으로 실패하던 결함을 수정. Status Approved 유지.
|
||||
|
||||
#### Intent
|
||||
- `app/api/v1_ledger.py:78`에서 `repo.insert_ledger_trade()`를 호출하지만 PostgresPortfolioRepository에 구현이 없어 AttributeError → HTTP 500이 발생했다. FakeRepo 기반 테스트는 통과했으나 실 DB 환경에서는 endpoint 전체가 불동작 상태였다. trex-basic의 write-back이 전면 차단된 High 심각도 결함이었으며, 구현을 추가해 정상화했다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added: 없음
|
||||
- Updated: 없음
|
||||
- Removed: 없음
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: 없음
|
||||
- Modules:
|
||||
- `app/repositories/postgres.py`: `insert_ledger_trade(asset_id, order_id, execution_id, side, quantity, price, executed_at, fee_amount, tax_amount)` 추가. `INSERT INTO ledger_trades ... ON CONFLICT ON CONSTRAINT uq_ledger_trades_idempotency DO NOTHING RETURNING *` 패턴으로 신규/중복 여부를 `(LedgerTrade, bool)` 튜플로 반환.
|
||||
- `app/repositories/portfolio_repository.py`: Protocol에 `insert_ledger_trade` 선언 추가, `LedgerTrade` import 추가
|
||||
- Tests: 기존 FakeRepo 기반 테스트는 영향 없음. 실 DB 통합 테스트(AC-1~7)는 별도 재검증 필요.
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: BAT-010 (release-candidate) — 결함 수정이 BAT-010 delivery scope에 포함
|
||||
- Releases: REL-006 (draft) — 배포 전 결함 수정 완료. 실 DB 통합 재검증 후 배포 권장.
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: yes
|
||||
- Existing Implementation Invalidated: no (AC 정의는 유효, postgres 구현만 누락되어 있었음)
|
||||
- Status Recommendation: keep-current (Approved; CHG-20260513-01에 의해 Approved 상태)
|
||||
- Follow-up Action: 실 DB 환경에서 AC-1(신규 체결 201), AC-2(중복 200+duplicate), AC-3(payload 불일치 409), AC-6~7(daemon mismatch/미배정 403) 통합 시나리오 검증 후 Implemented 전환 가능
|
||||
|
||||
#### Validation Plan
|
||||
- `POST /v1/assets/{asset_id}/ledger/trades`에 유효 daemon-bound service-token으로 요청 시 HTTP 201 반환 확인
|
||||
- 동일 (asset_id, order_id, execution_id) 재요청 시 HTTP 200 + status=duplicate 확인
|
||||
- daemon mismatch, 미배정 asset 요청 시 HTTP 403 확인
|
||||
|
||||
### CHG-20260513-01
|
||||
- Date: 2026-05-13
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- ledger write REQ에 daemon assignment authorization과 403 fail-closed 규칙을 추가하고, 기존 Implemented 상태를 Approved로 되돌림
|
||||
|
||||
#### Intent
|
||||
- dcy-006은 `trade-write` permission만으로는 충분하지 않고, asset이 인증 daemon에 배정됐는지까지 검증하도록 요구한다. 현재 구현은 asset 존재성만 확인하므로 revised authorization contract를 충족하지 못한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-6: daemon mismatch 403
|
||||
- AC-7: 미배정 asset 또는 daemon-less token 403
|
||||
- Updated:
|
||||
- AC-1: 성공 조건을 daemon-assigned asset으로 제한
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- `docs/interface-contract.md`, `docs/runtime-flows.md`, `docs/data-model.md`
|
||||
- Modules:
|
||||
- `app/api/v1_ledger.py`, `app/repositories/portfolio_repository.py`, `app/repositories/postgres.py`
|
||||
- Tests:
|
||||
- `tests/test_v1.py` 또는 신규 daemon assignment ledger authorization 테스트
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-001 (release-candidate; REL-001 released input) — ledger verification evidence는 404/409/idempotency 중심이라 daemon authz 케이스를 추가해 재검증해야 함
|
||||
- Releases:
|
||||
- REL-001 (released) — released trade-write contract는 daemon mismatch 403 정책을 포함하지 않음
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: yes
|
||||
- Existing Implementation Invalidated: yes
|
||||
- Status Recommendation: rollback-to-approved
|
||||
- Follow-up Action: dcy-006 후속 batch에서 asset assignment lookup과 ledger authorization guard를 구현하고 duplicate/conflict 회귀와 함께 재검증한다.
|
||||
|
||||
#### Validation Plan
|
||||
- `app/api/v1_ledger.py`가 현재 asset 존재성만 확인하는지 코드 리뷰로 확인한다.
|
||||
- 구현 후 success/duplicate/conflict/404와 daemon mismatch·unassigned 403 시나리오를 함께 검증한다.
|
||||
|
||||
### CHG-20260511-01
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Implemented 전환 — BAT-001 re-verified verification passed, confirm-req-implemented 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- BAT-001 verification.md (re-verified, 2026-05-03) AC-1~5 모두 PASS. Blocking Issues 없음.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: BAT-001 (release-candidate)
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: implemented
|
||||
- Follow-up Action: draft-release (BAT-001)
|
||||
|
||||
#### Validation Plan
|
||||
- BAT-001 verification.md (re-verified) AC-1~5 evidence 연결 확인 완료
|
||||
|
||||
### CHG-20260502-02
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-008 confirm-req 승인 전환 (Status: Proposed → Approved)
|
||||
|
||||
#### Intent
|
||||
- 필수 필드(Status, Type, Priority, Owner, Intent, Requirement, Acceptance Criteria 5개, Impacted Area, Change Log) 모두 충족 확인 후 승인
|
||||
|
||||
#### 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: keep-current
|
||||
- Follow-up Action: suggest-batch-reqs → draft-batch
|
||||
|
||||
### CHG-20260502-01
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-008 최초 생성 (source Discovery: dcy-002 FR-5)
|
||||
|
||||
#### Intent
|
||||
- trex-basic Consumer-Driven Contract의 POST /v1/assets/{asset_id}/ledger/trades 요구사항을 REQ backlog로 정규화
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- 전체 Acceptance Criteria 신규 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/interface-contract.md (REQ-011에서 갱신 예정)
|
||||
- Modules:
|
||||
- app/api/v1_ledger.py 신규
|
||||
- app/domain/models.py LedgerTrade 추가
|
||||
- Tests:
|
||||
- tests/test_v1_ledger.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 배정. REQ-009(ledger_trades 테이블 + unique constraint)와 함께 delivery 단위 구성 필수.
|
||||
@@ -1,211 +0,0 @@
|
||||
# req-012: service-token rotate CLI 명령 구현
|
||||
|
||||
- Status: Approved
|
||||
- Type: Interface
|
||||
- Priority: Medium
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
|
||||
- 발급된 service-token의 원문이 노출되었거나 주기적 교체가 필요한 경우, token을 revoke 없이 in-place로 갱신할 수 있는 CLI 명령이 필요하다.
|
||||
- 기존 `revoke → re-issue` 방식은 `token_id`, `user_id`, `permission`, `expires_at`, `created_at` 등 메타데이터가 변경되므로, 운영 시스템에서 동일한 이름으로 참조하는 통합 구성을 다시 설정해야 하는 불편이 있다.
|
||||
- rotate는 `token_hash`, `token_prefix`, `runtime_id`만 교체하고 `daemon_id`를 포함한 나머지 메타데이터를 유지하여, 동일한 token 이름과 daemon binding을 유지한 채 새 token 원문만 배포할 수 있게 한다. 단, `runtime_id`를 소비하는 시스템은 rotate 후 새 토큰 기준으로 runtime_id를 재조회해야 한다.
|
||||
|
||||
## Requirement
|
||||
|
||||
- `pfhub service-token rotate <name> [--force]` CLI 명령을 구현한다.
|
||||
- rotate는 기존 auth_token 행의 `token_hash`, `token_prefix`, `runtime_id`를 새 값으로 UPDATE하고, `daemon_id`는 유지해야 한다.
|
||||
- `id`, `user_id`, `name`, `permission`, `token_type`, `expires_at`, `created_at`, `daemon_id`는 변경하지 않는다.
|
||||
- rotate 대상 token이 존재하지 않으면 오류를 반환한다.
|
||||
- rotate 대상 token이 이미 revoked 상태이면 오류를 반환한다.
|
||||
- rotate 대상 token의 `expires_at`이 NULL이 아닌 경우(만료일이 설정된 토큰) 오류를 반환한다. rotate는 `--no-expiry`로 발급된 영구 토큰에만 허용된다.
|
||||
- `--force` 없이 실행하면 확인 프롬프트를 표시한다.
|
||||
- rotate 성공 시 새 token 원문을 1회 출력하고, 이후 list/조회에서는 token_prefix만 표시된다. rotate 출력 메타데이터에는 `daemon_id`가 포함되어야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
1. Given `expires_at IS NULL`인 유효한 service-token 이름, When `pfhub service-token rotate <name> --force`를 실행, Then DB 행의 `token_hash`, `token_prefix`, `runtime_id`가 새 값으로 변경되고 `id`, `permission`, `expires_at`(NULL), `daemon_id`는 기존과 동일하다.
|
||||
2. Given rotate 성공, When CLI 출력, Then 새 token 원문이 화면에 1회 출력되고 "이 토큰은 지금 1회만 표시" 안내 메시지와 함께 `daemon_id` 메타데이터가 표시되어야 한다.
|
||||
3. Given 존재하지 않는 token 이름, When `rotate`, Then 오류 메시지를 출력하고 종료 코드 1을 반환한다.
|
||||
4. Given revoked 상태의 token, When `rotate`, Then 오류 메시지를 출력하고 종료 코드 1을 반환한다.
|
||||
5. Given `expires_at`이 NULL이 아닌(만료일이 설정된) token, When `rotate`, Then "만료일이 설정된 토큰은 rotate할 수 없습니다" 오류를 출력하고 종료 코드 1을 반환한다.
|
||||
6. Given `--force` 없이 실행, When CLI, Then 확인 프롬프트를 표시하고 거절 시 변경 없이 종료한다.
|
||||
|
||||
## Impacted Area
|
||||
|
||||
- Docs: docs/project-structure.md (변경 없음), docs/runtime-flows.md (변경 없음)
|
||||
- Modules:
|
||||
- `app/repositories/portfolio_repository.py` — `rotate_service_token` Protocol stub 추가
|
||||
- `app/repositories/postgres.py` — `rotate_service_token` UPDATE 구현 추가
|
||||
- `app/services/auth_service.py` — `rotate_service_token(name)` 서비스 메서드 추가
|
||||
- `app/cli/commands/service_tokens.py` — `rotate` 명령 및 `daemon_id` 출력 추가
|
||||
- `tests/test_cli.py` — stub repo에 `rotate_service_token` 추가 및 테스트 케이스 추가
|
||||
- Tests:
|
||||
- `tests/test_cli.py`: rotate 성공, 없는 이름, revoked 상태, `daemon_id` 유지/출력 케이스
|
||||
|
||||
## Notes
|
||||
|
||||
- `expires_at`은 rotate 시 변경하지 않는다. 만료일 변경이 필요하면 revoke + re-issue를 사용한다.
|
||||
- rotate는 `--no-expiry`로 발급된 영구 토큰(`expires_at IS NULL`)에만 허용된다. 만료일이 설정된 토큰은 rotate 대상이 아니다. 해당 토큰은 만료 후 re-issue하는 것이 권장 패턴이다.
|
||||
- rotate는 `runtime_id`도 새 값으로 갱신하지만 `daemon_id`는 유지한다. trex-basic 등 `runtime_id`를 소비하는 시스템은 rotate 후 새 토큰으로 다시 인증하고 `GET /v1/user_info`를 재호출해 새 `runtime_id`를 재인식해야 한다.
|
||||
- 기존 `runtime_id`를 캐싱한 상태로 계속 사용하면 consumer 식별 불일치가 발생할 수 있다. rotate는 "토큰 원문 교체 시 token name과 메타데이터를 유지한다"는 의미이지, `runtime_id`까지 불변이라는 뜻은 아니다.
|
||||
- rotate는 daemon provisioning 경로가 아니며, unknown daemon 자동 생성/업서트를 수행하면 안 된다.
|
||||
- DB 스키마 변경(migration)은 없다. 기존 `auth_tokens` 테이블의 기존 컬럼만 UPDATE한다.
|
||||
- 구조/인터페이스/런타임 흐름 변경 없음 → minor-change fast path 적용.
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260513-01
|
||||
- Date: 2026-05-13
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- rotate REQ에 `daemon_id` 불변식과 CLI diagnostic 출력 요구를 추가하고, 기존 Implemented 상태를 Approved로 되돌림
|
||||
|
||||
#### Intent
|
||||
- dcy-006은 rotate 이후에도 `daemon_id`가 stable identity로 유지되어야 하고, 운영자는 rotate 출력과 provenance 절차에서 `daemon_id`를 확인할 수 있어야 한다. BAT-002/REL-002 구현은 runtime_id lifecycle만 다루므로 revised REQ를 충족하지 못한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- none
|
||||
- Updated:
|
||||
- AC-1: `daemon_id` 유지 불변식 추가
|
||||
- AC-2: CLI output에 `daemon_id` metadata 추가
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- `README.md`, token provenance 문서, `docs/runtime-flows.md`
|
||||
- Modules:
|
||||
- `app/cli/commands/service_tokens.py`, `app/services/auth_service.py`, `app/repositories/postgres.py`
|
||||
- Tests:
|
||||
- `tests/test_cli.py`, 필요한 경우 auth/v1 provenance 회귀 테스트
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-002 (release-candidate; REL-002 released input) — rotate verification evidence는 `daemon_id` 유지/출력 기준으로 재검증 필요
|
||||
- Releases:
|
||||
- REL-002 (released) — rotate 운영 메모는 runtime_id 재조회만 다루며 daemon-aware provenance는 미반영
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: yes
|
||||
- Existing Implementation Invalidated: yes
|
||||
- Status Recommendation: rollback-to-approved
|
||||
- Follow-up Action: dcy-006 후속 batch에서 rotate response metadata와 daemon binding invariants를 구현하고, REL-002 후속 tooling release evidence를 갱신한다.
|
||||
|
||||
#### Validation Plan
|
||||
- current CLI/service/repository 구현이 `daemon_id`를 보존·출력하지 않는지 코드 리뷰로 확인한다.
|
||||
- 구현 후 rotate 전후 `daemon_id` 불변, `runtime_id` 갱신, CLI output metadata를 targeted CLI 테스트로 검증한다.
|
||||
|
||||
### CHG-20260511-02
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Implemented 전환 — BAT-002 verification passed, confirm-req-implemented 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- BAT-002 verification.md에서 REQ-012 AC-1~6이 모두 PASS이고 blocking issue가 없음을 근거로 Implemented로 승격한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added: none
|
||||
- Updated: none
|
||||
- Removed: none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: none
|
||||
- Modules: none
|
||||
- Tests: none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-002 (release-candidate)
|
||||
- Releases:
|
||||
- none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: implemented
|
||||
- Follow-up Action: tooling release에 포함 시 rotate 후 runtime_id 재조회 운영 메모 반영
|
||||
|
||||
#### Validation Plan
|
||||
- BAT-002 verification.md의 REQ-012 AC-1~6 evidence와 Ready for Release: true 확인
|
||||
|
||||
### CHG-20260511-01
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- rotate 후 `runtime_id` lifecycle 명시 추가 — downstream consumer는 새 토큰 배포 후 `runtime_id`를 재조회해야 함
|
||||
|
||||
#### Intent
|
||||
- CONFLICT-3 분석 결과를 반영해 `runtime_id`가 rotate 시 변경된다는 사실과, trex-basic 같은 consumer가 이를 어떻게 재인식해야 하는지 REQ-012 문서에 명시한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- none
|
||||
- Updated:
|
||||
- none
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- `docs/srs/Interface/req-012_service-token-rotate-cli.md`: Intent/Notes에 rotate 후 `runtime_id` 재조회 lifecycle 추가
|
||||
- Modules:
|
||||
- none
|
||||
- Tests:
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-002 (release-candidate) — verification evidence는 유지 가능하나, rotate 후 consumer 재인식 절차를 운영 메모로 함께 검토해야 한다.
|
||||
- Releases:
|
||||
- none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: trex-basic 연동 runbook 또는 후속 REQ에서 rotate 후 `runtime_id` 재조회 절차를 운영 문서에 반영 검토
|
||||
|
||||
#### Validation Plan
|
||||
- REQ-005, REQ-007, REQ-012 문구를 대조해 rotate 시 `runtime_id` 변경과 `GET /v1/user_info` 재조회 필요성이 일관되게 설명되는지 코드 리뷰로 확인
|
||||
|
||||
### CHG-20260502-01
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-012 신규 작성 (minor-change fast path, Approved 직행)
|
||||
- rotate 허용 대상을 `expires_at IS NULL`(no-expiry) 토큰으로 제한
|
||||
|
||||
#### Intent
|
||||
- service-token rotate CLI 명령 필요성 확인 후 즉시 구현 진행
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- 6개 기준 신규 정의 (AC-5: expires_at 설정 토큰 rotate 거부 추가)
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Modules:
|
||||
- postgres.py, auth_service.py, service_tokens.py, test_cli.py 추가
|
||||
- Tests:
|
||||
- test_cli.py 3개 케이스 신규
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-002 (batch-lite)
|
||||
- Releases:
|
||||
- none (미정)
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: BAT-002 planning → implementation → verification 진행
|
||||
|
||||
#### Validation Plan
|
||||
- test_cli.py 3개 케이스 통과 + 기존 service-token 테스트 회귀 없음으로 완료 판단
|
||||
@@ -1,143 +0,0 @@
|
||||
# REQ-013: CLI `portfolio list --user` 필수화 및 소유자 기반 조회
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Interface
|
||||
- Priority: Medium
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- CLI `pfhub portfolio list`는 현재 `--user` 옵션이 없어 `owner_user_id=None`으로 호출되며 전체 포트폴리오를 반환한다. 이 동작은 소유자 구분 없이 DB 전체를 노출하는 문제가 있다.
|
||||
- `--user <username>` 옵션을 필수로 지정하여 CLI 실행 시 항상 특정 사용자의 포트폴리오만 조회하도록 강제한다.
|
||||
- username을 `owner_user_id`(UUID)로 변환하는 로직을 CLI 내부에 추가하여, `PortfolioService.list_portfolios` 호출 시 소유자 필터가 항상 적용되게 한다.
|
||||
|
||||
## Requirement
|
||||
- CLI `pfhub portfolio list` 명령은 `--user <username>` 옵션을 필수로 받아야 한다.
|
||||
- `--user` 없이 실행하면 오류 메시지를 출력하고 exit code 1로 종료해야 한다.
|
||||
- `--user`로 전달된 username을 user repository(`get_user_by_username`)로 조회하여 `owner_user_id`(UUID)를 얻고, 이를 `PortfolioService.list_portfolios(owner_user_id=...)` 호출에 전달해야 한다.
|
||||
- 존재하지 않는 username이 전달되면 기존 CLI 오류 출력 형식(Rich Console 또는 typer.echo)과 일관된 오류 메시지를 출력하고 비정상 종료해야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given `--user` 옵션 없이 `pfhub portfolio list`를 실행할 때, When 명령이 실행되면, Then 오류 메시지("--user 옵션이 필요합니다" 또는 동등한 내용)가 출력되고 exit code 1로 종료된다.
|
||||
2. Given 유효한 username `alice`로 `pfhub portfolio list --user alice`를 실행할 때, When 명령이 실행되면, Then `alice`의 `owner_user_id`로 필터된 포트폴리오 목록만 반환되고 다른 사용자 소유 포트폴리오는 포함되지 않는다.
|
||||
3. Given 존재하지 않는 username으로 `pfhub portfolio list --user unknown`을 실행할 때, When 명령이 실행되면, Then "사용자를 찾을 수 없습니다" 형태의 오류 메시지가 출력되고 exit code 1로 종료된다.
|
||||
4. Given in-memory 모드(`pfhub_DB_ENABLED=false`)에서 `pfhub portfolio list --user alice`를 실행할 때, When 명령이 실행되면, Then DB 모드와 동일하게 `alice` 소유 포트폴리오만 반환된다.
|
||||
5. Given 오류 발생 시, When 오류 메시지가 출력될 때, Then 메시지 형식은 기존 CLI 오류 출력 형식(Rich Console stderr 또는 typer.echo)과 일관성을 유지한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs:
|
||||
- `README.md` — `pfhub portfolio list` 예제 라인에 `--user <username>` 옵션 추가 및 breaking change 안내
|
||||
- Modules:
|
||||
- `app/cli/commands/portfolio.py` — `list_portfolios` 명령 시그니처에 `--user` 필수 옵션 추가, username → owner_user_id 변환 로직 추가, `PortfolioService.list_portfolios` 호출 시 `owner_user_id` 전달
|
||||
- `app/repositories/portfolio_repository.py` — `get_user_by_username` Protocol stub 기존 존재 확인(line 16), 추가 변경 불필요
|
||||
- `app/repositories/postgres.py` — `get_user_by_username` 기존 구현 확인(line 419), 추가 변경 불필요
|
||||
- Tests:
|
||||
- `tests/test_cli.py` — AC 1~5 커버 테스트 케이스 추가:
|
||||
- `test_cli_portfolio_list_without_user_exits_error`
|
||||
- `test_cli_portfolio_list_with_valid_user_filters_by_owner`
|
||||
- `test_cli_portfolio_list_with_unknown_user_exits_error`
|
||||
- `test_cli_portfolio_list_in_memory_mode_works`
|
||||
|
||||
## Notes
|
||||
- `PortfolioService.list_portfolios` 시그니처는 변경하지 않는다. CLI 호출부에서만 `owner_user_id`를 전달한다 (A-3, dcy-003).
|
||||
- HTTP API `GET /portfolios`의 접근 통제는 이번 REQ 범위 밖이다 (Out of Scope).
|
||||
- `--all` 관리자 전체 조회 옵션은 이번 REQ에 포함하지 않는다. 후속 Discovery로 분리한다.
|
||||
- username → owner_user_id 변환은 `repository.get_user_by_username(username)` 직접 호출로 구현한다. `UserService`에는 해당 메서드가 없음을 확인하였다.
|
||||
- 기존 `_with_service` 헬퍼는 `PortfolioService`만 생성한다. username 조회를 위해 별도로 repository를 직접 사용하거나 `_with_service` callback 안에서 repository 접근이 필요하다. 구현 시 `app_context.repository_factory(settings)` 반환 객체를 통해 `get_user_by_username`을 호출하는 방식으로 처리한다.
|
||||
- Source Discovery: [dcy-003](../../discovery/dcy-003_20260502_portfolio-list-user-required.md)
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260502-03
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Status Approved → Implemented. BAT-003(release-candidate) verification evidence 확인 완료.
|
||||
|
||||
#### Intent
|
||||
- confirm-req-implemented 실행. AC 1~5 전원 evidence 연결 확인, Blocking Issues 없음.
|
||||
|
||||
#### Evidence Batch
|
||||
- Batch: BAT-003 (release-candidate)
|
||||
- Verification: docs/batches/bat-003_20260502_portfolio-list-user-required/verification.md
|
||||
- Test result: 41 passed (pytest tests/test_cli.py)
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- 없음
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: 없음
|
||||
- Modules: 없음
|
||||
- Tests: 없음
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: BAT-003 (release-candidate)
|
||||
- Releases: none (draft-release 대기 중)
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: draft-release
|
||||
|
||||
### CHG-20260502-02
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Status Proposed → Approved. 승인 게이트 통과. 필수 필드, AC 5개, Impacted Area, Change Log 모두 충족.
|
||||
|
||||
#### Intent
|
||||
- confirm-req 실행으로 구현 delivery 입력 준비 확정.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added: 없음
|
||||
- Updated: 없음
|
||||
- Removed: 없음
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: 없음
|
||||
- Modules: 없음
|
||||
- Tests: 없음
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: none
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: batch 생성 진행 (draft-batch)
|
||||
|
||||
### CHG-20260502-01
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-013 최초 생성 (Proposed). dcy-003 FR-1, FR-2, FR-3 통합. NFR-1, NFR-2는 AC 5에 흡수.
|
||||
|
||||
#### Intent
|
||||
- dcy-003 확정 Discovery를 REQ backlog로 정규화.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC 1~5 신규 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- README.md breaking change 안내 추가 항목
|
||||
- Modules:
|
||||
- app/cli/commands/portfolio.py 신규 변경
|
||||
- Tests:
|
||||
- tests/test_cli.py 4개 테스트 케이스 신규 추가
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: none (batch 미생성)
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: confirm-req 실행 후 batch 계획 수립
|
||||
@@ -1,78 +0,0 @@
|
||||
# REQ-014: CLI `portfolio create --user` 필수화 및 소유자 설정
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Interface
|
||||
- Priority: Medium
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- CLI `pfhub portfolio create`는 현재 `--user` 옵션이 없어 `owner_user_id="system"` 고정값으로 포트폴리오가 생성된다.
|
||||
- 생성 시 `--user <username>` 을 필수로 받아 실제 소유자의 `owner_user_id`(UUID)로 포트폴리오가 생성되도록 강제한다.
|
||||
- REQ-013(`portfolio list --user` 필수화)과 대칭을 이루는 변경으로, 소유자 기반 포트폴리오 관리 정책을 CLI 전반에 일관되게 적용한다.
|
||||
|
||||
## Requirement
|
||||
- CLI `pfhub portfolio create` 명령은 `--user <username>` 옵션을 필수로 받아야 한다.
|
||||
- `--user` 없이 실행하면 오류 메시지를 출력하고 exit code 1로 종료해야 한다.
|
||||
- `--user`로 전달된 username을 `repository.get_user_by_username(username)`으로 조회하여 `owner_user_id`(UUID)를 얻고, 이를 `PortfolioService.create_portfolio(owner_user_id=...)` 호출에 전달해야 한다.
|
||||
- 존재하지 않는 username이 전달되면 기존 CLI 오류 출력 형식과 일관된 오류 메시지를 출력하고 비정상 종료해야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given `--user` 옵션 없이 `pfhub portfolio create <id> --symbol X --force`를 실행할 때, When 명령이 실행되면, Then 오류 메시지가 출력되고 exit code 1로 종료된다.
|
||||
2. Given 유효한 username `alice`로 `pfhub portfolio create <id> --symbol X --user alice --force`를 실행할 때, When 명령이 실행되면, Then 생성된 포트폴리오의 `owner_user_id`가 alice의 UUID로 설정된다.
|
||||
3. Given 존재하지 않는 username으로 실행할 때, When 명령이 실행되면, Then "사용자를 찾을 수 없습니다" 형태의 오류 메시지가 출력되고 exit code 1로 종료된다.
|
||||
4. Given in-memory 모드에서 `--user alice`로 실행할 때, When 명령이 실행되면, Then DB 모드와 동일하게 alice의 UUID가 `owner_user_id`로 설정된다.
|
||||
5. Given 오류 발생 시, When 오류 메시지가 출력될 때, Then 메시지 형식은 기존 CLI 오류 출력 형식(Rich Console)과 일관성을 유지한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs:
|
||||
- `README.md` — `pfhub portfolio create` 예제 라인에 `--user <username>` 옵션 추가
|
||||
- Modules:
|
||||
- `app/cli/commands/portfolio.py` — `create_portfolio` 명령 시그니처에 `--user` 필수 옵션 추가, `_with_service_and_repo` 콜백 사용, `owner_user_id` 전달
|
||||
- Tests:
|
||||
- `tests/test_cli.py` — 기존 `test_cli_create_buy_and_delete_flow` 수정 + AC 1~4 커버 케이스 추가
|
||||
|
||||
## Notes
|
||||
- `PortfolioService.create_portfolio` 시그니처(`owner_user_id: str = "system"`)는 변경하지 않는다. CLI 호출부에서만 실제 UUID를 전달한다.
|
||||
- REQ-013에서 도입한 `_with_service_and_repo` 헬퍼를 그대로 사용한다. 추가 헬퍼 불필요.
|
||||
- minor-change fast path 적용: Discovery 생략, Approved 직행. 범위는 CLI 옵션 1개 추가이며 기존 서비스/repository 인터페이스 변경 없음.
|
||||
- Source Discovery: 없음 (minor-change fast path)
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260502-01
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-014 최초 생성 (Approved 직행). minor-change fast path 적용. REQ-012, REQ-013 선례 동일 경로.
|
||||
|
||||
#### Intent
|
||||
- `pfhub portfolio create`의 소유자 설정 누락 문제를 CLI 레벨에서 해결.
|
||||
|
||||
### CHG-20260502-02
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- BAT-004 verification(44 passed) 기반으로 Approved → Implemented 전환.
|
||||
|
||||
#### Intent
|
||||
- 구현 및 검증 증거 확보 완료 후 상태 동기화.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added: AC 1~5 신규 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: README.md create 예제 갱신
|
||||
- Modules: app/cli/commands/portfolio.py create_portfolio 수정
|
||||
- Tests: tests/test_cli.py 케이스 추가/수정
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: none (batch 미생성)
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: draft-batch 진행
|
||||
@@ -1,143 +0,0 @@
|
||||
# req-015: CLI `credential` 명령 그룹 구현 (브로커 인증 정보 관리)
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Interface
|
||||
- Priority: Medium
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- 운영자가 CLI(`pfhub credential`)를 통해 KIS 브로커 인증 정보를 안전하게 등록, 조회, 삭제할 수 있어야 한다.
|
||||
- `broker_credentials` 테이블(migration 0014)과 기존 Fernet 암호화 인프라(`app/core/encryption.py`, `CREDENTIAL_ENCRYPTION_KEY`)를 재사용해 CLI 레이어만 추가한다.
|
||||
|
||||
## Requirement
|
||||
- 시스템은 `pfhub credential set --user <username> --broker <broker> --account-ref <ref> --app-key <key> --app-secret <secret>` 명령을 제공해야 한다. 이 명령은 `{"app_key": ..., "app_secret": ...}` JSON을 Fernet으로 암호화한 뒤 `broker_credentials` 테이블에 upsert한다.
|
||||
- 시스템은 `pfhub credential list --user <username>` 명령을 제공해야 한다. 이 명령은 사용자의 브로커 인증 정보 목록을 반환하되, `encrypted_payload`는 출력하지 않는다.
|
||||
- 시스템은 `pfhub credential remove --user <username> --broker <broker> [--force]` 명령을 제공해야 한다. 이 명령은 해당 인증 정보 레코드를 삭제한다.
|
||||
- 존재하지 않는 사용자를 지정하면 에러 메시지와 함께 exit code 1로 종료해야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given alice 사용자와 유효한 `CREDENTIAL_ENCRYPTION_KEY`가 설정된 환경에서, When `pfhub credential set --user alice --broker kis --account-ref REF --app-key KEY --app-secret SECRET`을 실행하면, Then `broker_credentials` 테이블에 암호화된 payload로 레코드가 생성(또는 갱신)된다.
|
||||
2. Given `broker_credentials`에 alice의 kis 레코드가 있을 때, When `pfhub credential list --user alice`를 실행하면, Then broker, account_ref, credential_version, last_rotated_at이 출력되고 `encrypted_payload`는 포함되지 않는다.
|
||||
3. Given 존재하지 않는 username을 지정할 때, When `pfhub credential set --user unknown ...`을 실행하면, Then 에러 메시지와 함께 exit code 1로 종료된다.
|
||||
4. Given alice의 kis 인증 정보가 있을 때, When `pfhub credential remove --user alice --broker kis --force`를 실행하면, Then 해당 레코드가 삭제되고 `pfhub credential list --user alice`에서 더 이상 표시되지 않는다.
|
||||
5. Given `CREDENTIAL_ENCRYPTION_KEY`가 설정되지 않은 환경에서, When `pfhub credential set ...`을 실행하면, Then 설정 미비 에러 메시지와 함께 exit code 1로 종료된다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: `docs/project-structure.md` (CLI 모듈 목록 갱신)
|
||||
- Modules:
|
||||
- `app/cli/commands/credential.py` (신규 — `credential_app`, `set`, `list`, `remove` 명령)
|
||||
- `app/cli/main.py` (`credential_app` 등록 추가)
|
||||
- `app/repositories/postgres.py` (`delete_broker_credential` 메서드 추가)
|
||||
- Tests: `tests/test_cli.py` (credential 명령 통합 테스트 추가)
|
||||
|
||||
## Notes
|
||||
- `broker_credentials` 테이블 DDL과 `upsert_broker_credential`, `list_broker_credentials`, `get_broker_credential` 메서드는 migration 0014에서 이미 구현됨. `delete_broker_credential` 메서드는 이번 REQ에서 추가.
|
||||
- `app/core/encryption.py`의 `encrypt_payload(key, plaintext)` 사용.
|
||||
- 기존 CLI 패턴(`_with_service` 헬퍼, `execute_command`, `render_output`, `_confirm`) 동일하게 적용.
|
||||
- `--broker` 기본값은 `kis`.
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260511-01
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Implemented 전환 — BAT-005 verification passed, confirm-req-implemented 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- BAT-005 verification.md에서 REQ-015 AC-1~5가 모두 passed이고 regression 없음이 확인되어 Implemented로 승격한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added: none
|
||||
- Updated: none
|
||||
- Removed: none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: none
|
||||
- Modules: none
|
||||
- Tests: none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-005 (release-candidate)
|
||||
- Releases:
|
||||
- none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: implemented
|
||||
- Follow-up Action: tooling release에 포함 시 credential smoke 절차 포함
|
||||
|
||||
#### Validation Plan
|
||||
- BAT-005 verification.md의 AC-1~5 passed evidence와 residual risk 없음 확인
|
||||
|
||||
### CHG-20260503-02
|
||||
- Date: 2026-05-03
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-015 Approved 전환 — minor-change fast path (단일 저위험 REQ, CLI 레이어만 추가, 구조/런타임 영향 없음)
|
||||
|
||||
#### Intent
|
||||
- Acceptance Criteria 5개 모두 구현 판단에 충분하며 blocking assumption 없음
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added: none
|
||||
- Updated: none
|
||||
- Removed: none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: none
|
||||
- Modules: none
|
||||
- Tests: none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: BAT-005 (batch-lite)
|
||||
- Releases: 미정
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: run-batch-implementation 진행
|
||||
|
||||
#### Validation Plan
|
||||
- BAT-005 verification 통과 확인
|
||||
|
||||
---
|
||||
|
||||
### CHG-20260503-01
|
||||
- Date: 2026-05-03
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-015 최초 작성 — CLI `credential` 명령 그룹 구현 (브로커 인증 정보 관리)
|
||||
|
||||
#### Intent
|
||||
- 운영자가 KIS 브로커 인증 정보를 CLI로 관리할 수 있도록 Interface 레이어 추가
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- 위 Acceptance Criteria 1~5 전체
|
||||
- Updated: none
|
||||
- Removed: none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: `docs/project-structure.md`
|
||||
- Modules: `app/cli/commands/credential.py` (신규), `app/cli/main.py`, `app/repositories/postgres.py`
|
||||
- Tests: `tests/test_cli.py`
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: 미정 (BAT-005 예정)
|
||||
- Releases: 미정
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: 없음
|
||||
|
||||
#### Validation Plan
|
||||
- `tests/test_cli.py`에 credential 명령 통합 테스트 작성 후 `pytest tests/test_cli.py` 전체 통과 확인
|
||||
@@ -1,186 +0,0 @@
|
||||
# req-017: CLI portfolio 명령 — name+user 조합 식별 방식 전환
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Interface
|
||||
- Priority: High
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- 현재 `portfolio_id` Argument로만 portfolio를 식별하는 CLI 뮤테이션 명령을 `<name>` + `--user <username>` 조합으로 전환해 소유권 검증을 명령 실행 경로에 포함한다.
|
||||
- CLI 내부에서 `(owner_user_id, name)` → UUID 단일 쿼리 조회 후 처리하고, 조회 실패 시 명확한 오류 메시지를 출력한다.
|
||||
|
||||
## Requirement
|
||||
- `portfolio create` 명령은 `name` Argument와 `--user <username>` 옵션을 필수로 받는다. `portfolio_id`는 서버가 UUID로 발급하며 사용자가 직접 지정하거나 조회할 수 없다.
|
||||
- `status`, `buy`, `sell`, `invest`, `transfer`, `reset`, `delete`, `update` 명령은 `<name>` Argument와 `--user <username>` 옵션으로 portfolio를 식별한다. 내부에서 `(owner_user_id, name)` → `portfolio_id(UUID)`를 단일 DB 쿼리로 조회한 뒤 처리한다.
|
||||
- `<name>` + `--user` 조합으로 portfolio를 찾지 못하면 오류 메시지 `포트폴리오를 찾을 수 없습니다: {name} (user: {username})`를 출력하고 명령을 중단한다.
|
||||
- `name`은 `update` 명령으로 변경 가능하다. 변경 시 동일 `owner_user_id` 내에 같은 `name`이 이미 존재하면 오류 메시지 `이미 사용 중인 이름입니다: {name}`를 반환한다.
|
||||
- `name` 변경 명령에는 명시적 확인 절차(`--force` 또는 confirm 프롬프트)를 요구한다.
|
||||
- `name` 허용 문자는 `[a-zA-Z0-9._:-]`이며, 공백 불허, 1~100자, 대소문자 구분이 있다. 이 범위를 벗어나면 유효성 검사 오류를 반환한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given `pfhub portfolio create <name> --user <username> ...`을 실행하면, When 서버가 UUID를 발급하면, Then CLI가 portfolio_id를 직접 지정하거나 조회하지 않고 UUID가 DB에 저장된다.
|
||||
2. Given `pfhub portfolio buy <name> --user alice ...`를 실행하면, When `(alice, <name>)` 조합으로 DB를 단일 쿼리로 조회해 UUID를 찾으면, Then 해당 portfolio에 buy 작업이 수행된다.
|
||||
3. Given `--user bob`으로 alice 소유의 portfolio `<name>`을 조작하면, When `(bob, <name>)` 조합으로 조회해 레코드가 없으면, Then `포트폴리오를 찾을 수 없습니다: {name} (user: bob)` 오류가 출력되고 명령이 중단된다.
|
||||
4. Given alice와 bob이 동일 name `tv`로 각각 portfolio를 생성하면, Then 두 레코드가 독립적으로 저장되고 각자 자신의 `tv` portfolio를 조작할 수 있다.
|
||||
5. Given alice의 portfolio name을 `tv2`로 변경할 때 alice에게 이미 `tv2` 이름의 portfolio가 존재하면, When `update` 명령이 DB의 `(owner_user_id, name)` UNIQUE 제약 위반을 감지하면, Then `이미 사용 중인 이름입니다: tv2` 오류를 출력한다.
|
||||
6. Given `--force` 없이 `update` 명령으로 name을 변경하려 하면, Then `--force`가 없으면 변경이 중단되거나 confirm 프롬프트가 표시된다.
|
||||
7. Given `name` 허용 문자 범위(`[a-zA-Z0-9._:-]`) 밖의 문자가 포함된 이름을 `create` 시 입력하면, Then 유효성 검사 오류가 반환된다.
|
||||
8. Given `name` 길이가 0이거나 100자를 초과하면, Then 유효성 검사 오류가 반환된다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: `docs/runtime-flows.md` (CLI 명령 흐름 변경 반영 — REQ-019에서 처리)
|
||||
- Modules:
|
||||
- `app/cli/commands/portfolio.py`: `create`, `status`, `buy`, `sell`, `invest`, `transfer`, `reset`, `delete`, `update` 명령의 Argument/Option 전환
|
||||
- `app/domain/services.py`: `(user_id, name)` → UUID 해석 로직 추가
|
||||
- `app/repositories/postgres.py`: `get_portfolio_by_name_and_user()` 단일 쿼리 구현 (REQ-016과 공유)
|
||||
- Tests:
|
||||
- `tests/test_cli.py`: 소유권 검증 케이스, 오류 메시지 검증, name 유효성 검사, name 중복 변경 거부 테스트
|
||||
|
||||
## Notes
|
||||
- `(owner_user_id, name)` → UUID 조회는 REQ-016에서 추가하는 `get_portfolio_by_name_and_user()` 메서드를 사용한다.
|
||||
- `name` 대소문자 구분 있음 — `TV`와 `tv`는 다른 이름으로 처리.
|
||||
- Source Discovery: dcy-004_20260511_portfolio-id-uuid-migration-and-user-scoped-name-resolution (FR-2, FR-3, FR-3a, NFR-2)
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260518-01
|
||||
- Date: 2026-05-18
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- `get_portfolio_by_name_and_user()` 미구현 결함 수정 — PostgresPortfolioRepository에 메서드가 존재하지 않아 실 DB 환경에서 모든 name+user 식별 경로가 AttributeError로 실패하던 결함을 수정. Status Implemented 유지.
|
||||
|
||||
#### Intent
|
||||
- REQ-017 AC-2~4(name+user 조합으로 portfolio 조회)를 구현한 CLI 코드와 FakeRepo는 완성되어 있었으나, PostgresPortfolioRepository에 `get_portfolio_by_name_and_user()`가 누락되어 실 DB 환경에서 AttributeError가 발생했다. 결함을 수정해 Implemented 근거를 복원한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added: 없음
|
||||
- Updated: 없음
|
||||
- Removed: 없음
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: 없음
|
||||
- Modules:
|
||||
- `app/repositories/postgres.py`: `get_portfolio_by_name_and_user(owner_user_id, name)` 추가 (`_SELECT_PORTFOLIO WHERE owner_user_id = %s AND name = %s`)
|
||||
- `app/repositories/portfolio_repository.py`: Protocol에 `get_portfolio_by_name_and_user` 선언 추가
|
||||
- Tests: `tests/test_portfolio_uuid.py` 14 passed (기존 FakeRepo 기반 테스트는 영향 없음)
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: BAT-006 (release-candidate) — 결함 수정이 BAT-006 delivery scope에 포함
|
||||
- Releases: REL-006 (draft) — 배포 전 결함 수정 완료
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current (Implemented)
|
||||
- Follow-up Action: 없음 (실 DB 통합 테스트로 AC-2~4 재확인 권장)
|
||||
|
||||
#### Validation Plan
|
||||
- `pfhub portfolio status <name> --user <user>`, `pfhub portfolio buy <name> --user <user>` 등 name+user 식별 명령이 실 DB 환경에서 정상 응답하는지 확인
|
||||
|
||||
### CHG-20260511-01
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- 최초 생성 — dcy-004 draft-req에 의해 생성
|
||||
|
||||
#### Intent
|
||||
- dcy-004 Discovery의 FR-2(portfolio create 명령 name+user 전환), FR-3(CLI 뮤테이션 명령 식별 방식 전환), FR-3a(name mutable + 중복 변경 거부), NFR-2(단일 DB 쿼리, 오류 메시지) 반영
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- 1~8 (최초 생성)
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/runtime-flows.md: CLI 명령 흐름 변경 (REQ-019에서 처리)
|
||||
- Modules:
|
||||
- app/cli/commands/portfolio.py: 명령 Argument/Option 전면 교체
|
||||
- app/domain/services.py: (user_id, name) → UUID 해석 추가
|
||||
- app/repositories/postgres.py: get_portfolio_by_name_and_user() 추가
|
||||
- Tests:
|
||||
- tests/test_cli.py: 소유권 검증, 오류 메시지, name 유효성 검사 케이스 추가
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: none (batch 미결정)
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: confirm-req → suggest-batch-reqs → draft-batch
|
||||
|
||||
#### Validation Plan
|
||||
- pytest: 소유권 검증 케이스, 오류 메시지 검증, name 유효성 검사, name 중복 변경 거부, alice/bob 독립 portfolio 생성 검증
|
||||
|
||||
### CHG-20260511-02
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Approved 전환 — confirm-req 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- Delivery 입력으로 사용할 수 있도록 REQ-017을 승인 상태로 승격한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- none
|
||||
- Updated:
|
||||
- none
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- none
|
||||
- Modules:
|
||||
- none
|
||||
- Tests:
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- none
|
||||
- Releases:
|
||||
- none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: suggest-batch-reqs로 batch grouping 검토
|
||||
|
||||
#### Validation Plan
|
||||
- confirm-req 게이트 재평가 결과: 필수 메타데이터, 구체적 Acceptance Criteria, Impacted Area, Change Log, blocker 없음 확인
|
||||
|
||||
### CHG-20260511-03
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Implemented 전환 — BAT-006 verification passed, confirm-req-implemented 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- BAT-006 verification.md의 REQ-017 AC-1~8 모두 test evidence 포함. Blocking Issues 없음. 구현 완료 상태로 전환한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: BAT-006 (release-candidate)
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: implemented
|
||||
- Follow-up Action: draft-release (BAT-006)
|
||||
|
||||
#### Validation Plan
|
||||
- BAT-006 verification.md AC-1~8 모두 test evidence 연결 확인 (tests/test_portfolio_uuid.py, tests/test_cli.py 전체 통과)
|
||||
@@ -1,152 +0,0 @@
|
||||
# req-018: HTTP API portfolio path parameter UUID 전환 및 v1 asset_id UUID 반환
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Interface
|
||||
- Priority: High
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- HTTP API의 portfolio 관련 path parameter를 기존 문자열 `portfolio_id`에서 UUID 기반으로 전환해 REQ-016의 스키마 변경과 일관성을 맞춘다.
|
||||
- `GET /v1/assets` 응답의 `asset_id` 필드를 UUID로 반환해 trex-basic 계약을 갱신하고, dcy-002 A-3을 철회한다.
|
||||
|
||||
## Requirement
|
||||
- `app/api/portfolios.py`의 portfolio 관련 path parameter를 UUID 기반으로 변경한다.
|
||||
- `GET /v1/assets` 응답의 `asset_id` 필드는 `portfolios.portfolio_id`(UUID)를 반환한다.
|
||||
- `app/api/v1_assets.py`의 `AssetItem` 직렬화에서 `asset_id`는 `portfolio_id`(UUID) 값을 사용한다.
|
||||
- `POST /v1/assets/{asset_id}/ledger/trades` 경로의 `asset_id` path parameter는 UUID를 받아 `repo.get(asset_id)`로 portfolio를 조회한다.
|
||||
- dcy-002 문서의 A-3("asset_id는 portfolio_id를 그대로 사용") 조항은 이번 REQ 구현으로 공식 철회된다. `docs/discovery/dcy-002_20260502_trex-basic-consumer-api-contract.md`에 철회 주석을 추가한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given `GET /v1/assets`를 유효한 service-token으로 호출하면, When 응답 JSON의 `assets[].asset_id` 필드를 확인하면, Then 값이 UUID 형식(`re.match(r'^[0-9a-f-]{36}$', ...)`)이다.
|
||||
2. Given UUID를 `asset_id`로 사용해 `POST /v1/assets/{asset_id}/ledger/trades`를 호출하면, When 해당 UUID의 portfolio가 존재하면, Then HTTP 201(`status="new"`) 또는 HTTP 200(`status="duplicate"`)으로 정상 처리된다.
|
||||
3. Given UUID를 `asset_id`로 사용해 `POST /v1/assets/{asset_id}/ledger/trades`를 호출하면, When 해당 UUID의 portfolio가 존재하지 않으면, Then HTTP 404가 반환된다.
|
||||
4. Given portfolio 관련 HTTP API path(`/portfolios/{portfolio_id}`)를 UUID로 호출하면, When 해당 UUID의 portfolio가 존재하면, Then 정상 응답이 반환된다.
|
||||
5. Given `docs/discovery/dcy-002_20260502_trex-basic-consumer-api-contract.md`를 확인하면, Then A-3 항목에 이번 REQ 구현으로 철회되었다는 주석이 추가되어 있다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs:
|
||||
- `docs/interface-contract.md` (GET /v1/assets asset_id 변경 반영 — REQ-019에서 처리)
|
||||
- `docs/discovery/dcy-002_20260502_trex-basic-consumer-api-contract.md` (A-3 철회 주석 추가)
|
||||
- Modules:
|
||||
- `app/api/portfolios.py`: path parameter UUID 기반 전환
|
||||
- `app/api/v1_assets.py`: asset_id 직렬화 UUID 사용
|
||||
- `app/schemas/portfolio.py`, `app/schemas/v1.py`: asset_id/portfolio_id 필드 타입 문서화
|
||||
- Tests:
|
||||
- `tests/test_app.py` 또는 `tests/test_v1.py`: GET /v1/assets asset_id UUID 형식 검증, POST /v1/assets/{asset_id}/ledger/trades UUID 호출 정상 동작 확인
|
||||
|
||||
## Notes
|
||||
- trex-basic 측 코드 변경은 이번 REQ 범위 밖. portfolio-hub API 변경만 담당.
|
||||
- trex-basic과 portfolio-hub는 동시에 배포한다(NFR-3 — 동시 배포 계획 기록은 REQ-019에서 `docs/interface-contract.md`에 처리).
|
||||
- dcy-002 A-3 철회 주석 추가는 이 REQ 구현 시 함께 수행한다.
|
||||
- `GET /v1/assets` flow의 `asset_id` 직렬화: `docs/runtime-flows.md` Flow `v1 API — GET /v1/assets` 갱신 필요 (REQ-019에서 처리).
|
||||
- Source Discovery: dcy-004_20260511_portfolio-id-uuid-migration-and-user-scoped-name-resolution (FR-4)
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260511-01
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- 최초 생성 — dcy-004 draft-req에 의해 생성
|
||||
|
||||
#### Intent
|
||||
- dcy-004 Discovery의 FR-4(HTTP API path parameter UUID 전환, GET /v1/assets asset_id UUID 반환, dcy-002 A-3 철회) 반영
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- 1~5 (최초 생성)
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/interface-contract.md: GET /v1/assets asset_id 변경 반영 (REQ-019에서 처리)
|
||||
- docs/discovery/dcy-002_*: A-3 철회 주석 추가
|
||||
- Modules:
|
||||
- app/api/portfolios.py: path parameter UUID 전환
|
||||
- app/api/v1_assets.py: asset_id UUID 직렬화
|
||||
- app/schemas/portfolio.py, app/schemas/v1.py: 필드 타입 변경
|
||||
- Tests:
|
||||
- tests/test_app.py 또는 tests/test_v1.py: GET /v1/assets asset_id UUID 형식 검증
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: none (batch 미결정)
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: confirm-req → suggest-batch-reqs → draft-batch
|
||||
|
||||
#### Validation Plan
|
||||
- pytest: GET /v1/assets asset_id UUID 형식 검증, POST /v1/assets/{asset_id}/ledger/trades UUID 호출 동작 검증, HTTP 404 반환 확인
|
||||
|
||||
### CHG-20260511-02
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Approved 전환 — confirm-req 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- Delivery 입력으로 사용할 수 있도록 REQ-018을 승인 상태로 승격한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- none
|
||||
- Updated:
|
||||
- none
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- none
|
||||
- Modules:
|
||||
- none
|
||||
- Tests:
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- none
|
||||
- Releases:
|
||||
- none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: suggest-batch-reqs로 batch grouping 검토
|
||||
|
||||
#### Validation Plan
|
||||
- confirm-req 게이트 재평가 결과: 필수 메타데이터, 구체적 Acceptance Criteria, Impacted Area, Change Log, blocker 없음 확인
|
||||
|
||||
### CHG-20260511-03
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Implemented 전환 — BAT-006 verification passed, confirm-req-implemented 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- BAT-006 verification.md의 REQ-018 AC-1~5 모두 evidence 포함 (AC-1~4: 구현 코드 검증, AC-5: dcy-002 A-3 철회 주석 문서 확인). Blocking Issues 없음.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: BAT-006 (release-candidate)
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: implemented
|
||||
- Follow-up Action: draft-release (BAT-006); trex-basic 동시 배포 조정 필요
|
||||
|
||||
#### Validation Plan
|
||||
- BAT-006 verification.md AC-1~5 evidence 연결 확인; dcy-002 A-3 철회 주석 직접 확인 완료
|
||||
@@ -1,143 +0,0 @@
|
||||
# REQ-023: Daemon Registry 관리 경로
|
||||
|
||||
- Status: Approved
|
||||
- Type: Interface
|
||||
- Priority: High
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- service-token issue/rotate가 기존 daemon에만 binding할 수 있으려면, daemon을 사전에 생성·수정할 수 있는 별도 관리 경로(daemon registry CRUD)가 필요하다.
|
||||
- daemon provisioning은 service-token issuance와 분리된 경로에서 수행되어야 하며, REQ-005(issuance binding)와 REQ-012(rotate daemon_id 유지)의 전제 조건이 된다.
|
||||
|
||||
## Requirement
|
||||
- 시스템은 daemon을 생성·수정할 수 있는 별도 관리 경로를 제공해야 한다.
|
||||
- daemon은 owner user 내에서 unique한 `daemon_slug`(lowercase kebab-case)와 `daemon_display_name`(non-empty human-readable label)을 가진다.
|
||||
- 동일 owner user 내에서 중복 `daemon_slug`로 생성 시 명시적으로 거부한다.
|
||||
- daemon list 조회는 owner user 범위로 제한된다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given admin context에서 유효한 `daemon_slug`와 `daemon_display_name`으로 daemon create를 호출할 때, Then 새 daemon entry가 registry에 생성되고 `daemon_id`가 반환된다.
|
||||
2. Given 기존 daemon에 대해 `daemon_display_name` 수정을 요청할 때, Then daemon entry가 갱신된다.
|
||||
3. Given 동일 owner user 내에 이미 존재하는 `daemon_slug`로 daemon create를 요청할 때, Then 명시적 오류로 거부되고 중복 entry가 생성되지 않는다.
|
||||
4. Given daemon list 조회를 요청할 때, Then 인증된 user 소유의 daemon만 반환된다.
|
||||
5. Given `pfhub portfolio update <name> --user <username> --daemon-id <daemon_id>`를 실행할 때, Then 해당 portfolio의 `managed_by_daemon_id`가 지정한 daemon_id로 갱신된다.
|
||||
6. Given `pfhub portfolio list --user <username>`을 실행할 때, Then `managed_by_daemon_id`가 설정된 portfolio에는 해당 daemon_id가 출력에 포함되고, 미설정 portfolio에는 해당 항목이 출력되지 않는다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: `docs/interface-contract.md`, `docs/runtime-flows.md`
|
||||
- Modules: `app/domain/models.py`, `app/repositories/postgres.py`, `app/api/auth_routes.py` 또는 별도 daemon management route, `app/cli/commands/` (daemon subcommand 신규)
|
||||
- Modules (AC-5~6 추가): `app/cli/commands/portfolio.py` (`update` 명령 `--daemon-id` 옵션), `app/schemas/portfolio.py` (`UpdatePortfolioRequest.managed_by_daemon_id`, `PortfolioSummary.managed_by_daemon_id`), `app/services/portfolio_service.py` (`_to_portfolio_summary` 필드 전달), `app/cli/core/utils.py` (`print_portfolio_list` daemon 표시)
|
||||
- Tests: 신규 `tests/test_daemon_registry.py`
|
||||
|
||||
## Notes
|
||||
- service-token issuance의 unknown daemon 거부(REQ-005 AC-6), rotate daemon_id 유지 불변식(REQ-012 CHG-20260513-01)은 이 REQ의 daemon registry가 사전 구축된 상태를 전제한다.
|
||||
- daemon registry CRUD의 구체적인 transport 형태(HTTP endpoint vs CLI subcommand)는 구현 시 결정한다.
|
||||
- canonical 운영 표기: `<username>/<daemon_slug>`
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260518-01
|
||||
- Date: 2026-05-18
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- AC-5(`portfolio update --daemon-id`), AC-6(`portfolio list` daemon-id 표시) 추가 및 Impacted Area 보강. 구현 완료. Status Approved 유지.
|
||||
|
||||
#### Intent
|
||||
- daemon provisioning runbook에서 "asset → daemon 배정" 단계가 CLI로 수행 가능해야 한다. 기존 AC-1~4는 daemon registry CRUD만 다루며 portfolio-daemon 배정 경로가 누락되어 있었다. 운영팀 요청(2026-05-18)에 따라 `portfolio update --daemon-id` CLI 옵션과 `portfolio list` 결과의 daemon-id 표시를 REQ 범위에 추가한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-5: `pfhub portfolio update <name> --user <username> --daemon-id <daemon_id>`로 `managed_by_daemon_id` 갱신
|
||||
- AC-6: `pfhub portfolio list --user <username>` 결과에 `managed_by_daemon_id` 조건부 표시
|
||||
- Updated: 없음
|
||||
- Removed: 없음
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Modules:
|
||||
- `app/cli/commands/portfolio.py`: `update` 명령에 `--daemon-id` 옵션 추가
|
||||
- `app/schemas/portfolio.py`: `UpdatePortfolioRequest.managed_by_daemon_id`, `PortfolioSummary.managed_by_daemon_id` 필드 추가
|
||||
- `app/services/portfolio_service.py`: `_to_portfolio_summary`에 `managed_by_daemon_id` 전달 추가
|
||||
- `app/repositories/postgres.py`: `update_portfolio` allowed dict에 `managed_by_daemon_id` 추가
|
||||
- `app/cli/core/utils.py`: `print_portfolio_list`에 daemon 줄 조건부 출력 추가
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: BAT-010 (release-candidate) — AC-5~6 구현이 BAT-010 delivery scope에 포함
|
||||
- Releases: REL-006 (draft)
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: yes (AC-5~6 신규이므로 검증 증거 추가 필요)
|
||||
- Existing Implementation Invalidated: no (AC-1~4 기존 구현 유효)
|
||||
- Status Recommendation: keep-current (Approved)
|
||||
- Follow-up Action: BAT-010 verification.md에 AC-5~6 검증 증거 추가 후 Implemented 전환 가능
|
||||
|
||||
#### Validation Plan
|
||||
- `pfhub portfolio update <name> --user <user> --daemon-id <id> --force` 실행 후 DB `portfolios.managed_by_daemon_id` 값 확인
|
||||
- `pfhub portfolio list --user <user>` 출력에서 daemon-id 유무 항목별 표시 확인
|
||||
|
||||
### CHG-20260513-02
|
||||
- Date: 2026-05-13
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Status: Proposed → Approved (confirm-req 게이트 통과)
|
||||
|
||||
#### Intent
|
||||
- 필수 필드, AC, blocker 없음 확인 후 승인 전환
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added: 없음
|
||||
- Updated: 없음
|
||||
- Removed: 없음
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: 없음
|
||||
- Modules: 없음
|
||||
- Tests: 없음
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: 미정
|
||||
- Releases: 미정
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: 없음
|
||||
|
||||
#### Validation Plan
|
||||
- 없음 (상태 전환만)
|
||||
|
||||
### CHG-20260513-01
|
||||
- Date: 2026-05-13
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- dcy-006 FR-1의 daemon provisioning 관리 경로 부분만 추출해 신규 생성 (issuance binding·rotate invariant·fail-closed는 REQ-005/012/006/008에 이미 반영)
|
||||
|
||||
#### Intent
|
||||
- service-token issuance(REQ-005)와 rotate(REQ-012)의 전제가 되는 daemon registry CRUD 경로를 별도 REQ로 정의
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~4 전체 신규 추가
|
||||
- Updated: 없음
|
||||
- Removed: 없음
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: `docs/interface-contract.md`, `docs/runtime-flows.md`
|
||||
- Modules: daemon registry route, CLI subcommand
|
||||
- Tests: `tests/test_daemon_registry.py`
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: 미정
|
||||
- Releases: 미정
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: 없음 (신규 REQ)
|
||||
|
||||
#### Validation Plan
|
||||
- pytest로 daemon create/duplicate reject/update/list 시나리오 통과 확인
|
||||
@@ -1,69 +0,0 @@
|
||||
# REQ-029: CLI `portfolio list` 출력 — 테두리 없는 리스트 형식
|
||||
|
||||
- Status: Approved
|
||||
- Type: Interface
|
||||
- Priority: Low
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- `pfhub portfolio list` 기본 출력을 Rich Table(테두리 포함) 대신 항목별 텍스트 블록으로 변경해 터미널 폭에 구애받지 않는 가독성을 확보한다.
|
||||
- JSON 출력(`--format json`)은 기존과 동일하게 유지한다.
|
||||
|
||||
## Requirement
|
||||
- `pfhub portfolio list --user <username>` 명령의 기본 출력(text 형식)은 테두리·구분선 없는 리스트 형태로 각 portfolio를 표시해야 한다.
|
||||
- 각 항목은 3줄 블록으로 구성한다: (1) name/symbol/status/broker [tags], (2) cash/qty/price/buffer/total 수치, (3) portfolio_id.
|
||||
- `managed_by_daemon_id`가 설정된 항목은 (3) 다음 줄에 daemon_id를 추가로 표시하고, 미설정 항목은 해당 줄을 생략한다.
|
||||
- 항목 간에 빈 줄 한 줄로 구분한다.
|
||||
- `--format json` 옵션 사용 시 기존 JSON 응답을 그대로 반환한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given `pfhub portfolio list --user <username>` 실행 시, Then Rich Table 형식(헤더·테두리)이 아닌 텍스트 블록 리스트가 출력된다.
|
||||
2. 각 portfolio 항목은 name, symbol, status, broker 정보와 cash/qty/price/buffer/total 수치, portfolio_id를 포함한다.
|
||||
3. Given `managed_by_daemon_id`가 설정된 portfolio가 있을 때, Then 해당 항목에 daemon_id 줄이 추가로 표시된다.
|
||||
4. Given `pfhub portfolio list --user <username> --format json` 실행 시, Then JSON 배열이 반환되며 텍스트 블록 출력이 표시되지 않는다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: 없음
|
||||
- Modules:
|
||||
- `app/cli/core/utils.py`: `print_portfolio_table` 제거, `print_portfolio_list` 신규 구현, `render_output`에서 `print_portfolio_list` 호출
|
||||
- Tests: 기존 `tests/test_portfolio_uuid.py` 출력 내용 미검증이므로 별도 영향 없음
|
||||
|
||||
## Notes
|
||||
- 이 변경은 CLI 출력 형식만 변경하며 API, 데이터 모델, DB 스키마에는 영향을 주지 않는다.
|
||||
- REQ-023 AC-6(managed_by_daemon_id 표시)와 구현을 공유한다.
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260518-01
|
||||
- Date: 2026-05-18
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- 최초 생성 및 Approved 전환 — 운영팀 요청(2026-05-18)에 따라 `portfolio list` 출력 형식을 테두리 없는 리스트 형태로 변경 완료. 구현 및 사용자 확인 완료.
|
||||
|
||||
#### Intent
|
||||
- Rich Table 형식은 터미널 폭이 좁거나 항목 수가 많을 때 가독성이 떨어진다. 텍스트 블록 리스트는 항목별 스캔이 쉽고 터미널 폭 의존성이 없다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added: AC-1~4 (최초 생성)
|
||||
- Updated: 없음
|
||||
- Removed: 없음
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Modules:
|
||||
- `app/cli/core/utils.py`: `print_portfolio_table` → `print_portfolio_list` 교체, REQ-023 AC-6 daemon 줄 출력 포함
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: 미정 (minor-change fast path로 batch-lite 생성 예정)
|
||||
- Releases: 미정
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no (신규 REQ, 기존 구현 무효화 없음)
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: Approved
|
||||
- Follow-up Action: batch-lite 생성 → 검증 → confirm-req-implemented
|
||||
|
||||
#### Validation Plan
|
||||
- `pfhub portfolio list --user <username>` 실행 결과에 Rich Table 헤더·테두리가 없는지 확인
|
||||
- daemon-id 있는 항목과 없는 항목 혼재 시 조건부 표시 확인
|
||||
- `--format json` 옵션 시 JSON 반환 확인
|
||||
Reference in New Issue
Block a user