feat: implement portfolio UUID migration and v1 API finalization (BAT-006, BAT-001 re-verified)

Core Changes:
- Migrate portfolio_id from string to UUID in schema and repository layer
- Update portfolio CLI commands to use name+user combination for identification
- Update HTTP API to accept portfolio_id as UUID path parameter
- Implement portfolio ownership validation in repository queries

Requirements Completed (REQ-016 to REQ-019):
- REQ-016: portfolios table UUID schema migration with data migration script
- REQ-017: CLI portfolio commands with name+user identification
- REQ-018: HTTP API portfolio path parameters and v1 asset_id UUID returns
- REQ-019: Portfolio UUID baseline documentation updates

BAT-001 Re-verification:
- REQ-004~010 marked as Implemented after verification evidence validation
- All v1 API endpoints verified with comprehensive test coverage

Documentation Updates:
- Update data-model.md with portfolio UUID structure
- Update interface-contract.md with UUID path parameters
- Update runtime-flows.md with ownership-based resolution flows
- Update project-structure.md with database layer changes
- Add migration script for portfolio UUID transition

Testing:
- Add test_portfolio_uuid.py for migration validation
- Update test_cli.py and test_portfolio_ownership.py for ownership checks
This commit is contained in:
2026-05-11 09:27:57 +00:00
parent 9ed307555a
commit 829629fa8f
46 changed files with 3260 additions and 220 deletions
@@ -0,0 +1,71 @@
# BAT-006 Planning
- Status: confirmed
- Batch: BAT-006
- Profile: standard
## Included REQ
- REQ-016: portfolios 테이블 UUID 전환 및 데이터 마이그레이션
- REQ-017: CLI portfolio 명령 — name+user 조합 식별 방식 전환
- REQ-018: HTTP API portfolio path parameter UUID 전환 및 v1 asset_id UUID 반환
- REQ-019: portfolio UUID 전환 관련 baseline 문서 갱신
## Delivery Plan
### 구현 순서
1. **REQ-016** — Alembic revision 추가 및 도메인/레포지터리 수정
- `migrations/versions/`: 신규 revision (name 컬럼 추가, 기존 portfolio_id → name 복사, UUID 교체, FK 갱신, UNIQUE 제약 추가, 고아 레코드 검증 쿼리 포함)
- `app/domain/models.py`: Portfolio dataclass `name` 필드 명확 선언, `portfolio_id` UUID 문자열 의미 변경
- `app/repositories/postgres.py`: `create_portfolio()` 서버 UUID 생성, `get_portfolio_by_name_and_user()` 신규 메서드 추가
2. **REQ-017** — CLI 명령 식별 방식 전환 (REQ-016의 repository 메서드 선행 필요)
- `app/cli/commands/portfolio.py`: `create`, `status`, `buy`, `sell`, `invest`, `transfer`, `reset`, `delete`, `update` Argument/Option 전환 (`portfolio_id` argument → `<name>` + `--user`)
- `app/domain/services.py`: `(user_id, name)` → UUID 해석 로직 추가
- name 유효성 검사(`[a-zA-Z0-9._:-]`, 1~100자), `update` name 변경 시 `--force` 또는 confirm 프롬프트, 중복 name 오류 메시지 처리 포함
3. **REQ-018** — HTTP API 전환 (REQ-016의 UUID 스키마 전제)
- `app/api/portfolios.py`: path parameter UUID 기반 전환
- `app/api/v1_assets.py`: `asset_id` 직렬화에서 `portfolio_id`(UUID) 사용
- `app/schemas/portfolio.py`, `app/schemas/v1.py`: asset_id/portfolio_id 필드 타입 문서화
- `docs/discovery/dcy-002_20260502_trex-basic-consumer-api-contract.md`: A-3 철회 주석 추가
4. **REQ-019** — 문서 갱신 (REQ-016~018 구현 흐름 내 또는 완료 후)
- `docs/project-structure.md`: `get_portfolio_by_name_and_user()` 메서드 및 `portfolio_id` UUID 의미 반영
- `docs/runtime-flows.md`: CLI `<name>` + `--user` 식별 흐름, `GET /v1/assets` `asset_id` UUID 반환 흐름 반영
- `docs/data-model.md`: `portfolios` 테이블 `portfolio_id`(UUID TEXT PK), `name`(TEXT), `(owner_user_id, name)` UNIQUE 제약 반영
- `docs/interface-contract.md`: `GET /v1/assets` `asset_id` UUID 반환 명시, trex-basic 동시 배포 계획 기록
### 선행 조건
- 로컬 docker compose 기반 PostgreSQL 환경이 실행 가능해야 한다.
- `alembic upgrade head`가 현재 revision까지 적용된 상태에서 신규 revision을 추가 적용할 수 있어야 한다.
## Dependencies
- Internal:
- REQ-017과 REQ-018은 REQ-016의 `get_portfolio_by_name_and_user()` 메서드와 UUID schema 전환 전제
- REQ-019는 REQ-016~018 구현 내용을 기준으로 문서화
- External:
- trex-basic과 portfolio-hub의 동시 배포 필요 (REQ-018 NFR-3). trex-basic 측 코드 변경은 이번 범위 밖이나 배포 시점 조율 필요. 계획은 REQ-019에서 `docs/interface-contract.md`에 기록.
## Design Gate
- Design Required Before Implementation: yes
- Reason: DB schema migration, CLI 인터페이스 전면 전환, HTTP API path parameter 변경이 포함되어 구조/인터페이스/런타임 흐름 영향이 크다. design.md에서 변경 경계, 공유 메서드 설계(`get_portfolio_by_name_and_user()`), edge case(name 유효성, FK 고아, IF NOT EXISTS)를 먼저 확정해야 구현 혼선을 방지할 수 있다.
## Milestones
1. REQ-016 구현 완료 및 pytest 기반 UUID 형식·FK 고아 0건·UNIQUE 제약·IF NOT EXISTS 재실행 검증 통과
2. REQ-017 구현 완료 및 CLI 소유권 검증·name 유효성·중복 변경 거부·alice/bob 독립 portfolio 테스트 통과
3. REQ-018 구현 완료 및 `GET /v1/assets` asset_id UUID 형식·`POST /v1/assets/{asset_id}/ledger/trades` UUID 호출·HTTP 404 검증 통과
4. REQ-019 문서 갱신 완료 및 코드 리뷰 기반 검증 (4개 baseline 문서 내용 확인)
5. 전체 acceptance criteria mapping 완료, verification.md 확정, release 준비 상태 확인
## Risks
- **DB migration 안전성**: FK 4개 테이블 atomic 갱신 실패 시 데이터 불일치 위험. 대응: 단일 트랜잭션 + revision 내 고아 레코드 검증 쿼리 + 로컬 환경 rollback 테스트 포함.
- **CLI 하위 호환 단절**: 기존 `portfolio_id` argument 기반 사용 흐름이 즉시 중단됨. 대응: migration 완료 후 CLI 명령 end-to-end 검증 suite 실행.
- **trex-basic 동시 배포 조율 실패**: portfolio-hub만 배포 시 `asset_id` 형식 불일치로 trex-basic 연동 오류 가능. 대응: 배포 조율 계획을 `docs/interface-contract.md`에 명시(REQ-019), 배포 전 trex-basic 팀 협의.
- **IF NOT EXISTS 재실행 안전성 누락**: revision 재실행 오류 발생 가능. 대응: REQ-016 AC-5 검증 포함(단순 재실행 확인).