DOCS/troubleshooting/250827_UUID_username_혼용_CRITICAL.md

7.1 KiB

UUID vs Username 혼용 - CRITICAL 시스템 전체 ID 체계 혼란

작성일: 2025-08-27

작성자: 51123 서버 관리자

상태: 🔴 CRITICAL - 즉시 해결 필요

영향 범위: 전체 시스템 (Auth, Gateway, Frontend, rb8001, DB)

위험 수준: 매우 높음


1. 문제 요약

🚨 핵심 문제

시스템 전체가 UUID와 username을 구분하지 못해 데이터 무결성 파괴

  • JWT sub 클레임에 UUID 대신 username 저장
  • Frontend가 하드코딩된 문자열 사용 ('test_user', 'default_user')
  • DB에 UUID 대신 username/slack_id 저장되어 외래키 제약 위반

실제 사례

  • User: happybell80
  • UUID: 1e16e9d5-59f3-54da-a661-8abeabff4230 (UUID4 랜덤 생성)
  • JWT sub: "happybell80" (username, UUID 아님)
  • ChromaDB user_id: "happybell80" (username으로 저장됨)
  • PostgreSQL: "Non-UUID user_id" 로그 발생
  • conversation_logs: user_id NULL, slack_user_id에 우회 저장

2. 영향 분석

2.1 auth-server (51123) - 확인 완료

# /home/admin/auth-server/app/providers/gmail.py
# Line 191: user_id_str = str(user.id)  # UUID 접근 가능
# Line 209: "sub": username  # 🔴 UUID 대신 username 사용
jwt_token = create_access_token(data={
    "sub": username,  # username 사용 (UUID 사용 가능한데도!)
    "email": user_email,
    "name": user_name,
    "username": username,
})
# Line 223: Redis에도 "user_id": username 저장

확인된 문제:

  • user.id (UUID) 접근 가능함에도 JWT sub에 username 사용
  • Redis에도 username을 user_id로 저장

2.2 robeing-gateway (51123) - 확인 완료

# /home/admin/robeing-gateway/app/main.py:232-235
user_info = await get_user_by_username(x_user_id)
if user_info:
    user_uuid = user_info['user_id']  # DB 조회로 UUID 획득
    
# database.py:184
SELECT id::text as user_id  # PostgreSQL UUID를 문자열로 변환

확인된 사항:

  • username → UUID 변환은 DB 조회로만 수행 (계산된 변환 없음)
  • UUID4 형식만 사용 (UUID5 사용 안 함)
  • users 테이블에 username 없으면 변환 실패

2.3 rb8001 (51124) - 확인 완료

# auth.py:36
user_id = payload.get("sub")  # JWT sub(username)를 그대로 사용
# UUID 변환 없이 ChromaDB에 저장
metadata={"user_id": user_id}  # username이 저장됨

확인된 문제:

  • ChromaDB에 "happybell80" (username) 형식으로 저장
  • PostgreSQL 저장 시 "Non-UUID user_id" 에러 로그 발생
  • user_id NULL, slack_user_id로 우회 저장

2.4 Frontend - 확인 완료

// robeing-api.ts:157
const userId = localStorage.getItem('user_id') || 'default_user';
// localStorage의 'user_id'는 Slack ID (U0925SXQFDK 형식)

확인된 문제:

  • localStorage 'user_id' = Slack ID (예: U0925SXQFDK)
  • JWT sub도 아니고 UUID도 아님
  • 완전히 다른 체계 사용 중

2.5 Database

-- conversation_logs 테이블
user_id UUID  -- UUID 타입 요구
slack_user_id VARCHAR(100)  -- username이 여기 저장됨

-- 실제 데이터
user_id: NULL  -- UUID 아니라서 저장 실패
slack_user_id: 'happybell80'  -- 우회 저장

3. 근본 원인

3.1 설계 문제

  • user_id, username, slack_id 개념 미구분
  • UUID 사용 표준 부재
  • 타입 검증 없는 문자열 전달

