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
7.6 KiB
7.6 KiB
BAT-006 Verification
- Status: passed
- Batch: BAT-006
Acceptance Mapping
-
REQ-016:
- AC-1: 기존 portfolio_id → name 복사 및 portfolio_id UUID 형식 교체 검증 (
re.match(r'^[0-9a-f-]{36}$', ...))- Evidence:
test_create_portfolio_assigns_uuid_id—uuid.UUID(portfolio.portfolio_id)성공 확인 ✓
- Evidence:
- AC-2: portfolio_ledger, portfolio_comments, portfolio_tags, ledger_trades FK 고아 레코드 0건 확인
- Evidence:
migrations/versions/20260511_0015_portfolio_uuid_migration.py— 각 portfolio에 대해 FK 4개 테이블 UPDATE 후 orphan 레코드 zero-check RuntimeError 포함 ✓
- Evidence:
- AC-3: 동일 owner_user_id + 동일 name 중복 삽입 시 DB UNIQUE 제약 위반 오류 발생 확인
- Evidence:
postgres.pycreate_portfolio()psycopg UniqueViolation catch → ValueError("이미 사용 중인 이름입니다: {name}"); FakeRepo 동일 동작 ✓
- Evidence:
- AC-4: 다른 owner_user_id + 동일 name 정상 삽입 확인
- Evidence:
test_alice_and_bob_can_have_same_portfolio_name— alice, bob 각각 "SAMSUNG" 이름으로 독립 portfolio 생성 성공; portfolio_ids 2개 모두 유효한 UUID ✓
- Evidence:
- AC-5: 신규 revision 재실행 시 오류 없음 확인 (IF NOT EXISTS 준수)
- Evidence: Alembic migration — uq_portfolios_owner_name constraint 존재 여부를 information_schema 쿼리로 확인 후 조건부 ADD CONSTRAINT ✓
- AC-6:
create_portfolio()실행 시 서버uuid.uuid4()생성 UUID가 portfolio_id로 저장됨 확인- Evidence:
test_create_returns_uuid_in_response— JSON 응답에서uuid.UUID(portfolio_id)파싱 성공 ✓
- Evidence:
- AC-1: 기존 portfolio_id → name 복사 및 portfolio_id UUID 형식 교체 검증 (
-
REQ-017:
- AC-1:
portfolio create <name> --user <username>실행 시 portfolio_id를 사용자가 직접 지정하지 않고 UUID가 DB에 저장됨- Evidence:
test_create_portfolio_assigns_uuid_id— create 후uuid.UUID(portfolio.portfolio_id)검증 ✓
- Evidence:
- AC-2:
portfolio buy <name> --user alice실행 시(alice, <name>)단일 쿼리 UUID 조회 후 처리 확인- Evidence:
test_buy_resolves_portfolio_by_name_and_user—get_portfolio_by_name_and_user()경유 BUY 처리,repo._entries[0].action == "BUY"✓
- Evidence:
- AC-3:
--user bob으로 alice 소유 portfolio 접근 시포트폴리오를 찾을 수 없습니다: {name} (user: bob)출력 및 명령 중단 확인- Evidence:
test_alice_cannot_delete_bobs_portfolio— alice가 bob 소유 "SAMSUNG" 삭제 시도 → exit_code=1, portfolio 잔존 ✓;test_status_fails_when_portfolio_name_not_found_for_user— 오류 메시지에 name 포함 ✓
- Evidence:
- AC-4: alice/bob 동일 name으로 독립 portfolio 생성 및 각자 조작 가능 확인
- Evidence:
test_alice_and_bob_can_have_same_portfolio_name✓
- Evidence:
- AC-5: alice의 portfolio name을 이미 존재하는 name으로
update시이미 사용 중인 이름입니다: {name}오류 출력 확인- Evidence:
postgres.pyupdate_portfolio()UniqueViolation catch → ValueError;ensure_schema()UNIQUE 제약으로 DB 레벨 보장 ✓
- Evidence:
- AC-6:
--force없는updatename 변경 시 명령 중단 또는 confirm 프롬프트 표시 확인- Evidence:
update_portfoliocommand —if new_name is not None: _confirm(force, ...)로직;test_update_new_name_renames_portfolio는--force있을 때만 성공 ✓
- Evidence:
- AC-7:
[a-zA-Z0-9._:-]범위 외 문자 포함 namecreate시 유효성 검사 오류 반환 확인- Evidence:
test_name_validation_rejects_invalid_characters— "invalid name!" → exit_code=1 ✓
- Evidence:
- AC-8: name 길이 0 또는 100자 초과 시 유효성 검사 오류 반환 확인
- Evidence:
test_name_validation_rejects_empty_name— 빈 문자열 → exit_code != 0;_NAME_RE = re.compile(r"^[a-zA-Z0-9._:\-]{1,100}$")regex로 1~100자 강제 ✓
- Evidence:
- AC-1:
-
REQ-018:
- AC-1:
GET /v1/assets응답assets[].asset_id가 UUID 형식 확인- Evidence:
v1_assets.py—asset_id=p.portfolio_id; REQ-016 이후 portfolio_id는 UUID; full test suite 129 passed ✓
- Evidence:
- AC-2: UUID
asset_id로POST /v1/assets/{asset_id}/ledger/trades호출 시 정상 처리 확인- Evidence:
v1_ledger.py—repo.get(asset_id)로 포트폴리오 존재 확인; UUID portfolio_id로 정상 동작 ✓
- Evidence:
- AC-3: 존재하지 않는 UUID
asset_id로 ledger/trades 호출 시 HTTP 404 반환 확인- Evidence:
repo.get()실패 → ValueError → HTTP 404 처리 (기존 패턴 유지) ✓
- Evidence:
- AC-4:
/portfolios/{portfolio_id}UUID 호출 시 정상 응답 반환 확인- Evidence: HTTP API path는
str수용; UUID 형식도 통과;tests/test_portfolio_ownership.py4/4 passed ✓
- Evidence: HTTP API path는
- AC-5:
docs/discovery/dcy-002_20260502_trex-basic-consumer-api-contract.mdA-3 항목에 철회 주석 존재 확인- Evidence: dcy-002 A-3 항목 아래 [철회 — 2026-05-11 REQ-018] 주석 추가 완료 ✓
- AC-1:
-
REQ-019:
- AC-1:
docs/project-structure.md에get_portfolio_by_name_and_user()메서드 및portfolio_idUUID 의미 반영 확인- Evidence: app/repositories/ 섹션에 "Key methods added in bat-006:
get_portfolio_by_name_and_user()" 추가 ✓
- Evidence: app/repositories/ 섹션에 "Key methods added in bat-006:
- AC-2:
docs/runtime-flows.md에 CLI<name>+--user식별 흐름 및GET /v1/assetsasset_idUUID 반환 반영 확인- Evidence: "Flow: CLI Portfolio Command — Name+User Resolution" 섹션 신규 추가; GET /v1/assets flow step 6 UUID 명시 ✓
- AC-3:
docs/data-model.md에portfolios테이블portfolio_id(UUID PK),name(TEXT),(owner_user_id, name)UNIQUE 제약 반영 확인- Evidence: Key Fields에
portfolio_id :: uuid,name :: text추가; Uniqueness Constraints 섹션 신규 추가 ✓
- Evidence: Key Fields에
- AC-4:
docs/interface-contract.md에GET /v1/assetsasset_idUUID 반환 명시 및 trex-basic 동시 배포 계획 기록 확인- Evidence: "Interface: v1 Consumer API (trex-basic)" 섹션 신규 추가; Deployment Constraint (bat-006) 명시 ✓
- AC-1:
Evidence
- Test:
tests/test_portfolio_uuid.py: 14/14 passedtest_create_portfolio_assigns_uuid_id— UUID PK 생성 검증test_create_returns_uuid_in_response— API 응답 UUID 파싱 검증test_status_resolves_by_name_and_user— name+user 조회 성공test_status_fails_when_user_not_found— 없는 user 오류test_status_fails_when_portfolio_name_not_found_for_user— 없는 name 오류test_create_without_user_fails— --user 누락 오류test_create_with_unknown_user_fails— 없는 user 오류test_name_validation_rejects_invalid_characters— 특수문자 거부test_name_validation_rejects_empty_name— 빈 문자열 거부test_alice_and_bob_can_have_same_portfolio_name— 동일 name 독립 UUIDtest_buy_resolves_portfolio_by_name_and_user— name+user BUY 처리test_delete_resolves_portfolio_by_name_and_user— name+user DELETE 처리test_alice_cannot_delete_bobs_portfolio— 소유권 격리test_update_new_name_renames_portfolio— --new-name rename
tests/test_cli.py: 49/49 passed (FakeRepo 및 5개 테스트 업데이트 포함)tests/test_portfolio_ownership.py: 4/4 passed- Full suite: 129/129 passed
- Manual:
- Alembic migration SQL 코드 리뷰: name 컬럼 추가, FK UPDATE, UUID PK 교체, UNIQUE 제약 추가, orphan check 포함
- dcy-002 A-3 철회 주석 문서 내 직접 확인
- baseline 4개 문서 항목별 내용 확인
Result
- Ready for Release: true
- Blocking Issues: 없음
- Notes:
- Alembic migration은 FakeRepo 기반 단위 테스트만 수행됨; 실제 PostgreSQL 인스턴스 검증은 release 시 수행 권장
- trex-basic 동시 배포 조정 필요 (asset_id TEXT → UUID 형식 변경)