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:
@@ -0,0 +1,74 @@
|
||||
# REQ-001: tags 마스터 테이블 도입
|
||||
|
||||
- Status: Proposed
|
||||
- Type: Data
|
||||
- Priority: High
|
||||
- Owner: Justin Ko
|
||||
|
||||
## Intent
|
||||
- 태그를 자유 문자열이 아닌 정규화된 마스터 테이블로 관리하여 소유권(created_by_user_id), admin 구분(is_admin_tag), 생명주기(is_active)를 추적할 수 있는 기반을 마련한다.
|
||||
- is_admin_tag는 태그 생성 시점의 권한을 스냅샷으로 기록하며 이후 권한 변경과 무관하게 고정된다.
|
||||
- 태그 삭제는 is_active = FALSE soft delete로만 수행하여 기존 참조가 archived 상태임을 확인할 수 있게 한다.
|
||||
|
||||
## Requirement
|
||||
- 시스템은 다음 스키마로 `tags` 테이블을 생성해야 한다: `(tag_id UUID PK DEFAULT gen_random_uuid(), name TEXT NOT NULL, created_by_user_id TEXT NOT NULL REFERENCES users(id), is_admin_tag BOOLEAN NOT NULL DEFAULT FALSE, is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()), UNIQUE(name)`
|
||||
- 태그 생성 시 요청자가 admin 권한(Permission.ADMIN)이면 is_admin_tag = TRUE로 기록하며 이후 이 값을 변경하지 않는다.
|
||||
- 태그 비활성화는 is_active = FALSE로만 수행하며 hard DELETE는 사용하지 않는다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given Alembic 마이그레이션이 적용된 DB, When `tags` 테이블 스키마를 조회, Then tag_id (UUID NOT NULL PK), name (TEXT NOT NULL UNIQUE), created_by_user_id (TEXT NOT NULL REFERENCES users.id), is_admin_tag (BOOLEAN NOT NULL DEFAULT FALSE), is_active (BOOLEAN NOT NULL DEFAULT TRUE), created_at (TIMESTAMPTZ NOT NULL DEFAULT NOW()) 컬럼이 모두 존재한다.
|
||||
2. Given admin 권한 토큰으로 태그 생성 요청, When 태그 행이 INSERT, Then is_admin_tag = TRUE이고 이후 권한이 변경되어도 tags.is_admin_tag는 변경되지 않는다.
|
||||
3. Given 일반(non-admin) 사용자 토큰으로 태그 생성 요청, When 태그 행이 INSERT, Then is_admin_tag = FALSE이다.
|
||||
4. Given 활성화된 태그, When 비활성화 요청, Then is_active = FALSE로 설정되며 해당 행은 DB에서 삭제되지 않는다.
|
||||
5. Given is_active = FALSE인 태그, When 태그를 조회, Then 행이 반환되며 비활성 상태를 확인할 수 있다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/data-model.md (tags 테이블 추가)
|
||||
- Modules:
|
||||
- migrations/versions/ — tags 테이블 생성 Alembic revision
|
||||
- app/domain/models.py — Tag 도메인 모델 추가
|
||||
- app/repositories/portfolio_repository.py — tags CRUD 메서드 프로토콜 추가
|
||||
- app/repositories/postgres.py — tags INSERT/SELECT/UPDATE SQL 구현
|
||||
- Tests: tags 테이블 스키마 검증, is_admin_tag 스냅샷 동작 검증
|
||||
|
||||
## Notes
|
||||
- created_by_user_id는 REFERENCES users(id)로 외래키를 가진다. users 테이블은 기존에 존재한다 (migration 0004).
|
||||
- is_admin_tag 판단은 런타임 JOIN 없이 tags 테이블 컬럼만으로 수행된다 (dcy-002 A-1).
|
||||
- name UNIQUE 제약은 TEXT 수준에서 적용되며, 소문자 정규화는 애플리케이션 레이어(REQ-004)에서 수행한다.
|
||||
- Source: dcy-002 FR-1, NFR-1(부분), OQ-4
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260519-01
|
||||
- Date: 2026-05-19
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- 최초 생성 — dcy-002 confirm-discovery 후 REQ 초안 작성
|
||||
|
||||
#### Intent
|
||||
- dcy-002 FR-1을 구현 가능한 REQ 단위로 정규화
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~5 최초 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/data-model.md — tags 테이블 추가
|
||||
- Modules:
|
||||
- migrations/versions/, app/domain/models.py, 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 계획 편입
|
||||
@@ -0,0 +1,73 @@
|
||||
# REQ-002: assets.tag_ids UUID[] 컬럼 추가
|
||||
|
||||
- Status: Proposed
|
||||
- Type: Data
|
||||
- Priority: High
|
||||
- Owner: Justin Ko
|
||||
|
||||
## Intent
|
||||
- assets(portfolios) 테이블에 UUID[] 배열 컬럼을 추가하여 junction 테이블 없이 tags 마스터 테이블 기반 태그 참조를 저장한다.
|
||||
- GIN 인덱스로 배열 조회 성능을 확보하고, 비활성화된 태그는 조용히 제거하지 않고 archived 상태로 반환하여 이력 추적을 가능하게 한다.
|
||||
- 태그 적용 정책 검증(is_admin_tag=TRUE AND is_active=TRUE 확인, 403 반환)은 REQ-005에서 구현한다.
|
||||
|
||||
## Requirement
|
||||
- portfolios 테이블(asset에 해당)에 `tag_ids UUID[] NOT NULL DEFAULT '{}'` 컬럼을 추가해야 한다.
|
||||
- portfolios.tag_ids에 GIN 인덱스를 생성해야 한다.
|
||||
- tag_ids 배열에 is_active = FALSE인 tag_id가 포함된 경우, 해당 항목을 조용히 제거하지 않고 archived 상태임을 명시하여 반환해야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given Alembic 마이그레이션이 적용된 DB, When portfolios 테이블 스키마를 조회, Then tag_ids UUID[] NOT NULL DEFAULT '{}' 컬럼이 존재한다.
|
||||
2. Given 마이그레이션이 적용된 DB, When portfolios.tag_ids 인덱스를 조회, Then GIN 인덱스가 존재한다.
|
||||
3. Given asset의 tag_ids 배열에 is_active = FALSE인 tag_id가 포함, When 해당 asset의 태그 목록을 조회, Then 비활성 태그가 archived 표시와 함께 반환되며 배열에서 자동 제거되지 않는다.
|
||||
4. Given tag_ids = '{}' 기본값인 asset, When 태그가 적용되지 않은 상태로 조회, Then 빈 배열이 반환된다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/data-model.md (portfolios 스키마에 tag_ids 컬럼 추가)
|
||||
- Modules:
|
||||
- migrations/versions/ — portfolios.tag_ids 컬럼 추가 및 GIN 인덱스 생성 Alembic revision
|
||||
- app/domain/models.py — Portfolio 도메인 모델에 tag_ids 필드 추가
|
||||
- app/repositories/postgres.py — tag_ids 배열 조회 시 archived 표시 로직
|
||||
- app/schemas/v1.py — AssetItem에 tag_ids 필드 추가
|
||||
- Tests: portfolios 테이블 스키마 검증, GIN 인덱스 존재 확인, archived 표시 동작 확인
|
||||
|
||||
## Notes
|
||||
- dcy-001의 assets 테이블(portfolios)이 확정된 이후 이 REQ를 구현해야 한다 (dcy-002 R-2).
|
||||
- 배열 참조 무결성은 애플리케이션 레이어에서 보장한다 (dcy-002 NFR-2). PostgreSQL ARRAY FK는 미사용.
|
||||
- portfolios 테이블이 v1 API의 "asset" 개념에 해당한다 (portfolio_id = asset_id in v1 API).
|
||||
- Source: dcy-002 FR-2, NFR-2
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260519-01
|
||||
- Date: 2026-05-19
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- 최초 생성 — dcy-002 confirm-discovery 후 REQ 초안 작성
|
||||
|
||||
#### Intent
|
||||
- dcy-002 FR-2의 스키마 변경 부분을 독립 구현 단위로 분리
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~4 최초 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/data-model.md — tag_ids 컬럼 추가
|
||||
- Modules:
|
||||
- migrations/versions/, app/domain/models.py, app/repositories/postgres.py, app/schemas/v1.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 계획 편입
|
||||
@@ -0,0 +1,73 @@
|
||||
# REQ-003: portfolios.tag_ids UUID[] 컬럼 추가 및 portfolio_tags 테이블 제거
|
||||
|
||||
- Status: Proposed
|
||||
- Type: Data
|
||||
- Priority: High
|
||||
- Owner: Justin Ko
|
||||
|
||||
## Intent
|
||||
- portfolios 테이블에 UUID[] 배열 컬럼을 추가하고 기존 자유 문자열 기반 portfolio_tags 테이블을 제거하여 tags 마스터 테이블 기반 태그 참조 구조로 전환한다.
|
||||
- 이 REQ는 스키마 변경에만 집중하며, 기존 portfolio_tags 데이터 이전 절차는 REQ-006에서 다룬다.
|
||||
- GIN 인덱스로 배열 조회 성능을 확보하고, 비활성 태그는 archived로 표시한다.
|
||||
|
||||
## Requirement
|
||||
- portfolios 테이블에 `tag_ids UUID[] NOT NULL DEFAULT '{}'` 컬럼을 추가해야 한다.
|
||||
- portfolios.tag_ids에 GIN 인덱스를 생성해야 한다.
|
||||
- REQ-006 데이터 마이그레이션 완료 후 portfolio_tags 테이블을 DROP해야 한다.
|
||||
- portfolios.tag_ids에 is_active = FALSE인 tag_id가 포함된 경우, archived 상태임을 명시하여 반환해야 하며 자동 제거하지 않는다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given Alembic 마이그레이션(REQ-006 포함)이 적용된 DB, When portfolios 테이블 스키마를 조회, Then tag_ids UUID[] NOT NULL DEFAULT '{}' 컬럼이 존재한다.
|
||||
2. Given 마이그레이션이 적용된 DB, When portfolios.tag_ids 인덱스를 조회, Then GIN 인덱스가 존재한다.
|
||||
3. Given 마이그레이션이 적용된 DB, When DB 스키마를 조회, Then portfolio_tags 테이블이 존재하지 않는다.
|
||||
4. Given portfolio의 tag_ids 배열에 is_active = FALSE인 tag_id가 포함, When 해당 portfolio의 태그 목록을 조회, Then 비활성 태그가 archived 표시와 함께 반환되며 배열에서 자동 제거되지 않는다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/data-model.md (portfolios 스키마에 tag_ids 추가, portfolio_tags 테이블 제거 반영)
|
||||
- Modules:
|
||||
- migrations/versions/ — portfolios.tag_ids 컬럼 추가, GIN 인덱스 생성, portfolio_tags DROP Alembic revision
|
||||
- app/domain/models.py — Portfolio 도메인 모델에 tag_ids 필드 추가
|
||||
- app/repositories/postgres.py — portfolio tag_ids 배열 조작 메서드, archived 표시 로직
|
||||
- app/schemas/ — PortfolioItem에 tag_ids 필드 추가 (해당 스키마 존재 시)
|
||||
- Tests: portfolios 테이블 스키마 검증, portfolio_tags 테이블 부재 확인, GIN 인덱스 존재 확인, archived 표시 동작
|
||||
|
||||
## Notes
|
||||
- REQ-006(portfolio_tags 데이터 마이그레이션)이 선행되어야 한다. portfolio_tags DROP은 데이터 마이그레이션 완료 후 수행.
|
||||
- 기존 `pfhub portfolio tag add/list/remove` 명령어는 portfolio_tags 테이블에 의존하므로 이 REQ와 함께 비활성화/제거한다 (REQ-007 참조).
|
||||
- Source: dcy-002 FR-3, NFR-2
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260519-01
|
||||
- Date: 2026-05-19
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- 최초 생성 — dcy-002 confirm-discovery 후 REQ 초안 작성
|
||||
|
||||
#### Intent
|
||||
- dcy-002 FR-3의 스키마 변경을 독립 REQ 단위로 분리
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~4 최초 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/data-model.md — portfolio_tags 제거, tag_ids 추가
|
||||
- Modules:
|
||||
- migrations/versions/, app/domain/models.py, app/repositories/postgres.py, app/schemas/ — 최초 지정
|
||||
- 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-006 선행 의존성 확인
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
# req-020: 실배포 admin bootstrap 및 steady-state operator access runbook
|
||||
|
||||
- Status: Approved
|
||||
- Type: Deployment
|
||||
- Priority: High
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- 실배포 환경에서 admin auth context를 확보하는 경로가 문서화되지 않으면, 운영자는 release smoke를 재현 가능하게 수행할 수 없고 bootstrap과 steady-state access를 혼동해 보안 사고가 발생할 수 있다.
|
||||
- README.md Production Operator Runbook에 admin bootstrap(신규 환경/disaster recovery 전용), steady-state canonical access(운영자 개인 admin 로그인), break-glass fallback(env admin token) 3-tier 경로를 명시하고 각 경로의 사용 조건을 구분한다.
|
||||
|
||||
## Requirement
|
||||
- README.md Production Operator Runbook 섹션은 다음 3-tier 경로를 조건과 함께 구분하여 문서화해야 한다.
|
||||
1. **bootstrap path**: `PORTFOLIOHUB_BOOTSTRAP_*` 기반 초기 사용자 생성. `users` 테이블이 비어 있는 신규 환경 또는 disaster recovery 직후 admin 사용자 부재가 확인된 경우에만 허용.
|
||||
2. **steady-state canonical path**: 운영자 소유 admin 사용자 계정으로 `/auth/login`하여 DB-issued admin session 또는 동일 컨텍스트에서 발급한 client token 확보. 이 admin context로 `POST /auth/service-tokens`를 호출해 release smoke용 read/trade-write service-token을 발급.
|
||||
3. **break-glass fallback**: 환경 변수 기반 admin token을 `/opt/portfoliohub/.env`에서 꺼내는 경로. 운영자 로그인 경로가 모두 막혔을 때만 허용. 정기 smoke의 표준 경로로 사용 금지.
|
||||
- 각 경로의 사용 조건, 운영 책임 역할(deployment secret custodian, production operator/release approver), secret 보관 위치(`/opt/portfoliohub/.env` / `EnvironmentFile`)를 명시한다.
|
||||
- raw credential, raw token, bootstrap password는 README 또는 release 문서에 기록하지 않는다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given README.md Production Operator Runbook 섹션이 존재할 때, When 운영자가 섹션을 읽을 때, Then bootstrap path / steady-state canonical path / break-glass fallback이 각각 사용 조건과 함께 구분되어 기술되어 있어야 한다.
|
||||
2. Given `users` 테이블이 비어 있지 않은 실배포 환경에서, When `PORTFOLIOHUB_BOOTSTRAP_*` 기반 bootstrap 로직이 실행될 때, Then 기존 사용자를 덮어쓰거나 중복 생성하지 않고 bootstrap을 건너뛰어야 한다 (idempotency 보장).
|
||||
3. Given README runbook에 역할 책임이 명시되어 있을 때, When 운영자가 runbook을 참조할 때, Then deployment secret custodian과 production operator/release approver 역할이 구분되어 있고 secret 보관 위치(`/opt/portfoliohub/.env`)가 명시되어 있어야 한다.
|
||||
4. Given 운영자가 steady-state canonical path를 따를 때, When `/auth/login` → `POST /auth/service-tokens` 순서로 실행할 때, Then admin session token 기반 service-token 발급 성공 경로가 runbook에 기술되어 있어야 한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: `README.md` — Production Operator Runbook 섹션 (3-tier 경로 구분 및 역할 책임 보강)
|
||||
- Modules: `app/core/config.py` (bootstrap 환경 변수 운영 제약 확인), `app/main.py` (bootstrap idempotency 동작 확인)
|
||||
- Tests: bootstrap idempotency는 기존 구현 확인으로 대체 가능. 별도 신규 테스트 불필요.
|
||||
|
||||
## Notes
|
||||
- NFR-1 (raw credential 비노출): 이 REQ의 핵심 제약으로 포함됨. Release 문서, README 등 모든 운영 문서에서 raw value 기록 금지.
|
||||
- NFR-3 (bootstrap idempotency): `app/main.py`에서 `users` 테이블이 비어 있을 때만 bootstrap 사용자를 생성하는 로직이 기존에 구현되어 있음. AC-2는 기존 구현 확인으로 검증한다.
|
||||
- `/auth/login` 엔드포인트가 실제 구현되어 있어야 steady-state canonical path가 완성된다. 현재 저장소에 로그인 엔드포인트가 없으면 해당 AC는 구현 시 재검토가 필요하다.
|
||||
- 이 REQ는 기능 추가보다 운영 절차 문서화가 주 목적이다. 코드 변경이 필요할 경우 최소 범위로 제한한다.
|
||||
- Source Discovery: dcy-005 FR-1
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260512-02
|
||||
- Date: 2026-05-12
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Status: Proposed → Approved (confirm-req 게이트 통과)
|
||||
|
||||
#### Intent
|
||||
- 필수 필드, AC, Notes blocker 없음 확인 후 승인 전환
|
||||
|
||||
#### 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: none
|
||||
|
||||
#### Validation Plan
|
||||
- 승인 전환만 수행, 추가 검증 불필요
|
||||
|
||||
### CHG-20260512-01
|
||||
- Date: 2026-05-12
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ 초안 생성 (dcy-005 FR-1 기반)
|
||||
|
||||
#### Intent
|
||||
- 실배포 admin bootstrap 및 steady-state access 경로 운영 문서화 요구사항 정의
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~4 초안 생성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- README.md Production Operator Runbook 섹션
|
||||
- Modules:
|
||||
- app/core/config.py, app/main.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: none
|
||||
|
||||
#### Validation Plan
|
||||
- README.md Production Operator Runbook 섹션의 3-tier 경로 구분 확인
|
||||
- app/main.py bootstrap idempotency 코드 리뷰로 AC-2 검증
|
||||
@@ -1,148 +0,0 @@
|
||||
# req-003: 로컬 DB 운영 runbook 및 baseline 문서 갱신
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Documentation
|
||||
- Priority: Medium
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- 이 요구사항은 로컬 docker compose 기반 DB 검증 결과를 운영자가 반복 사용할 수 있는 runbook과 baseline 문서로 정리하기 위한 문서화 backlog를 정의한다.
|
||||
- README, docs/runtime-flows.md, docs/project-structure.md에 로컬 DB 준비 절차, release gate 기준, rollback 또는 재시도 판단 기준을 반영하는 것이 목표다.
|
||||
|
||||
## Requirement
|
||||
- 프로젝트는 로컬 docker compose 기반 DB 검증 범위를 반영해 README, docs/runtime-flows.md, docs/project-structure.md를 갱신해야 하며, init-db와 migrate-db 실행 흐름, release gate 증거, rollback 또는 재시도 판단 기준을 운영자가 추적 가능한 runbook 형태로 정리해야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given 로컬 DB validation 범위가 확정되어 있을 때, When README를 갱신하면, Then docker compose 기반 준비 절차, init-db와 migrate-db 실행 순서, health-check 및 smoke flow 검증 기준이 포함되어 있어야 한다.
|
||||
2. Given Alembic와 runtime ownership 경계가 정리될 때, When docs/project-structure.md와 docs/runtime-flows.md를 갱신하면, Then 구조 제약과 실행 흐름 제약이 baseline 문서에 반영되어 있어야 한다.
|
||||
3. Given 이번 Discovery의 release gate가 로컬 DB validation 기준으로 확정되어 있을 때, When 운영 runbook을 작성하면, Then rollback 또는 재시도 판단 기준과 남겨야 할 검증 로그가 문서에 명시되어 있어야 한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: README.md, docs/project-structure.md, docs/runtime-flows.md, docs/discovery/dcy-001_20260430_real-db-migration-validation-and-operations-readiness.md
|
||||
- Modules: app/cli/commands/health.py, app/db/migrations.py, app/repositories/postgres.py
|
||||
- Tests: 문서 기반 수동 검증 체크리스트와 release gate evidence review 절차
|
||||
|
||||
## Notes
|
||||
- 이 요구사항은 dcy-001의 FR-3 일부, FR-4, NFR-3, S-3을 구현 가능한 Documentation 단위로 정규화한 것이다.
|
||||
- baseline 문서 전체를 복제하지 않고, 로컬 DB 검증과 직접 관련된 구조 제약과 흐름 제약만 업데이트 대상으로 삼는다.
|
||||
- 성공 지표의 세부 artifact 위치는 REQ 승인 또는 batch planning에서 확정할 수 있다.
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260511-01
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Implemented 전환 — BAT-007 verification passed, confirm-req-implemented 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- BAT-007 verification.md AC-1~3 모두 PASS. Blocking Issues 없음. README.md "Local DB Validation Runbook"(rollback 판단 기준, release gate criteria 포함), docs/project-structure.md "Schema Ownership Boundary", docs/runtime-flows.md 흐름 갱신 evidence 연결 확인 완료.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: BAT-007 (release-candidate)
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: implemented
|
||||
- Follow-up Action: draft-release (BAT-007)
|
||||
|
||||
#### Validation Plan
|
||||
- BAT-007 verification.md AC-1~3 evidence 연결 확인 완료
|
||||
|
||||
### CHG-20260430-02
|
||||
- Date: 2026-04-30
|
||||
- Author: GitHub Copilot
|
||||
|
||||
#### Change Summary
|
||||
- confirm-req 승인 게이트를 통과해 이 REQ를 Approved로 전환했다.
|
||||
|
||||
#### Intent
|
||||
- dcy-001의 delivery input으로 사용할 수 있는 확정 requirement로 승격하기 위해 상태를 변경했다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- none
|
||||
- Updated:
|
||||
- none
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/srs/index.md
|
||||
- Modules:
|
||||
- none
|
||||
- Tests:
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- none
|
||||
- Releases:
|
||||
- none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: approved
|
||||
- Follow-up Action: suggest-batch-reqs 또는 draft-batch 단계에서 REQ-003의 runbook 산출물 범위를 delivery scope로 연결한다.
|
||||
|
||||
#### Validation Plan
|
||||
- REQ 본문 필수 섹션, Acceptance Criteria 구체성, docs/srs/index.md 상태 동기화를 확인한다.
|
||||
|
||||
### CHG-20260430-01
|
||||
- Date: 2026-04-30
|
||||
- Author: GitHub Copilot
|
||||
|
||||
#### Change Summary
|
||||
- dcy-001에서 로컬 DB 운영 runbook 및 baseline 문서 갱신 요구사항을 신규 Proposed REQ로 생성했다.
|
||||
|
||||
#### Intent
|
||||
- 운영 준비 산출물과 baseline 문서 갱신 요구를 독립 Documentation backlog로 관리하기 위해 생성했다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- README 로컬 DB 검증 절차 갱신 기준 정의
|
||||
- docs/project-structure.md와 docs/runtime-flows.md baseline 갱신 기준 정의
|
||||
- rollback 또는 재시도 판단 기준과 로그 수집 기준 정의
|
||||
- Updated:
|
||||
- none
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- README.md
|
||||
- docs/project-structure.md
|
||||
- docs/runtime-flows.md
|
||||
- docs/discovery/dcy-001_20260430_real-db-migration-validation-and-operations-readiness.md
|
||||
- Modules:
|
||||
- app/cli/commands/health.py
|
||||
- app/db/migrations.py
|
||||
- app/repositories/postgres.py
|
||||
- Tests:
|
||||
- 문서 기반 수동 검증 체크리스트와 release gate evidence review 절차
|
||||
|
||||
#### 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 단계에서 baseline 문서 갱신 범위와 runbook 산출물 위치를 검토하고 승인한다.
|
||||
|
||||
#### Validation Plan
|
||||
- confirm-req 전까지 Acceptance Criteria가 dcy-001의 FR-3 일부, FR-4, NFR-3, S-3와 일치하는지 검토하고, 이후 batch 단계에서 README 및 baseline 문서 갱신안을 작성한다.
|
||||
@@ -0,0 +1,73 @@
|
||||
# REQ-008: 태그 모델 도입 baseline 문서 갱신
|
||||
|
||||
- Status: Proposed
|
||||
- Type: Documentation
|
||||
- Priority: Low
|
||||
- Owner: Justin Ko
|
||||
|
||||
## Intent
|
||||
- dcy-002에서 정의한 tags 마스터 테이블, UUID[] 배열 방식, HTTP API, CLI 변경 내용을 project-structure, runtime-flows, data-model, interface-contract 문서에 반영하여 baseline을 최신 상태로 유지한다.
|
||||
- 구현 완료 후 문서가 실제 코드와 일치하지 않으면 다음 Discovery/REQ 작성 시 잘못된 baseline 참조로 이어질 수 있으므로 구현 완료 시점에 함께 갱신한다.
|
||||
|
||||
## Requirement
|
||||
- docs/data-model.md에 tags 테이블 스키마, assets(portfolios).tag_ids UUID[] 컬럼, portfolio_tags 테이블 제거를 반영해야 한다.
|
||||
- docs/interface-contract.md에 /v1/tags (POST/GET/PATCH), /v1/assets/{asset_id}/tags (POST/DELETE), /v1/portfolios/{portfolio_id}/tags (POST/DELETE) 엔드포인트 명세를 추가해야 한다.
|
||||
- docs/project-structure.md에 pfhub tag 커맨드 그룹 추가, app/api/ 태그 모듈 추가, pfhub portfolio tag 제거를 반영해야 한다.
|
||||
- docs/runtime-flows.md에 tag 관련 CLI 흐름(create, list, deactivate, apply, remove)과 HTTP 흐름을 추가해야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given 구현 완료 후, When docs/data-model.md를 검토, Then tags 테이블 스키마(tag_id, name, created_by_user_id, is_admin_tag, is_active, created_at), portfolios.tag_ids UUID[] 컬럼, portfolio_tags 테이블 제거가 반영되어 있다.
|
||||
2. Given 구현 완료 후, When docs/interface-contract.md를 검토, Then /v1/tags (POST/GET/PATCH) 및 /v1/assets/{id}/tags, /v1/portfolios/{id}/tags (POST/DELETE) 엔드포인트 명세가 포함되어 있다.
|
||||
3. Given 구현 완료 후, When docs/project-structure.md를 검토, Then pfhub tag 커맨드 그룹이 CLI Command groups에 포함되고 app/api/ 섹션에 태그 API 모듈이 반영되어 있다.
|
||||
4. Given 구현 완료 후, When docs/runtime-flows.md를 검토, Then pfhub tag 커맨드 실행 흐름과 /v1/tags 관련 HTTP 흐름이 문서화되어 있다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs:
|
||||
- docs/data-model.md
|
||||
- docs/interface-contract.md
|
||||
- docs/project-structure.md
|
||||
- docs/runtime-flows.md
|
||||
- Modules: 없음 (문서 전용)
|
||||
- Tests: 없음 (문서 검토로 확인)
|
||||
|
||||
## Notes
|
||||
- 이 REQ는 REQ-001~007 구현 완료 후 마지막으로 수행한다.
|
||||
- data-model.md와 interface-contract.md는 dcy-002 영향 범위에 명시된 문서이다.
|
||||
- project-structure.md와 runtime-flows.md는 baseline 참조 문서로, 신규 CLI 커맨드 그룹과 API 흐름이 추가되면 함께 갱신해야 한다 (docs/project-structure.md Update Triggers: "새 top-level runtime 또는 domain 모듈이 추가되었을 때").
|
||||
- Source: dcy-002 영향 범위, skill 규칙 0(baseline 문서 갱신 REQ)
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260519-01
|
||||
- Date: 2026-05-19
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- 최초 생성 — dcy-002 confirm-discovery 후 REQ 초안 작성
|
||||
|
||||
#### Intent
|
||||
- dcy-002 영향 범위의 문서 갱신 요구를 Documentation REQ로 분리; baseline 문서 갱신 의무 명시
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~4 최초 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/data-model.md, docs/interface-contract.md, docs/project-structure.md, docs/runtime-flows.md — 최초 지정
|
||||
- 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: REQ-001~007 구현 완료 후 일괄 반영
|
||||
@@ -1,176 +0,0 @@
|
||||
# req-011: trex-basic 계약 반영을 위한 baseline 문서 갱신
|
||||
|
||||
- Status: Approved
|
||||
- Type: Documentation
|
||||
- Priority: Medium
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- dcy-002 구현 완료 후 interface-contract.md, data-model.md, runtime-flows.md를 실제 구현 결과와 동기화한다.
|
||||
- dcy-006의 daemon-aware 변경으로 baseline 문서는 runtime_id 중심 설명을 daemon binding/assignment 모델로 다시 정렬해야 한다.
|
||||
- 이 REQ는 구현이 완료된 시점에 수행하는 문서 갱신이며, 구현 전 선행 작업이 아니다.
|
||||
|
||||
## Requirement
|
||||
- REQ-005~009, REQ-012의 daemon-aware 변경이 구현 완료(Implemented)된 시점에 다음 3개 baseline 문서를 갱신해야 한다.
|
||||
1. docs/interface-contract.md: `POST /auth/service-tokens`, `GET /v1/assets`, `GET /v1/user_info`, `POST /v1/assets/{asset_id}/ledger/trades`의 daemon binding / daemon-scoped contract, `403` mismatch 정책, service-token bearer 인증 방식을 반영
|
||||
2. docs/data-model.md: `daemons` 테이블, `auth_tokens.daemon_id`, `portfolios.managed_by_daemon_id`, `auth_tokens.runtime_id`의 역할 분리와 transition `NULL` backfill 정책 반영
|
||||
3. docs/runtime-flows.md: daemon registry binding, `/v1/*` daemon-scoped read/write 흐름, rotate 시 `daemon_id` 유지 + `runtime_id` 갱신 불변식 반영
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given docs/interface-contract.md를 검토하면, Then `POST /auth/service-tokens`, `GET /v1/assets`, `GET /v1/user_info`, `POST /v1/assets/{asset_id}/ledger/trades`의 daemon-aware 요청/응답 명세와 `403` mismatch 정책이 포함되어야 한다.
|
||||
2. Given docs/data-model.md를 검토하면, Then `daemons`, `broker_credentials`, `ledger_trades` 테이블과 `portfolios.market`, `portfolios.managed_by_daemon_id`, `auth_tokens.runtime_id`, `auth_tokens.daemon_id`가 문서화되어야 한다.
|
||||
3. Given docs/runtime-flows.md를 검토하면, Then daemon registry binding 흐름, daemon-scoped v1 API 처리 흐름, rotate 시 `runtime_id`/`daemon_id` 역할 차이가 포함되어야 한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/interface-contract.md, docs/data-model.md, docs/runtime-flows.md
|
||||
- Modules: 없음
|
||||
- Tests: 없음
|
||||
|
||||
## Notes
|
||||
- 이 REQ는 구현 완료 후 수행하므로 batch 설계 단계에서 별도 implementation task로 명시한다.
|
||||
- 문서 갱신 내용은 draft-batch-verification 단계에서 실제 구현과 비교해 검증한다.
|
||||
- README.md 운영 provenance / release 절차 변경은 REQ-021 및 후속 dcy-006 REQ에서 다룬다.
|
||||
- Source Discovery: dcy-002 (전체 FR/NFR 구현 완료 후 documentation closure), dcy-006 (FR-5, FR-6, NFR-1)
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260513-01
|
||||
- Date: 2026-05-13
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- baseline 문서 REQ를 daemon-aware v1 contract 반영 범위로 확장하고, 기존 Implemented 상태를 Approved로 되돌림
|
||||
|
||||
#### Intent
|
||||
- dcy-006은 interface-contract, data-model, runtime-flows가 모두 daemon binding/assignment와 runtime_id/daemon_id 역할 분리를 반영하도록 요구한다. BAT-008/REL-002 문서 evidence는 runtime_id 중심 baseline만 다뤘으므로 revised REQ를 충족하지 못한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- none
|
||||
- Updated:
|
||||
- AC-1~3: daemon-aware contract, data model, runtime flow 기준으로 재정의
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- `docs/interface-contract.md`, `docs/data-model.md`, `docs/runtime-flows.md`
|
||||
- Modules:
|
||||
- none
|
||||
- Tests:
|
||||
- none (문서 리뷰 및 delivery verification evidence 중심)
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-008 (release-candidate; REL-002 released input) — 기존 verification evidence는 daemon-aware baseline을 포함하지 않아 재작성 필요
|
||||
- Releases:
|
||||
- REL-002 (released) — released baseline docs scope가 revised REQ 대비 불완전
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: yes
|
||||
- Existing Implementation Invalidated: yes
|
||||
- Status Recommendation: rollback-to-approved
|
||||
- Follow-up Action: dcy-006 후속 batch에서 daemon-aware baseline docs를 갱신하고 BAT-008에 대응하는 새 verification evidence를 작성한다.
|
||||
|
||||
#### Validation Plan
|
||||
- dcy-006 FR-5/FR-6와 현행 baseline 문서를 대조해 누락된 daemon contract 항목을 식별한다.
|
||||
- 구현 후 문서 리뷰와 batch verification에서 interface/data/runtime 3축이 모두 갱신됐는지 확인한다.
|
||||
|
||||
### CHG-20260511-01
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Implemented 전환 — BAT-008 verification passed, confirm-req-implemented 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- BAT-008 verification.md에서 REQ-011 AC-1~3의 문서화 기준과 evidence가 모두 PASS로 확인되어 Implemented로 승격한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added: none
|
||||
- Updated: none
|
||||
- Removed: none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: none
|
||||
- Modules: none
|
||||
- Tests: none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-008 (release-candidate)
|
||||
- Releases:
|
||||
- none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: implemented
|
||||
- Follow-up Action: draft-release 시 BAT-008 포함 여부 검토
|
||||
|
||||
#### Validation Plan
|
||||
- BAT-008 verification.md의 REQ-011 AC-1~3 evidence와 Ready for Release: true 확인
|
||||
|
||||
### CHG-20260502-02
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-011 confirm-req 승인 전환 (Status: Proposed → Approved)
|
||||
|
||||
#### Intent
|
||||
- 필수 필드(Status, Type, Priority, Owner, Intent, Requirement, Acceptance Criteria 3개, 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. REQ-004~010 Implemented 전환 후 실행.
|
||||
|
||||
### CHG-20260502-01
|
||||
- Date: 2026-05-02
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ-011 최초 생성 (source Discovery: dcy-002 문서화 클로저)
|
||||
|
||||
#### Intent
|
||||
- dcy-002 구현 완료 후 baseline 문서 갱신 요구사항을 독립 Documentation REQ로 정규화
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- 전체 Acceptance Criteria 신규 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/interface-contract.md
|
||||
- docs/data-model.md
|
||||
- docs/runtime-flows.md
|
||||
- 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: confirm-req 후 batch 배정. REQ-004~010 모두 Implemented 전환 후 이 REQ를 별도 구현 task로 수행.
|
||||
@@ -1,145 +0,0 @@
|
||||
# req-019: portfolio UUID 전환 관련 baseline 문서 갱신
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Documentation
|
||||
- Priority: Medium
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- REQ-016~018의 구현으로 변경되는 DB 스키마, CLI 흐름, HTTP API 계약을 baseline 문서(`docs/project-structure.md`, `docs/runtime-flows.md`, `docs/data-model.md`, `docs/interface-contract.md`)에 반영해 문서와 구현 간 불일치를 방지한다.
|
||||
- trex-basic 동시 배포 계획을 `docs/interface-contract.md`에 기록한다.
|
||||
|
||||
## Requirement
|
||||
- `docs/project-structure.md`를 갱신해 `app/repositories/postgres.py`에 신규 추가된 `get_portfolio_by_name_and_user()` 메서드와 `app/domain/models.py`의 `portfolio_id`(UUID 문자열) 의미 변경을 반영한다.
|
||||
- `docs/runtime-flows.md`를 갱신해 아래를 반영한다.
|
||||
- CLI 명령 흐름: `<name>` + `--user <username>` 조합으로 portfolio를 식별하고 내부에서 UUID를 조회하는 흐름
|
||||
- `v1 API — GET /v1/assets` flow: `asset_id` 필드가 UUID를 반환함
|
||||
- `docs/data-model.md`를 갱신해 `portfolios` 테이블의 `portfolio_id`(UUID, TEXT, PRIMARY KEY), `name`(TEXT) 신규 컬럼, `(owner_user_id, name)` 복합 UNIQUE 제약을 반영한다.
|
||||
- `docs/interface-contract.md`를 갱신해 `GET /v1/assets` `asset_id` 필드가 UUID를 반환함을 기록하고, trex-basic과 portfolio-hub의 동시 배포 계획을 명시한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given `docs/project-structure.md`를 검토하면, Then `app/repositories/postgres.py` 설명에 `get_portfolio_by_name_and_user()` 메서드가 언급되고, `app/domain/models.py`의 `portfolio_id`가 UUID 기반임이 반영된다.
|
||||
2. Given `docs/runtime-flows.md`를 검토하면, Then CLI 명령 흐름 설명에 `<name>` + `--user <username>` 조합 식별 방식이 반영되고, `v1 API — GET /v1/assets` flow에 `asset_id`가 UUID임이 명시된다.
|
||||
3. Given `docs/data-model.md`를 검토하면, Then `portfolios` 테이블 스키마에 `portfolio_id`(UUID TEXT, PK), `name`(TEXT), `(owner_user_id, name)` UNIQUE 제약이 반영된다.
|
||||
4. Given `docs/interface-contract.md`를 검토하면, Then `GET /v1/assets` `asset_id` 필드가 UUID를 반환함이 명시되고, trex-basic과 portfolio-hub의 동시 배포 계획이 기록된다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs:
|
||||
- `docs/project-structure.md`
|
||||
- `docs/runtime-flows.md`
|
||||
- `docs/data-model.md`
|
||||
- `docs/interface-contract.md`
|
||||
- Modules: 없음 (문서 전용)
|
||||
- Tests: 없음 (문서 전용)
|
||||
|
||||
## Notes
|
||||
- 이 REQ는 REQ-016, REQ-017, REQ-018 구현 완료 후 또는 동일 batch에서 함께 처리하는 것이 적절하다.
|
||||
- trex-basic 측 코드 변경은 이번 범위 밖이며, 동시 배포 계획을 문서화하는 것만 이 REQ 범위에 포함된다.
|
||||
- NFR-1(단일 revision, IF NOT EXISTS, atomic)은 REQ-016에 흡수. NFR-2(단일 DB 쿼리, 오류 메시지)는 REQ-017에 흡수. NFR-3(동시 배포 계획 기록)은 이 REQ에서 처리.
|
||||
- Source Discovery: dcy-004_20260511_portfolio-id-uuid-migration-and-user-scoped-name-resolution (FR-6, NFR-3)
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260511-01
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- 최초 생성 — dcy-004 draft-req에 의해 생성
|
||||
|
||||
#### Intent
|
||||
- dcy-004 Discovery의 FR-6(docs/project-structure.md, docs/runtime-flows.md 갱신), NFR-3(동시 배포 계획 docs/interface-contract.md 기록) 반영. docs/data-model.md, docs/interface-contract.md 갱신 포함.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- 1~4 (최초 생성)
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/project-structure.md
|
||||
- docs/runtime-flows.md
|
||||
- docs/data-model.md
|
||||
- docs/interface-contract.md
|
||||
|
||||
#### 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
|
||||
- 각 baseline 문서에 변경 내용이 포함됐는지 코드 리뷰로 확인
|
||||
|
||||
### CHG-20260511-02
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Approved 전환 — confirm-req 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- Delivery 입력으로 사용할 수 있도록 REQ-019를 승인 상태로 승격한다.
|
||||
|
||||
#### 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-019 AC-1~4 모두 baseline 문서 변경 내용 직접 확인으로 evidence 충족. 문서 전용 REQ로 테스트 불필요. 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~4: project-structure.md / runtime-flows.md / data-model.md / interface-contract.md 각 문서 변경 내용 manual 확인 완료
|
||||
-154
@@ -1,154 +0,0 @@
|
||||
# req-021: release 검증 credential matrix 및 token provenance 운영 절차
|
||||
|
||||
- Status: Approved
|
||||
- Type: Documentation
|
||||
- Priority: High
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- release 검증에 사용하는 credential의 용도, 발급 주체, 보관 위치, 폐기 절차가 정의되지 않으면 smoke 재현성이 없어지고 secret leakage 위험이 높아진다.
|
||||
- public/no-auth, read service-token, trade-write service-token, admin auth context 4개 credential 관점의 matrix를 문서화하고, daemon-aware CLI/API를 token provenance 확인 canonical path로 명시한다.
|
||||
|
||||
## Requirement
|
||||
- README.md Production Operator Runbook 또는 연결된 운영 문서는 아래 credential matrix를 명시해야 한다.
|
||||
- **public/no-auth**: `GET /health`, `/docs`, `/openapi.json`. 인증 불필요. 배포 직후 공개 smoke에 사용.
|
||||
- **read service-token**: `GET /v1/assets`, `GET /v1/user_info`. 환경 단위 운영 credential. 발급: admin context로 `POST /auth/service-tokens` 후 existing `daemon_id`에 binding. 보관: `/opt/portfoliohub/.env` 또는 동일 접근 통제 하 운영 절차. 공동 소유자: release approver / repository-maintainers.
|
||||
- **trade-write service-token**: `POST /v1/assets/{asset_id}/ledger/trades`. 환경 단위 운영 credential. 발급: admin context로 `POST /auth/service-tokens` 후 existing `daemon_id`에 binding. 보관: read token과 동일 정책. 공동 소유자: release approver / repository-maintainers.
|
||||
- **admin auth context**: `POST /auth/service-tokens`. 운영자 개인 소유. 공유 금지. 발급: steady-state는 `/auth/login` 경유 DB-issued session, break-glass는 env token.
|
||||
- release 문서에는 name, token_prefix, permission, `daemon_id`, `runtime_id`, issued_at, revoked_at만 기록하고 raw token값은 기록하지 않는다.
|
||||
- 운영자는 `pfhub service-token list`, `pfhub service-token issue`, `pfhub service-token rotate`, `pfhub user get`, `GET /v1/user_info`를 token provenance 확인 canonical support path로 사용한다. 각 명령의 출력 필드(name, token_prefix, token_id, user_id, permission, `daemon_id`, created_at, last_used_at, revoked_at, `runtime_id`)를 provenance 확인 기준으로 명시한다.
|
||||
- rotate 또는 재발급 이후에는 `daemon_id` 불변과 `runtime_id` 갱신 여부를 함께 대조해야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given README.md 또는 연결된 운영 문서가 존재할 때, When 운영자가 credential matrix를 참조할 때, Then public/read/trade-write/admin 4개 credential의 용도, 발급 주체, 보관 위치, 공동 소유 역할과 daemon binding 전제가 구분되어 기술되어 있어야 한다.
|
||||
2. Given release 문서(docs/releases/*.md)가 존재할 때, When smoke evidence를 기록할 때, Then name, token_prefix, permission, `daemon_id`, `runtime_id`, issued_at, revoked_at 필드만 남기고 raw token 값은 포함되지 않아야 한다.
|
||||
3. Given 운영자가 service-token provenance를 확인할 때, When `pfhub service-token list`를 실행할 때, Then name, permission, `daemon_id`, created_at, last_used_at, revoked_at 필드가 출력되고, `GET /v1/user_info`의 `runtime_id`, `daemon_id`와 대조해 배포된 토큰의 provenance를 재현 가능하게 확인할 수 있어야 한다.
|
||||
4. Given admin auth context가 필요한 smoke를 수행할 때, When 운영자가 credential matrix를 따를 때, Then admin context는 개인 소유로 취급되고 read/trade-write token은 release approver 역할과 공동 소유 형태로 관리되는 것이 문서에 명시되어 있어야 한다.
|
||||
5. Given 운영자가 rotate 또는 재발급 후 provenance를 재확인할 때, When `pfhub service-token rotate` 또는 issue 결과를 검토할 때, Then `daemon_id`는 유지 또는 요청한 binding 값으로 확인되고 `runtime_id`는 새 값으로 대조 가능해야 한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: `README.md` — credential matrix 항목 및 daemon-aware token provenance CLI 절차 추가/보강
|
||||
- Modules: `app/api/v1_user_info.py` (`runtime_id`, `daemon_id` 반환 확인), `app/cli/commands/service_tokens.py` (issue/list/rotate 출력 필드 확인)
|
||||
- Tests: 없음 (문서화 중심 REQ)
|
||||
|
||||
## Notes
|
||||
- NFR-1 (raw credential 비노출): 이 REQ의 핵심 제약. AC-2에 명시.
|
||||
- FR-4와 FR-2를 통합한 REQ. token provenance 확인 수단과 credential matrix는 운영자가 같은 맥락에서 참조하므로 분리 시 중복이 발생한다.
|
||||
- `runtime_id`는 service-token rotate 후 변경되고 `daemon_id`는 유지되므로, 문서에는 두 식별자의 역할 차이를 함께 명시해야 한다.
|
||||
- daemon provisioning 자체는 별도 관리 경로로 수행하고, provenance 절차는 binding 결과 확인에 집중한다.
|
||||
- Source Discovery: dcy-005 FR-2, FR-4; dcy-006 FR-5, FR-6
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260513-01
|
||||
- Date: 2026-05-13
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- token provenance REQ를 daemon-aware support path와 `daemon_id` evidence 필드 기준으로 보강
|
||||
|
||||
#### Intent
|
||||
- dcy-006은 issue/list/rotate와 `/v1/user_info`가 모두 `daemon_id`를 노출하고, release provenance도 `runtime_id` 단독이 아니라 daemon binding을 함께 추적하도록 요구한다. 기존 Approved 본문은 runtime_id 중심이라 운영 절차 기준이 불완전하다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-5: rotate/re-issue 후 `daemon_id`/`runtime_id` 대조 절차
|
||||
- Updated:
|
||||
- AC-1~3: daemon binding 전제와 `daemon_id` evidence 필드 반영
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- `README.md` credential matrix / provenance 절차
|
||||
- Modules:
|
||||
- `app/api/v1_user_info.py`, `app/cli/commands/service_tokens.py`
|
||||
- Tests:
|
||||
- none (문서화 중심 REQ)
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-009 (release-candidate; REL-005 confirmed input) — README provenance 절차와 release evidence field 정의를 daemon-aware 기준으로 재검토해야 함
|
||||
- Releases:
|
||||
- REL-005 (confirmed) — 배포 전 daemon-aware provenance field와 rotate invariant를 반영하도록 scope 재검토 필요
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: yes
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: BAT-009 구현/verification 전에 README와 release evidence 템플릿을 daemon-aware 필드 기준으로 조정한다.
|
||||
|
||||
#### Validation Plan
|
||||
- README.md와 release evidence 예시가 `daemon_id`, `runtime_id`, rotate invariant를 모두 설명하는지 코드 리뷰로 확인한다.
|
||||
- REQ-005, REQ-007, REQ-012 문구와 provenance 절차가 식별자 역할 측면에서 일관적인지 대조한다.
|
||||
|
||||
### CHG-20260512-02
|
||||
- Date: 2026-05-12
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Status: Proposed → Approved (confirm-req 게이트 통과)
|
||||
|
||||
#### Intent
|
||||
- 필수 필드, AC, Notes blocker 없음 확인 후 승인 전환
|
||||
|
||||
#### 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: none
|
||||
|
||||
#### Validation Plan
|
||||
- 승인 전환만 수행, 추가 검증 불필요
|
||||
|
||||
### CHG-20260512-01
|
||||
- Date: 2026-05-12
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ 초안 생성 (dcy-005 FR-2, FR-4 통합 기반)
|
||||
|
||||
#### Intent
|
||||
- release 검증 credential matrix 및 token provenance 확인 절차 문서화 요구사항 정의
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~4 초안 생성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- README.md credential matrix 및 token provenance 절차
|
||||
- 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: none
|
||||
|
||||
#### Validation Plan
|
||||
- README.md credential matrix 항목 구분 및 token provenance CLI 절차 존재 확인
|
||||
- release 문서 기록 정책 준수 여부 확인
|
||||
@@ -1,114 +0,0 @@
|
||||
# req-022: 운영 로그 접근 및 release evidence 기록 절차
|
||||
|
||||
- Status: Approved
|
||||
- Type: Documentation
|
||||
- Priority: Medium
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- 운영자가 startup/request 로그 접근 경로와 auth/permission/resource 오류 판독 방법을 모르면 release smoke의 증적을 재현 가능하게 수집할 수 없고, 장애 시 원인 분류가 불가능해진다.
|
||||
- systemd journal 기반 canonical log access 경로와 401/403/404 구분 판독 기준, release evidence 기록 필드를 README.md에 정의한다.
|
||||
|
||||
## Requirement
|
||||
- README.md Production Operator Runbook 섹션은 아래 로그 접근 및 evidence 기록 절차를 포함해야 한다.
|
||||
1. **애플리케이션 startup/runtime 로그**: `sudo journalctl -u portfoliohub -n 200 --no-pager` 또는 `-f` 옵션으로 실시간 확인. primary log path.
|
||||
2. **reverse proxy/access 로그**: `sudo journalctl -u caddy -n 200 --no-pager` 또는 `-f` 옵션. primary log path.
|
||||
3. **Loki**: `LOKI_ENABLED`와 실제 수집 파이프라인이 운영 환경에서 확인된 경우에만 보조 집계 경로로 취급.
|
||||
4. **auth/permission/resource 오류 구분**:
|
||||
- 401: 인증 정보 없음 또는 만료 — bearer token 미제공 또는 유효하지 않은 token
|
||||
- 403: 권한 부족 — token은 유효하나 해당 엔드포인트에 필요한 permission 미보유
|
||||
- 404: 리소스 없음 — 인증/권한은 통과했으나 대상 리소스가 DB에 존재하지 않음
|
||||
5. **release evidence 기록 필드**: 시각(executed_at, completed_at), 요청 경로, HTTP 상태 코드, 소스 시스템(journalctl unit name), 상관 가능한 요청 식별자. raw secret, raw token 값은 포함하지 않는다.
|
||||
- canonical acceptance smoke는 production에서 수행하고, staging smoke는 optional preflight로만 사용한다.
|
||||
- 절차의 source of truth는 README runbook으로 유지하고, 실행 evidence의 canonical record는 해당 release 문서에 남긴다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given README.md Production Operator Runbook이 존재할 때, When 운영자가 로그 접근 절차를 참조할 때, Then `journalctl -u portfoliohub`와 `journalctl -u caddy`를 각각 어느 용도로 사용하는지가 명시되어 있어야 한다.
|
||||
2. Given release smoke 중 HTTP 오류가 발생했을 때, When 운영자가 오류를 분류할 때, Then README runbook에 401(인증 없음), 403(권한 부족), 404(리소스 없음)의 의미가 분리되어 재현 가능하게 설명되어 있어야 한다.
|
||||
3. Given release 문서에 evidence를 기록할 때, When smoke 실행 결과를 기재할 때, Then 시각, 요청 경로, HTTP 상태 코드, 소스 시스템 필드가 포함되고 raw secret은 포함되지 않아야 한다.
|
||||
4. Given canonical acceptance 환경이 명시되어 있을 때, When 운영자가 smoke 환경을 선택할 때, Then production이 canonical acceptance이고 staging은 optional preflight임이 README runbook에 명시되어 있어야 한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: `README.md` — Production Operator Runbook 로그 접근 절차 및 오류 구분 기준 보강
|
||||
- Modules: 없음 (문서화 중심 REQ)
|
||||
- Tests: 없음
|
||||
|
||||
## Notes
|
||||
- NFR-2 (401/403/404 구분 설명): AC-2에 흡수.
|
||||
- NFR-1 (raw credential 비노출): AC-3에 흡수.
|
||||
- 외부 URL만으로는 startup log 접근이 불가능하다는 제약을 README에 명시해야 한다. (REL-001 Deployment Facts 참조)
|
||||
- Loki 관련 설정(`LOKI_ENABLED`, `LOKI_URL`)은 `app/core/config.py`에 존재하지만 현재 production에서 활성화가 확인되지 않으므로 기본 표준 경로로 다루지 않는다.
|
||||
- Source Discovery: dcy-005 FR-3
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260512-02
|
||||
- Date: 2026-05-12
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Status: Proposed → Approved (confirm-req 게이트 통과)
|
||||
|
||||
#### Intent
|
||||
- 필수 필드, AC, Notes blocker 없음 확인 후 승인 전환
|
||||
|
||||
#### 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: none
|
||||
|
||||
#### Validation Plan
|
||||
- 승인 전환만 수행, 추가 검증 불필요
|
||||
|
||||
### CHG-20260512-01
|
||||
- Date: 2026-05-12
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- REQ 초안 생성 (dcy-005 FR-3 기반)
|
||||
|
||||
#### Intent
|
||||
- 운영 로그 접근 및 release evidence 기록 절차 문서화 요구사항 정의
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~4 초안 생성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- README.md 로그 접근 절차 및 오류 구분 기준
|
||||
- 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: none
|
||||
|
||||
#### Validation Plan
|
||||
- README.md journalctl 명령 존재 및 401/403/404 구분 기술 확인
|
||||
- release evidence 기록 필드 정책 준수 확인
|
||||
@@ -1,98 +0,0 @@
|
||||
# REQ-028: README.md Daemon Provisioning Runbook 반영
|
||||
|
||||
- Status: Approved
|
||||
- Type: Documentation
|
||||
- Priority: Medium
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- interface-contract, data-model, runtime-flows의 daemon-aware 반영은 REQ-011 CHG-20260513-01에서 이미 다룬다.
|
||||
- 이 REQ는 REQ-011이 다루지 않는 `README.md` 운영 runbook 영역에 한정해, daemon provisioning 절차와 enforcement enablement gate를 반영한다.
|
||||
|
||||
## Requirement
|
||||
- `README.md` Production Operator Runbook 섹션은 daemon provisioning 절차(daemon create → service-token issue/rotate binding 순서)를 반영해야 한다.
|
||||
- `README.md`는 daemon-scoped enforcement enablement gate의 required evidence(inventory 완료, dry-run audit zero-active-NULL/zero-mismatch, smoke 검증 통과, release approver 승인)를 명시해야 한다.
|
||||
- `README.md`는 `runtime_id`와 `daemon_id`의 역할 차이(runtime identity vs stable logical identity)를 운영 provenance 절차에서 구분해 설명해야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given `README.md` Production Operator Runbook을 검토할 때, Then daemon create → service-token issue/rotate binding의 순서와 각 단계 조건이 명시되어 있다.
|
||||
2. Given `README.md` enforcement enablement gate 섹션을 확인할 때, Then inventory 완료, dry-run audit(zero-active-NULL/zero-mismatch), smoke 검증, release approver 승인의 4가지 required evidence가 모두 명시되어 있다.
|
||||
3. Given `README.md` 운영 provenance 절차를 확인할 때, Then `runtime_id`(rotate 시 갱신)와 `daemon_id`(rotate 후에도 유지)의 역할 차이가 구분되어 설명되어 있다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: `README.md` (Production Operator Runbook 섹션)
|
||||
- Modules: 없음
|
||||
- Tests: 없음 (문서 검토로 검증)
|
||||
|
||||
## Notes
|
||||
- interface-contract.md, data-model.md, runtime-flows.md의 daemon 반영은 REQ-011 CHG-20260513-01 범위이므로 이 REQ에서 중복 요구하지 않는다.
|
||||
- enforcement enablement gate의 실제 cutover evidence 수집은 release 단계에서 수행한다. 이 REQ는 절차 문서화만 대상으로 한다.
|
||||
|
||||
## Change Log
|
||||
|
||||
### 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
|
||||
- 최초 생성 시 REQ-011과 중복되는 interface-contract/data-model/runtime-flows 항목을 제거하고, README.md 운영 runbook 한정으로 범위 축소
|
||||
|
||||
#### Intent
|
||||
- REQ-011이 다루지 않는 README.md daemon provisioning runbook과 enforcement gate 절차만 별도 REQ로 정의
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~3 전체 신규 추가
|
||||
- Updated: 없음
|
||||
- Removed: 없음
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: `README.md` 한정
|
||||
- Modules: 없음
|
||||
- Tests: 없음
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: 미정
|
||||
- Releases: 미정
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: 없음 (신규 REQ)
|
||||
|
||||
#### Validation Plan
|
||||
- README.md에서 AC별 확인 항목(daemon provisioning 순서, gate evidence 4종, runtime_id/daemon_id 역할 구분)이 존재하는지 코드 리뷰로 검증
|
||||
@@ -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 반환 확인
|
||||
@@ -1,147 +0,0 @@
|
||||
# req-002: Alembic와 runtime schema ownership 경계 정리
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Migration
|
||||
- Priority: High
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- 이 요구사항은 Alembic migration 경로와 PostgresPortfolioRepository.ensure_schema() 경로가 같은 schema 객체를 다룰 때 발생할 수 있는 drift와 재실행 실패를 줄이기 위한 경계 규칙을 정의한다.
|
||||
- 로컬 docker compose 환경에서 fresh DB와 runtime-precreated schema 상태를 기준으로 허용 순서, 사전 점검, 보정 규칙을 문서화하는 것이 목표다.
|
||||
|
||||
## Requirement
|
||||
- 프로젝트는 로컬 docker compose 기반 DB 환경에서 Alembic migration과 runtime schema bootstrap이 다루는 테이블과 인덱스의 ownership 경계를 식별해야 하며, migrate-db 실행 시 허용되는 순서, 충돌 가능 지점, 사전 점검 규칙, 보정 원칙을 명시해야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given app/repositories/postgres.py와 migrations/versions/ 아래 현재 revision들이 있을 때, When schema ownership 분석을 수행하면, Then Alembic과 runtime ensure_schema()가 다루는 주요 객체와 충돌 가능 지점이 식별되어 있어야 한다.
|
||||
2. Given 로컬 docker compose 기반 fresh DB와 app runtime이 일부 schema를 먼저 만든 DB 시나리오가 있을 때, When migrate-db 실행 규칙을 정의하면, Then 허용 순서, 금지 순서, 필요한 사전 점검과 보정 규칙이 문서로 정리되어 있어야 한다.
|
||||
3. Given 코드 안에 legacy schema stamp 분기가 남아 있을 때, When migration 경계 문서를 작성하면, Then 이번 REQ와 관련 batch 범위에서 legacy DB 지원이 제외된다는 점이 명시되어 있어야 한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/project-structure.md, docs/runtime-flows.md, docs/data-model.md
|
||||
- Modules: app/repositories/postgres.py, app/db/migrations.py, migrations/versions/*.py
|
||||
- Tests: 로컬 schema ownership 검토 체크리스트 또는 migrate-db 충돌 시나리오 검증 절차
|
||||
|
||||
## Notes
|
||||
- 이 요구사항은 dcy-001의 FR-2, FR-3 일부, S-2, R-1, R-2를 구현 가능한 Migration 단위로 정규화한 것이다.
|
||||
- legacy DB support와 legacy stamp 경로 검증은 Discovery 범위에서 이미 제외되었으므로, 이 REQ는 local runtime bootstrap 흔적과 Alembic의 상호작용에 집중한다.
|
||||
- 문서화만으로 해결되지 않는 ownership 충돌이 발견되면 후속 batch에서 코드 수정이 필요할 수 있다.
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260511-01
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Implemented 전환 — BAT-007 verification passed, confirm-req-implemented 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- BAT-007 verification.md AC-1~3 모두 PASS. Blocking Issues 없음. docs/project-structure.md "Schema Ownership Boundary", docs/runtime-flows.md "Alembic vs ensure_schema() Schema Ownership Boundary" evidence 연결 확인 완료. 잔여 리스크(idx_auth_tokens_service_name_unique Alembic 미등록)는 후속 batch 검토 항목으로 남겨둠.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: BAT-007 (release-candidate)
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: implemented
|
||||
- Follow-up Action: draft-release (BAT-007); idx_auth_tokens_service_name_unique Alembic revision 추가 검토 권장
|
||||
|
||||
#### Validation Plan
|
||||
- BAT-007 verification.md AC-1~3 evidence 연결 확인 완료
|
||||
|
||||
### CHG-20260430-02
|
||||
- Date: 2026-04-30
|
||||
- Author: GitHub Copilot
|
||||
|
||||
#### Change Summary
|
||||
- confirm-req 승인 게이트를 통과해 이 REQ를 Approved로 전환했다.
|
||||
|
||||
#### Intent
|
||||
- dcy-001의 delivery input으로 사용할 수 있는 확정 requirement로 승격하기 위해 상태를 변경했다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- none
|
||||
- Updated:
|
||||
- none
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/srs/index.md
|
||||
- Modules:
|
||||
- none
|
||||
- Tests:
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- none
|
||||
- Releases:
|
||||
- none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: approved
|
||||
- Follow-up Action: suggest-batch-reqs 또는 draft-batch 단계에서 REQ-002의 ownership 문서를 delivery scope로 연결한다.
|
||||
|
||||
#### Validation Plan
|
||||
- REQ 본문 필수 섹션, Acceptance Criteria 구체성, docs/srs/index.md 상태 동기화를 확인한다.
|
||||
|
||||
### CHG-20260430-01
|
||||
- Date: 2026-04-30
|
||||
- Author: GitHub Copilot
|
||||
|
||||
#### Change Summary
|
||||
- dcy-001에서 Alembic와 runtime schema ownership 경계 요구사항을 신규 Proposed REQ로 생성했다.
|
||||
|
||||
#### Intent
|
||||
- migrate-db와 runtime bootstrap의 경계가 불분명해 생길 수 있는 drift와 재실행 실패를 독립 Migration backlog로 관리하기 위해 생성했다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- Alembic과 runtime ensure_schema() ownership 분석 기준 정의
|
||||
- local runtime-precreated schema 시나리오용 허용 순서와 보정 규칙 정의
|
||||
- legacy DB 비지원 범위 명시
|
||||
- Updated:
|
||||
- none
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/project-structure.md
|
||||
- docs/runtime-flows.md
|
||||
- docs/data-model.md
|
||||
- Modules:
|
||||
- app/repositories/postgres.py
|
||||
- app/db/migrations.py
|
||||
- migrations/versions/*.py
|
||||
- Tests:
|
||||
- migrate-db 충돌 시나리오 검토 체크리스트 또는 동등한 검증 절차
|
||||
|
||||
#### 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 단계에서 ownership 경계의 대상 객체와 범위 제외 항목을 검토하고 승인한다.
|
||||
|
||||
#### Validation Plan
|
||||
- confirm-req 전까지 Acceptance Criteria가 dcy-001의 FR-2, FR-3 일부, S-2와 일치하는지 검토하고, 이후 batch 단계에서 실제 객체 목록과 허용 순서 문서를 작성한다.
|
||||
@@ -0,0 +1,79 @@
|
||||
# REQ-006: portfolio_tags 데이터 마이그레이션
|
||||
|
||||
- Status: Proposed
|
||||
- Type: Migration
|
||||
- Priority: High
|
||||
- Owner: Justin Ko
|
||||
|
||||
## Intent
|
||||
- 기존 portfolio_tags.tag_value 자유 문자열 데이터를 tags 마스터 테이블로 이전하고, portfolios.tag_ids UUID[] 배열을 채운 후 portfolio_tags 테이블을 제거한다.
|
||||
- 소문자 정규화 후 UNIQUE 충돌을 방지하고, 마이그레이션 전 지정 admin 계정의 존재 여부를 사전 검증하여 데이터 무결성을 확보한다.
|
||||
- 마이그레이션된 기존 태그는 사용자 포트폴리오에서 유래했으므로 is_admin_tag=FALSE로 설정한다.
|
||||
|
||||
## Requirement
|
||||
- 마이그레이션 스크립트는 실행 전 운영자가 지정한 admin 계정 ID가 users 테이블에 존재하는지 검증해야 한다. 존재하지 않으면 오류와 함께 중단한다.
|
||||
- portfolio_tags.tag_value를 소문자 정규화(str.lower()) 후 tags 테이블에 INSERT해야 한다. ON CONFLICT DO NOTHING으로 중복을 무시한다.
|
||||
- 모든 INSERT는 is_admin_tag=FALSE, created_by_user_id=운영자 지정 admin 계정 ID로 설정해야 한다.
|
||||
- 각 portfolio의 portfolio_tags 행을 순회하여 해당 tag_value의 tag_id를 조회하고 portfolios.tag_ids 배열에 추가해야 한다.
|
||||
- 데이터 이전 완료 후 portfolio_tags 테이블을 DROP해야 한다.
|
||||
- 마이그레이션은 Alembic revision으로 관리하여 재실행 안전성(idempotent within revision)을 보장해야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given portfolio_tags 행이 존재하고 유효한 admin 계정 ID 지정, When 마이그레이션 실행, Then tags 테이블에 소문자 정규화된 DISTINCT tag_value 수만큼 행이 생성되고 모두 is_admin_tag=FALSE, created_by_user_id=지정 admin ID이다.
|
||||
2. Given portfolio_tags에 "TestTag"와 "testtag"가 존재, When 마이그레이션 실행, Then tags 테이블에 "testtag" 행이 하나만 생성된다 (ON CONFLICT DO NOTHING).
|
||||
3. Given 마이그레이션 실행 후, When 각 portfolio의 tag_ids를 조회, Then 기존 portfolio_tags에서 해당 portfolio에 연결된 tag_value들의 tag_id가 모두 포함된다.
|
||||
4. Given 마이그레이션 실행 후, When DB 스키마를 조회, Then portfolio_tags 테이블이 존재하지 않는다.
|
||||
5. Given 유효하지 않은 admin 계정 ID(users 테이블에 없음) 지정, When 마이그레이션 실행, Then 데이터 변경 없이 오류와 함께 중단된다.
|
||||
6. Given 마이그레이션 전 DISTINCT tag_value 수(소문자 정규화 기준) = N, When 마이그레이션 실행 후 tags 테이블 행 수 조회, Then N이다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/data-model.md (portfolio_tags 테이블 제거 반영)
|
||||
- Modules:
|
||||
- migrations/versions/ — 데이터 마이그레이션 Alembic revision (태그 이전, portfolios.tag_ids 채우기, portfolio_tags DROP)
|
||||
- Tests:
|
||||
- 마이그레이션 전후 DB 상태 SQL 검증
|
||||
- 잘못된 admin 계정 ID 시 중단 확인
|
||||
- DISTINCT 수 일치 확인
|
||||
|
||||
## Notes
|
||||
- 운영자는 마이그레이션 실행 전 admin 계정 ID를 확인하여 마이그레이션 스크립트에 명시한다.
|
||||
- 마이그레이션된 태그의 is_admin_tag=FALSE는 의도적 설계: 기존 portfolio_tags는 사용자 포트폴리오에서 유래했으며 asset 태그 적용 대상이 아니다.
|
||||
- REQ-003의 portfolios.tag_ids 컬럼 추가가 이 REQ 선행 조건이다.
|
||||
- 마이그레이션 완료 후 별도 소유권 재지정 스크립트 제공은 R-1 완화 방안으로, 이 REQ 범위 밖이다.
|
||||
- Source: dcy-002 FR-5, R-1, R-3, A-2
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260519-01
|
||||
- Date: 2026-05-19
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- 최초 생성 — dcy-002 confirm-discovery 후 REQ 초안 작성
|
||||
|
||||
#### Intent
|
||||
- dcy-002 FR-5를 Migration REQ로 분리하여 독립 구현·검증 단위로 정규화
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~6 최초 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/data-model.md — portfolio_tags 제거
|
||||
- Modules:
|
||||
- migrations/versions/ — 최초 지정
|
||||
- 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-003 선행 의존성 확인
|
||||
@@ -1,184 +0,0 @@
|
||||
# req-009: v1 API 지원을 위한 DB 스키마 migration 추가
|
||||
|
||||
- Status: Approved
|
||||
- Type: Migration
|
||||
- Priority: High
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- dcy-002에서 요구하는 4개 DB 변경(portfolios.market 컬럼, auth_tokens.runtime_id 컬럼, broker_credentials 테이블, ledger_trades 테이블)을 Alembic revision으로 구현한다.
|
||||
- dcy-006의 daemon-aware authorization 모델을 위해 `daemons` registry, `auth_tokens.daemon_id`, `portfolios.managed_by_daemon_id`, transition backfill 및 관련 제약을 같은 migration ownership 규칙 안에서 확장한다.
|
||||
- IF NOT EXISTS 패턴을 유지해 REQ-002 정책을 준수한다(NFR-4).
|
||||
|
||||
## Requirement
|
||||
- 다음 스키마 변경을 IF NOT EXISTS 패턴을 사용하는 신규 Alembic migration으로 추가해야 한다.
|
||||
1. portfolios 테이블에 market TEXT NULLABLE 컬럼 추가 (기존 행은 NULL로 유지)
|
||||
2. auth_tokens 테이블에 runtime_id TEXT UNIQUE NULLABLE 컬럼 추가
|
||||
3. broker_credentials 테이블 신규 생성 (user_id, broker, account_ref, encrypted_payload, credential_version, last_rotated_at 포함)
|
||||
4. ledger_trades 테이블 신규 생성 (ledger_entry_id PK, asset_id, order_id, execution_id, side, quantity, price, fee_amount, tax_amount, executed_at, recorded_at 포함, (asset_id, order_id, execution_id) unique constraint 포함)
|
||||
5. daemons registry 테이블 신규 생성 (`daemon_id`, `owner_user_id`, stable slug/display metadata, 생성/갱신 시각 포함)
|
||||
6. auth_tokens 테이블에 `daemon_id` NULLABLE FK 컬럼 추가, portfolios 테이블에 `managed_by_daemon_id` NULLABLE FK 컬럼 추가
|
||||
7. transition migration은 기존 service-token과 portfolio의 daemon 관련 컬럼을 `NULL`로 backfill하고, post-cutover exact-one assignment로 수렴할 수 있도록 same-user consistency 및 invalid reference rejection을 위한 FK/check/unique 제약을 제공해야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given alembic upgrade head 실행 후, When portfolios 테이블을 조회하면, Then market TEXT NULLABLE 컬럼이 존재해야 한다.
|
||||
2. Given alembic upgrade head 실행 후, When auth_tokens 테이블을 조회하면, Then runtime_id TEXT NULLABLE UNIQUE 컬럼이 존재해야 한다.
|
||||
3. Given alembic upgrade head 실행 후, Then broker_credentials 테이블이 존재해야 한다.
|
||||
4. Given alembic upgrade head 실행 후, Then ledger_trades 테이블이 존재해야 한다.
|
||||
5. Given (asset_id, order_id, execution_id) 동일 조합으로 ledger_trades에 두 번 삽입 시, Then UniqueViolation이 발생해야 한다.
|
||||
6. Given migration을 이미 실행한 DB에 동일 migration을 재실행하면, Then 에러 없이 완료되어야 한다(IF NOT EXISTS 보장).
|
||||
7. Given portfolios 테이블의 기존 행, When migration 실행 후 조회하면, Then market 값이 NULL이어야 한다(기존 데이터 보정 없음, DECIDE_MARKET_DEFAULT Answered).
|
||||
8. Given alembic upgrade head 실행 후, When schema를 조회하면, Then `daemons` 테이블과 `auth_tokens.daemon_id` 컬럼이 존재해야 한다.
|
||||
9. Given alembic upgrade head 실행 후, When portfolios 테이블을 조회하면, Then `managed_by_daemon_id` 컬럼이 존재하고 기존 행은 `NULL`로 backfill되어 있어야 한다.
|
||||
10. Given 존재하지 않는 `daemon_id`를 auth_tokens 또는 portfolios에 바인딩하려고 시도하면, Then FK 또는 동등 제약으로 거부되어야 하며, owner user 일관성을 깨는 binding/assignment는 DB 레벨 제약 또는 동등한 무결성 장치로 방지되어야 한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/data-model.md (REQ-011에서 갱신 예정)
|
||||
- Modules: migrations/versions/, app/domain/models.py, app/repositories/portfolio_repository.py, app/repositories/postgres.py
|
||||
- Tests: tests/test_app.py 또는 migration 검증 테스트, daemon schema integrity 검증
|
||||
|
||||
## Notes
|
||||
- NFR-4(IF NOT EXISTS 패턴) 준수 — REQ-002 Alembic migration 정책 기반.
|
||||
- broker_credentials 테이블의 encrypted_payload 컬럼은 Fernet 암호화된 ciphertext를 TEXT로 저장한다. 암복호화 로직은 REQ-010 참조.
|
||||
- 컬럼 상세 타입(NUMERIC vs FLOAT, TIMESTAMPTZ 등)은 설계 단계(draft-batch-design)에서 확정한다.
|
||||
- daemon exact-one assignment의 steady-state `NOT NULL`/강제 cutover는 inventory/backfill 완료 이후 단계적으로 적용할 수 있다. transition migration은 `NULL` backfill을 허용하되 fail-open을 허용하면 안 된다.
|
||||
- migration revision ID는 구현 시 기존 revision chain의 마지막 head를 down_revision으로 참조한다.
|
||||
- Source Discovery: dcy-002 (영향 범위, NFR-4, DECIDE_MARKET_DEFAULT), dcy-006 (FR-1, FR-2, NFR-2, NFR-3)
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260513-01
|
||||
- Date: 2026-05-13
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- runtime_id 중심 v1 migration REQ를 daemon registry/binding/assignment 스키마까지 포함하도록 확장하고, 기존 Implemented 상태를 Approved로 되돌림
|
||||
|
||||
#### Intent
|
||||
- dcy-006의 daemon-aware model은 기존 REQ-009 구현 범위를 넘어서 `daemons`, `auth_tokens.daemon_id`, `portfolios.managed_by_daemon_id`, transition backfill, same-user consistency 제약을 추가로 요구한다. BAT-001/REL-001 migration evidence는 이 범위를 포함하지 않는다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-8: `daemons`, `auth_tokens.daemon_id`
|
||||
- AC-9: `portfolios.managed_by_daemon_id` + NULL backfill
|
||||
- AC-10: daemon FK / 무결성 제약
|
||||
- Updated:
|
||||
- Requirement 본문에 daemon registry 및 transition backfill 항목 추가
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- `docs/data-model.md`, `docs/runtime-flows.md`
|
||||
- Modules:
|
||||
- `migrations/versions/`, `app/domain/models.py`, `app/repositories/portfolio_repository.py`, `app/repositories/postgres.py`
|
||||
- Tests:
|
||||
- migration integrity / daemon schema constraint 검증
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-001 (release-candidate; REL-001 released input) — 기존 migration verification은 daemon schema, backfill, constraint evidence를 포함하지 않음
|
||||
- Releases:
|
||||
- REL-001 (released) — release facts는 runtime_id/broker_credentials/ledger_trades까지만 다루므로 revised migration REQ를 충족하지 않음
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: yes
|
||||
- Existing Implementation Invalidated: yes
|
||||
- Status Recommendation: rollback-to-approved
|
||||
- Follow-up Action: dcy-006 후속 batch에서 신규 Alembic revision과 migration validation을 설계하고, cutover/backfill evidence를 release 단계에서 수집한다.
|
||||
|
||||
#### Validation Plan
|
||||
- 현재 migration chain과 `app/repositories/postgres.py` schema ownership을 재검토해 daemon schema 추가 위치를 설계한다.
|
||||
- 구현 후 alembic upgrade / re-run / invalid daemon reference 검증을 포함한 migration test plan을 수행한다.
|
||||
|
||||
### 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. DB 환경 실행 미확인은 non-blocker로 처리됨 (revision에 IF NOT EXISTS 패턴 전체 적용 확인). 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); 배포 전 Docker Compose 환경에서 실제 migration 실행 검증 권장
|
||||
|
||||
#### 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-009 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-009 최초 생성 (source Discovery: dcy-002)
|
||||
|
||||
#### Intent
|
||||
- v1 API 지원에 필요한 DB 스키마 변경을 REQ backlog로 정규화
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- 전체 Acceptance Criteria 신규 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/data-model.md (REQ-011에서 갱신 예정)
|
||||
- Modules:
|
||||
- migrations/versions/ 신규 migration 파일
|
||||
- app/domain/models.py 모델 필드 추가
|
||||
- Tests:
|
||||
- migration 검증 테스트
|
||||
|
||||
#### 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-005, REQ-006, REQ-007, REQ-008과 함께 delivery 단위 구성 필수(runtime_id, market, broker_credentials, ledger_trades 모두 이 migration에 의존).
|
||||
@@ -1,157 +0,0 @@
|
||||
# req-016: portfolios 테이블 UUID 전환 및 데이터 마이그레이션
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Migration
|
||||
- Priority: High
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- 현재 사용자가 직접 지정하는 TEXT PRIMARY KEY(`portfolio_id`)를 서버 생성 UUID로 교체하고, 기존 `portfolio_id` 문자열을 `name` 컬럼으로 이전한다.
|
||||
- `(owner_user_id, name)` 복합 UNIQUE 제약을 DB 레벨에서 도입해 사용자 범위 내 이름 유일성을 보장한다.
|
||||
- 기존 데이터와 FK 참조 테이블(`portfolio_ledger`, `portfolio_comments`, `portfolio_tags`, `ledger_trades`)을 단일 Alembic revision으로 atomic하게 마이그레이션한다.
|
||||
|
||||
## Requirement
|
||||
- 단일 Alembic revision을 추가해 아래를 수행한다.
|
||||
1. `portfolios` 테이블에 `name` TEXT 컬럼을 추가한다.
|
||||
2. 기존 `portfolio_id` 값을 `name` 컬럼으로 복사한다 (변환 없이 그대로).
|
||||
3. 각 기존 레코드에 `uuid.uuid4()`로 새 UUID를 생성해 `portfolio_id` 컬럼 값을 교체한다.
|
||||
4. FK 참조 테이블(`portfolio_ledger`, `portfolio_comments`, `portfolio_tags`, `ledger_trades`)의 `portfolio_id` 컬럼 값도 새 UUID로 함께 갱신한다.
|
||||
5. `(owner_user_id, name)` 복합 UNIQUE 제약을 `portfolios` 테이블에 추가한다.
|
||||
6. `Portfolio` dataclass(`app/domain/models.py`)의 `portfolio_id` 필드를 UUID 문자열로 유지하고 `name` 필드를 명확히 선언한다.
|
||||
7. `app/repositories/postgres.py`의 `create_portfolio()` 메서드가 서버에서 `uuid.uuid4()`로 생성된 UUID를 `portfolio_id`로 사용한다.
|
||||
- 마이그레이션은 IF NOT EXISTS 패턴을 준수해 재실행 시 오류가 없어야 한다(REQ-002 준수).
|
||||
- FK 참조 테이블과의 갱신은 단일 트랜잭션 내에서 atomic하게 처리한다.
|
||||
- 마이그레이션 완료 후 FK 고아 레코드(orphan) 0건을 검증하는 쿼리를 revision 안에 포함한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given 기존 `portfolio_id` 문자열로 운영 중인 portfolios 레코드가 있을 때, When 신규 Alembic revision을 `alembic upgrade head`로 실행하면, Then 각 레코드의 `name` 컬럼에 기존 `portfolio_id` 값이 그대로 복사되고, `portfolio_id`는 UUID 형식(`re.match(r'^[0-9a-f-]{36}$', ...)`)으로 교체된다.
|
||||
2. Given 마이그레이션 완료 후, When `portfolio_ledger`, `portfolio_comments`, `portfolio_tags`, `ledger_trades`의 `portfolio_id` 컬럼을 확인하면, Then 고아 레코드(FK 불일치 레코드)가 0건이다.
|
||||
3. Given `(owner_user_id, name)` 복합 UNIQUE 제약이 적용된 상태에서, When 동일 `owner_user_id`와 동일 `name`으로 portfolio 레코드를 추가하면, Then DB 레벨에서 UNIQUE 제약 위반 오류가 발생한다.
|
||||
4. Given 동일 `name`이지만 다른 `owner_user_id`로 portfolio 레코드를 추가하면, Then 정상 삽입된다.
|
||||
5. Given 신규 Alembic revision을 이미 적용한 환경에서, When 동일 revision을 재실행하면, Then 오류 없이 완료된다(IF NOT EXISTS 준수).
|
||||
6. Given `app/repositories/postgres.py`의 `create_portfolio()` 메서드가 실행되면, Then 서버에서 `uuid.uuid4()`로 생성된 UUID가 `portfolio_id`로 저장된다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: `docs/data-model.md` (portfolios 테이블 스키마 변경 반영 — REQ-019에서 처리)
|
||||
- Modules:
|
||||
- `migrations/versions/`: 신규 Alembic revision 파일
|
||||
- `app/domain/models.py`: Portfolio dataclass `portfolio_id` 및 `name` 필드
|
||||
- `app/repositories/postgres.py`: `create_portfolio()` UUID 생성, `get_portfolio_by_name_and_user()` 신규 메서드
|
||||
- Tests:
|
||||
- 신규 `tests/test_portfolio_uuid.py` 또는 `tests/test_cli.py` — portfolio_id UUID 형식 검증, 동일 name 독립 생성 테스트, (owner_user_id, name) UNIQUE 제약 동작 확인
|
||||
|
||||
## Notes
|
||||
- 기존 `portfolio_id` 문자열은 `name` 컬럼으로 변환 없이 복사한다(Discovery A-3 확정).
|
||||
- `portfolio_id` 컬럼 타입은 TEXT 유지(PostgreSQL UUID 타입으로의 전환은 이번 범위 밖).
|
||||
- `app/domain/models.py`의 `Portfolio.portfolio_id`는 UUID 문자열로 의미가 바뀌나 Python 타입(`str`)은 유지.
|
||||
- `get_portfolio_by_name_and_user()` 메서드는 REQ-017(CLI 식별 방식 전환)에서도 사용한다.
|
||||
- Source Discovery: dcy-004_20260511_portfolio-id-uuid-migration-and-user-scoped-name-resolution (FR-1, FR-5, NFR-1)
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260511-01
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- 최초 생성 — dcy-004 draft-req에 의해 생성
|
||||
|
||||
#### Intent
|
||||
- dcy-004 Discovery의 FR-1(portfolios.portfolio_id UUID 교체 및 name 컬럼 추가), FR-5(기존 데이터 마이그레이션), NFR-1(단일 revision, IF NOT EXISTS, atomic 트랜잭션) 반영
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- 1~6 (최초 생성)
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/data-model.md: portfolios 테이블 스키마 변경 (REQ-019에서 처리)
|
||||
- Modules:
|
||||
- migrations/versions/: 신규 revision 추가
|
||||
- app/domain/models.py: Portfolio dataclass 변경
|
||||
- app/repositories/postgres.py: create_portfolio UUID 생성, get_portfolio_by_name_and_user() 추가
|
||||
- Tests:
|
||||
- tests/test_portfolio_uuid.py 또는 tests/test_cli.py: UUID 형식 검증, UNIQUE 제약 동작 확인
|
||||
|
||||
#### 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: portfolio_id UUID 형식 검증, FK 고아 레코드 0건 확인, (owner_user_id, name) UNIQUE 제약 동작 확인, IF NOT EXISTS 재실행 안전성 확인
|
||||
|
||||
### CHG-20260511-02
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Approved 전환 — confirm-req 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- Delivery 입력으로 사용할 수 있도록 REQ-016을 승인 상태로 승격한다.
|
||||
|
||||
#### 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-016 Acceptance Mapping이 모든 AC에 대해 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~6 모두 test evidence 연결 확인 (tests/test_portfolio_uuid.py 14/14 passed, full suite 129/129 passed)
|
||||
@@ -1,128 +0,0 @@
|
||||
# req-010: credential_payload Fernet 암호화 및 startup validation
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Non-Functional
|
||||
- Priority: High
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- broker_credentials의 credential_payload(KIS app_key/app_secret)는 민감 데이터이므로 DB 평문 저장이 금지된다(R-1 High).
|
||||
- Python cryptography 패키지의 Fernet(AES-128-CBC + HMAC-SHA256)으로 저장 전 암호화, 조회 시 복호화한다.
|
||||
- CREDENTIAL_ENCRYPTION_KEY 환경변수가 없으면 서비스 기동을 거부해 운영 실수를 사전에 방지한다.
|
||||
|
||||
## Requirement
|
||||
- 서비스 기동 시 CREDENTIAL_ENCRYPTION_KEY 환경변수(base64 인코딩 32바이트)가 존재하지 않으면 기동을 중단하고 에러 메시지를 출력해야 한다.
|
||||
- broker_credentials에 credential_payload를 저장할 때 Fernet으로 암호화한 ciphertext를 저장해야 한다.
|
||||
- broker_credentials에서 credential_payload를 조회할 때 Fernet으로 복호화한 JSON을 반환해야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given CREDENTIAL_ENCRYPTION_KEY가 설정된 환경에서 서비스 기동 시, Then 정상 기동되어야 한다.
|
||||
2. Given CREDENTIAL_ENCRYPTION_KEY가 설정되지 않은 환경에서 서비스 기동 시, Then 기동이 실패하고 키 누락을 알리는 에러 메시지가 출력되어야 한다.
|
||||
3. Given credential_payload를 broker_credentials에 저장한 뒤 DB를 직접 조회하면, Then 암호화된 ciphertext가 저장되어 있어야 한다(평문 app_key/app_secret 불가).
|
||||
4. Given 암호화 저장된 credential_payload를 조회 API(GET /v1/user_info)로 읽으면, Then 복호화된 JSON({app_key: ..., app_secret: ...})이 반환되어야 한다.
|
||||
5. Given 잘못된 키로 복호화를 시도하면, Then cryptography.fernet.InvalidToken 예외가 발생하고 500 또는 적절한 오류 응답이 반환되어야 한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/project-structure.md (app/core/encryption.py 신규 모듈 반영 필요)
|
||||
- Modules: app/core/config.py (CREDENTIAL_ENCRYPTION_KEY 설정 필드 및 startup validation 추가), app/core/security.py 또는 app/core/encryption.py (Fernet 암복호화 유틸리티 신규), app/repositories/postgres.py (broker_credentials 저장·조회 시 암복호화 적용)
|
||||
- Tests: tests/test_auth.py 또는 신규 테스트에서 startup validation 및 암복호화 검증
|
||||
|
||||
## Notes
|
||||
- CREDENTIAL_ENCRYPTION_KEY는 `from cryptography.fernet import Fernet; Fernet.generate_key()`로 생성한 base64 인코딩 키를 사용한다.
|
||||
- startup validation은 FastAPI lifespan 이벤트 또는 Settings 초기화 시 수행한다. 설계 단계에서 위치를 확정한다.
|
||||
- 키 로테이션 절차는 이번 반복 Out of Scope이다.
|
||||
- Source Discovery: dcy-002 (NFR-3, R-1, OQ-3 Answered)
|
||||
|
||||
## 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 없음. AC3 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-010 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-010 최초 생성 (source Discovery: dcy-002 NFR-3)
|
||||
|
||||
#### Intent
|
||||
- credential_payload 암호화 및 startup validation 요구사항을 독립 Non-Functional REQ로 승격 정규화
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- 전체 Acceptance Criteria 신규 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/project-structure.md (encryption 모듈 반영 필요)
|
||||
- Modules:
|
||||
- app/core/config.py startup validation 추가
|
||||
- app/core/encryption.py 신규
|
||||
- Tests:
|
||||
- startup validation 및 암복호화 테스트
|
||||
|
||||
#### 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-007(GET /v1/user_info), REQ-009(broker_credentials 테이블)과 함께 delivery 단위 구성 권장.
|
||||
@@ -1,147 +0,0 @@
|
||||
# req-001: 로컬 DB 초기화 및 마이그레이션 검증 시나리오 정의
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Testing
|
||||
- Priority: High
|
||||
- Owner: repository-maintainers
|
||||
|
||||
## Intent
|
||||
- 이 요구사항은 로컬 docker compose 기반 PostgreSQL 또는 TimescaleDB 환경에서 init-db, migrate-db, health-check, 최소 smoke flow를 반복 가능하게 검증하기 위한 기준선을 정의한다.
|
||||
- 운영자와 유지보수 담당자가 같은 명령 순서와 같은 증거 형식으로 DB 준비 결과를 비교할 수 있도록 검증 절차를 명시하는 것이 목표다.
|
||||
|
||||
## Requirement
|
||||
- 프로젝트는 로컬 docker compose 기반 DB 환경에 대해 fresh DB 시나리오와 app runtime이 일부 schema를 먼저 만든 시나리오를 포함한 검증 매트릭스를 정의해야 하며, init-db, migrate-db, health-check, 최소 인증 또는 portfolio smoke flow의 실행 순서, 기대 결과, 실패 조건, 증거 수집 방식을 함께 제공해야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given 로컬 docker compose 기반 DB와 필요한 환경 변수가 준비되어 있을 때, When 운영자가 init-db, health-check, 최소 인증 또는 portfolio smoke flow를 실행하면, Then 명령 순서, 기대 출력, pass or fail 기준, 남겨야 할 로그가 문서로 정의되어 있어야 한다.
|
||||
2. Given fresh DB와 app runtime이 일부 schema를 먼저 만든 DB 시나리오가 있을 때, When 운영자가 migrate-db를 실행하면, Then 각 시나리오별 기대 결과와 실패 조건, 확인해야 할 증거가 구분되어 문서화되어 있어야 한다.
|
||||
3. Given 동일한 로컬 검증 절차를 반복 실행할 때, When 운영자가 같은 명령 세트를 다시 실행하면, Then 결과 비교가 가능하도록 출력 형식과 로그 수집 위치가 일관되게 정의되어 있어야 한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: README.md, docs/runtime-flows.md, docs/discovery/dcy-001_20260430_real-db-migration-validation-and-operations-readiness.md
|
||||
- Modules: docker-compose.local-test.yml, app/cli/commands/health.py, app/db/migrations.py
|
||||
- Tests: 로컬 docker compose 기반 수동 검증 체크리스트 또는 동등한 smoke validation 절차
|
||||
|
||||
## Notes
|
||||
- 이 요구사항은 dcy-001의 FR-1, NFR-1, NFR-2, S-1을 주로 구현 가능한 backlog로 정규화한 것이다.
|
||||
- shared dev DB, staging, production-like 환경 검증은 이번 요구사항 범위에 포함하지 않는다.
|
||||
- 성공 지표의 세부 artifact 형식은 REQ 승인 또는 batch planning 단계에서 확정할 수 있다.
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260511-01
|
||||
- Date: 2026-05-11
|
||||
- Author: repository-maintainers
|
||||
|
||||
#### Change Summary
|
||||
- Implemented 전환 — BAT-007 verification passed, confirm-req-implemented 게이트 통과
|
||||
|
||||
#### Intent
|
||||
- BAT-007 verification.md AC-1~3 모두 PASS. Blocking Issues 없음. README.md "Local DB Validation Runbook", docs/runtime-flows.md "Flow: Local DB Initialization and Validation" evidence 연결 확인 완료.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: BAT-007 (release-candidate)
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: implemented
|
||||
- Follow-up Action: draft-release (BAT-007)
|
||||
|
||||
#### Validation Plan
|
||||
- BAT-007 verification.md AC-1~3 evidence 연결 확인 완료
|
||||
|
||||
### CHG-20260430-02
|
||||
- Date: 2026-04-30
|
||||
- Author: GitHub Copilot
|
||||
|
||||
#### Change Summary
|
||||
- confirm-req 승인 게이트를 통과해 이 REQ를 Approved로 전환했다.
|
||||
|
||||
#### Intent
|
||||
- dcy-001의 delivery input으로 사용할 수 있는 확정 requirement로 승격하기 위해 상태를 변경했다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- none
|
||||
- Updated:
|
||||
- none
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- docs/srs/index.md
|
||||
- Modules:
|
||||
- none
|
||||
- Tests:
|
||||
- none
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- none
|
||||
- Releases:
|
||||
- none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: approved
|
||||
- Follow-up Action: suggest-batch-reqs 또는 draft-batch 단계에서 REQ-001의 검증 절차를 delivery scope로 연결한다.
|
||||
|
||||
#### Validation Plan
|
||||
- REQ 본문 필수 섹션, Acceptance Criteria 구체성, docs/srs/index.md 상태 동기화를 확인한다.
|
||||
|
||||
### CHG-20260430-01
|
||||
- Date: 2026-04-30
|
||||
- Author: GitHub Copilot
|
||||
|
||||
#### Change Summary
|
||||
- dcy-001에서 로컬 DB 검증 시나리오 요구사항을 신규 Proposed REQ로 생성했다.
|
||||
|
||||
#### Intent
|
||||
- 로컬 DB 준비와 smoke validation 절차를 독립 구현 및 독립 검증 가능한 Testing 단위로 분리하기 위해 생성했다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- 로컬 docker compose 기반 init-db, health-check, smoke flow의 검증 기준 정의
|
||||
- fresh DB와 runtime-precreated schema 시나리오별 migrate-db 검증 기준 정의
|
||||
- 반복 실행 가능한 증거 수집 형식 정의
|
||||
- Updated:
|
||||
- none
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- README.md
|
||||
- docs/runtime-flows.md
|
||||
- docs/discovery/dcy-001_20260430_real-db-migration-validation-and-operations-readiness.md
|
||||
- Modules:
|
||||
- docker-compose.local-test.yml
|
||||
- app/cli/commands/health.py
|
||||
- app/db/migrations.py
|
||||
- Tests:
|
||||
- 로컬 DB 수동 검증 체크리스트 또는 동등한 smoke validation 절차
|
||||
|
||||
#### 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 단계에서 검증 매트릭스 초안의 범위와 증거 형식을 승인한다.
|
||||
|
||||
#### Validation Plan
|
||||
- confirm-req 전까지 Acceptance Criteria가 dcy-001의 FR-1 및 S-1과 일치하는지 검토하고, 이후 batch 단계에서 실제 검증 절차와 로그 수집 artifact를 작성한다.
|
||||
+10
-31
@@ -74,43 +74,22 @@
|
||||
|
||||
## Next Requirement ID
|
||||
|
||||
- Current: `REQ-030`
|
||||
- Current: `REQ-009`
|
||||
- Rule: `Requirement Register`에 있는 가장 큰 REQ 번호보다 정확히 1 커야 한다.
|
||||
|
||||
## Requirement Register
|
||||
|
||||
| ID | Title | Type | Status | Priority | Owner | Link |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| REQ-001 | 로컬 DB 초기화 및 마이그레이션 검증 시나리오 정의 | Testing | Implemented | High | repository-maintainers | [REQ-001](./Testing/req-001_local-db-validation-scenarios.md) |
|
||||
| REQ-002 | Alembic와 runtime schema ownership 경계 정리 | Migration | Implemented | High | repository-maintainers | [REQ-002](./Migration/req-002_alembic-runtime-schema-ownership.md) |
|
||||
| REQ-003 | 로컬 DB 운영 runbook 및 baseline 문서 갱신 | Documentation | Implemented | Medium | repository-maintainers | [REQ-003](./Documentation/req-003_local-db-operations-runbook-and-baseline-updates.md) |
|
||||
| REQ-004 | GET /health 응답 스키마 확장 | Interface | Implemented | High | repository-maintainers | [REQ-004](./Interface/req-004_health-response-schema-extension.md) |
|
||||
| REQ-005 | service-token 발급 시 runtime_id 동시 생성 | Interface | Approved | High | repository-maintainers | [REQ-005](./Interface/req-005_service-token-runtime-id-issuance.md) |
|
||||
| REQ-006 | GET /v1/assets 엔드포인트 구현 | Interface | Approved | High | repository-maintainers | [REQ-006](./Interface/req-006_v1-assets-endpoint.md) |
|
||||
| REQ-007 | GET /v1/user_info 엔드포인트 구현 | Interface | Approved | High | repository-maintainers | [REQ-007](./Interface/req-007_v1-user-info-endpoint.md) |
|
||||
| REQ-008 | POST /v1/assets/{asset_id}/ledger/trades 엔드포인트 구현 | Interface | Approved | High | repository-maintainers | [REQ-008](./Interface/req-008_v1-ledger-trades-endpoint.md) |
|
||||
| REQ-009 | v1 API 지원을 위한 DB 스키마 migration 추가 | Migration | Approved | High | repository-maintainers | [REQ-009](./Migration/req-009_v1-api-db-schema-migration.md) |
|
||||
| REQ-010 | credential_payload Fernet 암호화 및 startup validation | Non-Functional | Implemented | High | repository-maintainers | [REQ-010](./Non-Functional/req-010_credential-payload-fernet-encryption.md) |
|
||||
| REQ-011 | trex-basic 계약 반영을 위한 baseline 문서 갱신 | Documentation | Approved | Medium | repository-maintainers | [REQ-011](./Documentation/req-011_baseline-docs-update-for-trex-basic-contract.md) |
|
||||
| REQ-012 | service-token rotate CLI 명령 구현 | Interface | Approved | Medium | repository-maintainers | [REQ-012](./Interface/req-012_service-token-rotate-cli.md) |
|
||||
| REQ-013 | CLI `portfolio list --user` 필수화 및 소유자 기반 조회 | Interface | Implemented | Medium | repository-maintainers | [REQ-013](./Interface/req-013_portfolio-list-user-required.md) |
|
||||
| REQ-014 | CLI `portfolio create --user` 필수화 및 소유자 설정 | Interface | Implemented | Medium | repository-maintainers | [REQ-014](./Interface/req-014_portfolio-create-user-required.md) |
|
||||
| REQ-015 | CLI `credential` 명령 그룹 구현 (브로커 인증 정보 관리) | Interface | Implemented | Medium | repository-maintainers | [REQ-015](./Interface/req-015_broker-credential-cli.md) |
|
||||
| REQ-016 | portfolios 테이블 UUID 전환 및 데이터 마이그레이션 | Migration | Implemented | High | repository-maintainers | [REQ-016](./Migration/req-016_portfolios-uuid-schema-migration.md) |
|
||||
| REQ-017 | CLI portfolio 명령 — name+user 조합 식별 방식 전환 | Interface | Implemented | High | repository-maintainers | [REQ-017](./Interface/req-017_portfolio-cli-name-user-identification.md) |
|
||||
| REQ-018 | HTTP API portfolio path parameter UUID 전환 및 v1 asset_id UUID 반환 | Interface | Implemented | High | repository-maintainers | [REQ-018](./Interface/req-018_portfolio-http-api-uuid-path-param.md) |
|
||||
| REQ-019 | portfolio UUID 전환 관련 baseline 문서 갱신 | Documentation | Implemented | Medium | repository-maintainers | [REQ-019](./Documentation/req-019_portfolio-uuid-baseline-docs-update.md) |
|
||||
| REQ-020 | 실배포 admin bootstrap 및 steady-state operator access runbook | Deployment | Approved | High | repository-maintainers | [REQ-020](./Deployment/req-020_production-admin-bootstrap-and-operator-access-runbook.md) |
|
||||
| REQ-021 | release 검증 credential matrix 및 token provenance 운영 절차 | Documentation | Approved | High | repository-maintainers | [REQ-021](./Documentation/req-021_release-credential-matrix-and-token-provenance-procedures.md) |
|
||||
| REQ-022 | 운영 로그 접근 및 release evidence 기록 절차 | Documentation | Approved | Medium | repository-maintainers | [REQ-022](./Documentation/req-022_operator-log-access-and-release-evidence-recording.md) |
|
||||
| REQ-023 | Daemon Registry 관리 경로 | Interface | Approved | High | repository-maintainers | [REQ-023](./Interface/req-023_daemon-registry-and-service-token-daemon-binding.md) |
|
||||
| REQ-028 | README.md Daemon Provisioning Runbook 반영 | Documentation | Approved | Medium | repository-maintainers | [REQ-028](./Documentation/req-028_daemon-model-baseline-docs-update.md) |
|
||||
| REQ-029 | CLI `portfolio list` 출력 — 테두리 없는 리스트 형식 | Interface | Approved | Low | repository-maintainers | [REQ-029](./Interface/req-029_portfolio-list-borderless-output.md) |
|
||||
| REQ-001 | tags 마스터 테이블 도입 | Data | Proposed | High | Justin Ko | [req-001](./Data/req-001_tags-master-table.md) |
|
||||
| REQ-002 | assets.tag_ids UUID[] 컬럼 추가 | Data | Proposed | High | Justin Ko | [req-002](./Data/req-002_assets-tag-ids-column.md) |
|
||||
| REQ-003 | portfolios.tag_ids UUID[] 컬럼 추가 및 portfolio_tags 테이블 제거 | Data | Proposed | High | Justin Ko | [req-003](./Data/req-003_portfolios-tag-ids-and-portfolio-tags-removal.md) |
|
||||
| REQ-004 | tags 마스터 HTTP API | Interface | Proposed | High | Justin Ko | [req-004](./Interface/req-004_tags-http-api.md) |
|
||||
| REQ-005 | 태그 적용·해제 HTTP API | Interface | Proposed | High | Justin Ko | [req-005](./Interface/req-005_tag-apply-remove-http-api.md) |
|
||||
| REQ-006 | portfolio_tags 데이터 마이그레이션 | Migration | Proposed | High | Justin Ko | [req-006](./Migration/req-006_portfolio-tags-data-migration.md) |
|
||||
| REQ-007 | pfhub tag CLI 명령어 | Interface | Proposed | Medium | Justin Ko | [req-007](./Interface/req-007_pfhub-tag-cli.md) |
|
||||
| REQ-008 | 태그 모델 도입 baseline 문서 갱신 | Documentation | Proposed | Low | Justin Ko | [req-008](./Documentation/req-008_tag-baseline-docs-update.md) |
|
||||
|
||||
## Recent Change Log Summary
|
||||
|
||||
- 2026-05-18: REQ-029 Approved 생성 — `portfolio list` 테두리 없는 리스트 형식, minor-change fast path, 구현 완료
|
||||
- 2026-05-18: REQ-023 CHG-20260518-01 — AC-5(`portfolio update --daemon-id`), AC-6(`portfolio list` daemon-id 표시) 추가, Impacted Area 보강, Status Approved 유지
|
||||
- 2026-05-18: REQ-008 CHG-20260518-01 — `insert_ledger_trade` postgres 미구현 결함 수정, HTTP 500 정상화, Status Approved 유지
|
||||
- 2026-05-18: REQ-017 CHG-20260518-01 — `get_portfolio_by_name_and_user` postgres 미구현 결함 수정, Status Implemented 유지
|
||||
- 2026-05-13: REQ-023, REQ-028 Approved 전환 — confirm-req 게이트 통과 (필수 필드, AC, blocker 없음)
|
||||
- 2026-05-19: REQ-001~008 최초 생성 — dcy-002 (태그 소유권 및 적용 대상 정책) confirm-discovery 후 draft-req 실행
|
||||
|
||||
Reference in New Issue
Block a user