π ν¬νΈν΄λ¦¬μ€ μ¬μ΄νΈ λ°λ‘κ°κΈ°
μ΄ νλ‘μ νΈλ AI μΈν°λ·° μ€λΉλ₯Ό λμμ£Όλ μΉ μ±μ
λλ€.
React + Vite κΈ°λ° νλ‘ νΈμλ λ°±μλ (μΆν λ°°ν¬ν μμ ) ꡬμ±μΌλ‘, μΈν°λ·° μμ μ§λ¬Έ μμ±, λ΅λ³ μμ μ 곡 λ±μ μ§μν©λλ€.
νμ κ΄μ μ λ΄μ, μ€λ¬΄ μ΄ν΄μ μ μ©ν μ§λ¬Έκ³Ό μλ£λ₯Ό μ 곡νλ μΈν°λ·° μ€λΉ
μ΄λ‘ 곡λΆλ§μΌλ‘λ νμ
μμ νμν κ΄μ μ λͺ¨λ μ±μ°κΈ° μ΄λ ΅μ΅λλ€.
μ λ βμμΌλ‘ κ°μ΄ μΌν λλ£λΌλ©΄ 미리 μκ³ μμ΄μΌ ν μ§λ¬Έκ³Ό κΈ°μ€, μ°Έκ³ μλ£κ°
ν λ²μ 보μ΄λ©΄ μ’κ² λ€βλ μκ°μΌλ‘ μ΄ νλ‘μ νΈλ₯Ό λ§λ€μμ΅λλ€.
- ν¨κ» μΌν μ μλκ°? νμ Β·μ½λ νμ§Β·μ΄μ κ΄μ μ μ§λ¬Έ
- λ¬Έμ λ₯Ό μ΄λ»κ² ν΄κ²°ν μ μλκ°? μ₯μ /μ±λ₯/λ°μ΄ν° νλ¦/보μ μλλ¦¬μ€ κΈ°λ° μ§λ¬Έ
- κ·Όκ±°κ° μλκ°? λ² μ€νΈ νλν°μ€Β·λ νΌλ°μ€ λ§ν¬Β·μ²΄ν¬λ¦¬μ€νΈ ν¨κ» μ 곡
- λ°λ‘ μ μ© κ°λ₯νκ°? 리뷰 ν¬μΈνΈ/ν μ€νΈ μμ΄λμ΄/μΆκ° νμ΅ μλ£ ν¬ν¨
μ΄λ κ² κ΅¬ννμ΅λλ€
- μ¬μ©μκ° μν /κ²½λ ₯/μ€ν/ν€μλλ₯Ό μ
λ ₯νλ©΄
backend/controllers/questionController.js+backend/utils/prompts.jsκ°
μ€λ¬΄ μλ리μ€ν μ§λ¬Έκ³Ό μ§λ¬Έμ λν μ°Έκ³ μλ£(μ΄λ‘ Β·λ² μ€νΈ νλν°μ€)λ₯Ό μμ±ν©λλ€. - νλ‘ νΈμ
InterviewPrep.jsxμμ μμ½λμΈ ννλ‘ νμΈνκ³ ,
AIResponsePreview.jsxλ‘ κ·Όκ±°/μμ/μμ½μ ν¨κ» 보μ¬μ€λλ€.
ν¨κ» μΌνκ³ μΆμ λλ£μμ λλ¬λ΄λ, λλ§μ μ λ¬Έμ νλ¨κ³Ό κ³ μ ν κ΄μ μ μμ§ μλ λ΅μ μ€λΉνλ κ²μ λͺ©νλ‘ ν©λλ€.
- β Frontend β React 18 Β· Vite Β· TailwindCSS Β· React Router Β· Axios
- β Backend β Node.js(Express) Β· Multer Β· JWT Β· Dotenv Β· CORS
- β DB β MongoDB(Mongoose)
- β Dev β Nodemon Β· (μ ν) Docker Β· ESLint/Prettier
- β
AI β
Gemini 2.5 Flash(λΉ λ₯Έ μλ΅Β·μ λΉμ©Β·JSON μΉν β νΌ κΈ°λ° μ§λ¬Έ μμ±μ μ΅μ )
ν둬ννΈ/ν νλ¦Ώ:backend/utils/prompts.js
μ€μ¬μ© νλ¦μ μ§§μ GIFλ‘ λͺ¨μμ΅λλ€. (μ΄λ―Έμ§λ ν΄λ¦ν΄ νλ)
λλ© νμ΄μ§
|
|
νμκ°μ
|
λ‘κ·ΈμΈ
|
β¨π μ§λ¬Έ μμ± νΌ β μν Β·κ²½λ ₯Β·μ€νμ μ λ ₯νλ©΄ μ€λ¬΄ κ΄μ μ§λ¬Έκ³Ό μ°Έκ³ μλ£κ° μμ±λ©λλ€.
μ§λ¬Έ μμ± νΌ
|
μ§μμ μ 보λ₯Ό κ°λ¨ν μ
λ ₯νλ©΄, νμ΄ μ€μ λ‘ νμΈνλ ν¬μΈνΈ(νμ
/νμ§/μ΄μ/보μ λ±)λ₯Ό κΈ°μ€μΌλ‘
μ§λ¬Έμ λν κ°λ΅ν λ΅λ³κ³Ό λ΅λ³μ λν μμΈν κ·Όκ±° μλ£λ₯Ό μλ μμ±ν©λλ€.
μ λ ₯ νλͺ©
-
ν¬λ§ μ§λ¬΄: μ€λΉ μ€μΈ μν
μ: νλ‘ νΈμλ, λ°±μλ, UI/UX -
μ΄ κ²½λ ₯(κ΅μ‘Β·μ 무 κΈ°κ°): μ«μλ§ μ λ ₯
μ: 1, 2, 3 -
μ£Όμ μ€λΉ νλͺ©: μΌν(,)λ‘ κ΅¬λΆν κΈ°μ /ν€μλ/μ£Όμ
μ: React, Next.js, μνκ΄λ¦¬, μ±λ₯ μ΅μ ν -
λΉκ³ / λ©λͺ¨: μ΄λ² μ°μ΅μ λͺ©νΒ·μ λ΅Β·μ£Όμν μ
μ: βSEOΒ·λ λλ§ μ λ΅ κ°μ‘°, μ½λ μμλ κ°λ¨νβκ΅¬μ± νμΌ
- Frontend:
frontend/ai-interview/src/pages/InterviewPrep/InterviewPrep.jsx,
frontend/ai-interview/src/pages/InterviewPrep/components/AIResponsePreview.jsx - Backend:
backend/routes/questionRoutes.js,backend/controllers/questionController.js,
backend/utils/prompts.js
- Frontend:
πβ μμ± κ²°κ³Ό νμΈ (κ°μΈ μ§λ¬Έ νμ΄μ§) β μμ±λ μ§λ¬Έκ³Ό μ°Έκ³ μλ£λ₯Ό ν νλ©΄μμ νμΈν©λλ€.
β¨π μμ± κ²°κ³Ό νμΈ (μΈλΆ μλ£) β κ° μ§λ¬Έμμ ν΅μ¬ λ°°κ²½Β·μ€λ¬΄ ν¬μΈνΈΒ·μμ μ½λλ₯Ό ν¨κ» νμΈν μ μμ΅λλ€.
- μμ±λ μ§λ¬Έ μΉ΄λμ μμΈν 보기λ₯Ό μ΄λ©΄ μλλ₯Ό νμΈν©λλ€.
- μ§λ¬Έμ κ·Όκ±°: λ©΄μ μλ, κ²μ¦ κΈ°μ€, μ°Έκ³ κ·Όκ±°
- μ€λ¬΄μμ μ μ©ν μ 보: μ μ© μ μ£Όμμ , λͺ¨λ² μ¬λ‘, 체ν¬λ¦¬μ€νΈ/λ νΌλ°μ€
- μμ μ½λ λΈλ‘: λ°λ‘ μ€νν΄λ³Ό μ μλ κ°λ¨ν μ½λ μμ
- π μΈμ¦: νμκ°μ
/λ‘κ·ΈμΈ (JWT) β
backend/controllers/authController.js,routes/authRoutes.js - β μ§λ¬Έ μμ±/μΆμ²: μ§λ¬΄Β·ν€μλ κΈ°λ° β
controllers/questionController.js,models/Question.js - π£οΈ μ°μ΅ UI: μ§λ¬Έ μΉ΄λ/λ΅λ³ 미리보기 β
frontend/ai-interview/src/pages/InterviewPrep/* - π€ μΈμ
κ΄λ¦¬: μμ±Β·λͺ©λ‘/μ‘°ν β
controllers/sessionController.js,models/Session.js - π€ μ
λ‘λ: νλ‘ν μ΄λ―Έμ§ β
middlewares/uploadMiddleware.js,ProfilePhotoSelector.jsx - π€ AI ν리뷰: λ§ν¬λ€μ΄/μ½λ λ λ β
pages/InterviewPrep/components/AIResponsePreview.jsx - π§± κ³΅ν΅ λ μ΄μμ/μ»΄ν¬λνΈ:
layout/DashboardLayout.jsx,component/Cards/*,utils/*
.
ββ backend/
β ββ config/
β ββ controllers/
β β ββ aiController.js
β β ββ authController.js
β β ββ questionController.js
β β ββ sessionController.js
β ββ middlewares/
β β ββ authMiddleware.js
β β ββ uploadMiddleware.js
β ββ models/
β β ββ Question.js
β β ββ Session.js
β β ββ User.js
β ββ routes/
β β ββ authRoutes.js
β β ββ questionRoutes.js
β β ββ sessionRoutes.js
β ββ uploads/
β ββ utils/prompts.js
β
ββ frontend/
ββ ai-interview/
ββ public/
ββ src/
ββ assets/ (hero-img.png, heroImg.png)
ββ component/
β ββ Cards/ (ProfileInfoCard.jsx, QuestionInfoCard.jsx, SummaryCard.jsx)
β ββ inputs/ (Input.jsx, ProfilePhotoSelector.jsx)
β ββ layout/ (DashboardLayout.jsx, Navbar.jsx)
β ββ Loader.jsx, Drawer.jsx, Modal.jsx, DeleteAlertContent.jsx
ββ context/userContext.jsx
ββ pages/
β ββ Auth/ (Login.jsx, SignUp.jsx)
β ββ Home/ (CreateSessionForm.jsx, Dashboard.jsx)
β ββ InterviewPrep/
β ββ components/ (AIResponsePreview.jsx, RoleInfoHeader.jsx)
β ββ InterviewPrep.jsx
ββ utils/ (apiPaths.js, axiosInstance.js, data.js, helper.js, uploadImage.js)
ββ App.jsx, main.jsx, index.css
ββ index.html# 0) 루νΈ
cd <repo-root>
# 1) λ°±μλ
cd backend
npm i
cp .env.example .env
npm run dev
# 2) νλ‘ νΈμλ
cd ../frontend/ai-interview
npm i
cp .env.example .env
npm run devbackend/.env
PORT=μ¬μ©νλ ν¬νΈλ²νΈ μ
λ ₯ μ) 4000
MONGO_URI=mongodb://localhost:27017/interview_prep
JWT_SECRET=replace_me # λλ€ JWT ν κ·Ό Key μμ± -> JWT key μμ±μ¬μ΄νΈμμ μμμ λ§λ€μ΄ μ€λλ€
JEMINIAI_API_KEY=sk-... # JEMINI API μΈμ¦ key κ° μ
λ ₯
UPLOAD_DIR=uploads # νλ‘ν IMG κ²½λ‘
CORS_ORIGIN=http://localhost:5173frontend/ai-interview/.env
VITE_API_BASE_URL=http://localhost:4000LandingPage β Auth(Login/SignUp) β DashboardLayout
β Home(Dashboard / CreateSessionForm) β InterviewPrep(μ§λ¬ΈΒ·μ°μ΅Β·ν리뷰)
backend/package.json
{
"scripts": {
"dev": "nodemon server.js",
"start": "node server.js",
"lint": "eslint ."
}
}frontend/ai-interview/package.json
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint src --ext .js,.jsx"
}
}| Method | Path | μ€λͺ | νμΌ |
|---|---|---|---|
| POST | /api/auth/register |
νμκ°μ | routes/authRoutes.js |
| POST | /api/auth/login |
λ‘κ·ΈμΈ(JWT) | routes/authRoutes.js |
| GET | /api/questions |
μ§λ¬Έ λͺ©λ‘ | routes/questionRoutes.js |
| POST | /api/sessions |
μΈμ μμ± | routes/sessionRoutes.js |
| GET | /api/sessions/:id |
μΈμ μ‘°ν | routes/sessionRoutes.js |
| POST | /api/upload |
μ΄λ―Έμ§ μ λ‘λ | middlewares/uploadMiddleware.js |
| POST | /api/ai/complete |
AI μλ΅(μ΅μ ) | controllers/aiController.js |
MIT Β© dmsgp2627@naver.com





