From de97b5071e3ea9418a6b631eb240ca21a02cdd52 Mon Sep 17 00:00:00 2001 From: Macbook Date: Sun, 12 Jul 2026 19:22:29 +0900 Subject: [PATCH] =?UTF-8?q?=EB=8B=A4=ED=81=AC=EB=AA=A8=EB=93=9C=EB=A5=BC?= =?UTF-8?q?=20=EB=94=94=ED=8F=B4=ED=8A=B8=EB=A1=9C=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/bizcare/agent/SecurityConfig.java | 3 ++ deploy_server_guide.md | 15 ++++++- frontend/src/index.css | 40 +++++++++---------- frontend/src/theme.ts | 2 +- frontend/src/themeContext.tsx | 2 +- scripts/deploy.sh | 7 ++-- 6 files changed, 42 insertions(+), 27 deletions(-) diff --git a/backend/src/main/java/com/bizcare/agent/SecurityConfig.java b/backend/src/main/java/com/bizcare/agent/SecurityConfig.java index 3d23572..94a072b 100644 --- a/backend/src/main/java/com/bizcare/agent/SecurityConfig.java +++ b/backend/src/main/java/com/bizcare/agent/SecurityConfig.java @@ -68,6 +68,9 @@ class SecurityConfig { } else { // 로컬/사설망 개발 접근을 허용하면서도 credentials 유지 List patterns = new ArrayList<>(origins); + // 도메인 전환(billcare→bizcare) 시 env 미반영이어도 로그인 CORS 403 방지 + patterns.add("https://*.exdev.co.kr"); + patterns.add("http://*.exdev.co.kr"); patterns.add("http://localhost:*"); patterns.add("http://127.0.0.1:*"); patterns.add("http://192.168.*.*:*"); diff --git a/deploy_server_guide.md b/deploy_server_guide.md index d8b9ce6..8aee9d4 100644 --- a/deploy_server_guide.md +++ b/deploy_server_guide.md @@ -66,13 +66,24 @@ CERT_OUT=/Users/aidev/dev/exAIChatbot2.0/docker/nginx/certs/bizcare \ docker exec ex-chatbot-caddy caddy reload --config /etc/caddy/Caddyfile ``` -### 4) CORS -배포 스크립트/`APP_CORS_ORIGINS`에 `https://bizcare.exdev.co.kr` 와 `https://billcare.exdev.co.kr` 가 모두 포함되어 있습니다. 컨테이너 재기동 후 반영됩니다. +### 4) CORS (로그인 403 / `Invalid CORS request`) +브라우저에서 `https://bizcare.exdev.co.kr` 로 로그인 시 Origin 이 `bizcare` 인데, 백엔드 컨테이너 env에 `billcare`만 있으면 Spring 이 **403 Invalid CORS request** 를 반환합니다. + +배포 스크립트/`APP_CORS_ORIGINS`에 두 도메인이 포함되어 있어야 하고, **기존 컨테이너는 `up -d`만으로는 env가 갱신되지 않으므로** backend 를 강제 재생성해야 합니다. ```bash cd /Users/aidev/apps/BizCare # work-tree +export APP_CORS_ORIGINS="https://bizcare.exdev.co.kr,https://billcare.exdev.co.kr,http://bizcare.exdev.co.kr,http://billcare.exdev.co.kr,http://localhost:83,http://127.0.0.1:83" docker compose up -d --force-recreate backend + +# 확인 (200 + JSON 이어야 함, 403/Invalid CORS 이면 실패) +curl -sS -X POST 'https://bizcare.exdev.co.kr/api/auth/login' \ + -H 'Content-Type: application/json' \ + -H 'Origin: https://bizcare.exdev.co.kr' \ + -d '{"userid":"x","password":"x"}' ``` +즉시 조치만 필요하면 위 명령만 실행하면 됩니다. 코드에 `https://*.exdev.co.kr` 패턴도 추가되어 이후 배포 시에도 동일 이슈를 막습니다. + 공유 인증서(`stock`/`chatbot`) SAN에 bizcare가 없어 **별도 발급**이 필요합니다. `gc-frontend`에 acme-webroot가 마운트되어 있어야 갱신이 됩니다. diff --git a/frontend/src/index.css b/frontend/src/index.css index 44c8650..c7b6ef5 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -86,28 +86,28 @@ html.theme-blue { --focus-ring: rgba(30, 138, 212, 0.45); } -/* 테마 클래스 적용 전 깜빡임 방지용 기본값 = 라이트 (:root 는 theme-* 보다 특이도가 낮음) */ +/* 테마 클래스 적용 전 깜빡임 방지용 기본값 = 다크 (:root 는 theme-* 보다 특이도가 낮음) */ html:not(.theme-light):not(.theme-dark):not(.theme-blue), :root:not(.theme-light):not(.theme-dark):not(.theme-blue) { - --primary: #2563eb; - --primary-dark: #1d4ed8; - --on-primary: #ffffff; - --bg: #f1f5f9; - --surface: #ffffff; - --surface-2: #f8fafc; - --surface-3: #ffffff; - --elevated: #eff6ff; - --text: #0f172a; - --muted: #64748b; - --border: #e2e8f0; - --danger: #dc2626; - --success: #16a34a; - --highlight-bg: #fffbe6; - --highlight-bg-strong: #fff3bf; - --highlight-text: #0f172a; - --shadow: 0 8px 24px rgba(0,0,0,.14); - --shadow-lg: 0 20px 60px rgba(0,0,0,.3); - --focus-ring: #bfdbfe; + --primary: #7aa2f7; + --primary-dark: #5a7dc7; + --on-primary: #0b1020; + --bg: #16181e; + --surface: #24283b; + --surface-2: #1f2335; + --surface-3: #1a1b26; + --elevated: #2a2f45; + --text: #c0caf5; + --muted: #8a93b8; + --border: rgba(122, 162, 247, 0.16); + --danger: #f7768e; + --success: #9ece6a; + --highlight-bg: #2f3650; + --highlight-bg-strong: #3a4463; + --highlight-text: #c0caf5; + --shadow: 0 8px 24px rgba(0,0,0,.5); + --shadow-lg: 0 20px 60px rgba(0,0,0,.45); + --focus-ring: rgba(122, 162, 247, 0.5); } * { box-sizing: border-box; } diff --git a/frontend/src/theme.ts b/frontend/src/theme.ts index 01ee33b..bbe9a29 100644 --- a/frontend/src/theme.ts +++ b/frontend/src/theme.ts @@ -16,7 +16,7 @@ export function loadTheme(): Theme { } catch { /* private mode */ } - return 'light' + return 'dark' } export function applyTheme(theme: Theme): void { diff --git a/frontend/src/themeContext.tsx b/frontend/src/themeContext.tsx index 9e33ef8..fc95e60 100644 --- a/frontend/src/themeContext.tsx +++ b/frontend/src/themeContext.tsx @@ -7,7 +7,7 @@ type ThemeCtx = { } const ThemeContext = createContext({ - theme: 'light', + theme: 'dark', changeTheme: () => undefined, }) diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 7961e90..38b4f1e 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -97,16 +97,17 @@ esac # Phase 3 info "[Phase 3] Docker Compose up" +# --force-recreate: APP_CORS_ORIGINS 등 env 변경이 기존 컨테이너에 미반영되는 문제 방지 case "$SERVICE_NAME" in frontend) - docker compose -f "$DOCKER_COMPOSE_FILE" up -d --no-deps frontend + docker compose -f "$DOCKER_COMPOSE_FILE" up -d --no-deps --force-recreate frontend ;; backend) docker compose -f "$DOCKER_COMPOSE_FILE" up -d mysql - docker compose -f "$DOCKER_COMPOSE_FILE" up -d --no-deps backend + docker compose -f "$DOCKER_COMPOSE_FILE" up -d --no-deps --force-recreate backend ;; all|docker-only) - docker compose -f "$DOCKER_COMPOSE_FILE" up -d + docker compose -f "$DOCKER_COMPOSE_FILE" up -d --force-recreate ;; esac