feat(V1-API): implement TREX-Basic consumer API contract with encryption and persistence

- Add V1 API endpoints: assets, ledger, user-info
- Implement Fernet-based credential payload encryption (req-010)
- Extend health response schema with runtime info (req-004)
- Add service token runtime ID issuance (req-005)
- Implement database schema migration for V1 API (req-009)
- Add comprehensive test coverage for V1 endpoints
- Update SRS with 10 new requirements (REQ-004 through REQ-011)
- Create batch planning, design, and verification for BAT-001
- Integrate review-discovery StagePilot skill
- Update documentation indices and baseline specs
This commit is contained in:
2026-05-02 09:06:15 +00:00
parent 24096a1e58
commit ce63c75c9c
37 changed files with 2851 additions and 21 deletions
@@ -0,0 +1,157 @@
# BAT-001 Implementation
- Status: implemented
- Batch: BAT-001
## Plan Summary
design.md에서 확정된 결정 사항을 기반으로 아래 범위를 구현한다.
1. app/core/encryption.py 신규 — Fernet 암복호화 유틸리티
2. app/core/config.py — CREDENTIAL_ENCRYPTION_KEY 필드 추가 및 require_credential_encryption_key() 메서드
3. Alembic migration 신규 — 4개 스키마 변경 (IF NOT EXISTS 패턴)
4. app/domain/models.py — AuthToken.runtime_id, TokenPrincipal.runtime_id, BrokerCredential, LedgerTrade 추가
5. app/services/auth_service.py — service-token 발급 시 UUID v4 runtime_id 생성·저장
6. app/cli/commands/service_tokens.py — 응답/출력에 runtime_id 포함
7. app/core/auth.py — AuthContext.runtime_id 추가, _resolve_auth_context에서 전달
8. app/api/health.py, app/schemas/v1.py — HealthResponse 스키마 적용
9. app/api/v1_assets.py — GET /v1/assets 구현
10. app/api/v1_user_info.py — GET /v1/user_info 구현 (R-4: 404 반환)
11. app/api/v1_ledger.py — POST /v1/assets/{asset_id}/ledger/trades 구현
12. app/repositories/postgres.py — broker_credentials, ledger_trades, runtime_id 쿼리 추가
13. app/main.py — /v1 라우터 등록
14. tests/ — 테스트 파일 작성 및 기존 테스트 확장
## Changed Files
- app/core/encryption.py (신규)
- app/core/config.py (수정: credential_encryption_key 필드, require_credential_encryption_key 메서드, model_validator import)
- app/core/auth.py (수정: AuthContext.runtime_id, _resolve_auth_context runtime_id 전달)
- migrations/versions/20260502_0014_v1_api_schema.py (신규)
- app/domain/models.py (수정: AuthToken.runtime_id, TokenPrincipal.runtime_id, Portfolio.market, BrokerCredential, LedgerTrade)
- app/services/auth_service.py (수정: uuid import, runtime_id 생성·전달)
- app/cli/commands/service_tokens.py (수정: ServiceTokenIssueCliResponse에 runtime_id 포함)
- app/api/health.py (수정: HealthResponse 스키마 적용)
- app/schemas/auth.py (수정: ServiceTokenIssueCliResponse.runtime_id 추가)
- app/schemas/v1.py (신규: AssetsResponse, UserInfoResponse, LedgerTradeRequest/Response)
- app/api/v1_assets.py (신규)
- app/api/v1_user_info.py (신규)
- app/api/v1_ledger.py (신규)
- app/repositories/postgres.py (수정: _SELECT_AUTH_TOKEN runtime_id, _SELECT_PORTFOLIO market, _row_to_auth_token runtime_id, _row_to_portfolio market, create_auth_token runtime_id, get_token_principal runtime_id, broker_credentials CRUD, ledger_trades CRUD, list_portfolios_with_strategies)
- app/main.py (수정: v1 라우터 3개 등록)
- tests/test_app.py (수정: test_healthcheck 응답 필드 검증 업데이트)
- tests/test_auth.py (수정: _AuthRepo.create_auth_token runtime_id 파라미터 추가)
- tests/test_cli.py (수정: FakeRepo.create_auth_token runtime_id 파라미터 추가)
- tests/test_v1.py (신규: health/assets/user_info/ledger 9개 테스트)
## Execution Log
1. [x] app/core/encryption.py 신규 구현
2. [x] app/core/config.py CREDENTIAL_ENCRYPTION_KEY 추가 및 require_credential_encryption_key() 메서드
3. [x] Alembic migration 파일 작성 (20260502_0014_v1_api_schema.py)
4. [x] app/domain/models.py 모델 필드/클래스 추가
5. [x] auth_service.py runtime_id 생성·저장 구현
6. [x] service_tokens.py runtime_id 출력 추가
7. [x] app/core/auth.py AuthContext.runtime_id 추가
8. [x] app/api/health.py HealthResponse 스키마 적용
9. [x] app/api/v1_assets.py 구현
10. [x] app/api/v1_user_info.py 구현 (runtime_id 없는 구형 토큰 → HTTP 404)
11. [x] app/api/v1_ledger.py 구현 (idempotent)
12. [x] app/repositories/postgres.py 쿼리 추가
13. [x] app/main.py /v1 라우터 등록
14. [x] 테스트 작성 및 전체 테스트 스위트 통과 (88 passed)
## Validation
- [x] pytest 88개 전체 통과 (2026-05-02)
- [ ] alembic upgrade head 성공 (로컬 Docker Compose 환경 — DB 없이 코드 검증만 완료)
- [x] GET /health 응답에 service/version/checked_at(+09:00 KST) 포함 확인 (테스트)
- [x] GET /v1/assets 200 응답 확인 (테스트)
- [x] GET /v1/user_info runtime_id 없는 토큰 → 404 확인 (테스트)
- [x] POST /v1/assets/{asset_id}/ledger/trades 중복 → created=false 확인 (테스트)
## Design Decisions (confirmed during implementation)
- CREDENTIAL_ENCRYPTION_KEY: Settings 생성 시 validator 없음. `require_credential_encryption_key()` 메서드 호출 시 RuntimeError 발생 (lazy validation)
- R-4 (구형 service-token runtime_id 없음): HTTP 404, detail="runtime_id not assigned to this token"
- disabled_reason: is_active=False 시 "account_inactive" 고정값
## Remaining Risks
- (해소) R1: CREDENTIAL_ENCRYPTION_KEY — lazy validation으로 처리. 테스트 환경 unblocked.
design.md에서 확정된 결정 사항을 기반으로 아래 범위를 구현한다.
1. app/core/encryption.py 신규 — Fernet 암복호화 유틸리티
2. app/core/config.py — CREDENTIAL_ENCRYPTION_KEY 필드 추가 및 startup validation
3. Alembic migration 신규 — 4개 스키마 변경 (IF NOT EXISTS 패턴)
4. app/domain/models.py — AuthToken.runtime_id, BrokerCredential, LedgerTrade 추가
5. app/services/auth_service.py — service-token 발급 시 UUID v4 runtime_id 생성·저장
6. app/api/auth_routes.py, app/cli/commands/service_tokens.py — 응답/출력에 runtime_id 포함
7. app/api/health.py, app/schemas/ — HealthResponse 스키마 적용
8. app/api/v1_assets.py — GET /v1/assets 구현
9. app/api/v1_user_info.py — GET /v1/user_info 구현 (R-4: 404 반환)
10. app/api/v1_ledger.py — POST /v1/assets/{asset_id}/ledger/trades 구현
11. app/repositories/postgres.py — broker_credentials, ledger_trades, runtime_id 쿼리 추가
12. app/main.py — /v1 라우터 등록
13. 테스트 파일 작성 및 기존 테스트 확장
## Changed Files
- app/core/encryption.py (신규)
- app/core/config.py (수정)
- migrations/versions/20260502_0014_v1_api_schema.py (신규)
- app/domain/models.py (수정)
- app/services/auth_service.py (수정)
- app/api/auth_routes.py (수정)
- app/cli/commands/service_tokens.py (수정)
- app/api/health.py (수정)
- app/schemas/ (수정: HealthResponse 추가, v1 스키마 추가)
- app/api/v1_assets.py (신규)
- app/api/v1_user_info.py (신규)
- app/api/v1_ledger.py (신규)
- app/repositories/postgres.py (수정)
- app/main.py (수정)
- tests/test_health.py (신규 또는 test_app.py 확장)
- tests/test_auth.py (확장)
- tests/test_v1_assets.py (신규)
- tests/test_v1_user_info.py (신규)
- tests/test_v1_ledger.py (신규)
## Execution Log
_(구현 진행 시 단계별 기록)_
1. [ ] app/core/encryption.py 신규 구현
2. [ ] app/core/config.py CREDENTIAL_ENCRYPTION_KEY 추가 및 startup validation
3. [ ] Alembic migration 파일 작성 및 로컬 upgrade head 성공 확인
4. [ ] app/domain/models.py 모델 필드/클래스 추가
5. [ ] auth_service.py runtime_id 생성·저장 구현
6. [ ] auth_routes.py, service_tokens.py runtime_id 출력 추가
7. [ ] app/api/health.py HealthResponse 스키마 적용
8. [ ] app/api/v1_assets.py 구현
9. [ ] app/api/v1_user_info.py 구현
10. [ ] app/api/v1_ledger.py 구현
11. [ ] app/repositories/postgres.py 쿼리 추가
12. [ ] app/main.py /v1 라우터 등록
13. [ ] 테스트 작성 및 전체 테스트 스위트 통과
## Validation
_(구현 완료 시 기록)_
- [ ] pytest 전체 통과
- [ ] CREDENTIAL_ENCRYPTION_KEY 없이 기동 시 RuntimeError 확인
- [ ] alembic upgrade head 성공 (로컬 Docker Compose 환경)
- [ ] GET /health 응답에 service/version/checked_at 포함 확인
- [ ] GET /v1/assets 200 응답 확인
- [ ] GET /v1/user_info runtime_id 없는 토큰 → 404 확인
- [ ] POST /v1/assets/{asset_id}/ledger/trades 중복 → 200+duplicate 확인
## Remaining Risks
_(구현 전 상태 — 진행 중 업데이트)_
- R1: CREDENTIAL_ENCRYPTION_KEY 테스트 픽스처 처리 방식 확정 필요
- R2: psycopg UniqueViolation import 경로 확인 필요 (psycopg v3 기준)