15 KiB
15 KiB
0. 문서 상태
이 문서의 현재 상태와 식별 정보를 기록한다.
- 상태: confirmed
- 문서 ID: sdlc-002_20260423_service-token-user-based
- 이슈명: service-token user-based 소유권
- 참조 Design: docs/sdlc/sdlc-002_20260423_service-token-user-based/3_design.md
- 작성 시각(KST): 2026-04-23
- 마지막 갱신 시각(KST): 2026-04-23 (confirmed)
1. Design 인계 요약
Design에서 확정된 핵심 내용을 요약한다. 원본은 3_design.md를 참조하며, 이 섹션은 Implementation 작업의 입력 기준선이 된다.
이슈 목적
bot_principals / auth_audit_logs 테이블을 제거하고, service token을 auth_tokens 단일 엔티티로 직접 발급하도록 재구현한다. CLI pfhub service-token issue <name> --user <username> 명령으로 사용자 기반 소유권을 명확히 한다.
확정 태스크 및 변경 대상
| ID | 태스크 제목 | 변경 대상 파일/함수 | 담당자 |
|---|---|---|---|
| T-1 | DB 마이그레이션 파일 작성 | migrations/versions/20260423_0013_remove_bot_principals_service_tokens.py (신규) |
copilot |
| T-2 | 도메인/스키마/인터페이스 정리 | app/domain/models.py, app/schemas/auth.py, app/repositories/portfolio_repository.py |
copilot |
| T-3 | postgres.py 구현체 정리 | app/repositories/postgres.py |
copilot |
| T-4 | AuthContext/security.py 변경 | app/core/auth.py, app/core/security.py |
copilot |
| T-5 | AuthService 재구현 | app/services/auth_service.py |
copilot |
| T-6 | API 경로 정리 | app/api/auth_routes.py |
copilot |
| T-7 | CLI 재구현 | app/cli/commands/bot_tokens.py (삭제), app/cli/commands/service_tokens.py (신규), app/cli/core/output.py, app/cli/main.py |
copilot |
| T-8 | 테스트 업데이트 | tests/test_auth.py, tests/test_cli.py, tests/test_portfolio_ownership.py, tests/test_users.py |
copilot |
| T-9 | 기술 문서 업데이트 | docs/technical/auth-and-token-lifecycle.md, docs/technical/api-contracts.md, docs/technical/management-cli-operations.md, README.md |
copilot |
이월된 오픈 질문 / 리스크
없음. Design 단계에서 모든 OQ 해소 완료.
2. 구현 계획
태스크(T-N)별 구현 순서와 접근 방법을 기술한다.
구현 순서
태스크 간 의존 관계에 따른 순서:
- T-1 (DB 마이그레이션 파일 작성) — T-2와 병렬 가능, 독립적
- T-2 (도메인/스키마/인터페이스 정리) — T-1과 병렬 가능
- T-3 (postgres.py 구현체 정리) — T-2 완료 후 (인터페이스 변경 선행 필요)
- T-4 (AuthContext/security.py 변경) — T-2 완료 후 (모델 변경 선행 필요)
- T-5 (AuthService 재구현) — T-3, T-4 완료 후
- T-6 (API 경로 정리) — T-5 완료 후, T-7과 병렬 가능
- T-7 (CLI 재구현) — T-5 완료 후, T-6과 병렬 가능
- T-8 (테스트 업데이트) — T-5, T-6, T-7 완료 후
- T-9 (기술 문서 업데이트) — T-8 완료 후
T-1: DB 마이그레이션 파일 작성
- 구현 방법: Alembic 마이그레이션 파일을 신규 생성한다.
upgrade()내 첫 스텝은bot_principals.owner_user_id IS NULL검사로, NULL이 있으면MigrationError를 raise하고 중단한다. 이후 user_id 보정 → token_type rename → unique index → bot_principal_id 컬럼 DROP → auth_audit_logs DROP → bot_principals DROP 순으로 실행한다.downgrade()는 역방향 구조 복원만 수행한다. - 변경 대상:
migrations/versions/20260423_0013_remove_bot_principals_service_tokens.py(신규 생성) - 완료 조건:
alembic upgrade head실행 시bot_principals,auth_audit_logs테이블이 DROP되고,auth_tokens.user_id가 실제 user FK를 참조하며,token_type = 'service'로 업데이트됨.alembic downgrade -1실행 시 역방향 복원 가능. - 주의사항:
op.execute()SQL은 파라미터 바인딩 없이 직접 실행 (Alembic DDL 관례). NULL 검사 쿼리는op.get_bind().execute()패턴 사용.
T-2: 도메인/스키마/인터페이스 정리
- 구현 방법: 파일별 삭제/변경을 수행한다.
models.py에서BotPrincipal,bot_principal_id필드를 삭제한다.schemas/auth.py에서 bot 관련 스키마를 삭제하고ServiceTokenIssueCliResponse,ServiceTokenRevokeCliResponse를 추가한다.portfolio_repository.py에서 bot 관련 메서드 시그니처를 삭제하고get_service_token_by_name()을 추가한다. - 변경 대상:
app/domain/models.py,app/schemas/auth.py,app/repositories/portfolio_repository.py - 완료 조건:
python -c "from app.domain.models import AuthToken"ImportError 없음.BotPrincipal클래스 미존재.ServiceTokenIssueCliResponseimport 가능. - 주의사항:
AuthTokenResponse.token_typeLiteral 변경("bot"→"service")은 API 응답 직렬화에 즉시 영향을 주므로 T-6 완료 전에 수행해도 무방 (기존 bot 토큰 데이터 없음 전제).
T-3: postgres.py 구현체 정리
- 구현 방법:
ensure_schema()내 bot 관련 DDL 블록을 순서대로 제거한다.get_token_principal()의 SELECT문을 단순화한다. bot/audit 관련 메서드를 삭제하고get_service_token_by_name()을 추가한다. - 변경 대상:
app/repositories/postgres.py - 완료 조건:
ensure_schema()재실행 후bot_principals,auth_audit_logs테이블 미생성.get_token_principal()반환값에bot_principal_id없음.get_service_token_by_name("test")호출 시None또는AuthToken반환. - 주의사항:
_SELECT_AUTH_TOKEN상수에서bot_principal_id컬럼 제거.TokenPrincipal생성 시bot_principal_id인자 제거.
T-4: AuthContext/security.py 변경
- 구현 방법:
AuthContext데이터클래스에서bot_principal_id필드를 제거하고token_type: str | None = None을 추가한다._resolve_auth_context()에서token_type=principal.token_type전달을 추가하고bot_principal_id할당을 제거한다.security.py에서build_audit_event()함수를 삭제한다. - 변경 대상:
app/core/auth.py,app/core/security.py - 완료 조건:
AuthContext생성 시token_type파라미터 사용 가능.bot_principal_id파라미터 없음.from app.core.security import build_audit_eventImportError 발생.
T-5: AuthService 재구현
- 구현 방법: bot 관련 메서드와
_require_db_user_context(),_build_bot_expiration(),_record_audit_event()헬퍼를 삭제한다.issue_client_token(),list_tokens(),revoke_token()내bot_principal_id가드를token_type == "service"가드로 교체한다.issue_service_token(),revoke_service_token()메서드를 추가한다.IssuedBotToken→IssuedServiceToken교체. - 변경 대상:
app/services/auth_service.py - 완료 조건:
AuthService().issue_service_token(name="test", username="user")시그니처 존재.issue_client_token()에서 service token AuthContext로 호출 시 ValueError 발생. bot 관련 메서드 미존재. - 주의사항:
issue_service_token()내 unique constraint 위반 시psycopg.errors.UniqueViolation예외를ValueError로 래핑해야 한다.
T-6: API 경로 정리
- 구현 방법:
auth_routes.py에서/auth/bots,/auth/me/bots관련 라우트 핸들러와 헬퍼 함수를 삭제한다. 관련 import를 제거한다._to_auth_token_response()에서bot_principal_id인자를 제거한다. - 변경 대상:
app/api/auth_routes.py - 완료 조건: FastAPI 앱 기동 후
/openapi.json에/auth/bots,/auth/me/bots경로 미노출.
T-7: CLI 재구현
- 구현 방법:
app/cli/commands/service_tokens.py신규 생성 (Design# 3 T-7시그니처 기준).bot_tokens.py파일 삭제.app/cli/main.pyimport 경로 변경.output.py에서render_bot_result()→render_service_token_result()rename. - 변경 대상:
app/cli/commands/service_tokens.py(신규),app/cli/commands/bot_tokens.py(삭제),app/cli/core/output.py,app/cli/main.py - 완료 조건:
pfhub service-token issue --help실행 시NAME,--user인수 노출. help 텍스트에 "bot" 문자열 없음. - 주의사항:
service_tokens.py는token_app = typer.Typer(...)인스턴스를 export해야 한다 (app/cli/main.py에서token_app으로 import).
T-8: 테스트 업데이트
- 구현 방법: bot_principal 관련 픽스처와 테스트 함수를 제거하고 service token 시나리오 테스트를 추가한다.
AuthContextmock에서bot_principal_id→token_type교체. - 변경 대상:
tests/test_auth.py,tests/test_cli.py,tests/test_portfolio_ownership.py,tests/test_users.py - 완료 조건:
pytest실행 결과 0 failures, 0 errors. service token 발급/폐기 시나리오 테스트 포함.
T-9: 기술 문서 업데이트
- 구현 방법: 4개 문서에서 "bot_principal", "bot token" 참조를 제거하고 service token 기반 설명으로 갱신한다.
- 변경 대상:
docs/technical/auth-and-token-lifecycle.md,docs/technical/api-contracts.md,docs/technical/management-cli-operations.md,README.md - 완료 조건: 4개 문서에서 "bot_principal", "bot token" 잔류 참조 없음.
pfhub service-token명령 예제 포함.
3. 변경 파일 목록
이번 Implementation에서 생성/수정/삭제되는 파일을 미리 나열한다.
| 파일 경로 | 변경 유형 | 관련 태스크 | 비고 |
|---|---|---|---|
migrations/versions/20260423_0013_remove_bot_principals_service_tokens.py |
생성 | T-1 | Alembic 마이그레이션 신규 |
app/domain/models.py |
수정 | T-2 | BotPrincipal 삭제, bot_principal_id 필드 삭제 |
app/schemas/auth.py |
수정 | T-2 | bot 스키마 삭제, ServiceToken* 스키마 추가 |
app/repositories/portfolio_repository.py |
수정 | T-2 | bot 메서드 삭제, get_service_token_by_name 추가 |
app/repositories/postgres.py |
수정 | T-3 | ensure_schema DDL 제거, get_token_principal 단순화 |
app/core/auth.py |
수정 | T-4 | AuthContext.token_type 추가, bot_principal_id 삭제 |
app/core/security.py |
수정 | T-4 | build_audit_event 함수 삭제 |
app/services/auth_service.py |
수정 | T-5 | bot 메서드 삭제, issue/revoke_service_token 추가 |
app/api/auth_routes.py |
수정 | T-6 | /auth/bots, /auth/me/bots 라우트 삭제 |
app/cli/commands/bot_tokens.py |
삭제 | T-7 | service_tokens.py로 대체 |
app/cli/commands/service_tokens.py |
생성 | T-7 | 신규 CLI 명령 모듈 |
app/cli/core/output.py |
수정 | T-7 | render_bot_result → render_service_token_result |
app/cli/main.py |
수정 | T-7 | import 경로 변경 |
tests/test_auth.py |
수정 | T-8 | bot 테스트 삭제, service token 테스트 추가 |
tests/test_cli.py |
수정 | T-8 | service-token CLI 테스트 업데이트 |
tests/test_portfolio_ownership.py |
수정 | T-8 | token_type 기반 mock으로 교체 |
tests/test_users.py |
수정 | T-8 | bot_principal 참조 제거 (있는 경우) |
docs/technical/auth-and-token-lifecycle.md |
수정 | T-9 | bot → service 전반 업데이트 |
docs/technical/api-contracts.md |
수정 | T-9 | /auth/bots 경로 삭제 |
docs/technical/management-cli-operations.md |
수정 | T-9 | service-token 명령 예제 교체 |
README.md |
수정 | T-9 | CLI 섹션 service-token 예제 추가 |
4. 리스크 및 제약
Implementation 단계에서 새로 식별된 리스크와 제약사항을 기록한다.
리스크
- R-1 (High, 이월): 마이그레이션 upgrade 전
bot_principals.owner_user_id IS NULL행 존재 시 FK 위반 — upgrade() 사전 검사로 차단. - R-2 (Medium, 이월): 15개 파일 rename 중 누락 시 런타임 AttributeError — T-8 완료 후
grep잔류 검사. - R-3 (Medium, 이월):
revoke_service_token(name)호출 시 이미 폐기된 토큰 → "찾을 수 없음" 오류 — 설계상 의도된 동작. - R-4 (Low, 이월):
ensure_schema()DDL 제거 후 테스트 환경 스키마 캐시로 인한 bot_principals 잔류 — 재실행 검증으로 확인. - R-5 (Medium):
psycopg.errors.UniqueViolation예외를ValueError로 래핑하지 않으면 FastAPI/CLI에서 500 응답 발생.- 완화 방안: T-5 구현 시
try/except UniqueViolation → raise ValueError(...)처리 포함.
- 완화 방안: T-5 구현 시
가정
- IA-1:
get_user_by_username()메서드가app/repositories/postgres.py에 이미 구현되어 있다 (auth_service.login()에서 사용 중으로 확인됨). - IA-2:
revoke_auth_token(user_id, token_id)메서드가app/repositories/postgres.py에 구현되어 있다. - IA-3:
app/cli/main.py의name="service-token"등록이 완료되어 있어 T-7에서 import 경로만 변경하면 된다. - IA-4: 현재 테스트 환경에서 Docker Compose DB 접속이 가능하다.
오픈 질문
없음.
5. Verification으로 넘기기 전 확인 체크
- 모든 T-N 태스크 구현 완료
- 기준: T-1
T-9 각 태스크의 완료 조건(DoD)을 충족해야 한다 — **T-1T-9 모두 완료**
- 기준: T-1
- 변경 파일 목록과 실제 변경 일치
- 기준: 3_design.md의 변경 대상과 실제 변경된 파일이 일치해야 한다 — 일치 확인
- 단위 테스트 또는 로컬 검증 완료
- 기준:
pytest실행 결과 0 failures, 0 errors — 73 passed
- 기준:
- 모든 오픈 질문(OQ)
Open상태 없음 확인- 기준: OQ 목록에
Open상태 항목이 0개 — 확인 완료
- 기준: OQ 목록에
- Freeze 확정 담당자(CONFIRMED_BY) 지정
- 기준: 담당자 Justin 지정 완료 — 문서 서명 대기
6. 파일 처리 결과
- 처리 결과: 생성
- 생성 경로: docs/sdlc/sdlc-002_20260423_service-token-user-based/4_implementation.md
- 참조 문서:
- docs/sdlc/sdlc-002_20260423_service-token-user-based/3_design.md
- docs/sdlc/sdlc-002_20260423_service-token-user-based/2_planning.md
7. 사용자 결정 필요 항목 요약
DECIDE
없음. 모든 구현 결정이 Design에서 완료되었다.
CONFIRM
- Freeze 확정 담당자(
CONFIRMED_BY): Justin — confirm-implementation 단계에서 처리
DATA
- 마이그레이션 실행 전 운영 DB
bot_principals행 수 및owner_user_id NULL행 수 확인 권장 (R-1 완화)
8. Implementation Freeze
섹션 참조
- 구현 계획: # 2. 구현 계획
- 변경 파일 목록: # 3. 변경 파일 목록
- 리스크/오픈 질문: # 4. 리스크 및 제약
확정 플래그
- Handoff Decision: 승인
- Handoff Rationale: T-1~T-9 전체 태스크 완료, 73개 단위 테스트 통과, 변경 파일 목록 일치 확인
- Ready for Verification: true
- Confirmed By: Justin
- Confirmed At (KST): 2026-04-23