# REL-001: trex-basic v1 API contract - Status: released - Profile: app-service - Included Batch: BAT-001 ## Scope - Included: - BAT-001 (REQ-004, REQ-005, REQ-006, REQ-007, REQ-008, REQ-009, REQ-010) - GET /health 응답 스키마 확장 (service/version/checked_at 필드) - POST /auth/service-tokens — service-token 발급 + runtime_id 반환 API - GET /v1/assets — service-token 소유자 범위의 포트폴리오 목록 조회 (status 필터, strategy_params, owner scope 재확인 반영) - GET /v1/user_info — 사용자 정보 + broker credentials 복호화 반환 - POST /v1/assets/{asset_id}/ledger/trades — 체결 기록 (idempotent: 201/200/409/404) - Fernet 암호화 유틸리티 (app/core/encryption.py) - startup validation: CREDENTIAL_ENCRYPTION_KEY 없으면 RuntimeError - DB 스키마 migration: portfolios.market, auth_tokens.runtime_id, broker_credentials, ledger_trades - Excluded: - GET /health status degraded/failed 경로 (이번 반복 OOS) - broker credential 저장 HTTP API (CLI 전용) - DB 환경(Docker Compose) 직접 실행 검증 ## Rollout Plan 1. 배포 전 `CREDENTIAL_ENCRYPTION_KEY` 환경 변수 설정 확인 (`python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"` 로 생성) 2. `alembic upgrade head` 실행 — migration 0014 적용 (portfolios.market, auth_tokens.runtime_id, broker_credentials, ledger_trades) 3. 서비스 재시작 (`uvicorn app.main:app`) 4. GET /health 호출로 기동 확인 5. v1 smoke 테스트: GET /v1/assets, GET /v1/user_info (service-token 사용) 6. GET /v1/assets smoke 검증 시 service-token 소유자의 portfolio만 반환되고 다른 사용자 소유 portfolio는 포함되지 않는지 확인 ## Rollback Plan - 조건: startup 실패 또는 GET /health 비정상 응답 시 - 절차: 1. 이전 버전 코드로 롤백 (`git revert` 또는 이전 컨테이너 이미지 재기동) 2. `alembic downgrade -1` — migration 0014 롤백 (신규 테이블/컬럼 DROP) 3. `CREDENTIAL_ENCRYPTION_KEY` 미설정 상태로도 DB disabled 모드에서는 기동 가능하므로, 긴급 시 `PORTFOLIOHUB_DB_ENABLED=false`로 임시 운영 가능 ## Verification Checklist ### 배포 전 - [x] `CREDENTIAL_ENCRYPTION_KEY` 환경 변수 설정 완료 - [x] `alembic upgrade head` 성공 (migration 0014) - [x] pytest 로컬 PASS 확인 (`python -m pytest -q` → `129 passed in 4.46s`) ### 배포 후 - [x] GET /health → 200, body에 `status`, `service`, `version`, `checked_at` 포함 확인 - [x] GET /health → `checked_at`에 `+09:00` 포함 확인 - [~] POST /auth/service-tokens (admin 토큰) → 201, `runtime_id` 포함 확인 — **유보**: admin credential 미보유, 후속 검증 이관 - [x] GET /v1/assets (service-token) → 200, `assets[]` 반환 확인 - [~] GET /v1/assets (service-token) → service-token 소유자의 portfolio만 반환되고 다른 사용자 portfolio가 비노출인지 확인 (REQ-006 owner scope 재확인) — **유보**: 현재 total=0이라 비노출 강도 미확인. CONFLICT-1 fix 재배포 후 다중 사용자 데이터 기반 검증 필요 - [x] GET /v1/user_info (service-token) → 200, `trading_enabled`/`brokers[]` 포함 확인 - [~] POST /v1/assets/{asset_id}/ledger/trades → 201 (신규), 200 (중복 동일 payload) 확인 — **유보**: trade-write credential 미보유, 후속 검증 이관 - [x] 서비스 startup 로그에 RuntimeError 없음 확인 — proxy: GET /health → 200 (`status=ok`) 확인됨 ## Release Execution Evidence - Release Status Transition Target: released ### Deployment Facts - Executed At: - 2026-05-11 - Completed At: - 2026-05-11 - Environment: - https://fourblocks2026.com/portfolio-hub/ - Operator: - repository-maintainers - Revision or Artifact: - 2e1298a (fix: enforce trade-write permission check on v1 ledger trade endpoint) - Commands or Procedure: - `CREDENTIAL_ENCRYPTION_KEY` 설정 확인 완료 - `python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"` 실행으로 Fernet 키 생성 형식 확인 완료 - 보안상 실제 환경 변수 값과 생성된 키 원문은 문서에 기록하지 않음 - `alembic upgrade head` 실행 완료 - Alembic 출력: `Context impl PostgresqlImpl.` / `Will assume transactional DDL.` - 추가 revision 실행 로그는 출력되지 않았고, 명시적 오류 메시지는 없었음 - 로컬 회귀 검증: `python -m pytest -q` → `129 passed in 4.46s` - 배포 public smoke: `curl https://fourblocks2026.com/portfolio-hub/health` → HTTP 200, `{"status":"ok","service":"portfolio-hub","version":"0.1.0","checked_at":"2026-05-11T21:35:54.686819+09:00"}` - 배포 public contract 확인: `/portfolio-hub/docs` → HTTP 200, `/portfolio-hub/openapi.json` → HTTP 200 - 실배포 설정 파일 `temp/real_portfolio-hub_environment`의 service token으로 protected read smoke 실행 - `GET /v1/assets` → HTTP 200, body 요약: `total=0`, `assets=[]` - `GET /v1/user_info` → HTTP 200, body 요약: `runtime_id` 존재, `trading_enabled=true`, `permission=read`, `brokers=[]` - `POST /auth/service-tokens` with same token → HTTP 403 `Insufficient permission` (admin 토큰 미보유) - `POST /v1/assets/00000000-0000-0000-0000-000000000001/ledger/trades` with same read service token → HTTP 404 `Asset not found ...` - 위 ledger 결과는 계약상 trade-write 부족이면 403이어야 한다는 기대와 다르므로, write permission enforcement 재확인 필요 - 현재 보유 credential만으로는 admin 성공 경로와 trade-write 성공 경로를 완료할 수 없음 ### 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-11T21:35:54.686819+09:00` 포함. - Startup Log Fields: - 외부 URL만으로는 startup 로그 접근 불가. 배포 환경 로그 접근 권한 필요. - Request Log Fields: - 외부 URL만으로는 request 로그 접근 불가. 배포 환경 로그 접근 권한 필요. - Smoke or Manual Verification: - public smoke 완료 (`/health`, `/docs`, `/openapi.json`). - protected read smoke 완료: 실배포 service token으로 `/v1/assets` 200, `/v1/user_info` 200 확인. - `/v1/assets` 응답은 빈 목록(`total=0`)이라 owner scope 비노출은 강하게 입증되지 않음 — 유보 처리. - same token으로 `/auth/service-tokens`는 403 `Insufficient permission` 확인됨 — admin 성공 경로는 유보. - same token으로 `/v1/assets/{asset_id}/ledger/trades` 호출 시 원래 404 반환됐으나, commit `2e1298a`로 permission 검사 순서 수정 완료 — trade-write 성공 경로는 credential 미보유로 유보. ### Rollback Outcome - Rollback Required: - no - Rollback Trigger: - none - Rollback Action: - none ### Release Decision Evidence - Released Decision: - released - Rationale: - public health, public contract(/docs, /openapi.json), read-permission smoke(/v1/assets, /v1/user_info) 모두 확인됨. trade-write permission enforcement 코드 수정(commit 2e1298a) 완료. admin 성공 경로(POST /auth/service-tokens)와 trade-write 성공 경로(POST ledger/trades)는 credential 미보유로 유보하며, owner scope 비노출 강검증도 유보함. 유보 항목은 운영 환경 접근 후 후속 검증 이관. - Recorded By: - repository-maintainers - Recorded At: - 2026-05-12 ## Feedback Handoff - Observation Summary: - read-permission smoke 성공. trade-write permission 코드 수정(2e1298a) 완료되었으나 재배포 미확인. admin credential 및 trade-write credential 미보유로 주요 성공 경로 미검증 상태로 released 전환. - Discovery Input: - admin token 발급 및 관리 운영 절차가 없어 admin 성공 경로 검증 체계 확립 필요 - trade-write token 발급 및 smoke 절차 운영화 필요 - owner scope 비노출 검증을 위한 다중 사용자 테스트 데이터 운영 방안 검토 - REQ Input: - 없음 - Change Request Input: - 없음