Files
portfolio-hub/docs/batches/bat-001_20260502_trex-basic-v1-api-contract/implementation.md
T
genichin 3509606c7e feat(REQ-005): implement TrEx Basic V1 API contract with auth, assets, ledger, and user endpoints
- Add V1 API routes for assets, ledger, and user info with complete CRUD operations
- Implement authentication scopes and request validation via auth_routes.py
- Extend schemas with V1-specific models for accounts, holdings, and positions
- Add database queries and aggregations for P&L, performance, and account data
- Include comprehensive test coverage for all V1 endpoints and integration flows
- Update batch and release documentation with implementation and verification evidence
- Sync project structure and runtime flows per V1 API contract requirements

Closes implementation phase of BAT-001 (TrEx Basic V1 API Contract)
2026-05-02 11:37:42 +00:00

10 KiB

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. app/core/encryption.py 신규 구현
  2. app/core/config.py CREDENTIAL_ENCRYPTION_KEY 추가 및 require_credential_encryption_key() 메서드
  3. Alembic migration 파일 작성 (20260502_0014_v1_api_schema.py)
  4. app/domain/models.py 모델 필드/클래스 추가
  5. auth_service.py runtime_id 생성·저장 구현
  6. service_tokens.py runtime_id 출력 추가
  7. app/core/auth.py AuthContext.runtime_id 추가
  8. app/api/health.py HealthResponse 스키마 적용
  9. app/api/v1_assets.py 구현
  10. app/api/v1_user_info.py 구현 (runtime_id 없는 구형 토큰 → HTTP 404)
  11. app/api/v1_ledger.py 구현 (idempotent)
  12. app/repositories/postgres.py 쿼리 추가
  13. app/main.py /v1 라우터 등록
  14. 테스트 작성 및 전체 테스트 스위트 통과 (98 passed, 2026-05-01 blocker 수정 후)

Validation

  • pytest 98개 전체 통과 (2026-05-01, blocker B-1~B-12 수정 후)
  • alembic upgrade head 성공 (로컬 Docker Compose 환경 — DB 없이 코드 검증만 완료)
  • GET /health 응답에 service/version/checked_at(+09:00 KST) 포함 확인 (테스트)
  • GET /v1/assets 200 응답, 필드명 확인 (cash/quantity/broker_type/strategy_params)
  • GET /v1/assets ?status 필터 확인 (테스트)
  • GET /v1/user_info runtime_id 없는 토큰 → 404 확인 (테스트)
  • GET /v1/user_info trading_enabled, brokers[] 확인 (테스트)
  • GET /v1/user_info Fernet 복호화 → credential_payload 반환 확인 (테스트)
  • POST /v1/assets/{asset_id}/ledger/trades: new → 201, duplicate same payload → 200, different payload → 409, unknown asset → 404 (테스트)
  • POST /auth/service-tokens → 201 + runtime_id 확인 (테스트)
  • startup: CREDENTIAL_ENCRYPTION_KEY 없으면 RuntimeError (테스트)
  • Fernet encrypt/decrypt roundtrip 확인 (테스트)

Blocker Fixes (2026-05-01)

  • B-1: POST /auth/service-tokens 엔드포인트 추가 (app/api/auth_routes.py, app/schemas/auth.py)
  • B-2: GET /v1/assets ?status 필터 추가 (app/api/v1_assets.py)
  • B-3: 응답 필드명 수정 (cash/quantity/broker_type/strategy_id → 계약 정의명)
  • B-4: strategy_params {} 폴백 구현
  • B-5: UserInfoResponse trading_enabled 필드 추가
  • B-6: brokers[] 배열 구현 + Fernet 복호화
  • B-7: 중복 수신 → HTTP 200 + status="duplicate" (was created: bool)
  • B-8: 다른 payload → HTTP 409
  • B-9: 없는 asset_id → HTTP 404
  • B-10: lifespan startup validation (CREDENTIAL_ENCRYPTION_KEY 없으면 RuntimeError)
  • B-11: list_broker_credentials postgres 구현
  • B-12: docs/project-structure.md, docs/runtime-flows.md에 신규 모듈 및 v1 흐름 반영

Changed Files (Blocker Fixes)

  • app/api/auth_routes.py (수정: POST /auth/service-tokens 엔드포인트 추가)
  • app/schemas/auth.py (수정: IssueServiceTokenRequest, IssueServiceTokenApiResponse 추가)
  • app/schemas/v1.py (수정: 필드명 전면 수정, BrokerItem, trading_enabled, status)
  • app/api/v1_assets.py (수정: status 필터, strategy_params, 새 필드명)
  • app/api/v1_user_info.py (수정: trading_enabled, brokers[], Fernet 복호화, Depends(get_settings))
  • app/api/v1_ledger.py (수정: 200/201/404/409 분기, _payloads_match 비교)
  • app/repositories/postgres.py (수정: list_broker_credentials 추가)
  • app/main.py (수정: startup validation 추가)
  • tests/test_v1.py (전면 재작성: 19개 테스트로 확장)
  • tests/test_app.py (수정: db_enabled=True 테스트에 credential_encryption_key 추가)
  • docs/project-structure.md (수정: v1 모듈, encryption.py 반영)
  • docs/runtime-flows.md (수정: v1 API 흐름, startup 검증 흐름 추가)

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 기준)