# 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 ### 배포 전 - [ ] migration 20260513_0016이 target DB에 적용 가능한지 dry-run 확인 (alembic history 정상) - [ ] 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`) - [ ] daemon mismatch dry-run 확인 (`SELECT COUNT(*) FROM portfolios WHERE managed_by_daemon_id IS NOT NULL`) - [ ] `pytest tests/` 128 passed / 7 failed (pre-existing) 확인 - [ ] release approver 승인 확보 ### 배포 후 - [ ] `GET /health` → HTTP 200, `{"status": "ok", "service": "portfolio-hub"}` - [ ] `pfhub_DB_ENABLED=true pfhub health-check` → exit code 0 - [ ] `pfhub daemon create alpha-bot --user ` → daemon_id 반환 확인 - [ ] `pfhub service-token issue test-daemon-token --user --daemon-id --no-expiry` → token 발급 확인 - [ ] `GET /v1/assets` (daemon-bound token) → HTTP 200, daemon 소유 asset만 포함 - [ ] `GET /v1/assets` (NULL daemon_id token) → HTTP 403 확인 - [ ] `GET /v1/user_info` (daemon-bound token) → HTTP 200, `daemon_id` 필드 포함 - [ ] `pfhub service-token rotate test-daemon-token --force` → 새 runtime_id, 동일 daemon_id 확인 - [ ] 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: - - Request Log Fields: - - Smoke or Manual Verification: - <배포 후 재실행한 검증과 결과> ### Rollback Outcome - Rollback Required: - - Rollback Trigger: - <발생 시 원인, 없으면 none> - Rollback Action: - <수행한 조치, 없으면 none> ### Release Decision Evidence - Released Decision: - - Rationale: - - 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)