feat: implement daemon model with registry and single-asset assignment (BAT-010, REQ-023/028)
Core Implementation (BAT-010):
- Add daemon registry schema and CRUD operations (req-023)
- Implement single-daemon asset assignment constraint (one asset per daemon)
- Add daemon_id field to service_token for daemon identification
- Add daemon.py CLI module for daemon management commands
- Add 20260513_0016_daemon_model.py migration for daemon tables
API Changes:
- GET /v1/assets: include daemon_id in AssetResponse
- POST /v1/assets/{asset_id}/ledger/trades: require daemon token binding
- GET /v1/user_info: include daemon metadata
- Enhanced service-token rotate to preserve daemon bindings
CLI Commands:
- pfhub daemon register --name <name> --runtime-id <runtime-id>
- pfhub daemon list
- pfhub daemon get <daemon-id>
- pfhub daemon revoke <daemon-id>
Requirements (REQ-023, REQ-028):
- REQ-023: Daemon Registry and Service Token Daemon Binding (Interface, Approved)
* AC-1: daemon CRUD operations
* AC-2: service token daemon binding for POST /v1/assets/{asset_id}/ledger/trades
* AC-3: single daemon per asset (exact-one assignment model)
- REQ-028: README.md Daemon Provisioning Runbook update (Documentation, Approved)
Documentation:
- Add dcy-006 Discovery for daemon-id and single-daemon asset assignment
- Update README.md with Daemon Provisioning Runbook section
- Add BAT-010 batch documentation with planning, implementation, verification
- Update rel-006 release document (daemon model implementation)
- Update data-model.md with daemon and daemon_asset_assignment tables
- Update interface-contract.md with daemon registry APIs
- Update runtime-flows.md with daemon lifecycle flows
Breaking Changes:
- REQ-005~009, REQ-011~012 status reverted to Approved due to revised contract
* daemon_id field addition and exact-one asset assignment requirement
* Existing Implemented evidence invalidated by contract revision
* BAT-001/002/008 re-verification required
Testing:
- Add test_daemon_registry.py for daemon CRUD operations
- Add test_daemon_assignment.py for single-asset assignment constraints
- Update test_auth.py, test_cli.py, test_v1.py for daemon support
- Verify daemon token binding in trade endpoint authorization
Impact:
- Database: 2 new tables (daemons, daemon_asset_assignments)
- Migration: 20260513_0016 creates daemon model schema
- CLI: 4 new daemon subcommands
- API: daemon_id propagation through v1 endpoints
- Verification: BAT-001/002/008 re-verification gates next release
This commit is contained in:
@@ -12,4 +12,5 @@
|
||||
| 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-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) |
|
||||
@@ -0,0 +1,124 @@
|
||||
# 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 <admin_user>` → daemon_id 반환 확인
|
||||
- [ ] `pfhub service-token issue test-daemon-token --user <user> --daemon-id <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:
|
||||
- <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