diff --git a/README.md b/README.md index 93d5ea3..1ee1791 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,59 @@ npm run build npm run preview # http://localhost:4173 ``` +## 프로덕션 배포 (Apache) +이 프로젝트는 기본적으로 API 호출을 `API_BASE_URL` 기준으로 수행합니다. + +- `VITE_API_BASE_URL`를 지정하면 해당 주소로 호출합니다. +- 미지정 시: + - 개발( `npm run dev` )에서는 `http://localhost:8010` + - 프로덕션 빌드에서는 **same-origin**(현재 접속한 도메인)으로 호출합니다. + +즉, Apache로 프론트를 HTTPS로 서비스하는 경우에는 아래처럼 **리버스 프록시**로 백엔드(예: `http://127.0.0.1:8010`)를 연결하는 방식을 권장합니다. + +### Apache 모듈 활성화 +```bash +sudo a2enmod proxy proxy_http rewrite +sudo systemctl reload apache2 +``` + +### VirtualHost 예시 (프론트 정적 + API 프록시) +```apache + + ServerName your-domain.com + + DocumentRoot /var/www/ncuetalk_frontend + + + AllowOverride All + Require all granted + + + # SPA 라우팅 + RewriteEngine On + RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR] + RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d + RewriteRule ^ - [L] + RewriteRule ^ /index.html [L] + + # Backend reverse proxy (HTTP backend on :8010) + ProxyPreserveHost On + ProxyPass /auth http://127.0.0.1:8010/auth + ProxyPassReverse /auth http://127.0.0.1:8010/auth + + ProxyPass /community http://127.0.0.1:8010/community + ProxyPassReverse /community http://127.0.0.1:8010/community + + ProxyPass /chat http://127.0.0.1:8010/chat + ProxyPassReverse /chat http://127.0.0.1:8010/chat + + ProxyPass /tools http://127.0.0.1:8010/tools + ProxyPassReverse /tools http://127.0.0.1:8010/tools + +``` + +백엔드 엔드포인트가 더 있다면 동일 패턴으로 `ProxyPass`를 추가하거나, `/api` prefix로 백엔드를 묶어 프론트 코드에서 `VITE_API_BASE_URL=/api`로 통일하는 것도 가능합니다. + ## 빌드 산출물 구조 프로덕션 빌드시 `dist/` 폴더가 생성되며, 정적 파일을 Nginx·S3 등에 바로 서빙할 수 있습니다. diff --git a/src/config.js b/src/config.js index 3034528..5a29ec7 100644 --- a/src/config.js +++ b/src/config.js @@ -1,3 +1,15 @@ -export const API_BASE_URL = - import.meta.env.VITE_API_BASE_URL || - `${window.location.protocol}//${window.location.hostname}:8010`; +/** + * API base URL strategy + * - If `VITE_API_BASE_URL` is provided, always use it. + * - In production, default to same-origin (expects Apache/Nginx reverse proxy). + * - In dev, default to local backend. + */ +export const API_BASE_URL = (() => { + const fromEnv = import.meta.env.VITE_API_BASE_URL; + if (fromEnv) return fromEnv.replace(/\/+$/, ''); + + // Vite replaces `import.meta.env.PROD/DEV` at build time. + if (import.meta.env.PROD) return window.location.origin; + + return 'http://localhost:8010'; +})(); diff --git a/src/pages/AiNewsPage.jsx b/src/pages/AiNewsPage.jsx index 0dfd6bf..5b20fe1 100644 --- a/src/pages/AiNewsPage.jsx +++ b/src/pages/AiNewsPage.jsx @@ -2,6 +2,21 @@ import React, { useEffect, useRef, useState } from 'react'; import { useAuth } from '../context/AuthContext'; import { API_BASE_URL } from '../config'; +function normalizeExternalUrl(raw) { + if (!raw) return ''; + const s = String(raw).trim(); + if (!s) return ''; + // already absolute + if (/^https?:\/\//i.test(s)) return s; + // protocol-relative + if (s.startsWith('//')) return `https:${s}`; + // common "missing scheme" cases from DB/meta + if (s.startsWith('img.youtube.com/')) return `https://${s}`; + if (s.startsWith('www.youtube.com/')) return `https://${s}`; + if (s.startsWith('youtube.com/')) return `https://${s}`; + return s; // leave as-is (could be relative path on same origin) +} + export default function AiNewsPage() { const { user } = useAuth(); const [news, setNews] = useState([]); @@ -101,10 +116,20 @@ export default function AiNewsPage() {
{n.meta?.image ? ( - thumb + thumb ) : null}
- + {n.meta?.title || n.url}
{n.meta?.description}