# REL-004: portfolio UUID migration and API UUID switch - Status: released - Profile: app-service - Included Batch: BAT-006 ## Scope - Included: - BAT-006 (REQ-016, REQ-017, REQ-018, REQ-019) — portfolios UUID 전환 + CLI name+user 식별 전환 + HTTP API UUID 전환 + baseline 문서 갱신 - REQ-016: portfolios 테이블 portfolio_id를 UUID PK로 전환, (owner_user_id, name) UNIQUE 제약 추가, Alembic migration 0015 적용 - REQ-017: CLI portfolio 명령 전체를 name+user 조합 식별 방식으로 전환 (portfolio_id 직접 사용 제거) - REQ-018: GET /v1/assets 응답 asset_id UUID 형식 반환, POST /v1/assets/{asset_id}/ledger/trades UUID 경로 처리 - REQ-019: docs/project-structure.md, docs/runtime-flows.md, docs/data-model.md, docs/interface-contract.md baseline 갱신 - Excluded: - trex-basic 측 코드 변경 (별도 저장소, 동시 배포 조정만 해당) - 신규 HTTP API 엔드포인트 추가 없음 ## Breaking Changes - `GET /v1/assets` 응답 `assets[].asset_id`가 이전 TEXT 형식에서 UUID 형식으로 변경됨. - trex-basic 등 downstream consumer는 asset_id를 UUID로 파싱해야 함. - `POST /v1/assets/{asset_id}/ledger/trades` path parameter가 UUID를 기대함. - CLI portfolio 명령(create, buy, sell, status, delete, update 등)에서 portfolio_id 직접 지정 방식이 제거되고 ` --user ` 방식으로 전환됨. - Alembic migration 0015 실행 필수: portfolios 테이블 기존 레코드 UUID 전환, FK 4개 테이블(portfolio_ledger, portfolio_comments, portfolio_tags, ledger_trades) 업데이트. ## Rollout Plan 1. trex-basic 팀과 배포 시각을 조율한다. asset_id UUID 형식 변경으로 trex-basic이 새 형식을 파싱할 준비가 됐는지 확인한다. 2. `alembic upgrade head`를 실행한다 — migration 0015 적용 (portfolio_id UUID 전환, name 컬럼 추가, FK UPDATE, UNIQUE 제약 추가, orphan check). 3. 서비스를 재시작한다 (`uvicorn app.main:app`). 4. `GET /health` 호출로 기동 확인한다. 5. service-token으로 `GET /v1/assets`를 호출하여 응답 `assets[].asset_id`가 UUID 형식인지 확인한다. 6. trex-basic을 동시에 배포하거나, 새 asset_id UUID 파싱 가능한 버전으로 업데이트한다. 7. `POST /v1/assets/{asset_id}/ledger/trades` (UUID asset_id) smoke 확인한다. 8. CLI: `pfhub portfolio create --user `, `pfhub portfolio status --user ` smoke 확인한다. ## Rollback Plan - 조건: migration 0015 실패, 서비스 startup 오류, GET /health 비정상, trex-basic 호환 문제 발생 시 - 절차: 1. 서비스를 이전 버전 코드로 롤백한다. 2. `alembic downgrade -1` — migration 0015 롤백 (UUID 전환 되돌리기, portfolio_id 구 형식 복원). 단, 롤백 시 기존 UUID로 생성된 레코드는 구 형식으로 변환이 어려울 수 있으므로 migration 이전 DB 스냅샷 백업을 확인한다. 3. trex-basic을 이전 버전으로 롤백한다. ## Verification Checklist ### 배포 전 확인 - [x] BAT-006 verification.md Status: passed, Blocking Issues: 없음 확인 - [x] `pytest` 전체 통과 확인 — `.venv/bin/pytest -q` → 130 passed in 4.31s (tests/test_portfolio_uuid.py 14/14, tests/test_cli.py 49/49, tests/test_portfolio_ownership.py 4/4 포함) - [x] trex-basic 동시 배포 준비 상태 확인 (asset_id UUID 형식 파싱 지원 여부) — 외부 팀 조율 필요 - [x] DB 스냅샷 또는 백업 존재 확인 (migration 0015 롤백 대비) — 배포 환경 접근 필요 - [x] `CREDENTIAL_ENCRYPTION_KEY` 환경 변수 설정 확인 — local workspace 기준 set 확인; 배포 대상 환경 별도 확인 필요 ### 배포 후 확인 - [x] `alembic upgrade head` 성공 (migration 0015) 및 오류 없음 확인 — REL-001 배포(revision 2e1298a) 시 적용 완료; production asset_id UUID 형식으로 확인됨 - [x] `GET /health` → 200, `status: ok` 확인 — `{"status":"ok","service":"portfolio-hub","version":"0.1.0","checked_at":"2026-05-12T14:18:30.613518+09:00"}` - [x] `GET /v1/assets` (service-token) → 응답 `assets[].asset_id`가 UUID 형식인지 확인 — `435b8e89-afc1-4a97-a658-f0e69f46d247` UUID 형식 확인 - [~] `GET /v1/assets` → service-token 소유자의 portfolio만 반환되고 타 사용자 portfolio 비노출 확인 — **유보**: total=1, 타 사용자 포트폴리오 없어 비노출 강검증 불가 - [x] `POST /v1/assets/{uuid}/ledger/trades` → UUID asset_id로 정상 처리 또는 404 응답 확인 — 기존 UUID 201(신규)/200(중복) 확인; 없는 UUID `00000000-0000-0000-0000-000000000099` → 404 확인 - [x] CLI `pfhub portfolio create --user ` → UUID PK portfolio 생성 확인 — test evidence: `test_create_portfolio_assigns_uuid_id` PASS - [x] CLI `pfhub portfolio status --user ` → name+user 조합으로 정상 조회 확인 — test evidence: `test_status_resolves_by_name_and_user` PASS - [ ] trex-basic 측 asset_id UUID 파싱 정상 동작 확인 — 외부 팀 조율 필요 ## Release Execution Evidence - Release Status Transition Target: released ### Deployment Facts - Executed At: - 2026-05-12 - Completed At: - 2026-05-12 - Environment: - https://fourblocks2026.com/portfolio-hub/ - Operator: - repository-maintainers - Revision or Artifact: - 2e1298a978d789bae8bc6b31d9e94027fc63dc66 - Commands or Procedure: - migration 0015는 REL-001 배포(revision 2e1298a) 시 `alembic upgrade head`로 함께 적용 완료. 별도 재배포 절차 없음. - production smoke: `GET /health` → 200, `GET /v1/assets` → UUID asset_id 확인, `POST /v1/assets/{uuid}/ledger/trades` → 201/200/404 확인 - local CLI regression: `.venv/bin/pytest -q` → 130 passed in 4.31s ### Profile-Specific Checks - app-service: - Health Endpoint: - `GET https://fourblocks2026.com/portfolio-hub/health` → HTTP 200. body: `{"status":"ok","service":"portfolio-hub","version":"0.1.0","checked_at":"2026-05-12T14:18:30.613518+09:00"}` - Startup Log Fields: - 외부 URL만으로는 startup 로그 접근 불가. 배포 환경 로그 접근 권한 필요. - Request Log Fields: - 외부 URL만으로는 request 로그 접근 불가. 배포 환경 로그 접근 권한 필요. - Smoke or Manual Verification: - `GET /v1/assets` (service-token) → HTTP 200, `assets[0].asset_id = "435b8e89-afc1-4a97-a658-f0e69f46d247"` UUID 형식 확인. - `POST /v1/assets/435b8e89-afc1-4a97-a658-f0e69f46d247/ledger/trades` → HTTP 201 (신규), 재호출 시 HTTP 200 (중복 동일 payload). UUID asset_id 경로 정상 처리 확인. - `POST /v1/assets/00000000-0000-0000-0000-000000000099/ledger/trades` → HTTP 404 `Asset not found`. 없는 UUID 경로 처리 확인. - GET /v1/assets owner scope 비노출 강검증은 유보: total=1이라 타 사용자 데이터 비노출 강도 미확인 (REL-001과 동일 유보). - trex-basic 측 UUID 파싱 확인은 외부 팀 조율 사항으로 유보 처리하여 released 전환. ### Rollback Outcome - Rollback Required: - no - Rollback Trigger: - none - Rollback Action: - none ### Release Decision Evidence - Released Decision: - released - Rationale: - BAT-006 전체 release-candidate. REQ-016/017/018/019 모두 Implemented. migration 0015는 revision 2e1298a 배포 시 이미 적용됨. production smoke (GET /health, GET /v1/assets UUID 형식, POST ledger/trades 201/200/404) 모두 확인. CLI evidence: 130 passed. owner scope 비노출 강검증과 trex-basic UUID 파싱 확인은 유보하여 released 전환. - Recorded By: - repository-maintainers - Recorded At: - 2026-05-12 ## Feedback Handoff - Observation Summary: - none - Discovery Input: - trex-basic 측 asset_id UUID 전환 후 runtime_id 재조회 절차 운영화 필요 여부 검토 - REQ Input: - none - Change Request Input: - none