Files
portfolio-hub/docs/sdlc/sdlc-002_20260423_service-token-user-based/2_planning.md
T

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_principals DROP
  • 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 존재 시 오류 후 중단.
  • R-2 (Medium): 약 15개 파일 rename 중 일부 누락 시 런타임 AttributeError/NameError.
    • 완화 방안: T-8 완료 후 grep -r "bot_principal\|BotPrincipal\|bot_token\|token_type.*bot" 잔류 참조 검사. 테스트 전체 통과를 gate로 설정.
  • 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}})가 지정되어야 한다
  • 공수 추정 완료 및 총 공수 확인
    • 기준: 17 SP — 모든 태스크 추정값 채움 완료
  • 마일스톤 및 이터레이션 계획 확정
    • 기준: M-1, M-2 목표 날짜({{MILESTONE_N_DATE}})가 확정되어야 한다
  • 외부 의존성 해소 계획 확인
    • 기준: 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

섹션 참조

Freeze 플래그

  • Handoff Decision: 보류
  • Handoff Rationale: 담당자(TASK_OWNER_19), 마일스톤 날짜(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}}