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
56 lines
4.0 KiB
Markdown
56 lines
4.0 KiB
Markdown
# BAT-010 Design
|
|
|
|
- Status: confirmed
|
|
- Batch: BAT-010
|
|
|
|
## Architecture Summary
|
|
|
|
daemon identity 모델을 도입해 service-token과 asset에 stable `daemon_id`를 부여하고, `/v1/assets`와 `/v1/assets/{asset_id}/ledger/trades`의 authorization 축을 user-scope에서 daemon-scope로 전환한다. 기존 service-token bearer auth와 permission 모델은 유지하고, daemon assignment는 그 위에 추가되는 두 번째 authorization 축이다. 전환 구간에서는 NULL backfill을 허용하고 fail-closed로 처리한다.
|
|
|
|
## Changed Areas
|
|
|
|
- Docs:
|
|
- `docs/interface-contract.md` — daemon binding, daemon-scoped contract, 403 mismatch policy
|
|
- `docs/data-model.md` — daemons 테이블, auth_tokens.daemon_id, portfolios.managed_by_daemon_id
|
|
- `docs/runtime-flows.md` — daemon registry binding 흐름, rotate invariant, daemon-scoped v1 API 흐름
|
|
- `README.md` — daemon provisioning runbook, enforcement enablement gate
|
|
- Modules:
|
|
- `migrations/versions/` — daemons, auth_tokens.daemon_id, portfolios.managed_by_daemon_id migration
|
|
- `app/domain/models.py` — Daemon entity 추가
|
|
- `app/repositories/postgres.py` — daemon CRUD methods
|
|
- `app/repositories/portfolio_repository.py` — daemon-scoped asset query
|
|
- `app/services/auth_service.py` — daemon binding at issue/rotate
|
|
- `app/api/auth_routes.py` (또는 신규 daemon route) — daemon registry management endpoint
|
|
- `app/api/v1_assets.py` — daemon-scoped GET, daemon assignment auth for ledger write
|
|
- `app/api/v1_user_info.py` — daemon_id 필드 노출
|
|
- `app/schemas/v1.py` — daemon_id 필드 추가
|
|
- `app/cli/commands/service_tokens.py` — daemon_id binding at issue, daemon_id invariant at rotate, daemon_id in output
|
|
- Interfaces:
|
|
- Daemon registry management: HTTP endpoint(`POST /daemons`, `GET /daemons`, `PATCH /daemons/{daemon_id}`) 또는 CLI subcommand(`pfhub daemon create/list/update`) — **아래 Key Decisions 참조**
|
|
- `POST /auth/service-tokens` request body: `daemon_id` 필드 추가
|
|
- `GET /v1/assets` response: daemon-scoped 필터
|
|
- `GET /v1/user_info` response: `daemon_id` 필드 추가
|
|
- `POST /v1/assets/{asset_id}/ledger/trades`: daemon assignment 검증 추가
|
|
|
|
## Key Decisions
|
|
|
|
1. **Daemon registry 관리 경로 형태**: CLI subcommand(`pfhub daemon create/list/update`)를 1차 관리 경로로 채택. 운영자 중심 도구이고, HTTP endpoint로 노출 시 별도 admin-only auth guard 설계가 필요하다. HTTP endpoint는 향후 필요 시 추가한다.
|
|
2. **daemon_slug uniqueness**: owner user 내에서 unique. DB unique constraint(`daemons.owner_user_id + daemons.daemon_slug` composite unique)로 강제.
|
|
3. **enforcement enablement gate**: migration level에서 별도 flag 없이 진행. NULL backfill token/asset에 대한 fail-closed는 코드 레벨에서 처리. production cutover는 inventory + dry-run + release approver 승인 후 수동으로 진행.
|
|
4. **NULL backfill fail-closed boundary**: `daemon_id = NULL`인 token이 daemon-scoped endpoint(`GET /v1/assets`, `POST /v1/assets/{asset_id}/ledger/trades`)를 호출하면 403 Forbidden. `GET /v1/user_info`는 NULL이어도 200 OK + `daemon_id: null` 진단 노출.
|
|
|
|
## Edge Cases
|
|
|
|
- 동일 user 아래 daemon이 없는 상태에서 service-token 발급 시: daemon registry에 daemon이 없으면 발급 불가. 운영자가 먼저 daemon create를 수행해야 한다.
|
|
- rotate 중 daemon이 삭제된 경우: daemon FK 참조 무결성 위반으로 rotate 거부. 소프트 삭제(is_active flag) 방식으로 daemon을 비활성화하는 것이 안전하다.
|
|
- managed_by_daemon_id가 설정된 asset을 다른 daemon으로 재배정: 명시적 reassignment API/CLI 또는 migration-level 절차로만 허용. 자동 재배정 없음.
|
|
|
|
## Architecture Impact
|
|
|
|
- runtime-flows
|
|
|
|
## Reference Doc Update Plan
|
|
|
|
- project-structure.md: none (파일 구조 변경 없음)
|
|
- runtime-flows.md: 갱신 필요 — daemon registry binding 흐름, daemon-scoped v1 API 처리 흐름, rotate `runtime_id`/`daemon_id` 역할 차이 반영 (REQ-011 범위)
|