IMPLEMENTATION NOTE · 2026.10.01

KBC의 Jira 연결을
이 대시보드에 어떻게 가져왔나요?

KBC는 Krafton BGMI Code의 약자이며, 기존 PTU-31의 새 이름입니다. 전체 플랫폼을 복제한 것이 아니라 사용자 식별 → OAuth → 토큰 보관 → MCP 호출이라는 연결 경계를 이 대시보드 앱(Python/FastAPI)에 이식했습니다.

현재 소스 재확인 · KBC commit beacd2d

이 문서는 설명용입니다. 인증 요청이나 토큰 발급을 실행하지 않습니다.

01 · 전체 연결 구성

사용자 브라우저Microsoft로 로그인
Jira 연결 / AI Chat
→
AX DashboardHttpOnly 세션 · 사용자 ID
Chat / 승인 실행기
→
사내 Jira MCPAuthorization: Bearer
사용자별 권한 적용
→
Jira프로젝트·티켓 조회
허용된 날짜 변경

모델 호출 경로는 별개

대시보드 → Anthropic API. 사용자가 키를 등록하지 않고 Key Vault에 둔 팀 공용 Claude 키 하나를 서버가 사용합니다. 키는 사용자에게 보이지 않으며, 사용자별 하루 비용 한도가 있습니다. Jira OAuth 토큰은 모델에 보내지 않습니다. 모델은 제한된 읽기·검증 도구만 사용합니다.

KBC 자체 MCP 서버와도 별개

KBC의 backend/routers/mcp.py는 외부 클라이언트에 KBC 기능을 제공하는 들어오는 MCP입니다. 여기서 이식한 것은 사내 Jira MCP로 나가는 클라이언트입니다.

02 · 사용자가 “Jira 연결”을 누른 다음

  1. 앱 사용자 확인. 회사 계정(SSO)으로 로그인한 세션을 확인합니다. 비상 관리자 키로 들어온 세션은 이메일이 없어 Jira에 연결할 수 없습니다. 공용 Jira 봇 계정으로 대체하지 않습니다.
  2. 연결 요청 생성. POST /api/me/jira/connect에서 nonce, PKCE S256 challenge, 서명된 state를 생성합니다. 시도는 10분간 유효하고 한 번만 소비합니다.
  3. 사내 인증 화면으로 이동. authorize URL에 앱 client ID, callback, scope, resource를 포함합니다. 사용자는 사내 계정으로 로그인하고 권한에 동의합니다.
  4. HTTPS callback 검증. /api/jira/oauth/callback이 state 서명, 브라우저 nonce 쿠키, 사용자·세션, 만료·일회성 상태를 검증합니다.
  5. 서버에서 토큰 교환. code와 PKCE verifier로 access/refresh token을 받습니다. 토큰을 브라우저 응답·URL·LLM에 싣지 않습니다.
  6. 암호화 저장 및 계정 확인. 사용자 ID에 묶어 AES-256-GCM으로 저장하고 MCP get_myself로 계정을 확인합니다.
  7. 실제 업무 호출. 현재 사용자 토큰을 선택해 MCP tools/call을 전송합니다. 만료 전 갱신하며, 연결 해제/변경 중인 결과는 그대로 저장하지 않습니다.

연결 버튼만 있으면 끝나는 것은 아닙니다. 운영자가 이 대시보드 전용 OAuth client와 HTTPS callback을 먼저 등록해야 합니다. KBC의 client secret이나 사용자 토큰을 복사하지 않았으며, 앱 등록은 자동 수행하지 않았습니다.

03 · 실제 확인한 KBC 파일 → 적용 위치

KBC 코드확인한 동작이 앱의 대응 코드
backend/routers/jira_oauth.py연결/콜백/상태/해제, PKCE, 서명 state, Secure nonce 쿠키src/server/oauth.cjs
server.cjs
backend/jira_tokens.py
backend/llm/user_keys.py
사용자별 암호화 access/refresh token, 만료 60초 전 갱신oauth.cjs
crypto.cjs · store.cjs
backend/agents/jira_ticket_agent/mcp.py사용자 Bearer token + 직접 JSON-RPC, JSON/SSE 응답mcp-client.cjs
jira-mcp.cjs
backend/agents/jira_ticket_agent/plugin.py연결 여부 확인, 제안/확인 후 Jira 액션chat.cjs → service.cjs
채팅 계획 카드 → 검증/승인/실행
frontend/src/pages/SettingsPage.tsx본인 Jira 연결·재연결·해제 UIpublic/assets/js/platform-ui.js

