feat: dcy-003/004 토큰 surface 개편 및 daemon lifecycle 정책 구현 (BAT-006/007)

BAT-006 (REQ-016/017/018):
- client token 발급 경로 제거 (issue_client_token, POST /auth/tokens, 관련 스키마/테스트)
- service-token rotate unique index revoked_at IS NULL 조건 추가 (Alembic CONCURRENTLY 마이그레이션)
- POST /auth/service-tokens body daemon_id forward 누락 보정 (1-line fix)

BAT-007 (REQ-022/023):
- daemon deactivate 시 바인딩 service token 자동 revoke (CLI --force 옵션 + revoke_tokens_by_daemon_id)
- NULL daemon_id legacy token 진단 CLI (migrate-null-daemon --dry-run)

거버넌스 문서: dcy-003/004 Discovery, REQ-016~023/025~032 신규, BAT-006/007 전체 산출물

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-21 01:03:39 +00:00
co-authored by Claude Sonnet 4.6
parent d4b841bc37
commit c815ce39b6
48 changed files with 3573 additions and 117 deletions
@@ -0,0 +1,48 @@
# BAT-007 Planning
- Status: confirmed
- Batch: BAT-007
- Profile: standard
## Included REQ
- REQ-022: daemon deactivation 시 바인딩 service token 자동 revoke (Interface, High)
- REQ-023: NULL daemon_id legacy token 마이그레이션 CLI (Interface, Medium)
## Delivery Plan
1. REQ-022:
- `app/repositories/postgres.py` — `revoke_tokens_by_daemon_id(daemon_id)` 구현: `UPDATE auth_tokens SET revoked_at=NOW() WHERE daemon_id=<id> AND revoked_at IS NULL`
- `app/repositories/portfolio_repository.py` — 추상 메서드 추가
- `app/services/auth_service.py` — `revoke_tokens_for_daemon(daemon_id)` 헬퍼 추가
- `app/cli/commands/daemon.py:update_daemon` — `deactivate=True` 분기에서 `revoke_tokens_for_daemon` 호출
2. REQ-023:
- `app/repositories/postgres.py` — `list_service_tokens_with_null_daemon()` 구현: `SELECT ... FROM auth_tokens WHERE daemon_id IS NULL AND token_type='service' AND revoked_at IS NULL`
- `app/repositories/portfolio_repository.py` — 추상 메서드 추가
- `app/services/auth_service.py` — `list_null_daemon_service_tokens()`, `find_candidate_daemons_for_user(user_id)` 추가
- `app/cli/commands/service_tokens.py` — `migrate_null_daemon` 서브커맨드: `--dry-run` inventory 출력, `--dry-run` 미포함 시 non-zero exit + 안내 메시지
3. 테스트:
- `tests/test_daemon_registry.py` 갱신 (REQ-022 AC-1~4)
- `tests/test_null_daemon_migration.py` 신규 (REQ-023 AC-1~5, FakeRepo 기반)
## Dependencies
- Internal:
- `app/cli/commands/daemon.py:update_daemon` — `--deactivate` 분기 기존 위치 확인 후 revoke 호출 삽입
- `app/cli/commands/service_tokens.py` — 기존 `service_token_app` Typer에 `migrate_null_daemon` 커맨드 추가
- `app/repositories/postgres.py` — `revoke_auth_token` 기존 구현 패턴 참조
- BAT-006 (REQ-016/017/018, release-candidate): auth_service.py token 기반 안정 상태
- External:
- 없음
## Design Gate
- Design Required Before Implementation: yes
- Reason: REQ-022의 트랜잭션 처리 방식(daemon deactivate + token revoke 동일 트랜잭션 여부), REQ-023의 dry-run 출력 형식 및 --dry-run 미포함 시 거부 동작을 design.md에서 확정해야 구현 시 누락 없이 진행 가능
## Milestones
1. design.md confirmed — 트랜잭션 전략, dry-run 출력 스펙, 테스트 전략 확정
2. REQ-022 repository + service 메서드 + daemon CLI 연결 + 회귀 테스트 통과
3. REQ-023 repository + service 헬퍼 + migrate_null_daemon CLI + 신규 테스트 통과
4. pytest 전체 통과 (regression 없음)
## Risks
- R-1 (Medium): REQ-022 트랜잭션 경계 — daemon update와 token revoke를 동일 트랜잭션으로 묶어야 원자성 보장. postgres.py에서 트랜잭션 패턴 확인 필요
- R-2 (Low): REQ-023 dry-run 출력 — 매핑 후보 daemon 조회에 `list_daemons_for_user(user_id)` 활용 가능 여부 확인 필요
- R-3 (Low): DATA-2 admin 테스트 fixture (NULL daemon active token 1건) — release plan에 수동 정리 절차 명시