핫픽스 2dcbafb(목록 조회 405 갭 해소)를 REQ-053에 change-req로 기록. 스코프 갭(GET-list AC 누락) 정정 + AC-13/14 추가, 라이브 통합검증 근거 기재. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
12 KiB
12 KiB
REQ-053: admin 데몬 CRUD HTTP API
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: Justin Ko
Intent
- 현재
Daemon엔티티는GET /v1/daemons(read 전용, REQ-045)만 HTTP로 노출되며, 생성·변경·(비)활성화 HTTP API가 없다. 관리자(admin)가 HTTP API로 데몬을 provisioning하고 owner를 할당·변경·(비)활성화할 수 있어야 한다. - trex-web dcy-009 admin UI가 소비하는 백엔드 경로를 신설한다.
- 데몬은 운영 런타임 식별자(service-token daemon_id 바인딩, KIS 계좌 연결)로 하드 삭제는 제공하지 않으며 비활성화로 대체한다(dcy-011 FR-4 결정). owner 재할당은 허용하되 owner 변경 시 해당 데몬의 기존 인증정보를 자동 무효화한다(이전 owner의 KIS 계좌 이관 금지, dcy-011 OQ-3 결정).
Requirement
- 시스템은 admin role로 인증된 요청자가 데몬을 생성하고
owner_user_id를 할당할 수 있는 POST 엔드포인트를 제공해야 한다.- 입력:
daemon_slug(고유 식별자),display_name(선택),owner_user_id. - 성공 시 생성된 Daemon의
id,daemon_slug,display_name,owner_user_id,is_active반환.
- 입력:
- 시스템은 admin이 기존 데몬의
display_name또는owner_user_id를 변경할 수 있는 PATCH 엔드포인트를 제공해야 한다.- owner 변경 시 해당 데몬의 기존
BrokerCredential전체를 자동 삭제(무효화) 해야 한다 — 이전 owner의 KIS 계좌 정보가 새 owner에게 이관되는 것을 방지한다.
- owner 변경 시 해당 데몬의 기존
- 시스템은 admin이 데몬을 비활성화(
is_active=false) 및 재활성화(is_active=true)할 수 있는 엔드포인트를 제공해야 한다.- 비활성화 시 해당 데몬에 바인딩된 service token을 자동 revoke해야 한다(기존 REQ-022 정책 재사용).
- 하드 삭제(DELETE) 엔드포인트는 제공하지 않는다. 비활성화가 유일한 종료 경로이다.
- admin role이 아닌 요청(user-token, service-token 포함)은 HTTP 403 Forbidden을 반환해야 한다.
- 엔드포인트 경로·HTTP 메서드의 구체 형태는 draft-batch-design에서 v1 admin 컨벤션(dcy-011 OQ-2 Deferred, dcy-006 admin 경로 참고)에 맞춰 확정한다.
Acceptance Criteria
- Given admin 토큰으로 daemon_slug, display_name, owner_user_id를 포함한 생성 요청, When POST 엔드포인트를 호출, Then HTTP 201 + 생성된 Daemon(
id,daemon_slug,display_name,owner_user_id,is_active=true) 반환. - Given admin 토큰으로 중복
daemon_slug로 생성 요청, When POST 엔드포인트를 호출, Then HTTP 409(또는 422) Conflict 반환(중복 슬러그 거부). - Given admin 토큰으로 존재하는 daemon D의
display_name변경 요청(owner 변경 없음), When PATCH 엔드포인트를 호출, Then HTTP 200 + 갱신된 Daemon 반환. 기존 BrokerCredential은 유지된다. - Given admin 토큰으로 daemon D의
owner_user_id를 사용자 B로 재할당 요청(원래 소유자 A), When PATCH 엔드포인트를 호출, Then HTTP 200 + 갱신된 Daemon 반환 + 해당 daemon D의 BrokerCredential이 모두 삭제(무효화)된다. - Given daemon D의 owner가 변경된 직후, When 변경 전 소유자 A의 service-token으로
/v1/user_info를 호출, Thenbroker: null반환(이전 owner 인증정보 이관 차단). - Given admin 토큰으로 활성 daemon D 비활성화 요청, When 비활성화 엔드포인트를 호출, Then HTTP 200 +
is_active: false반환 + daemon D에 바인딩된 service token 자동 revoke(REQ-022 정책). - Given admin 토큰으로 비활성 daemon D 재활성화 요청, When 재활성화 엔드포인트를 호출, Then HTTP 200 +
is_active: true반환. - Given admin 토큰으로 daemon D에 DELETE 요청(하드 삭제), When 호출, Then HTTP 405 Method Not Allowed(또는 404) 반환 — 하드 삭제 엔드포인트 미제공.
- Given user-token(admin role 없음)으로 데몬 생성·변경·비활성화 엔드포인트 호출, When 호출, Then HTTP 403 Forbidden 반환.
- Given service-token으로 데몬 CRUD 엔드포인트 호출, When 호출, Then HTTP 403 Forbidden 반환.
- Given 인증 토큰 없는 요청으로 데몬 CRUD 엔드포인트 호출, When 호출, Then HTTP 401 반환.
- Given admin 토큰으로 존재하지 않는 daemon_id에 PATCH/비활성화 요청, When 호출, Then HTTP 404 반환.
Impacted Area
- Docs:
docs/interface-contract.md— admin 데몬 CRUD 엔드포인트 경로·권한·owner 재할당 시 인증정보 무효화 정책 신규 섹션 추가.
- Modules:
- 신규 또는 확장 admin 데몬 라우터(경로·파일명은 design 확정).
app/schemas/—DaemonCreateRequest,DaemonUpdateRequest,DaemonAdminResponse스키마 신규 정의.app/services/— 데몬 생성·변경·비활성화 서비스 메서드 신규. owner 재할당 시BrokerCredential무효화 로직 포함.app/repositories/—DaemonRepositorycreate/update/deactivate/reactivate 메서드 신규.app/repositories/broker_credential_repository.py— owner 재할당 시 credential 삭제 메서드(신규 또는 확장).- REQ-022(
daemon deactivation service token auto-revoke) 서비스 로직 재사용 — 비활성화 경로에서 호출.
- Tests:
- AC-1~12 커버 pytest 케이스. AC-4/5(owner 재할당 + 인증정보 무효화), AC-8(DELETE 405 음성), AC-9/10/11(권한 음성) 강제 검증.
Notes
- OQ-2(엔드포인트 경로): draft-batch-design 위임(dcy-011 Deferred).
/v1/admin/daemonsvs/v1/daemons(admin 분기) — dcy-006 admin 경로 컨벤션 참고. - owner 재할당 + 인증정보 자동 무효화(AC-4/5): dcy-011 OQ-3 Answered(2026-06-28 결정). 새 owner는 자기 KIS 인증정보를 REQ-052 API로 재등록해야 한다. 이 정책은 이전 owner의 KIS 계좌 정보가 데몬에 잔류하는 보안 위험을 제거한다.
- 하드 삭제 미제공(AC-8): 데몬은 운영 런타임 식별자(service-token daemon_id 바인딩)이므로 참조 무결성 보호를 위해 비활성화가 유일 종료 경로. dcy-011 FR-4 결정.
- 비활성화 → service token revoke(AC-6): 기존 REQ-022 정책(
daemon deactivation auto-revoke)을 이 경로에서도 호출. REQ-022 구현 재사용. - NFR-2(권한 — admin role 강제): AC-9/10/11로 흡수한다.
- daemon_slug 중복 처리(AC-2): HTTP 409 vs 422는 design 단계에서 v1 컨벤션에 맞춰 확정.
- Source: dcy-011 FR-4, NFR-2, OQ-3 Answered.
Change Log
CHG-20260628-01
- Date: 2026-06-28
- Author: Justin Ko
Change Summary
- 신규 생성 (Proposed) — dcy-011 FR-4 산출물.
Intent
- dcy-011 confirmed Discovery의 FR-4(admin 데몬 생성·owner 할당·변경·(비)활성화, 삭제 제외) 및 OQ-3 결정(owner 재할당 허용 + 인증정보 자동 무효화)을 Interface REQ로 정규화한다.
Acceptance Criteria Delta
- Added:
- AC-1 ~ AC-12 전체 (신규 초안)
- Updated: 없음
- Removed: 없음
Impacted Area Delta
- Docs:
docs/srs/Interface/req-053_admin-daemon-crud-api.md신규 생성docs/interface-contract.md갱신 예고
- Modules:
- admin 데몬 라우터(신규), DaemonCreate/UpdateRequest/AdminResponse 스키마(신규), 서비스·repository 신규
- Tests:
- owner 재할당+인증정보 무효화(AC-4/5), DELETE 음성(AC-8), 권한 음성(AC-9~11) 케이스 신규
Delivery Trace Delta
- Batches: 미정 (suggest-batch-reqs 대기)
- Releases: 미정
Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 후 suggest-batch-reqs. REQ-052/REQ-054와 동일 batch 묶기 권고. OQ-2(경로)은 design 단계 해소.
Validation Plan
- pytest로 AC-1~12 각 케이스 확인. AC-4/5(owner 재할당 + 인증정보 무효화) 통합 시나리오, AC-8(DELETE 음성), AC-9(admin role 강제 음성) 강제 검증.
CHG-20260628-02
- Date: 2026-06-28
- Author: 팀장(Claude)
- confirm-req:
Proposed→Approved. dcy-011 FR-4/OQ-3 추적. 데몬 생성·할당·(비)활성화, owner 재할당 시 인증정보 자동 무효화(AC-4/5) 보안정합, 하드 삭제 미제공(AC-8)·비활성화→service token revoke(REQ-022 재사용, AC-6)·admin role 강제(AC-9/10/11) 적절. 경로(OQ-2)·409/422·405/404 design 위임. blocker 없음.
CHG-20260628-03
- Date: 2026-06-28
- Author: 팀장(Claude)
- confirm-req-implemented:
Approved→Implemented. 근거: BAT-022 PR #19 mergeCommit1b78c18, QC PASS-WITH-NOTES(opus, blocker 0). AC-1~12 전건 테스트 통과(565 passed). owner 재할당 원자화 수정(83e6dde) — 단일 트랜잭션+선삭제 방식으로 기존 BrokerCredential 삭제 후 owner 변경을 원자적으로 처리, leak 방지 테스트 3종 PASS. AC-4/5(owner 재할당+인증정보 무효화), AC-8(DELETE 405 음성), AC-9/10/11(권한 음성) 전건 통과. 잔여 리스크 없음.
CHG-20260628-04
- Date: 2026-06-28
- Author: 팀장(Claude) — change-req (핫픽스 백필 / 스코프 갭 정정)
Change Summary
- GET
/v1/admin/daemons(전체 데몬 목록) 엔드포인트 누락 갭을 정정한다. StatusImplemented유지(이번 변경으로 스코프 완결).
Intent / 증상·영향·근본원인 (핫픽스 예외 경로)
- 증상: trex-web admin "데몬 관리" 화면이
adminListDaemons(REQ-035)로GET /v1/admin/daemons호출 시 405 Method Not Allowed → "데몬 목록을 불러오지 못했습니다" 에러. - 영향: admin 데몬 목록 열람 불가(생성·변경 자체는 가능하나 목록 미표시). 라이브 통합테스트 전까지 미발견.
- 근본원인: REQ-053 최초 스코프가 POST/PATCH/activate/deactivate(+DELETE 405 음성)만 AC로 잡고 목록 조회(GET-list)를 AC로 누락. 목록 수요는 trex-web REQ-035(admin API 클라/훅)에서 발생했으나 백엔드 계약(REQ-053)에 반영되지 않음. mock 기반 UI 단위테스트는 실제 405를 포착하지 못함(실연동 갭).
Acceptance Criteria Delta
- Added:
- AC-13: Given admin 인증, When
GET /v1/admin/daemons, Then 전체 데몬 목록({daemons:[{id,daemon_slug,display_name,is_active,owner_user_id}], total})을 200으로 반환한다. - AC-14: Given 비admin 인증, When
GET /v1/admin/daemons, Then 403으로 차단된다(admin role 강제 회귀).
- AC-13: Given admin 인증, When
- Updated: 없음
- Removed: 없음
Impacted Area Delta
- Modules:
app/api/v1_admin_daemons.py(GET 핸들러list_all_daemons),app/schemas/v1.py(DaemonDetail,DaemonDetailListResponse),app/repositories/postgres.py(list_daemons_all()) - Tests:
tests/test_bat022_req053_admin_daemon_crud.py(GET 목록 케이스 추가)
Delivery Trace Delta
- 핫픽스 커밋
2dcbafb(로컬 main 직접 커밋 — worktree/PR/QC 정식 게이트 대신 핫픽스 fast-path). 정식 QC 게이트는 생략했고, 대신 **라이브 통합검증(실행 중 portfolio-hub :8000 상대 API E2E 18항목 PASS, GET 목록에 신규 데몬 포함 확인)**으로 검증을 대체했다.
Revalidation Impact
- Reverification Needed: no (라이브 E2E로 검증 완료)
- Existing Implementation Invalidated: no (순수 추가, 기존 핸들러 무변경)
- Status Recommendation: implemented
- Rollback:
git revert 2dcbafb(순수 추가라 안전). 롤백 시 목록 화면만 405로 회귀, 생성/변경 영향 없음. - Follow-up Action: 후속 batch에서 GET 목록 케이스를 정식 회귀 테스트 스위트에 편입. 동종 갭 예방 위해 UI API 클라(REQ-035)와 백엔드 계약(REQ-053) 간 엔드포인트 교차대조 체크리스트화.