chore: restructure SRS for asset catalog and tag model redesign (dcy-001/002, REQ-001~008)
Architecture Redesign (May 19, 2026): - Separate admin-managed asset catalog from user portfolios - Eliminate portfolio as asset definition; clarify portfolio as user position - Introduce new asset_catalog + portfolio structure Discovery Documents: - dcy-001: asset-catalog-and-user-portfolio-model — admin asset management and user portfolio separation - dcy-002: tag-ownership-and-applicability-policy — tag model implementation strategy New Requirements (REQ-001~008): - REQ-001: tags master table introduction (Data, Proposed) - REQ-002: assets.tag_ids UUID[] column addition (Data, Proposed) - REQ-003: portfolios.tag_ids and portfolio_tags removal (Data, Proposed) - REQ-004: tags master HTTP API (Interface, Proposed) - REQ-005: tag apply/remove HTTP API (Interface, Proposed) - REQ-006: portfolio_tags data migration (Migration, Proposed) - REQ-007: pfhub tag CLI commands (Interface, Proposed) - REQ-008: tag model baseline docs update (Documentation, Proposed) Cleanup: - Remove archived SRS documents (REQ-001~029 old structure) - Remove archived batch documentation (BAT-001~010) - Remove archived discovery documents (dcy-001~006 old structure) - Remove archived release documentation (REL-001~006) Data Model Updates: - Add Deployment category to SRS structure - Add Data category for new data model requirements - Update app/cli/core/utils.py for new tag handling Documentation: - Create new SRS index with consolidated requirement structure - Update docs/discovery/index.md with new discovery references - Migrate from requirement-centric to domain-model-centric organization Rationale: - Existing single-portfolio model lacks admin catalog governance - New asset catalog enables central management of tradeable symbols - Tag system supports user-driven asset organization and discovery - Cleaner separation of concerns between admin operations and user trading
This commit is contained in:
@@ -1,16 +0,0 @@
|
||||
# Release Index
|
||||
|
||||
## 목적
|
||||
- 이 문서는 release 단위의 전역 인덱스다.
|
||||
- 각 release는 하나 이상의 release-candidate batch를 묶고, profile(`docs-only` | `tooling` | `app-service`)에 맞는 배포와 후속 환류를 추적한다.
|
||||
|
||||
## Release Register
|
||||
|
||||
| REL ID | Profile | Status | Included Batch | Discovery/REQ Input | Link |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| REL-001 | app-service | released | BAT-001 | dcy-002 / REQ-004~010 | [rel-001_20260502_trex-basic-v1-api-contract](./rel-001_20260502_trex-basic-v1-api-contract.md) |
|
||||
| REL-002 | tooling | released | BAT-002, BAT-005, BAT-008 | minor-change + dcy-002 / REQ-011, REQ-012, REQ-015 | [rel-002_20260511_operator-cli-tooling-and-baseline-docs-sync](./rel-002_20260511_operator-cli-tooling-and-baseline-docs-sync.md) |
|
||||
| REL-003 | tooling | released | BAT-003, BAT-004, BAT-007 | dcy-003 + dcy-001 / REQ-013, REQ-014, REQ-001~003 | [rel-003_20260512_cli-user-scoping-and-db-ops-runbook](./rel-003_20260512_cli-user-scoping-and-db-ops-runbook.md) |
|
||||
| REL-004 | app-service | released | BAT-006 | dcy-004 / REQ-016~019 | [rel-004_20260512_portfolio-uuid-migration-and-api-uuid-switch](./rel-004_20260512_portfolio-uuid-migration-and-api-uuid-switch.md) |
|
||||
| REL-005 | docs-only | confirmed | BAT-009 | dcy-005 / REQ-020~022 | [rel-005_20260512_production-operator-runbook-and-credential-matrix](./rel-005_20260512_production-operator-runbook-and-credential-matrix.md) |
|
||||
| REL-006 | app-service | draft | BAT-010 | dcy-006 / REQ-005~009, REQ-011~012, REQ-023, REQ-028 | [rel-006_20260513_daemon-model-implementation](./rel-006_20260513_daemon-model-implementation.md) |
|
||||
@@ -1,142 +0,0 @@
|
||||
# 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:
|
||||
- 없음
|
||||
@@ -1,118 +0,0 @@
|
||||
# REL-002: operator CLI tooling and trex-basic baseline docs sync
|
||||
|
||||
- Status: released
|
||||
- Profile: tooling
|
||||
- Included Batch: BAT-002, BAT-005, BAT-008
|
||||
|
||||
## Scope
|
||||
|
||||
- Included:
|
||||
- BAT-002 (REQ-012) — `pfhub service-token rotate <name> [--force]` CLI 명령 추가
|
||||
- BAT-005 (REQ-015) — `pfhub credential set/list/remove` CLI 명령 그룹 추가
|
||||
- BAT-008 (REQ-011) — `docs/interface-contract.md`, `docs/data-model.md`, `docs/runtime-flows.md` trex-basic 계약 기준 baseline 동기화
|
||||
- rotate 운영 메모 — 새 토큰 배포 후 downstream consumer는 새 토큰으로 다시 인증하고 `GET /v1/user_info` 기준 `runtime_id`를 재조회해야 함
|
||||
|
||||
- Excluded:
|
||||
- BAT-001 app-service 배포 및 runtime health 확인
|
||||
- DB schema migration 실행
|
||||
- 신규 HTTP API 엔드포인트 추가 또는 서비스 프로세스 재기동 필수 변경
|
||||
|
||||
## Rollout Plan
|
||||
|
||||
1. 대상 운영자 환경에 BAT-002, BAT-005, BAT-008이 포함된 현재 revision을 배포하거나 패키지 갱신한다.
|
||||
2. `CREDENTIAL_ENCRYPTION_KEY` 설정 여부를 확인하고, rotate smoke용 no-expiry service-token과 credential smoke용 테스트 사용자를 준비한다.
|
||||
3. 비운영 토큰으로 `pfhub service-token rotate <name> --force`를 실행해 one-time token 출력과 DB 갱신을 확인한다.
|
||||
4. rotate한 토큰을 실제 consumer에 배포할 계획이 있으면, 새 토큰으로 재인증 후 `GET /v1/user_info`를 재호출해 새 `runtime_id`를 재인식하는 절차를 운영 메모에 반영한다.
|
||||
5. `pfhub credential set`, `pfhub credential list`, `pfhub credential remove --force` smoke를 실행해 broker credential 관리 동작을 확인한다.
|
||||
6. 배포 산출물 또는 저장소에서 baseline 문서 3종이 최신 내용으로 노출되는지 확인한다.
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
- 조건: CLI 명령 실행 실패, 패키지 회귀, 운영자 가이드 누락으로 release를 유지할 수 없을 때
|
||||
- 절차:
|
||||
1. 이전 revision 또는 패키지 버전으로 롤백한다.
|
||||
2. rotate smoke가 이미 토큰 값을 변경했으면, 해당 비운영 토큰을 다시 rotate하거나 새로 발급해 테스트 상태를 복구한다.
|
||||
3. credential smoke가 테스트 레코드를 남겼으면 `pfhub credential remove --force` 또는 기존 값 재설정으로 정리한다.
|
||||
4. 문서 게시 산출물이 있다면 이전 문서 버전으로 되돌린다.
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
### 배포 전
|
||||
|
||||
- [x] BAT-002 verification `verified`, BAT-005 verification `passed`, BAT-008 verification `passed` 확인
|
||||
- [x] REQ-011, REQ-012, REQ-015가 `Implemented` 상태로 전환되었는지 확인
|
||||
- [x] `CREDENTIAL_ENCRYPTION_KEY` 설정 및 비운영 smoke 대상(token, user) 준비 확인 — tooling profile, test evidence로 대체
|
||||
- [x] DB schema migration이 이번 release 범위에 포함되지 않음을 운영자에게 재확인 — BAT-002/005/008 모두 tooling/docs 배치, 해당 없음
|
||||
|
||||
### 배포 후
|
||||
|
||||
- [x] `pfhub service-token rotate <name> --force` smoke 성공 및 one-time token 안내 메시지 확인 — BAT-002 test evidence로 대체: `test_cli_service_token_rotate_no_expiry_succeeds` 외 4개 PASS
|
||||
- [x] rotate 대상 consumer의 `runtime_id` 재조회 필요성 전달 또는 runbook 반영 확인 — REQ-012 CHG-20260511-01에 lifecycle 및 consumer 재조회 필요성 명시 완료
|
||||
- [x] `pfhub credential set/list/remove` smoke 성공 및 `encrypted_payload` 비노출 확인 — BAT-005 test evidence로 대체: `test_cli_credential_set_creates_record` 외 4개 PASS
|
||||
- [x] `docs/interface-contract.md`, `docs/data-model.md`, `docs/runtime-flows.md` 최신 반영본 확인 — BAT-008 verification REQ-011 AC-1~3 PASS
|
||||
|
||||
## Release Execution Evidence
|
||||
|
||||
- Release Status Transition Target: released
|
||||
|
||||
### Deployment Facts
|
||||
|
||||
- Executed At:
|
||||
- 2026-05-11
|
||||
- Completed At:
|
||||
- 2026-05-12
|
||||
- Environment:
|
||||
- local workspace (tooling profile — 서버 배포 불필요)
|
||||
- Operator:
|
||||
- repository-maintainers
|
||||
- Revision or Artifact:
|
||||
- 2e1298a (fix: enforce trade-write permission check on v1 ledger trade endpoint)
|
||||
- Commands or Procedure:
|
||||
- tooling profile — 별도 패키지 설치 단계 없음
|
||||
- CLI regression 확인: `python -m pytest tests/test_cli.py -q` → `49 passed in 1.49s` (BAT-005 verification 기준)
|
||||
- rotate CLI evidence: BAT-002 verification — `test_cli_service_token_rotate_*` 5개 PASS
|
||||
- credential CLI evidence: BAT-005 verification — `test_cli_credential_*` 5개 PASS
|
||||
- baseline 문서 sync: BAT-008 verification — REQ-011 AC-1~3 PASS
|
||||
|
||||
### Profile-Specific Checks
|
||||
|
||||
- tooling:
|
||||
- Install or Upgrade Smoke:
|
||||
- Source checkout 기준 tooling release로 별도 패키지 설치 단계는 없음. 현재 workspace revision에서 CLI regression evidence 확인: BAT-005 verification 기준 `python -m pytest tests/test_cli.py -q` → `49 passed in 1.49s`.
|
||||
- CLI or Script Execution:
|
||||
- BAT-002 verification 기준 rotate CLI acceptance evidence 확보: `test_cli_service_token_rotate_no_expiry_succeeds`, `test_cli_service_token_rotate_unknown_name_exits_error`, `test_cli_service_token_rotate_revoked_token_exits_error`, `test_cli_service_token_rotate_with_expiry_exits_error`, `test_cli_service_token_rotate_can_abort` 모두 PASS.
|
||||
- BAT-005 verification 기준 credential CLI acceptance evidence 확보: `test_cli_credential_set_creates_record`, `test_cli_credential_list_hides_payload`, `test_cli_credential_set_with_unknown_user_exits_error`, `test_cli_credential_remove_deletes_record`, `test_cli_credential_set_requires_encryption_key` 모두 PASS.
|
||||
- BAT-008 verification 기준 baseline 문서 sync evidence 확보: REQ-011 AC-1~3 PASS, Ready for Release true.
|
||||
- Compatibility Note:
|
||||
- rotate는 `runtime_id`를 새 값으로 갱신하므로 downstream consumer는 새 토큰 배포 후 `GET /v1/user_info` 기준 `runtime_id`를 재조회해야 함
|
||||
|
||||
### Rollback Outcome
|
||||
|
||||
- Rollback Required:
|
||||
- no
|
||||
- Rollback Trigger:
|
||||
- none
|
||||
- Rollback Action:
|
||||
- none
|
||||
|
||||
### Release Decision Evidence
|
||||
|
||||
- Released Decision:
|
||||
- released
|
||||
- Rationale:
|
||||
- BAT-002/005/008 모두 release-candidate. REQ-011/012/015 모두 Implemented. tooling profile이므로 서버 재기동 불필요. rotate/credential 실환경 smoke는 각 batch test evidence(BAT-002 5개, BAT-005 5개 PASS)로 대체. baseline 문서 3종 BAT-008 완료로 확인. rotate 후 runtime_id lifecycle은 REQ-012 change log에 명시 완료.
|
||||
- Recorded By:
|
||||
- repository-maintainers
|
||||
- Recorded At:
|
||||
- 2026-05-12
|
||||
|
||||
## Feedback Handoff
|
||||
|
||||
- Observation Summary:
|
||||
- tooling profile release 전 항목 모두 test evidence로 확인 완료. 실환경 CLI smoke는 수행하지 않고 batch verification evidence로 대체함.
|
||||
- Discovery Input:
|
||||
- rotate 후 downstream consumer(trex-basic) runtime_id 재인식 절차를 운영 runbook에 반영하는 것을 검토할 수 있음
|
||||
- REQ Input:
|
||||
- 없음
|
||||
- Change Request Input:
|
||||
- 없음
|
||||
@@ -1,127 +0,0 @@
|
||||
# REL-003: CLI user scoping and local DB ops runbook
|
||||
|
||||
- Status: released
|
||||
- Profile: tooling
|
||||
- Included Batch: BAT-003, BAT-004, BAT-007
|
||||
|
||||
## Scope
|
||||
|
||||
- Included:
|
||||
- BAT-003 (REQ-013) — `pfhub portfolio list --user <username>` 필수화; owner_user_id 기반 포트폴리오 필터링
|
||||
- BAT-004 (REQ-014) — `pfhub portfolio create --user <username>` 필수화; 생성 시 owner_user_id 설정
|
||||
- BAT-007 (REQ-001, REQ-002, REQ-003) — 로컬 DB 운영 runbook 및 baseline 문서 갱신
|
||||
- README.md "Local DB Validation Runbook" 섹션: init-db/migrate-db 절차, Scenario A/B, rollback 기준, release gate 기준
|
||||
- docs/runtime-flows.md: "Flow: Local DB Initialization and Validation", "Flow: Alembic vs ensure_schema() Schema Ownership Boundary"
|
||||
- docs/project-structure.md: "Schema Ownership Boundary" 섹션
|
||||
|
||||
- Excluded:
|
||||
- BAT-006 (REQ-016~019) — portfolios UUID migration 및 HTTP API/CLI UUID 전환 (app-service, 별도 릴리즈)
|
||||
- HTTP API 변경 없음 (서버 재기동 불필요)
|
||||
- DB 스키마 migration 없음
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- `pfhub portfolio list`에서 `--user <username>` 이 필수가 됨. `--user` 없이 실행 시 오류 메시지와 exit code 1 반환.
|
||||
- `pfhub portfolio create`에서 `--user <username>` 이 필수가 됨. `--user` 없이 실행 시 오류 메시지와 exit code 1 반환.
|
||||
- 기존 스크립트 또는 자동화에서 `portfolio list` / `portfolio create`를 `--user` 없이 호출하고 있다면 수정 필요.
|
||||
|
||||
## Rollout Plan
|
||||
|
||||
1. 패키지 또는 소스를 최신 커밋으로 업데이트한다.
|
||||
2. `pfhub --help` 실행 → `portfolio` 커맨드 그룹이 정상 로드되는지 확인한다.
|
||||
3. `pfhub portfolio list` (--user 없이) 실행 → exit code 1과 오류 메시지가 출력되는지 확인한다.
|
||||
4. `pfhub portfolio list --user <valid_username>` 실행 → 해당 사용자의 포트폴리오만 출력되는지 확인한다.
|
||||
5. `pfhub portfolio create <name> --symbol X --force` (--user 없이) 실행 → exit code 1과 오류 메시지가 출력되는지 확인한다.
|
||||
6. README.md "Local DB Validation Runbook" 섹션이 정상 렌더링되는지 확인한다.
|
||||
7. 서버 재기동 불필요.
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
- 이 릴리즈는 CLI 동작 변경과 문서 추가만 포함한다. DB 상태 변경 없음.
|
||||
- 이전 버전으로 rollback 시: 이전 소스/패키지로 되돌리면 `--user` 없이 `portfolio list` / `portfolio create` 실행 가능한 이전 동작으로 복원된다.
|
||||
- 문서 rollback은 git revert로 처리한다.
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
### 배포 전 확인
|
||||
|
||||
- [x] BAT-003 verification.md Status: verified, Blocking Issues: 없음 확인
|
||||
- [x] BAT-004 verification.md Status: verified, Blocking Issues: 없음 확인
|
||||
- [x] BAT-007 verification.md Status: passed, Blocking Issues: 없음 확인
|
||||
- [x] `pytest tests/test_cli.py -v` 전체 통과 확인 — 49 passed in 1.44s
|
||||
- [x] README.md "Local DB Validation Runbook" 섹션 존재 확인
|
||||
- [x] docs/runtime-flows.md "Flow: Local DB Initialization and Validation" 섹션 존재 확인
|
||||
- [x] docs/project-structure.md "Schema Ownership Boundary" 섹션 존재 확인
|
||||
|
||||
### 배포 후 확인
|
||||
|
||||
- [x] `pfhub portfolio list` 실행 → `--user` 미입력 시 exit code 1 반환 확인 — test evidence: `test_cli_portfolio_list_without_user_exits_error` PASS
|
||||
- [x] `pfhub portfolio list --user <valid>` 실행 → 해당 사용자 포트폴리오만 반환 확인 — test evidence: `test_cli_portfolio_list_with_valid_user_filters_by_owner` PASS
|
||||
- [x] `pfhub portfolio create <name> --symbol X --force` 실행 → `--user` 미입력 시 exit code 1 반환 확인 — test evidence: `test_cli_portfolio_create_without_user_exits_error` PASS
|
||||
- [x] `pfhub portfolio create <name> --symbol X --user <valid> --force` 실행 → 정상 생성 확인 — test evidence: `test_cli_portfolio_create_with_valid_user_sets_owner` PASS
|
||||
|
||||
## Release Execution Evidence
|
||||
|
||||
- Release Status Transition Target: released
|
||||
|
||||
### Deployment Facts
|
||||
|
||||
- Executed At:
|
||||
- 2026-05-12
|
||||
- Completed At:
|
||||
- 2026-05-12
|
||||
- Environment:
|
||||
- local workspace (tooling profile — 서버 배포 불필요)
|
||||
- Operator:
|
||||
- repository-maintainers
|
||||
- Revision or Artifact:
|
||||
- 2e1298a978d789bae8bc6b31d9e94027fc63dc66
|
||||
- Commands or Procedure:
|
||||
- tooling profile — 별도 패키지 설치 단계 없음
|
||||
- CLI regression 확인: `.venv/bin/pytest tests/test_cli.py -v` → `49 passed in 1.44s`
|
||||
- portfolio list CLI evidence: BAT-003 verification — `test_cli_portfolio_list_without_user_exits_error`, `test_cli_portfolio_list_with_valid_user_filters_by_owner`, `test_cli_portfolio_list_with_unknown_user_exits_error`, `test_cli_portfolio_list_in_memory_mode_filters_owner` 모두 PASS
|
||||
- portfolio create CLI evidence: BAT-004 verification — `test_cli_portfolio_create_without_user_exits_error`, `test_cli_portfolio_create_with_valid_user_sets_owner`, `test_cli_portfolio_create_with_unknown_user_exits_error` 모두 PASS
|
||||
- DB runbook 문서 확인: BAT-007 verification — REQ-001/002/003 AC 전체 PASS
|
||||
|
||||
### Profile-Specific Checks
|
||||
|
||||
- tooling:
|
||||
- Install or Upgrade Smoke:
|
||||
- Source checkout 기준 tooling release로 별도 패키지 설치 단계는 없음. 현재 workspace revision에서 CLI regression evidence 확인: `.venv/bin/pytest tests/test_cli.py -v` → `49 passed in 1.44s`.
|
||||
- CLI or Script Execution:
|
||||
- BAT-003 verification 기준 portfolio list acceptance evidence 확보: `test_cli_portfolio_list_without_user_exits_error`, `test_cli_portfolio_list_with_valid_user_filters_by_owner`, `test_cli_portfolio_list_with_unknown_user_exits_error`, `test_cli_portfolio_list_in_memory_mode_filters_owner` 모두 PASS.
|
||||
- BAT-004 verification 기준 portfolio create acceptance evidence 확보: `test_cli_portfolio_create_without_user_exits_error`, `test_cli_portfolio_create_with_valid_user_sets_owner`, `test_cli_portfolio_create_with_unknown_user_exits_error` 모두 PASS.
|
||||
- BAT-007 verification 기준 DB runbook 문서 evidence 확보: REQ-001 AC-1~3, REQ-002 AC-1~2, REQ-003 AC-1~3 전체 PASS.
|
||||
- Compatibility Note:
|
||||
- Breaking change: `portfolio list`, `portfolio create` 명령에 `--user` 필수. 기존 스크립트 점검 필요.
|
||||
|
||||
### Rollback Outcome
|
||||
|
||||
- Rollback Required:
|
||||
- no
|
||||
- Rollback Trigger:
|
||||
- none
|
||||
- Rollback Action:
|
||||
- none
|
||||
|
||||
### Release Decision Evidence
|
||||
|
||||
- Released Decision:
|
||||
- released
|
||||
- Rationale:
|
||||
- BAT-003/004/007 모두 release-candidate. REQ-001/002/003/013/014 모두 Implemented. tooling profile이므로 서버 재기동 불필요. portfolio list/create CLI smoke는 각 batch test evidence(BAT-003 4개, BAT-004 3개 PASS)로 대체. DB runbook 문서 3종 BAT-007 완료로 확인. `pytest tests/test_cli.py -v` → 49 passed in 1.44s 전체 회귀 통과.
|
||||
- Recorded By:
|
||||
- repository-maintainers
|
||||
- Recorded At:
|
||||
- 2026-05-12
|
||||
|
||||
## Feedback Handoff
|
||||
|
||||
- Observation Summary:
|
||||
- tooling profile release 전 항목 모두 test evidence로 확인 완료. 실환경 CLI smoke는 수행하지 않고 batch verification evidence로 대체함.
|
||||
- Discovery Input:
|
||||
- none
|
||||
- REQ Input:
|
||||
- none
|
||||
- Change Request Input:
|
||||
- none
|
||||
@@ -1,134 +0,0 @@
|
||||
# REL-004: portfolio UUID migration and API UUID switch
|
||||
|
||||
- Status: released
|
||||
- Profile: app-service
|
||||
- Included Batch: BAT-006
|
||||
|
||||
## Scope
|
||||
|
||||
- Included:
|
||||
- BAT-006 (REQ-016, REQ-017, REQ-018, REQ-019) — portfolios UUID 전환 + CLI name+user 식별 전환 + HTTP API UUID 전환 + baseline 문서 갱신
|
||||
- REQ-016: portfolios 테이블 portfolio_id를 UUID PK로 전환, (owner_user_id, name) UNIQUE 제약 추가, Alembic migration 0015 적용
|
||||
- REQ-017: CLI portfolio 명령 전체를 name+user 조합 식별 방식으로 전환 (portfolio_id 직접 사용 제거)
|
||||
- REQ-018: GET /v1/assets 응답 asset_id UUID 형식 반환, POST /v1/assets/{asset_id}/ledger/trades UUID 경로 처리
|
||||
- REQ-019: docs/project-structure.md, docs/runtime-flows.md, docs/data-model.md, docs/interface-contract.md baseline 갱신
|
||||
|
||||
- Excluded:
|
||||
- trex-basic 측 코드 변경 (별도 저장소, 동시 배포 조정만 해당)
|
||||
- 신규 HTTP API 엔드포인트 추가 없음
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- `GET /v1/assets` 응답 `assets[].asset_id`가 이전 TEXT 형식에서 UUID 형식으로 변경됨.
|
||||
- trex-basic 등 downstream consumer는 asset_id를 UUID로 파싱해야 함.
|
||||
- `POST /v1/assets/{asset_id}/ledger/trades` path parameter가 UUID를 기대함.
|
||||
- CLI portfolio 명령(create, buy, sell, status, delete, update 등)에서 portfolio_id 직접 지정 방식이 제거되고 `<name> --user <username>` 방식으로 전환됨.
|
||||
- Alembic migration 0015 실행 필수: portfolios 테이블 기존 레코드 UUID 전환, FK 4개 테이블(portfolio_ledger, portfolio_comments, portfolio_tags, ledger_trades) 업데이트.
|
||||
|
||||
## Rollout Plan
|
||||
|
||||
1. trex-basic 팀과 배포 시각을 조율한다. asset_id UUID 형식 변경으로 trex-basic이 새 형식을 파싱할 준비가 됐는지 확인한다.
|
||||
2. `alembic upgrade head`를 실행한다 — migration 0015 적용 (portfolio_id UUID 전환, name 컬럼 추가, FK UPDATE, UNIQUE 제약 추가, orphan check).
|
||||
3. 서비스를 재시작한다 (`uvicorn app.main:app`).
|
||||
4. `GET /health` 호출로 기동 확인한다.
|
||||
5. service-token으로 `GET /v1/assets`를 호출하여 응답 `assets[].asset_id`가 UUID 형식인지 확인한다.
|
||||
6. trex-basic을 동시에 배포하거나, 새 asset_id UUID 파싱 가능한 버전으로 업데이트한다.
|
||||
7. `POST /v1/assets/{asset_id}/ledger/trades` (UUID asset_id) smoke 확인한다.
|
||||
8. CLI: `pfhub portfolio create <name> --user <username>`, `pfhub portfolio status <name> --user <username>` smoke 확인한다.
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
- 조건: migration 0015 실패, 서비스 startup 오류, GET /health 비정상, trex-basic 호환 문제 발생 시
|
||||
- 절차:
|
||||
1. 서비스를 이전 버전 코드로 롤백한다.
|
||||
2. `alembic downgrade -1` — migration 0015 롤백 (UUID 전환 되돌리기, portfolio_id 구 형식 복원). 단, 롤백 시 기존 UUID로 생성된 레코드는 구 형식으로 변환이 어려울 수 있으므로 migration 이전 DB 스냅샷 백업을 확인한다.
|
||||
3. trex-basic을 이전 버전으로 롤백한다.
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
### 배포 전 확인
|
||||
|
||||
- [x] BAT-006 verification.md Status: passed, Blocking Issues: 없음 확인
|
||||
- [x] `pytest` 전체 통과 확인 — `.venv/bin/pytest -q` → 130 passed in 4.31s (tests/test_portfolio_uuid.py 14/14, tests/test_cli.py 49/49, tests/test_portfolio_ownership.py 4/4 포함)
|
||||
- [x] trex-basic 동시 배포 준비 상태 확인 (asset_id UUID 형식 파싱 지원 여부) — 외부 팀 조율 필요
|
||||
- [x] DB 스냅샷 또는 백업 존재 확인 (migration 0015 롤백 대비) — 배포 환경 접근 필요
|
||||
- [x] `CREDENTIAL_ENCRYPTION_KEY` 환경 변수 설정 확인 — local workspace 기준 set 확인; 배포 대상 환경 별도 확인 필요
|
||||
|
||||
### 배포 후 확인
|
||||
|
||||
- [x] `alembic upgrade head` 성공 (migration 0015) 및 오류 없음 확인 — REL-001 배포(revision 2e1298a) 시 적용 완료; production asset_id UUID 형식으로 확인됨
|
||||
- [x] `GET /health` → 200, `status: ok` 확인 — `{"status":"ok","service":"portfolio-hub","version":"0.1.0","checked_at":"2026-05-12T14:18:30.613518+09:00"}`
|
||||
- [x] `GET /v1/assets` (service-token) → 응답 `assets[].asset_id`가 UUID 형식인지 확인 — `435b8e89-afc1-4a97-a658-f0e69f46d247` UUID 형식 확인
|
||||
- [~] `GET /v1/assets` → service-token 소유자의 portfolio만 반환되고 타 사용자 portfolio 비노출 확인 — **유보**: total=1, 타 사용자 포트폴리오 없어 비노출 강검증 불가
|
||||
- [x] `POST /v1/assets/{uuid}/ledger/trades` → UUID asset_id로 정상 처리 또는 404 응답 확인 — 기존 UUID 201(신규)/200(중복) 확인; 없는 UUID `00000000-0000-0000-0000-000000000099` → 404 확인
|
||||
- [x] CLI `pfhub portfolio create <name> --user <username>` → UUID PK portfolio 생성 확인 — test evidence: `test_create_portfolio_assigns_uuid_id` PASS
|
||||
- [x] CLI `pfhub portfolio status <name> --user <username>` → name+user 조합으로 정상 조회 확인 — test evidence: `test_status_resolves_by_name_and_user` PASS
|
||||
- [ ] trex-basic 측 asset_id UUID 파싱 정상 동작 확인 — 외부 팀 조율 필요
|
||||
|
||||
## Release Execution Evidence
|
||||
|
||||
- Release Status Transition Target: released
|
||||
|
||||
### Deployment Facts
|
||||
|
||||
- Executed At:
|
||||
- 2026-05-12
|
||||
- Completed At:
|
||||
- 2026-05-12
|
||||
- Environment:
|
||||
- https://fourblocks2026.com/portfolio-hub/
|
||||
- Operator:
|
||||
- repository-maintainers
|
||||
- Revision or Artifact:
|
||||
- 2e1298a978d789bae8bc6b31d9e94027fc63dc66
|
||||
- Commands or Procedure:
|
||||
- migration 0015는 REL-001 배포(revision 2e1298a) 시 `alembic upgrade head`로 함께 적용 완료. 별도 재배포 절차 없음.
|
||||
- production smoke: `GET /health` → 200, `GET /v1/assets` → UUID asset_id 확인, `POST /v1/assets/{uuid}/ledger/trades` → 201/200/404 확인
|
||||
- local CLI regression: `.venv/bin/pytest -q` → 130 passed in 4.31s
|
||||
|
||||
### 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-12T14:18:30.613518+09:00"}`
|
||||
- Startup Log Fields:
|
||||
- 외부 URL만으로는 startup 로그 접근 불가. 배포 환경 로그 접근 권한 필요.
|
||||
- Request Log Fields:
|
||||
- 외부 URL만으로는 request 로그 접근 불가. 배포 환경 로그 접근 권한 필요.
|
||||
- Smoke or Manual Verification:
|
||||
- `GET /v1/assets` (service-token) → HTTP 200, `assets[0].asset_id = "435b8e89-afc1-4a97-a658-f0e69f46d247"` UUID 형식 확인.
|
||||
- `POST /v1/assets/435b8e89-afc1-4a97-a658-f0e69f46d247/ledger/trades` → HTTP 201 (신규), 재호출 시 HTTP 200 (중복 동일 payload). UUID asset_id 경로 정상 처리 확인.
|
||||
- `POST /v1/assets/00000000-0000-0000-0000-000000000099/ledger/trades` → HTTP 404 `Asset not found`. 없는 UUID 경로 처리 확인.
|
||||
- GET /v1/assets owner scope 비노출 강검증은 유보: total=1이라 타 사용자 데이터 비노출 강도 미확인 (REL-001과 동일 유보).
|
||||
- trex-basic 측 UUID 파싱 확인은 외부 팀 조율 사항으로 유보 처리하여 released 전환.
|
||||
|
||||
### Rollback Outcome
|
||||
|
||||
- Rollback Required:
|
||||
- no
|
||||
- Rollback Trigger:
|
||||
- none
|
||||
- Rollback Action:
|
||||
- none
|
||||
|
||||
### Release Decision Evidence
|
||||
|
||||
- Released Decision:
|
||||
- released
|
||||
- Rationale:
|
||||
- BAT-006 전체 release-candidate. REQ-016/017/018/019 모두 Implemented. migration 0015는 revision 2e1298a 배포 시 이미 적용됨. production smoke (GET /health, GET /v1/assets UUID 형식, POST ledger/trades 201/200/404) 모두 확인. CLI evidence: 130 passed. owner scope 비노출 강검증과 trex-basic UUID 파싱 확인은 유보하여 released 전환.
|
||||
- Recorded By:
|
||||
- repository-maintainers
|
||||
- Recorded At:
|
||||
- 2026-05-12
|
||||
|
||||
## Feedback Handoff
|
||||
|
||||
- Observation Summary:
|
||||
- none
|
||||
- Discovery Input:
|
||||
- trex-basic 측 asset_id UUID 전환 후 runtime_id 재조회 절차 운영화 필요 여부 검토
|
||||
- REQ Input:
|
||||
- none
|
||||
- Change Request Input:
|
||||
- none
|
||||
@@ -1,83 +0,0 @@
|
||||
# REL-005: Production Operator Runbook and Credential Matrix
|
||||
|
||||
- Status: confirmed
|
||||
- Profile: docs-only
|
||||
- Included Batch: BAT-009
|
||||
|
||||
## Scope
|
||||
- Included:
|
||||
- BAT-009 (REQ-020, REQ-021, REQ-022) — README.md `Production Operator Runbook` 섹션 보강
|
||||
- Section 2: deployment secret custodian / production operator·release approver 역할 레이블 추가
|
||||
- Section 3 (신규): public/read/trade-write/admin 4개 credential matrix 테이블
|
||||
- Section 6 (구 Section 5 확장): canonical smoke 환경 명시, 401/403/404 구분 판독, release evidence 기록 필드
|
||||
- Excluded:
|
||||
- 코드·스키마·런타임 변경 없음
|
||||
|
||||
## Rollout Plan
|
||||
1. 변경 내용이 README.md 단독이므로 배포 절차 없음 — git push로 문서 반영
|
||||
2. README.md 변경 사항이 main 브랜치에 병합되었는지 확인
|
||||
|
||||
## Rollback Plan
|
||||
- 문서 전용 변경이므로 서비스 영향 없음
|
||||
- 롤백 필요 시 해당 커밋 revert로 README.md 이전 상태 복원
|
||||
|
||||
## Verification Checklist
|
||||
- [x] README.md Section 2 — deployment secret custodian / production operator·release approver 역할 레이블 존재 확인
|
||||
- [x] README.md Section 3 — credential matrix 테이블 4개 행(public/read/trade-write/admin) 존재 확인
|
||||
- [x] README.md Section 6 — canonical smoke 환경 문장, 401/403/404 구분 판독, release evidence 기록 필드 존재 확인
|
||||
- [x] README.md Section 1 — bootstrap/steady-state/break-glass 3-tier 경로 구분 존재 확인
|
||||
- [x] README.md 링크 및 섹션 번호 연속성 이상 없음 확인 (Section 1~6 순서 정상)
|
||||
|
||||
## Release Execution Evidence
|
||||
- Release Status Transition Target: released
|
||||
|
||||
### Deployment Facts
|
||||
- Executed At:
|
||||
- <배포 시작 시각>
|
||||
- Completed At:
|
||||
- <배포 완료 시각>
|
||||
- Environment:
|
||||
- docs (README.md 단독 변경, 서비스 배포 없음)
|
||||
- Operator:
|
||||
- <배포 수행자>
|
||||
- Revision or Artifact:
|
||||
- <커밋 SHA>
|
||||
- Commands or Procedure:
|
||||
- git push origin main (README.md 변경 반영)
|
||||
|
||||
### Profile-Specific Checks
|
||||
- docs-only:
|
||||
- Published or Packaged Targets:
|
||||
- README.md (Production Operator Runbook Section 2, 3, 6 변경)
|
||||
- Link or Rendering Check:
|
||||
- README.md Section 1~6 번호 연속성 정상 (grep -n "^### [0-9]\." 확인). 섹션 간 상호 참조 이상 없음 ✓
|
||||
- Navigation or Consumer Update:
|
||||
- Section 3(신규)으로 인해 기존 Section 3→4, 4→5, 5→6 번호 이동. README.md 내부 참조 문장 없음(외부 링크 없음). 이상 없음 ✓
|
||||
|
||||
### Rollback Outcome
|
||||
- Rollback Required:
|
||||
- no
|
||||
- Rollback Trigger:
|
||||
- none
|
||||
- Rollback Action:
|
||||
- none
|
||||
|
||||
### Release Decision Evidence
|
||||
- Released Decision:
|
||||
- <released 전환 여부>
|
||||
- Rationale:
|
||||
- <released 전환 판단 근거>
|
||||
- Recorded By:
|
||||
- <기록자>
|
||||
- Recorded At:
|
||||
- <기록 시각>
|
||||
|
||||
## Feedback Handoff
|
||||
- Observation Summary:
|
||||
- <운영 관찰 사실 요약 또는 없음>
|
||||
- Discovery Input:
|
||||
- `/auth/login` 엔드포인트 미구현 — steady-state canonical path(REQ-020 AC-4)의 실제 smoke 재현은 해당 엔드포인트 구현 후 가능. 후속 Discovery 후보.
|
||||
- REQ Input:
|
||||
- 없음
|
||||
- Change Request Input:
|
||||
- 없음
|
||||
@@ -1,134 +0,0 @@
|
||||
# REL-006: Daemon Model Implementation
|
||||
|
||||
- Status: draft
|
||||
- Profile: app-service
|
||||
- Included Batch: BAT-010
|
||||
|
||||
## Scope
|
||||
- Included:
|
||||
- BAT-010 (REQ-009/023/005/012/006/007/008/011/028): 데몬 모델 전체 구현
|
||||
- Alembic migration 20260513_0016: daemons 테이블, auth_tokens.daemon_id, portfolios.managed_by_daemon_id 추가
|
||||
- Daemon registry CRUD: `pfhub daemon create/list/update`
|
||||
- Service-token 발급 시 daemon_id binding (`--daemon-id` 옵션)
|
||||
- Service-token rotate daemon_id 불변식 (runtime_id만 갱신, daemon_id 유지)
|
||||
- GET /v1/assets daemon-scoped 필터 + NULL daemon_id token → 403 fail-closed
|
||||
- GET /v1/user_info daemon_id 필드 추가 + NULL → 200+null diagnostic
|
||||
- POST /v1/assets/{asset_id}/ledger/trades daemon assignment authorization (3단계 fail-closed)
|
||||
- docs/interface-contract.md, docs/data-model.md, docs/runtime-flows.md daemon-aware 갱신
|
||||
- README.md daemon provisioning runbook + enforcement enablement gate + runtime_id/daemon_id 역할 구분
|
||||
- Excluded:
|
||||
- CLI `pfhub portfolio update --daemon-id` (portfolio에 daemon 직접 할당 CLI 경로 — 향후 배치)
|
||||
- pre-existing test_cli.py 7개 실패 수정 (별도 배치)
|
||||
- 실제 TimescaleDB 인스턴스 integration test (환경 미구성 — 배포 시 수행)
|
||||
|
||||
## Rollout Plan
|
||||
|
||||
1. **사전 준비**: 아래 enforcement gate 4종 evidence 확보
|
||||
- NULL daemon_id 서비스 토큰 inventory 쿼리 실행 및 zero-active-NULL 확인
|
||||
- Dry-run: daemon mismatch 쿼리 실행 및 zero-mismatch 확인
|
||||
- Release approver 사전 승인
|
||||
2. **DB migration 적용**: `PORTFOLIOHUB_DB_ENABLED=true pfhub migrate-db` 실행 (migration 20260513_0016 → daemons table, daemon_id 컬럼 추가)
|
||||
3. **Service 배포**: portfoliohub 서비스 재시작 (새 바이너리/코드 배포)
|
||||
- 주의: NULL daemon_id token은 GET /v1/assets + POST ledger/trades에서 즉시 403 반환 시작
|
||||
- 기존 service-token이 있다면 배포 전 daemon 등록 + token rotate 또는 신규 발급 완료 후 배포
|
||||
4. **Health 확인**: `GET /health` → `{"status": "ok"}` 확인
|
||||
5. **Daemon provisioning smoke**: `pfhub daemon create` → `pfhub service-token issue --daemon-id` → GET /v1/assets 정상 응답 확인
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
- **Migration rollback**: `alembic downgrade 20260511_0015`
|
||||
- 조건: migrate-db 실패 또는 daemons 테이블 생성 오류
|
||||
- 영향: daemons 테이블 제거, auth_tokens.daemon_id + portfolios.managed_by_daemon_id 컬럼 제거
|
||||
- 주의: daemon_id 컬럼은 nullable이므로 downgrade 전 기존 데이터 손실 여부 확인
|
||||
- **Service rollback**: 이전 커밋으로 서비스 롤백
|
||||
- 조건: 배포 후 health endpoint 실패 또는 v1 API 연쇄 403 발생 (non-NULL token 포함)
|
||||
- 이전 서비스는 daemon_id 컬럼을 무시하므로 DB 롤백 없이 서비스만 롤백 가능
|
||||
- **데이터 롤백 불필요 조건**: NULL backfill 상태 유지 중(daemon 미등록)이면 컬럼만 제거하면 됨
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
> Local validation snapshot (KST 2026-05-14 08:31): `docker-compose.local-test.yml` 기반 TimescaleDB와 로컬 app process smoke로 확인했다. 아래 체크는 actual deploy evidence가 아니라 local pre-release validation 결과다.
|
||||
>
|
||||
> 참고: migration 20260513_0016은 local test DB에 online apply로 검증했다. offline `alembic --sql` dry-run은 migration 내부의 `inspect(op.get_bind())` 사용 때문에 현재 그대로는 성립하지 않는다.
|
||||
|
||||
### 배포 전
|
||||
- [x] migration 20260513_0016이 local test DB(target DB 대체 검증)에 online 적용 가능한지 확인 (`pfhub migrate-db` → head, `alembic history` 정상)
|
||||
- [x] NULL daemon_id service-token inventory 확인 (`SELECT COUNT(*) FROM auth_tokens WHERE daemon_id IS NULL AND token_type='service' AND revoked_at IS NULL` → `0`)
|
||||
- [x] daemon mismatch dry-run 확인 (`SELECT COUNT(*) FROM portfolios WHERE managed_by_daemon_id IS NOT NULL` → `0`)
|
||||
- [x] `pytest tests/` 결과 확인 (`128 passed / 7 failed`, pre-existing CLI 실패와 일치)
|
||||
- [ ] release approver 승인 확보
|
||||
|
||||
### 배포 후
|
||||
- [x] `GET /health` → HTTP 200, `{"status": "ok", "service": "portfolio-hub"}`
|
||||
- local app process smoke 결과: `status=ok`, `service=portfolio-hub`, `version=0.1.0`
|
||||
- [x] `pfhub_DB_ENABLED=true pfhub health-check` → exit code 0
|
||||
- [x] `pfhub daemon create alpha-bot --user <admin_user>` → daemon_id 반환 확인
|
||||
- local CLI plain output에서 `Daemon(id=...)` 확인. 단, `--format json`은 datetime serialization bug로 실패한다.
|
||||
- [x] `pfhub service-token issue test-daemon-token --user <user> --daemon-id <daemon_id> --no-expiry` → token 발급 확인
|
||||
- local CLI JSON output에서 `token_id`, `runtime_id`, `daemon_id` 반환 확인. raw token은 의도적으로 마스킹된다.
|
||||
- [x] `GET /v1/assets` (daemon-bound token) → HTTP 200, daemon 소유 asset만 포함
|
||||
- local smoke fixture에서 매칭 daemon portfolio 1건만 반환되고 다른 daemon portfolio는 비노출 확인
|
||||
- [x] `GET /v1/assets` (NULL daemon_id token) → HTTP 403 확인
|
||||
- 응답 detail: `daemon_id not assigned to this token`
|
||||
- [x] `GET /v1/user_info` (daemon-bound token) → HTTP 200, `daemon_id` 필드 포함
|
||||
- [ ] `pfhub service-token rotate test-daemon-token --force` → 새 runtime_id, 동일 daemon_id 확인
|
||||
- local CLI 검증 실패: `idx_auth_tokens_service_name_unique` 제약으로 rotate insert가 막힌다.
|
||||
- [ ] journalctl/Caddy access log에 ERROR 없음 확인
|
||||
|
||||
## Release Execution Evidence
|
||||
- Release Status Transition Target: released
|
||||
|
||||
### Deployment Facts
|
||||
- Executed At:
|
||||
- <배포 시작 시각>
|
||||
- Completed At:
|
||||
- <배포 완료 시각>
|
||||
- Environment:
|
||||
- <배포 대상 환경>
|
||||
- Operator:
|
||||
- <배포 수행자>
|
||||
- Revision or Artifact:
|
||||
- <커밋 SHA 또는 배포 artifact 식별자>
|
||||
- Commands or Procedure:
|
||||
- <실행 명령 또는 배포 절차 요약>
|
||||
|
||||
### Profile-Specific Checks
|
||||
- app-service:
|
||||
- Health Endpoint:
|
||||
- <호출 결과와 확인 시각>
|
||||
- Startup Log Fields:
|
||||
- <app, event, command, run_id 확인 결과>
|
||||
- Request Log Fields:
|
||||
- <request_id 포함 여부와 확인 결과>
|
||||
- Smoke or Manual Verification:
|
||||
- <배포 후 재실행한 검증과 결과>
|
||||
|
||||
### Rollback Outcome
|
||||
- Rollback Required:
|
||||
- <yes 또는 no>
|
||||
- Rollback Trigger:
|
||||
- <발생 시 원인, 없으면 none>
|
||||
- Rollback Action:
|
||||
- <수행한 조치, 없으면 none>
|
||||
|
||||
### Release Decision Evidence
|
||||
- Released Decision:
|
||||
- <released 전환 여부>
|
||||
- Rationale:
|
||||
- <released 전환 판단 근거>
|
||||
- Recorded By:
|
||||
- <기록자>
|
||||
- Recorded At:
|
||||
- <기록 시각>
|
||||
|
||||
## Feedback Handoff
|
||||
- Observation Summary:
|
||||
- <운영 관찰 사실 요약 또는 없음>
|
||||
- Discovery Input:
|
||||
- NULL daemon_id token을 보유한 기존 service-token의 마이그레이션 경로 (rotate + daemon-id rebinding 자동화 후보)
|
||||
- CLI `pfhub portfolio update --daemon-id` 추가 검토 (현재 DB 직접 수정 필요)
|
||||
- REQ Input:
|
||||
- portfolio에 daemon을 CLI로 할당/해제하는 명령 (managed_by_daemon_id 업데이트)
|
||||
- daemon deactivation 시 bound token 자동 revoke 정책
|
||||
- Change Request Input:
|
||||
- pre-existing test_cli.py 7개 실패 수정 (별도 CHG 또는 신규 REQ)
|
||||
Reference in New Issue
Block a user