Skip to content

feat: LLM을 DeepSeek로 교체하고 AI API를 소유자 계정으로 제한 - #66

Merged
ParkBible merged 3 commits into
masterfrom
feat/server-llm-key-deepseek
Nov 1, 2026
Merged

ParkBible merged 3 commits into
masterfrom
feat/server-llm-key-deepseek

Conversation

@ParkBible

Copy link
Copy Markdown
Owner

요약

LLM 을 Gemini 에서 DeepSeek 로 바꾸고, 키를 브라우저 입력에서 서버 환경변수로 옮긴다. /api/ai/* 는 ALLOWED_EMAILS 계정으로 로그인한 세션만 부를 수 있다.

 브라우저
-  GeminiKeyCard 에 키 입력 → IndexedDB settings (드라이브 백업에도 포함)
-  POST /api/ai/* { ..., apiKey, model }
+  POST /api/ai/* { ..., model }            # 키 없음. 401 이면 AiLoginNotice 로 드라이브 로그인 재사용
 서버 /api/ai/*
-  key = body.apiKey || GEMINI_API_KEY → @google/generative-ai
+  withAiRoute: requireAiSession()          # 서명 nb_session 쿠키 + ALLOWED_EMAILS
+  key = DEEPSEEK_API_KEY → fetch api.deepseek.com/chat/completions
 서버 /api/auth/callback
-  code → refresh_token 쿠키
+  code → id_token 의 email·email_verified·aud·iss 확인 → 허용 계정만 세션 + refresh 쿠키, 아니면 403 + 토큰 폐기
  • 사용자별 클라이언트 ID 입력(ClientIdGuideModal)을 없애고 서버 GOOGLE_CLIENT_ID 를 /api/auth/config 로 내려준다.
  • 예전 geminiApiKey·geminiModel 설정은 Dexie v16 업그레이드에서 한 번 지우고, 드라이브 백업 올리기·받기 양쪽에서 뺀다.
  • 모델 선택: deepseek-chat(기본) · deepseek-reasoner. JSON 모드(문법 검사)는 항상 deepseek-chat.
  • 드라이브 보류 동작(업로드/다운로드)은 그것을 만든 로그인(state)이 끝났을 때만 실행한다.

증거

  • Before: 브라우저 IndexedDB 와 드라이브 백업 파일에 Gemini 키가 남는다. 서버에 GEMINI_API_KEY 를 두면 누구나 /api/ai/* 로 쓸 수 있다.
    After: next start 로컬 운영 서버에 curl
    /api/ai/* 쿠키 없음 · 위조 · 만료 · 허용 안 된 이메일 → 401
    유효 세션 + 키 없음 → 503 / 필드 누락 → 400 / 깨진 JSON → 500 (공용 래퍼)
    가짜 DeepSeek 키 → DeepSeek 401 → 502 한국어 메시지, 로그에 키 없음
    운영 모드 + 인증 환경변수 없음 → 503
    /api/auth/refresh 세션 없음 → 401 (예전 refresh 쿠키만 있으면 code: "session_required")
    /api/auth/logout Origin 없음·외부 → 403, 같은 출처 → 200
    
  • DeepSeek 래퍼(stub fetch): 문법 검사에 deepseek-reasoner 를 넘겨도 deepseek-chat + JSON 모드로 보냄 · 저장된 오류 답변은 기록에서 빠지고 앞뒤 user 턴은 합쳐짐 · 깨진 JSON 응답 → 502.
  • npm run lint(Biome 2.3.13, 변경 코드 경고 없음), npm run build 통과.
  • 미확인: 실제 구글 로그인·DeepSeek 응답, 브라우저 클릭 테스트(팝업 닫힘 시 보류 동작 정리, 401 후 입력 복원, 재로그인 안내, 기존 DB 의 Dexie v16 업그레이드), deepseek-reasoner 응답 시간과 Vercel 함수 제한.

머지 위험도

Door: one-way

Dexie v16 업그레이드가 기존 사용자 DB 에서 geminiApiKey·geminiModel 설정을 지운다. 되돌려도 키는 다시 입력해야 한다. 나머지(라우트·UI)는 되돌릴 수 있다.

Blast Radius: AI 기능

배포 후 기존 드라이브 연결은 세션이 없어 한 번 다시 로그인해야 한다. Vercel 에 DEEPSEEK_API_KEY, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, ALLOWED_EMAILS, SESSION_SECRET(32자 이상)이 빠지면 AI 와 드라이브 백업이 모두 멈춘다. 구글 OAuth 동의 화면에 userinfo.email 범위 추가, 게시 상태 프로덕션 필요.

🤖 Generated with Claude Code

ParkBible and others added 2 commits November 1, 2026 00:40
- Gemini SDK 제거, DeepSeek Chat Completions를 fetch로 호출 (키는 DEEPSEEK_API_KEY 서버 환경변수만)
- 모델 목록을 deepseek-chat(기본)/deepseek-reasoner로 교체, 서버에서 허용 목록 검증
- 문법 검사는 JSON 모드로 받아 형식 검증 후 기존 문자열 응답으로 변환
- DeepSeek 401/402/429/5xx를 한국어 오류 메시지로 매핑
- 클라이언트 Gemini 키 입력 카드·저장소 제거, 기존 geminiApiKey 설정은 로드 시 삭제하고 백업에서도 제외
- OAuth client ID는 서버 GOOGLE_CLIENT_ID만 사용, 사용자 입력 client ID 흐름과 안내 모달 제거
- 로그인 범위에 openid email 추가, id_token의 aud·email_verified·ALLOWED_EMAILS 확인 후 HMAC 서명 세션 쿠키 발급
- 허용되지 않은 계정은 쿠키 없이 403과 안내 문구, 토큰 폐기
- /api/ai/*와 토큰 갱신은 유효한 세션 필요, 배포 환경에서 인증 설정이 없으면 503
- AI 호출이 401이면 Drive와 같은 구글 로그인으로 들어가는 안내 표시
- README·.env.example에 환경변수와 Google Cloud Console 설정 정리

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Drive 보류 동작을 OAuth state(loginId)에 묶어 해당 로그인 완료 시에만 실행, 실패·팝업 닫힘·AI 로그인 시 정리
- 세션 없이 refresh 쿠키만 남은 경우 재로그인 안내 표시 (refresh가 session_required 코드 반환)
- README 로컬 개발 안내에서 Drive는 인증 변수가 모두 있어야 동작함을 명시
- 401 시 저장된 사용자 메시지를 지우고 입력창·첨부 컨텍스트 복원
- JSON 모드(문법 검사)는 deepseek-chat으로 고정
- AI 오류는 대화 기록에 저장하지 않고 화면에만 표시, 예전에 저장된 오류 응답은 LLM 기록에서 제외
- 로그아웃 요청의 Origin/Referer가 같은 출처가 아니면 403
- 예전 Gemini 설정 삭제를 매 로드에서 Dexie v16 업그레이드로 이동 (백업 필터링은 유지)
- /api/ai/* 공통 처리(세션 확인·오류 변환)를 withAiRoute로 통합
- 인증 콜백 페이지 문구를 번역 테이블(ko/en)로 이동

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
novel-bunker Ready Ready Preview Nov 1, 2026 1:25pm UTC

…-deepseek

# Conflicts:
#	app/(shared)/hooks/useGoogleDrive.ts
@ParkBible
ParkBible merged commit 19c4bd4 into master Nov 1, 2026
2 checks passed
@ParkBible
ParkBible deleted the feat/server-llm-key-deepseek branch November 1, 2026 13:31

This branch was successfully deployed

1 active deployment
Preview — 761c94c8 Deployed Nov 1, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant