feat: extend daemon model with daemon status tracking and list support

- Add daemon status tracking with state and metrics (idle, running, error)
- Implement pfhub daemon list CLI command for viewing registered daemons
- Extend auth schema and service for daemon lifecycle management
- Add postgres repository queries for daemon state persistence
- Expand test coverage for daemon registry and status transitions
- Update rel-006 release document with daemon model verification results
- Support daemon graceful shutdown and error recovery patterns
This commit is contained in:
2026-05-14 06:29:52 +00:00
parent e6b6a8715b
commit 3bb3ff547d
9 changed files with 298 additions and 17 deletions
@@ -47,22 +47,32 @@
## 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())` 사용 때문에 현재 그대로는 성립하지 않는다.
### 배포 전
- [ ] 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) 확인
- [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 승인 확보
### 배포 후
- [ ] `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` 필드 포함
- [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