이번 재검토에서 맞춘 부분: KBC는 initialize 없이 직접 도구를 호출하므로 JIRA_MCP_INITIALIZE=false를 기본값으로 맞췄습니다. 이 앱은 추가로 tools/list를 확인해 필요한 도구와 날짜 입력 규격을 검사합니다. 표준 handshake가 필요한 서버는 true로 선택할 수 있습니다.

KBC는 PostgreSQL에, 현재 대시보드는 SQLite에 보관합니다. Python 코드를 그대로 실행하거나 KBC의 DB·비밀 값을 공유하는 방식이 아닙니다.

04 · 대화와 실제 변경은 어떻게 이어지나요?

“지연된 작업을 설명해줘”
  → 사용자/프로젝트별 대화 이력 + 최신 조회(연결 시) 또는 저장 스냅샷
  → AI 답변과 일정 제안 · 실행 권한 없음

“앞서 제안한 일정으로 변경해줘”
  → 명시적 요청 감지 (인용·부정·질문·조건부·모호한 요청은 보수적으로 제외)
  → 최신 Jira baseline으로 새 계획 생성
  → Chat 안에 [이렇게 변경할 예정입니다] 카드
  → 변경 전/후 검토 → 검증 → 확인 문구로 승인 → 별도 실행
  → MCP update_issue (시작일·종료일만)
  → 재조회 검증 → 결과와 감사 이력

모델이 “변경 완료”라고 말한다고 Jira가 바뀌지 않습니다. 모델에 쓰기 도구를 주지 않았습니다. 자연어의 “승인해”도 카드 승인을 대신하지 않습니다. 스냅샷 대화는 실제 반영할 수 없습니다.

KBC와 다르게 더 좁힌 안전 경계
  • 이슈 생성·삭제·코멘트·상태·담당자 변경 기능은 가져오지 않았습니다.
  • MCP result.isError, 응답 ID와 SSE 이벤트를 확인합니다.
  • 401 읽기는 제한적으로 재시도하지만 쓰기는 재시도하지 않습니다.
  • 최종 정책 검증·사용자/연결 binding·승인 만료·중복 실행 차단을 서버에서 강제합니다.
  • 실행 응답 유실/부분 실패는 불확실 상태로 남기고 수동 확인합니다.

05 · .env와 AKS Key Vault의 역할

로컬 .envJIRA_OAUTH_*
PLATFORM_SECRET_ENCRYPTION_KEY
또는
AKS Key VaultCSI → Secret
→ 서버 환경변수
→
같은 앱비밀 값은 UI에 반환 안 함
설정 변경 후 재시작

Key Vault/.env에는 앱의 client secret과 비밀 봉인 키(PLATFORM_SECRET_ENCRYPTION_KEY)를 보관합니다. 팀 공용 Claude 키(ANTHROPIC_API_KEY)도 Key Vault에 있고 사용자에게 돌려주지 않습니다. 사용자별 Jira access/refresh token은 앱 DB의 암호문으로 관리하며, 같은 봉인 키로 암호화됩니다. 사용자가 등록하는 LLM 키는 없습니다.

HTTPS는 브라우저 ↔ Ingress 구간에서 제공하면 됩니다. Ingress ↔ 앱 내부는 HTTP여도 됩니다. 현재 앱은 HTTPS callback을 요구하며 localhost HTTP 예외를 구현하지 않았습니다.

이 문서는 연결 코드와 적용 방식을 설명합니다. 실제 OAuth client 등록, AKS 배포, 본인 계정 연결 및 Jira 운영 티켓 쓰기 검증이 완료되었다는 의미는 아닙니다.

06 · 로그아웃과 연결 해제

앱 로그아웃: 브라우저 세션만 종료하고 Jira 연결과 본인 대화/감사 이력은 유지합니다.
Jira 연결 해제: 사용자 토큰·조회 캐시를 지우고 대기 계획을 무효화합니다. Jira 티켓은 삭제하지 않습니다.
원격 동의 폐기: 로컬 토큰 삭제와 별개입니다. 현재 코드는 사내 서버의 revoke API를 호출하지 않습니다.

GitHub 개발 근거 수집 기능은 제거했습니다. 이 맵과 설명은 실시간 연동 모니터가 아닙니다.