3.2 구현 문제 (확인 완료)

  • auth-server: JWT sub에 username 사용 (UUID 대신)
  • Gateway: DB 조회로만 UUID 변환 (실패 시 원래 값 전달)
  • Frontend: localStorage에 Slack ID 저장 (UUID도 username도 아님)
  • rb8001: JWT sub를 변환 없이 그대로 user_id로 사용
  • skill-email: slack_user_id 컬럼으로 Slack ID 조회

4. 해결 방안

4.1 긴급 조치 (Phase 1)

auth-server 수정 (즉시 가능)

# gmail.py:209 수정 필요 (Line 191에서 이미 user.id 사용 가능)
jwt_token = create_access_token(data={
    "sub": str(user.id),  # Line 191의 user_id_str 사용
    "username": username,  # username은 별도 필드
    "email": user_email,
    "name": user_name,
})

# Line 223 Redis 저장도 수정
"user_id": str(user.id),  # username 대신 UUID

Gateway username → UUID 매핑 (확인 완료)

# database.py:170-199 이미 완벽 구현
async def get_user_by_username(username: str):
    # SELECT id::text as user_id FROM users WHERE username = :username
    # username으로 UUID 조회 정상 작동
    # JWT sub가 UUID로 바뀌면 이 변환 불필요해짐

4.2 중기 개선 (Phase 2)

Frontend localStorage 정리

// JWT 디코딩 후
const payload = jwt_decode(token);
localStorage.setItem('user_id', payload.sub);  // UUID
localStorage.setItem('username', payload.username);

rb8001 JWT 처리 수정

# auth.py 수정
user_uuid = payload.get("sub")  # UUID
username = payload.get("username")  # username

4.3 장기 개선 (Phase 3)

  • 전체 시스템 ID 타입 표준화
  • UUID 전용 타입 클래스 생성
  • 타입 검증 미들웨어 추가

5. 테스트 시나리오

5.1 현재 상태 확인 (51123 검증 완료)

# Users 테이블 확인 (51123)
SELECT id, username FROM users WHERE username='happybell80';
# id: 1e16e9d5-59f3-54da-a661-8abeabff4230 (정상 UUID4)
# username: happybell80

# auth-server 코드 확인
# Line 191: user_id_str = str(user.id)  # UUID 문자열 생성
# Line 209: "sub": username  # 하지만 JWT에 username 사용
# Line 223: "user_id": username  # Redis에도 username

# Gateway 변환 함수 확인
# database.py:184: SELECT id::text as user_id
# username → UUID 변환 정상 작동

# conversation_logs 확인 (51124 보고)  
# user_id: NULL, slack_user_id: 'happybell80'
# "Non-UUID user_id" 에러 발생

5.2 수정 후 검증

  • JWT sub 필드가 UUID 형식 (36자)
  • conversation_logs.user_id에 UUID 저장
  • ChromaDB metadata.user_id가 UUID

6. 영향도 및 우선순위

컴포넌트 영향도 우선순위 담당
auth-server JWT 🔴 극심 1 로컬 개발자
Frontend localStorage 🔴 극심 2 로컬 개발자
rb8001 JWT 처리 🟡 높음 3 로컬 개발자
Gateway 매핑 🟢 중간 4 이미 구현됨

7. 관련 문서


8. 결론

현재 시스템은 UUID와 username을 구분하지 못해 데이터 무결성이 깨진 상태

즉시 필요한 조치

  1. auth-server: JWT sub에 UUID 사용
  2. Frontend: localStorage에 UUID 저장
  3. rb8001: UUID와 username 구분 처리

예상 작업 시간

  • auth-server 수정: 10분 (Line 209, 223만 수정)
  • Frontend 수정: 1시간
  • rb8001 수정: 30분
  • 테스트 및 검증: 1시간
  • 총 예상: 2시간 40분

51123 서버 준비 완료

  • users 테이블에 UUID 정상 저장됨
  • Gateway UUID 변환 함수 구현 완료
  • auth-server에서 user.id 접근 가능 확인
  • 즉시 수정 가능한 상태

작성 완료: 2025-08-27 15:45