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