14 KiB
14 KiB
0. 문서 상태
이 문서의 현재 상태와 식별 정보를 기록한다.
- 상태: draft
- 문서 ID: sdlc-002_20260423_service-token-user-based
- 이슈명: service-token user-based 소유권
- 참조 Discovery: docs/sdlc/sdlc-002_20260423_service-token-user-based/1_discovery.md
- 작성 시각(KST): 2026-04-23
- 마지막 갱신 시각(KST): 2026-04-23
1. Discovery 인계 요약
Discovery에서 확정된 핵심 내용을 요약한다. 원본은 1_discovery.md를 참조하며, 이 섹션은 Planning 작업의 입력 기준선이 된다.
이슈 목적
bot_principals 테이블과 audit log를 제거하고, service token을 auth_tokens 단일 엔티티로 직접 발급하도록 재구현한다. CLI 명령 pfhub service-token issue <name> --user <username>으로 사용자 기반 소유권을 명확히 한다.
확정 범위
- In Scope
bot_principals테이블 및 관련 코드 완전 제거 (도메인/스키마/서비스/리포지터리/API/CLI, 약 15개 파일, DB 마이그레이션 포함)auth_audit_logs테이블 및 audit 함수(build_audit_event,record_audit_event,_record_audit_event) 삭제auth_tokens.token_type = "bot"→"service"rename (기존 데이터 UPDATE 포함)auth_tokens.user_id소유권 보정 및bot_principal_id컬럼 DROP (마이그레이션)- service token 직접 발급 CLI 구현 (
pfhub service-token issue <name> --user <username>) AuthContext.token_type필드 추가, service token 가드 교체- 기존 테스트 업데이트 및 신규 검증 테스트 추가
- 기술 문서(
api-contracts.md,auth-and-token-lifecycle.md,README.md) 업데이트
- Out of Scope
- 외부 IAM(OAuth/OIDC) 연동
- service_principal 셀프서비스 UI/포털 제공
- token 권한 모델(read/trade-write/admin) 변경
- API 경로 변경에 대한 하위 호환성 레이어(alias route) 제공 — 외부 클라이언트 없으므로 즉시 제거
기능 요구사항 (FR) 요약
- FR-1:
bot_principals테이블,BotPrincipal모델, 관련 스키마/서비스/리포지터리/API,auth_tokens.bot_principal_id컬럼,auth_audit_logs테이블, audit 함수 전체 제거 - FR-2: service 토큰 발급 시
auth_tokens.user_id에 username에서 조회한 실제 user_id 직접 저장 - FR-3: 기존 bot 토큰
user_id→bot_principal.owner_user_id로 마이그레이션 보정 후bot_principalsDROP - FR-4:
get_token_principal()COALESCE/JOIN 제거 →t.user_id단순 참조 - FR-5: service token
name유니크, 중복 시 오류 반환 - FR-6:
--user <username>→ users 테이블 조회 →auth_tokens.user_id로 저장, 존재하지 않는 username이면 오류 - FR-7:
--user필수 옵션, 생략 시 오류
비기능 요구사항 (NFR) 요약
- NFR-1: 변경 전후 모든 테스트 통과 (pytest 기준)
- NFR-2: DB 마이그레이션 upgrade/downgrade 양방향 지원
- NFR-3: 변경 완료 후 CLI help 텍스트 및 오류 메시지에서 "bot" 잔류 참조 없음
이월된 오픈 질문 / 리스크
Discovery에서 Deferred 처리된 항목 없음. 모든 OQ 해소 완료 (OQ-1 Answered, OQ-2/3/5 Dropped, OQ-4 Answered).
2. 작업 분해 (Task Breakdown)
FR/NFR 각각을 실행 가능한 단위 태스크로 분해한다.
| ID | 태스크 제목 | 유형 | 참조 요구사항 | 의존 태스크 | 담당자 |
|---|---|---|---|---|---|
| T-1 | DB 마이그레이션 파일 작성 | 개발 | FR-3, NFR-2 | - | {{TASK_OWNER_1:TBD}} |
| T-2 | 도메인/스키마/인터페이스 정리 | 개발 | FR-1 | - | {{TASK_OWNER_2:TBD}} |
| T-3 | postgres.py 구현체 정리 | 개발 | FR-1, FR-4 | T-2 | {{TASK_OWNER_3:TBD}} |
| T-4 | AuthContext/security.py 변경 | 개발 | FR-1 (OQ-4) | T-2 | {{TASK_OWNER_4:TBD}} |
| T-5 | AuthService 재구현 | 개발 | FR-2, FR-5, FR-6, FR-7 | T-3, T-4 | {{TASK_OWNER_5:TBD}} |
| T-6 | API 경로 정리 | 개발 | FR-1 | T-5 | {{TASK_OWNER_6:TBD}} |
| T-7 | CLI 재구현 | 개발 | FR-5, FR-6, FR-7, NFR-3 | T-5 | {{TASK_OWNER_7:TBD}} |
| T-8 | 테스트 업데이트 | 개발 | NFR-1 | T-5, T-6, T-7 | {{TASK_OWNER_8:TBD}} |
| T-9 | 기술 문서 업데이트 | 문서 | - | T-7, T-8 | {{TASK_OWNER_9:TBD}} |
태스크 완료 조건 (DoD)
- T-1:
alembic upgrade head실행 시bot_principals,auth_audit_logs테이블이 DROP되고,auth_tokens.user_id가 users FK를 정상 참조하며,token_type = 'service'로 UPDATE됨.alembic downgrade -1실행 시 역방향 복원 가능. - T-2:
BotPrincipal,AuthToken.bot_principal_id,TokenPrincipal.bot_principal_id,CreateBotPrincipalRequest,BotPrincipalResponse,BotTokenIssueCliResponse.bot_id,BotTokenRevokeCliResponse.bot_id삭제/정리 완료.PortfolioRepository프로토콜에서 bot_principal 메서드 제거.python -c "from app.domain.models import AuthToken"import 오류 없음. - T-3:
ensure_schema()재실행 시bot_principals,auth_audit_logs테이블 미생성.get_token_principal()이 단일 테이블auth_tokens만 참조.record_audit_event()메서드 삭제 완료. - T-4:
AuthContext에token_type: str | None필드 추가 완료._resolve_auth_context()가 DB 토큰 조회 시principal.token_type을 전달.build_audit_event()함수 삭제 완료. - T-5:
issue_service_token(name, username, ...)메서드가 존재하고, username → user_id 조회 후auth_tokens직접 발급. bot_principal 관련 메서드 전체 삭제.issue_client_token,list_tokens,revoke_token의 가드가auth_context.token_type == "service"체크로 교체됨. - T-6: FastAPI 앱 기동 후
/auth/bots,/auth/me/bots경로 미노출.curl /openapi.json에서 해당 경로 없음. - T-7:
pfhub service-token issue --help에서<name>,--user인수 노출. help 텍스트에 "bot" 문자열 없음.pfhub service-token issue kis-token --user justin명령이 토큰을 발급하고 출력. - T-8:
pytest실행 결과 0 failures, 0 errors. service token 발급/폐기 시나리오 테스트 신규 추가. - T-9:
auth-and-token-lifecycle.md,api-contracts.md,management-cli-operations.md,README.md에서 "bot_principal", "bot token" 잔류 참조 없음.pfhub service-token명령 예제 포함.
3. 공수 추정
| ID | 태스크 제목 | 추정 공수 | 추정 단위 | 비고 |
|---|---|---|---|---|
| T-1 | DB 마이그레이션 파일 작성 | 2 | SP | user_id 보정 로직 + downgrade 구현 포함 |
| T-2 | 도메인/스키마/인터페이스 정리 | 2 | SP | 다수 파일이나 삭제 위주 — 복잡도 낮음 |
| T-3 | postgres.py 구현체 정리 | 2 | SP | ensure_schema DDL 제거 + get_token_principal 단순화 — 주의 필요 |
| T-4 | AuthContext/security.py 변경 | 1 | SP | 변경 범위 소규모 |
| T-5 | AuthService 재구현 | 3 | SP | username 조회 신규 로직 + 가드 교체 + bot 메서드 삭제 |
| T-6 | API 경로 정리 | 1 | SP | 삭제 위주 |
| T-7 | CLI 재구현 | 2 | SP | 파일 rename + 인수 변경 + 출력 함수 rename |
| T-8 | 테스트 업데이트 | 3 | SP | 4개 파일 업데이트 + 신규 시나리오 추가 |
| T-9 | 기술 문서 업데이트 | 1 | SP | 내용 갱신 위주 |
- 총 추정 공수: 17 SP
- 추정 신뢰도: Medium
- 추정 근거: sdlc-001(CLI bot token 발급 구현, 약 8 SP)과 유사한 레이어 범위이나 삭제 중심 + 기존 테스트 보정 작업이 추가됨. T-5/T-8이 가장 불확실 요소.
4. 일정 계획
마일스톤
| 마일스톤 | 목표 날짜 | 포함 태스크 | 완료 조건 |
|---|---|---|---|
| M-1: 정리 완료 | {{MILESTONE_1_DATE:TBD}} | T-1, T-2, T-3, T-4 | bot_principals/auth_audit_logs 관련 코드·스키마·DDL 전체 삭제, import 오류 없음 |
| M-2: 구현·검증 완료 | {{MILESTONE_2_DATE:TBD}} | T-5, T-6, T-7, T-8, T-9 | pytest 0 failures, CLI --help 정상 노출, 문서 갱신 완료 |
이터레이션 계획
- 이터레이션 단위: 없음(단일 배포)
- 이터레이션 1 ({{ITERATION_1_PERIOD:TBD}}): T-1, T-2 (병렬 가능)
- 이터레이션 2 ({{ITERATION_2_PERIOD:TBD}}): T-3, T-4 (T-2 완료 후)
- 이터레이션 3 ({{ITERATION_3_PERIOD:TBD}}): T-5 (T-3, T-4 완료 후)
- 이터레이션 4 ({{ITERATION_4_PERIOD:TBD}}): T-6, T-7 (병렬 가능, T-5 완료 후)
- 이터레이션 5 ({{ITERATION_5_PERIOD:TBD}}): T-8, T-9 (T-6, T-7 완료 후)
5. 의존성 및 제약
태스크 간 의존성
- T-1은 T-2와 독립적으로 병렬 진행 가능
- T-3, T-4는 T-2 완료 후 시작 가능 (인터페이스 정리 선행 필요)
- T-5는 T-3, T-4 완료 후 시작 가능 (repository 메서드, AuthContext 변경 선행 필요)
- T-6, T-7은 T-5 완료 후 병렬 시작 가능
- T-8은 T-5, T-6, T-7 완료 후 시작 가능
- T-9는 T-8 완료 후 시작 (최종 동작 확인 후 문서화)
외부 의존성
- DB 접속 가능 환경 필요 (마이그레이션 실행 및 S-3 검증)
- pytest 실행 환경 (Docker Compose 또는 로컬 DB)
기술/환경 제약
- Alembic 마이그레이션 파일명 패턴:
YYYYMMDD_NNNN_<slug>.py(기존 패턴 준수) ensure_schema()는 테스트 환경에서도 호출되므로 DDL 제거 후 테스트 환경에서 재실행 검증 필요app/cli/commands/bot_tokens.py→service_tokens.py파일 rename 시app/cli/main.py의 import 경로도 함께 수정 필요
6. 검증 계획 개요
Discovery의 성공 기준과 연결해 검증 방법 초안을 적는다.
| 성공 기준 | 검증 방법 초안 | 담당자 |
|---|---|---|
| S-1: pytest 0 failures | pytest 전체 실행 후 결과 확인 |
{{VERIFY_OWNER_1:TBD}} |
| S-2: pfhub service-token --help 정상 노출 | 터미널에서 pfhub service-token issue --help 실행, <name> 및 --user 인수 확인 |
{{VERIFY_OWNER_2:TBD}} |
| S-3: auth_tokens.user_id FK 정합성 | 마이그레이션 upgrade 후 SELECT COUNT(*) FROM auth_tokens WHERE user_id NOT IN (SELECT id FROM users) = 0 확인 |
{{VERIFY_OWNER_3:TBD}} |
7. 리스크
리스크
- R-1 (High): 기존
auth_tokens에user_id = bot_principal.id인 행의bot_principal.owner_user_id가 NULL이거나users테이블에 없으면 마이그레이션 FK 위반 발생.- 완화 방안: T-1 구현 시 upgrade 전 사전 검증 쿼리(
SELECT COUNT(*) FROM bot_principals WHERE owner_user_id IS NULL) 포함. NULL 존재 시 오류 후 중단.
- 완화 방안: T-1 구현 시 upgrade 전 사전 검증 쿼리(
- R-2 (Medium): 약 15개 파일 rename 중 일부 누락 시 런타임
AttributeError/NameError.- 완화 방안: T-8 완료 후
grep -r "bot_principal\|BotPrincipal\|bot_token\|token_type.*bot"잔류 참조 검사. 테스트 전체 통과를 gate로 설정.
- 완화 방안: T-8 완료 후
- R-3 (Medium): ensure_schema() DDL 제거 누락 시 재실행 때 bot_principals 테이블 재생성.
- 완화 방안: T-3 DoD에 ensure_schema() 재실행 검증 포함.
가정
- PA-1: 현재 운영 중인 bot 토큰은 모두
owner_user_id가 설정된bot_principal에 연결되어 있다 (migration 0011 backfill 완료). user_id 보정 후 DROP이 안전하다. - PA-2:
app/cli/main.py의name="service-token"등록은 이미 완료되어 있으므로 T-7에서 import 경로만 수정하면 된다. - PA-3: 테스트 환경에서 Docker Compose DB 접속이 가능하다.
오픈 질문
없음. Discovery에서 모든 OQ 해소 완료.
8. Design으로 넘기기 전 확인 체크
- 전체 태스크 목록 확정 및 담당자 지정
- 기준: T-1 ~ T-9 모든 태스크에 담당자(
{{TASK_OWNER_N}})가 지정되어야 한다
- 기준: T-1 ~ T-9 모든 태스크에 담당자(
- 공수 추정 완료 및 총 공수 확인
- 기준: 17 SP — 모든 태스크 추정값 채움 완료
- 마일스톤 및 이터레이션 계획 확정
- 기준: M-1, M-2 목표 날짜(
{{MILESTONE_N_DATE}})가 확정되어야 한다
- 기준: M-1, M-2 목표 날짜(
- 외부 의존성 해소 계획 확인
- 기준: DB 접속 환경 및 pytest 실행 환경 확인
- 모든 오픈 질문(OQ)
Open상태 없음 확인- 기준: 없음 — Discovery에서 전체 해소 완료
- Freeze 확정 담당자(CONFIRMED_BY) 지정
- 기준: 담당자 Justin 지정 완료 — 문서 서명 대기
9. 파일 처리 결과
- 처리 결과: 생성
- 생성 경로: docs/sdlc/sdlc-002_20260423_service-token-user-based/2_planning.md
- 참조 문서:
- docs/sdlc/sdlc-002_20260423_service-token-user-based/1_discovery.md
- app/domain/models.py
- app/core/auth.py
- app/core/security.py
- app/services/auth_service.py
- app/repositories/postgres.py
- app/repositories/portfolio_repository.py
- app/schemas/auth.py
- app/api/auth_routes.py
- app/cli/commands/bot_tokens.py
- app/cli/core/output.py
10. 사용자 결정 필요 항목 요약
DECIDE
- (없음) — Discovery 범위에서 모든 설계 결정 완료
CONFIRM
- T-1 ~ T-9 담당자 지정: 현재 전부
TBD. 단독 개발자 환경이면 Justin으로 일괄 지정 가능 - M-1, M-2 목표 날짜 및 이터레이션 기간 확정
DATA
- 마이그레이션 실행 전 운영 DB
bot_principals행 수 및owner_user_id NULL행 수 확인 필요 (R-1 완화)
11. Planning Freeze
섹션 참조
- 작업 분해: # 2. 작업 분해
- 공수/일정: # 3. 공수 추정, # 4. 일정 계획
- 의존성: # 5. 의존성 및 제약
- 검증 계획: # 6. 검증 계획 개요
- 리스크/오픈 질문: # 7. 리스크
- 인계 전 확인: # 8. Design으로 넘기기 전 확인 체크
- 사용자 결정 필요: # 10. 사용자 결정 필요 항목 요약
Freeze 플래그
- Handoff Decision: 보류
- Handoff Rationale: 담당자(TASK_OWNER_1
9), 마일스톤 날짜(MILESTONE_1_DATE, MILESTONE_2_DATE), 이터레이션 기간(ITERATION_15_PERIOD)이 TBD 상태. 확정 후 인계 가능. - Ready for Design: false
- Confirmed By: {{CONFIRMED_BY:TBD}}
- Confirmed At (KST): {{CONFIRMED_AT_KST:TBD}}