diff --git a/.dockerignore b/.dockerignore index ca56b08..3bed94d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,40 +1,3 @@ -네, default.conf 파일 잘 받았습니다. - -파일을 보니... expires -1; 설정이 있어서, Nginx가 JS/CSS 파일을 캐시하는 문제는 아니었습니다. - -하지만 드디어 진짜 원인을 찾은 것 같습니다. 님이 겪는 문제는 두 가지의 심각한 오류가 동시에 발생하고 있었기 때문입니다. - -화면이 안 바뀌는 문제: web 컨테이너의 .dockerignore 파일에 Vite 캐시(.vite)가 누락되어, 님이 수정한 Review.jsx가 아닌 옛날 파일로 계속 빌드되었습니다. - -"Failed to fetch" 문제: Nginx와 FastAPI의 API 주소 끝에 슬래시(/)가 일치하지 않아 API 요청이 404 오류로 실패하고 있었습니다. - -🛠️ 최종 해결 (1+2번 문제 동시 해결) -아래 4단계를 순서대로 진행하시면, 디자인과 API 오류가 모두 해결됩니다. - -1단계: review-service의 API 경로 수정 -FastAPI(main.py)가 Nginx(default.conf)와 동일하게 슬래시가 붙은 주소를 받도록 수정합니다. - -apps/review-service/main.py 파일을 열어서 @app.post 부분을 수정하세요. - -수정 전: - -Python - -@app.post("/api/review") -async def handle_code_review(code: str = Form(...)): -수정 후: (끝에 / 추가) - -Python - -@app.post("/api/review/") -async def handle_code_review(code: str = Form(...)): -2단계: web의 .dockerignore 파일 수정 -Vite 캐시 폴더(.vite)가 Docker 빌드 시 복사되지 않도록 .dockerignore 파일에 추가합니다. - -apps/web/.dockerignore 파일을 열어서 맨 아래에 .vite를 추가하세요. - -수정 후: - # 기본 무시 항목 node_modules dist diff --git a/.gitignore b/.gitignore index a547bf3..8dea234 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ dist-ssr *.njsproj *.sln *.sw? + +# Environment variables (🔒 절대 Git에 올리면 안 되는 민감 정보) +.env diff --git a/eslint.config.js b/eslint.config.js index cee1e2c..3387607 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -5,7 +5,13 @@ import reactRefresh from 'eslint-plugin-react-refresh' import { defineConfig, globalIgnores } from 'eslint/config' export default defineConfig([ - globalIgnores(['dist']), + globalIgnores([ + 'dist', + 'tailwind.config.js', + 'vite.config.js', + 'postcss.config.cjs', + ]), + { files: ['**/*.{js,jsx}'], extends: [ diff --git a/src/App.jsx b/src/App.jsx index c77cd51..fb0bc70 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,6 +1,6 @@ import { Routes, Route } from "react-router-dom"; -// 맨 위 import 부분 +// Auth import Login from "@/features/auth/Login"; import GithubCallback from "@/features/auth/GithubCallback"; @@ -17,7 +17,7 @@ import Result from "./features/interview/pages/Result"; export default function App() { return ( - {/* 기본 */} + {/* 기본 홈 */} } /> {/* 코딩테스트 */} @@ -30,7 +30,11 @@ export default function App() { } /> } /> } /> + + {/* 로그인 페이지 */} } /> + + {/* GitHub OAuth 콜백*/} } /> {/* 404 */} diff --git a/src/api/reviewService.js b/src/api/reviewService.js index aa1d852..62bcb75 100644 --- a/src/api/reviewService.js +++ b/src/api/reviewService.js @@ -45,6 +45,7 @@ export const fetchCodeReview = async (code, comment, repoUrl) => { try { return JSON.parse(raw); } catch { + // 응답이 순수 텍스트일 때 return { review: raw, questions: [] }; } } catch (error) { diff --git a/src/features/codingTest/CodingTest.jsx b/src/features/codingTest/CodingTest.jsx index d55f52a..3a9f999 100644 --- a/src/features/codingTest/CodingTest.jsx +++ b/src/features/codingTest/CodingTest.jsx @@ -110,7 +110,7 @@ export default function CodingTest() { if (code !== LANGUAGE_TEMPLATES[language] && code.trim() !== "") { if ( !window.confirm( - "언어를 변경하면 작성 중인 코드가 초기화됩니다. 계속하시겠습니까?" + "언어를 변경하면 작성 중인 코드가 초기화됩니다. 계속하시겠습니까?", ) ) { return; @@ -132,7 +132,7 @@ export default function CodingTest() { setProblem(data); } catch (err) { setErrorMsg( - err?.message || "문제 로딩 중 오류가 발생했습니다. (백엔드 서버 확인 필요)" + err?.message || "문제 로딩 중 오류가 발생했습니다. (백엔드 서버 확인 필요)", ); } finally { setIsLoadingProblem(false); @@ -160,7 +160,7 @@ export default function CodingTest() { problemId: problem.id, code, language, - userId: 1, // Long 타입이므로 숫자 1 사용 + // userId는 codingService에서 guest 처리 (또는 나중에 로그인 정보 연결) }); setResult(res); } catch (err) { diff --git a/tailwind.config.cjs b/tailwind.config.js similarity index 58% rename from tailwind.config.cjs rename to tailwind.config.js index 28addd7..16b3e54 100644 --- a/tailwind.config.cjs +++ b/tailwind.config.js @@ -1,30 +1,31 @@ +/** @type {import('tailwindcss').Config} */ module.exports = { content: [ "./index.html", - "./src/**/*.{js,ts,jsx,tsx}", + "./src/**/*.{js,jsx,ts,tsx}", ], theme: { extend: { keyframes: { fadeIn: { "0%": { opacity: 0, transform: "translateY(10px)" }, - "100%": { opacity: 1, transform: "translateY(0)" } + "100%": { opacity: 1, transform: "translateY(0)" }, }, fadeInUp: { "0%": { opacity: 0, transform: "translateY(20px)" }, - "100%": { opacity: 1, transform: "translateY(0)" } + "100%": { opacity: 1, transform: "translateY(0)" }, }, fadeOut: { "0%": { opacity: 1, transform: "translateY(0)" }, - "100%": { opacity: 0, transform: "translateY(10px)" } + "100%": { opacity: 0, transform: "translateY(10px)" }, }, }, animation: { fadeIn: "fadeIn 0.5s ease-out forwards", fadeInUp: "fadeInUp 0.8s ease-out forwards", - fadeInOut: "fadeIn 0.3s ease-out, fadeOut 0.3s ease-in 2.7s forwards", + fadeInOut: + "fadeIn 0.3s ease-out, fadeOut 0.3s ease-in 2.7s forwards", }, }, }, - // plugins: [] // v4에서는 CSS에서 @plugin으로 불러옵니다 }; \ No newline at end of file diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..4acab45 --- /dev/null +++ b/vercel.json @@ -0,0 +1,5 @@ +{ + "rewrites": [ + { "source": "/(.*)", "destination": "/index.html" } + ] +} \ No newline at end of file diff --git a/vite.config.js b/vite.config.js index 4ad32c6..7e2814a 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,24 +1,27 @@ -// vite.config.js -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react-swc' -import path from 'path' -import { fileURLToPath } from 'url' +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react-swc"; +import path from "path"; +import { fileURLToPath } from "url"; -// ⬇️ ESM 환경용 __dirname 설정 (CI 에러 해결) -const __filename = fileURLToPath(import.meta.url) -const __dirname = path.dirname(__filename) +// ESM 환경용 __dirname 설정 (CI 에러 방지) +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); export default defineConfig({ plugins: [react()], - resolve: { alias: { '@': path.resolve(__dirname, './src') } }, + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, server: { port: 3000, proxy: { "/api": { target: "http://localhost:8080", - changeOrigin: true - } - } - } -}) + changeOrigin: true, + }, + }, + }, +});