Files
portfolio-hub/docs/batches/bat-010_20260513_daemon-model-implementation/design.md
T
genichin e6b6a8715b 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
2026-05-13 23:07:24 +00:00

4.0 KiB

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 범위)