콘솔에 발급된 설정이 설계와 어긋나 있었다. 클라이언트 시크릿이 켜져 있고 Redirect URI 가
프론트 경로(/auth/kakao/callback)인데, 코드는 "프론트가 액세스 토큰을 들고 온다" 는
전제였다 — 시크릿을 번들에 구울 수 없으므로 그 흐름으로는 토큰을 받을 수 없다.
- services/external/kakao_identity: access_token 검증 → **인가 코드 교환**으로 교체.
★ 우리 REST 키·시크릿으로 교환한 토큰이라 정의상 우리 앱 것이다 — 구글의 aud 대조에
해당하는 검사(KAKAO_LOGIN_APP_ID)가 구조적으로 필요 없어져 설정 칸째로 지웠다.
★ 로그인 앱과 챗봇 앱이 다르면 로그인은 되는데 채널 매칭만 조용히 안 된다 —
REST 키가 어긋나면 경고 로그를 남긴다.
★ 미인증 이메일은 신원으로 쓰지 않는다(is_email_valid·is_email_verified 둘 다). 이 값으로
auth_service 가 다른 수단 가입과의 충돌을 판정한다.
- config/config_models: KAKAO_LOGIN_APP_ID → REST_API_KEY · CLIENT_SECRET · REDIRECT_URI
- router/v1/auth: Req_KakaoLogin {access_token} → {code, redirect_uri}
- frontend: lib/kakaoIdentity(인가 URL · sessionStorage state) · KakaoSignInButton ·
pages/KakaoCallbackPage(코드는 1회용이라 ref 로 한 번만 보낸다) · routes
★ 로그인 폼에서 카카오를 구글 위에 둔다 — 이 수단으로 들어와야 6자리 코드 없이 채널이 이어진다
- compose · nginx/Dockerfile: REST 키·Redirect URI 만 프론트로 흘려보낸다. 시크릿은 안 나간다
- 어드민 키는 저장하지 않는다 — 탈퇴까지 되는 키인데 로그인에는 쓰이지 않는다
- api/generated: orval 재생성. 카카오 외에도 오래 밀려 있던 문구·agent 경로가 함께 따라왔다
테스트 8건 추가(tests/test_kakao_identity.py), 관련 85 passed
(test_auth::test_google_login_is_off_when_client_id_is_empty 는 기존 실패)
lint(react-router typegen + tsc + eslint) 통과
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
55 lines
3.2 KiB
Docker
55 lines
3.2 KiB
Docker
# 공개 진입점 이미지 — 사장님 앱 정적 번들을 구워 넣고, nginx 가 그것과 발행 사이트를 함께 준다.
|
|
#
|
|
# ★ 왜 dev 서버를 안 띄우나
|
|
# 운영에 `vite dev` 를 두면 요청마다 트랜스파일하고, 기동이 `npm install` 네트워크에 의존하고,
|
|
# `/src/*` 원본과 소스맵이 그대로 나간다. 실측(킹서버): 컨테이너 기동에 npm install 이 걸려
|
|
# 재기동 시간이 네트워크 상태에 좌우됐다.
|
|
#
|
|
# ★ 발행 사이트(`/s/...`)는 이 이미지에 안 들어간다. named volume(site-out)에서 읽는다 —
|
|
# 사이트가 늘 때마다 이미지를 다시 굽지 않는다.
|
|
|
|
FROM node:24-alpine AS build
|
|
WORKDIR /app
|
|
|
|
# 의존성 레이어를 소스와 분리한다. 소스만 바뀌면 npm ci 를 건너뛴다.
|
|
COPY package.json package-lock.json tsconfig.base.json ./
|
|
COPY solution/shared/package.json solution/shared/
|
|
COPY solution/frontend/package.json solution/frontend/
|
|
COPY solution/site/package.json solution/site/
|
|
COPY admin/frontend/package.json admin/frontend/
|
|
RUN npm ci
|
|
|
|
COPY solution ./solution
|
|
COPY admin ./admin
|
|
|
|
# ★ VITE_* 는 **빌드 시점에 번들로 구워진다.** 런타임 환경변수로는 못 바꾼다 —
|
|
# 주소를 바꾸면 이 이미지를 다시 빌드해야 한다(`./deploy.sh solution-site`).
|
|
ARG VITE_API_BASE_URL
|
|
ARG VITE_PUBLISH_HOST
|
|
ARG VITE_SITE_PREVIEW_URL
|
|
# 구글 OAuth 클라이언트 ID. 비밀이 아니라 번들에 들어가도 된다 — 다만 백엔드 GOOGLE_CLIENT_ID 와
|
|
# 같은 값이어야 한다(백엔드가 이 값으로 토큰의 aud 를 대조한다).
|
|
ARG VITE_GOOGLE_CLIENT_ID
|
|
# 카카오 REST API 키와 Redirect URI. 둘 다 비밀이 아니다 — 인가 URL 에 그대로 실려 나간다.
|
|
# ★ 클라이언트 시크릿은 여기 없다. 인가 코드를 토큰으로 바꾸는 일은 **백엔드가 한다** —
|
|
# 시크릿이 번들에 구워지면 누구나 우리 앱 이름으로 토큰을 받을 수 있다.
|
|
ARG VITE_KAKAO_REST_API_KEY
|
|
ARG VITE_KAKAO_REDIRECT_URI
|
|
ENV VITE_API_BASE_URL=$VITE_API_BASE_URL \
|
|
VITE_PUBLISH_HOST=$VITE_PUBLISH_HOST \
|
|
VITE_SITE_PREVIEW_URL=$VITE_SITE_PREVIEW_URL \
|
|
VITE_GOOGLE_CLIENT_ID=$VITE_GOOGLE_CLIENT_ID \
|
|
VITE_KAKAO_REST_API_KEY=$VITE_KAKAO_REST_API_KEY \
|
|
VITE_KAKAO_REDIRECT_URI=$VITE_KAKAO_REDIRECT_URI
|
|
# ★ VITE_AUTO_LOGIN_ID·PW 를 여기서 **절대 받지 않는다.** 이 이미지가 사장님에게 열리는
|
|
# 운영 진입점(solution-site)이다 — 자동 로그인 계정이 번들에 구워지면 페이지를 연 누구나
|
|
# JS 에서 그대로 읽는다. 내부 테스트용 자동 로그인은 solution-frontend(--profile dev,
|
|
# vite dev)에만 있다 — 그쪽은 이 Dockerfile 을 타지 않는다(lib/autoSession.ts 의 DEV 가드도
|
|
# 같은 이유로 있다 — 이 ARG 가 실수로 되돌아와도 프로덕션 빌드에서는 죽은 코드가 된다).
|
|
RUN npm run build -w @o2o/frontend
|
|
|
|
FROM nginx:alpine
|
|
# ★ 프레임워크 모드(React Router)의 산출물은 `build/client` 다 — 예전 `dist` 가 아니다.
|
|
# 경로가 어긋나면 COPY 가 조용히 빈 디렉토리를 만들고 컨테이너는 정상으로 뜬다.
|
|
COPY --from=build /app/solution/frontend/build/client /srv/app
|