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:
2026-05-19 13:54:25 +00:00
parent 47c4f9bfde
commit 1082f041a1
96 changed files with 1133 additions and 9303 deletions
@@ -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)