Skip to content

TeamKoHong/teamitakaBackend

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

1,228 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿš€ TeamItaka Backend

Node.js Version License

ํŒ€ ํ”„๋กœ์ ํŠธ ๋ชจ์ง‘ ๋ฐ ํ˜‘์—…์„ ์œ„ํ•œ ์ข…ํ•ฉ RESTful API ์„œ๋น„์Šค

English | ํ•œ๊ตญ์–ด

๐Ÿ“‹ ๋ชฉ์ฐจ

๐Ÿ“Š ํ”„๋กœ์ ํŠธ ํ˜„ํ™ฉ ์š”์•ฝ

๋งˆ์ง€๋ง‰ ๋ถ„์„: 2026-01-31 | ์ „์ฒด ์™„๋ฃŒ์œจ: 97%

ํ•ญ๋ชฉ ํ˜„ํ™ฉ ์ƒ์„ธ
API ์—”๋“œํฌ์ธํŠธ 90๊ฐœ 97% ๊ตฌํ˜„ ์™„๋ฃŒ
์ปจํŠธ๋กค๋Ÿฌ 24๊ฐœ ์ „์ฒด ๊ตฌํ˜„
์„œ๋น„์Šค 21๊ฐœ ์ „์ฒด ๊ตฌํ˜„
DB ๋ชจ๋ธ 33๊ฐœ ์ŠคํŽ™ 26๊ฐœ ์ค‘ 19๊ฐœ + ์ถ”๊ฐ€ 14๊ฐœ
๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ 14๊ฐœ ์ตœ์‹  ์—…๋ฐ์ดํŠธ ์™„๋ฃŒ
๋ฏธ๋“ค์›จ์–ด 9๊ฐœ ์ธ์ฆ, ๊ฒ€์ฆ, ์—…๋กœ๋“œ, UUID ๋“ฑ

ํ•ต์‹ฌ ๊ธฐ๋Šฅ ๊ตฌํ˜„ ํ˜„ํ™ฉ

๊ธฐ๋Šฅ ์ƒํƒœ ๋น„๊ณ 
์ธ์ฆ (์ด๋ฉ”์ผ/๊ตฌ๊ธ€/ํœด๋Œ€ํฐ) โœ… JWT, Firebase, OAuth
SMS ์ธ์ฆ โœ… Solapi, sessionId ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ํ”Œ๋กœ์šฐ
ํ”„๋กœ์ ํŠธ CRUD + ํ‚ฅ์˜คํ”„ โœ… ๋ชจ์ง‘โ†’ํ”„๋กœ์ ํŠธ ์ „ํ™˜
๋ชจ์ง‘๊ณต๊ณ  ์‹œ์Šคํ…œ โœ… ํ•ด์‹œํƒœ๊ทธ, ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ
์ง€์›/์ˆ˜๋ฝ/๊ฑฐ์ ˆ ํ”Œ๋กœ์šฐ โœ… ํฌํŠธํด๋ฆฌ์˜ค ์—ฐ๊ฒฐ
ํŒ€์› ํ‰๊ฐ€ ์‹œ์Šคํ…œ โœ… 5๊ฐœ ํ‰๊ฐ€ ํ•ญ๋ชฉ
ํˆฌํ‘œ/์ผ์ • ๊ด€๋ฆฌ โš ๏ธ ๋ผ์šฐํŠธ ๋“ฑ๋ก ํ•„์š”
์•Œ๋ฆผ ์‹œ์Šคํ…œ โœ… 5๊ฐœ API ๊ตฌํ˜„ ์™„๋ฃŒ
iOS ํ‘ธ์‹œ ์•Œ๋ฆผ โœ… APNs ์ง€์›, ์ดˆ๋Œ€/์ƒํƒœ/๋ฆฌ๋ทฐ ํŠธ๋ฆฌ๊ฑฐ
MBTI ์‹œ์Šคํ…œ โœ… ์œ ํ˜• ์ €์žฅ ๋ฐ ์กฐํšŒ
์ง€์› ์ทจ์†Œ โœ… POST/DELETE ๋ฐฉ์‹ ์ง€์›
ํ”„๋กœ์ ํŠธ ์ฆ๊ฒจ์ฐพ๊ธฐ โœ… ํ† ๊ธ€ API

โœจ ์ฃผ์š” ๊ธฐ๋Šฅ

๐Ÿ” ์‚ฌ์šฉ์ž ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๊ด€๋ฆฌ

  • 6์ž๋ฆฌ ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ํ†ตํ•œ ์ด๋ฉ”์ผ ์ธ์ฆ (SendGrid Web API)
  • ๋„๋ฉ”์ธ ์ธ์ฆ ์™„๋ฃŒ (teamitaka.com)
  • JWT ๊ธฐ๋ฐ˜ ์ธ์ฆ ์‹œ์Šคํ…œ
  • ๊ตฌ๊ธ€ OAuth ์†Œ์…œ ๋กœ๊ทธ์ธ
  • Firebase ์ „ํ™”๋ฒˆํ˜ธ ์ธ์ฆ (Phone Authentication)
    • Firebase Admin SDK ํ†ตํ•ฉ
    • SMS ๊ธฐ๋ฐ˜ ์ „ํ™”๋ฒˆํ˜ธ ์ธ์ฆ
    • ์ž๋™ ์‚ฌ์šฉ์ž ์ƒ์„ฑ ๋ฐ JWT ํ† ํฐ ๋ฐœ๊ธ‰
    • ์ „ํ™”๋ฒˆํ˜ธ ์ธ์ฆ ์ƒํƒœ ์ถ”์ 
  • bcrypt ๊ธฐ๋ฐ˜ ์•ˆ์ „ํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™”
  • ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ…: ์˜๋ฌธ + ์ˆซ์ž ํฌํ•จ, 8์ž ์ด์ƒ
  • Rate Limiting ์ ์šฉ (์ค‘๋ณต ์š”์ฒญ ๋ฐฉ์ง€)

๐Ÿ“ฑ SMS ์ธ์ฆ

  • Solapi ๊ธฐ๋ฐ˜ SMS ๋ฐœ์†ก
  • sessionId ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ์ธ์ฆ ํ”Œ๋กœ์šฐ
  • node-cache๋ฅผ ํ™œ์šฉํ•œ ์ธ์ฆ ์ฝ”๋“œ ์บ์‹ฑ
  • ์ธ์ฆ ์ฝ”๋“œ ์œ ํšจ ์‹œ๊ฐ„ ๊ด€๋ฆฌ

๐Ÿง  MBTI ์œ ํ˜• ์‹œ์Šคํ…œ

  • MBTI ๊ฒฐ๊ณผ ์ €์žฅ API (POST /api/users/mbti)
  • /api/auth/me ์‘๋‹ต์— mbtiType ํ•„๋“œ ํฌํ•จ
  • ํŒ€ ๊ตฌ์„ฑ ์‹œ ์„ฑํ–ฅ ์ฐธ๊ณ  ๊ฐ€๋Šฅ

๐Ÿ“ฒ ํ‘ธ์‹œ ์•Œ๋ฆผ

  • iOS APNs (Apple Push Notification service) ์ง€์›
  • ์ดˆ๋Œ€, ์ƒํƒœ ๋ณ€๊ฒฝ, ๋ฆฌ๋ทฐ ์•Œ๋ฆผ ํŠธ๋ฆฌ๊ฑฐ
  • DeviceToken ๋ชจ๋ธ๋กœ ํ† ํฐ ๊ด€๋ฆฌ
  • ์•ฑ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์•Œ๋ฆผ ์ง€์›

๐Ÿ“Š ํ”„๋กœ์ ํŠธ ๊ด€๋ฆฌ

  • ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ, ์กฐํšŒ, ์ˆ˜์ •, ์‚ญ์ œ (CRUD)
  • ๋‚ด ํ”„๋กœ์ ํŠธ ์กฐํšŒ (ํ‰๊ฐ€ ์ƒํƒœ ์ถ”์ )
  • ํŒ€์› ๋ชจ์ง‘ ์‹œ์Šคํ…œ (์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์ง€์›)
  • ํ”„๋กœ์ ํŠธ ํ‚ฅ์˜คํ”„ (๋ชจ์ง‘๊ธ€ โ†’ ํ”„๋กœ์ ํŠธ ์ „ํ™˜)
    • ์Šน์ธ๋œ ์ง€์›์ž ์ค‘ ํŒ€์› ์„ ํƒ
    • ํ”„๋กœ์ ํŠธ ์ œ๋ชฉ, ๋‹ค์ง(resolution), ๊ธฐ๊ฐ„ ์„ค์ •
    • Recruitment์—์„œ project_type ์ž๋™ ๋ณต์‚ฌ
  • ํ‚ค์›Œ๋“œ(ํ•ด์‹œํƒœ๊ทธ) ๊ธฐ๋ฐ˜ ๋ชจ์ง‘๊ธ€ ํƒœ๊น… ๋ฐ ๊ฒ€์ƒ‰
    • ๋ชจ์ง‘๊ธ€๋‹น ์ตœ๋Œ€ 5๊ฐœ ํ‚ค์›Œ๋“œ ์ง€์›
    • ๊ธฐํ˜ธ ์ž๋™ ์ œ๊ฑฐ ๋ฐ ์ค‘๋ณต ์ œ๊ฑฐ

    • ํ‚ค์›Œ๋“œ๋ณ„ ๋ชจ์ง‘๊ธ€ ํ•„ํ„ฐ๋ง
    • ์ „์ฒด ๋ชจ์ง‘๊ธ€ ๋ชฉ๋ก์—์„œ ํ‚ค์›Œ๋“œ ํ‘œ์‹œ
  • ์ง€์›์„œ ์ œ์ถœ ๋ฐ ์ถ”์  ๊ด€๋ฆฌ
    • ์ž๊ธฐ์†Œ๊ฐœ ์ž‘์„ฑ (1-500์ž)
    • ํฌํŠธํด๋ฆฌ์˜ค ํ”„๋กœ์ ํŠธ ์—ฐ๊ฒฐ
    • ๋ณธ์ธ ๋ชจ์ง‘๊ธ€ ์ง€์› ๋ฐฉ์ง€
  • ํŒ€ ๋ฉค๋ฒ„ ๊ด€๋ฆฌ
  • ํŒ€์› ์ƒํ˜ธ ํ‰๊ฐ€ ์‹œ์Šคํ…œ

๐Ÿ“ˆ ๋Œ€์‹œ๋ณด๋“œ

  • ํ”„๋กœ์ ํŠธ ํ†ต๊ณ„ (์ฐธ์—ฌ ํ”„๋กœ์ ํŠธ ์ˆ˜, ๋ชจ์ง‘๊ณต๊ณ  ์ˆ˜)
  • ์ง€์›์„œ ๋ฐ ์•Œ๋ฆผ ์ถ”์ 
  • ํ‰๊ฐ€ ๋Œ€๊ธฐ ํ”„๋กœ์ ํŠธ ํ™•์ธ
  • ์ตœ๊ทผ ํ™œ๋™ ํƒ€์ž„๋ผ์ธ

๐Ÿ‘ค ์‚ฌ์šฉ์ž ํ”„๋กœํ•„

  • ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๊ฐ€๋Šฅํ•œ ํ”„๋กœํ•„
  • ๊ธฐ์ˆ  ์Šคํƒ ๋ฐ ๊ฒฝ๋ ฅ ๊ด€๋ฆฌ
  • ํฌํŠธํด๋ฆฌ์˜ค ๊ด€๋ฆฌ

๐Ÿ’ฌ ์†Œ์…œ ๊ธฐ๋Šฅ

  • ๋Œ“๊ธ€ ๋ฐ ๋‹ต๊ธ€
  • ํ”„๋กœ์ ํŠธ ๋ฆฌ๋ทฐ ๋ฐ ํ‰์ 
  • ๋ถ๋งˆํฌ/์Šคํฌ๋žฉ ๊ธฐ๋Šฅ
  • ํˆฌํ‘œ ์‹œ์Šคํ…œ

๐Ÿ” ๊ฒ€์ƒ‰ ๋ฐ ํƒ์ƒ‰

  • ๊ณ ๊ธ‰ ํ”„๋กœ์ ํŠธ ๊ฒ€์ƒ‰
  • ๊ธฐ์ˆ  ์Šคํƒ, ์—ญํ• , ์ƒํƒœ๋ณ„ ํ•„ํ„ฐ๋ง
  • ์‚ฌ์šฉ์ž ๊ฒ€์ƒ‰

๐Ÿ–ผ๏ธ ํŒŒ์ผ ์—…๋กœ๋“œ

  • ๋ชจ์ง‘๊ณต๊ณ  ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ (Supabase Storage)
  • ์ด๋ฏธ์ง€ ํŒŒ์ผ ๊ฒ€์ฆ (jpeg, png, webp)
  • ํŒŒ์ผ ํฌ๊ธฐ ์ œํ•œ (์ตœ๋Œ€ 5MB)
  • UUID ๊ธฐ๋ฐ˜ ํŒŒ์ผ๋ช… ์ƒ์„ฑ

๐Ÿ›ก๏ธ ๊ด€๋ฆฌ์ž ๊ธฐ๋Šฅ

  • ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ
  • ์ฝ˜ํ…์ธ  ๊ด€๋ฆฌ
  • ์‹œ์Šคํ…œ ๋ชจ๋‹ˆํ„ฐ๋ง

๐Ÿ›  ๊ธฐ์ˆ  ์Šคํƒ

ํ•ต์‹ฌ ๊ธฐ์ˆ 

  • ๋Ÿฐํƒ€์ž„: Node.js 18+
  • ํ”„๋ ˆ์ž„์›Œํฌ: Express.js
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค: MySQL / PostgreSQL (Supabase)
  • ORM: Sequelize (๋งˆ์ด๊ทธ๋ ˆ์ด์…˜) + Raw SQL (ํ”„๋กœ๋•์…˜ ์ฟผ๋ฆฌ)
    • PostgreSQL snake_case ๋ช…๋ช… ๊ทœ์น™ (project_members, created_at ๋“ฑ)

์ธ์ฆ ๋ฐ ๋ณด์•ˆ

  • JWT: jsonwebtoken, jose
  • ๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™”: bcrypt, bcryptjs
  • Firebase: firebase-admin (์ „ํ™”๋ฒˆํ˜ธ ์ธ์ฆ)
  • ์œ ํšจ์„ฑ ๊ฒ€์ฆ: Joi, express-validator
  • Rate Limiting: express-rate-limit
  • CORS: cors

์ด๋ฉ”์ผ, SMS ๋ฐ ํ‘ธ์‹œ ์•Œ๋ฆผ

  • ์ด๋ฉ”์ผ ์„œ๋น„์Šค: Resend (๋„๋ฉ”์ธ ์ธ์ฆ ์™„๋ฃŒ)
  • SMS ์„œ๋น„์Šค: Solapi (๊ตญ๋‚ด SMS ๋ฐœ์†ก)
  • ํ‘ธ์‹œ ์•Œ๋ฆผ: apns2 (iOS APNs)
  • ์บ์‹œ: node-cache (์ธ์ฆ ์ฝ”๋“œ ๊ด€๋ฆฌ)
  • ํ…œํ”Œ๋ฆฟ ์—”์ง„: markdown-it, marked

๊ฐœ๋ฐœ ๋ฐ ํ…Œ์ŠคํŠธ

  • ํ…Œ์ŠคํŒ…: Jest, Supertest
  • ์ฝ”๋“œ ํ’ˆ์งˆ: ESLint, Prettier
  • ํ”„๋กœ์„ธ์Šค ๊ด€๋ฆฌ: nodemon
  • ํ™˜๊ฒฝ ๋ณ€์ˆ˜: dotenv, cross-env

ํŒŒ์ผ ๋ฐ ์Šคํ† ๋ฆฌ์ง€

  • ํŒŒ์ผ ์—…๋กœ๋“œ: multer
  • ํŒŒ์ผ ์ €์žฅ์†Œ: Supabase Storage
  • ํŒŒ์ผ๋ช… ์ƒ์„ฑ: uuid

ํด๋ผ์šฐ๋“œ ๋ฐ ๋ฐฐํฌ

  • ํ˜ธ์ŠคํŒ…: Render (ํ”„๋กœ๋•์…˜)
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค: Supabase PostgreSQL (Shared Pooler)
  • ์Šคํ† ๋ฆฌ์ง€: Supabase Storage (์ด๋ฏธ์ง€ ์—…๋กœ๋“œ)
  • ์ด๋ฉ”์ผ: Resend (๋„๋ฉ”์ธ ์ธ์ฆ ์™„๋ฃŒ)
  • SMS: Solapi (๊ตญ๋‚ด SMS ๋ฐœ์†ก)
  • ํ‘ธ์‹œ ์•Œ๋ฆผ: APNs (iOS)
  • ๋ฒ„์ „ ๊ด€๋ฆฌ: GitHub

๐Ÿš€ ์‹œ์ž‘ํ•˜๊ธฐ

์‚ฌ์ „ ์š”๊ตฌ์‚ฌํ•ญ

  • Node.js >= 18.0.0
  • npm ๋˜๋Š” yarn
  • MySQL 8.0+ ๋˜๋Š” PostgreSQL 14+
  • Git

์„ค์น˜ ๋ฐฉ๋ฒ•

1๏ธโƒฃ ์ €์žฅ์†Œ ๋ณต์ œ

git clone https://github.com/TeamKoHong/teamitakaBackend.git
cd teamitakaBackend

2๏ธโƒฃ ์˜์กด์„ฑ ํŒจํ‚ค์ง€ ์„ค์น˜

npm install

3๏ธโƒฃ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •

# ์˜ˆ์ œ ํ™˜๊ฒฝ ํŒŒ์ผ ๋ณต์‚ฌ
cp .env.example .env.development

# ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ํŒŒ์ผ ์ˆ˜์ •
nano .env.development

4๏ธโƒฃ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ดˆ๊ธฐํ™”

# ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์‹คํ–‰
npm run migrate:dev

# ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ์‹œ๋”ฉ (์„ ํƒ์‚ฌํ•ญ)
npm run seed:dev

5๏ธโƒฃ ๊ฐœ๋ฐœ ์„œ๋ฒ„ ์‹œ์ž‘

npm run dev

์„œ๋ฒ„๊ฐ€ http://0.0.0.0:8080 ์—์„œ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.

๐Ÿณ Docker๋กœ ๋น ๋ฅด๊ฒŒ ์‹œ์ž‘ํ•˜๊ธฐ

# Docker Compose ์‚ฌ์šฉ
docker-compose up -d

๐Ÿ“ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

teamitakaBackend/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ config/          # ์„ค์ • ํŒŒ์ผ (4๊ฐœ: database, env, ...)
โ”‚   โ”œโ”€โ”€ controllers/     # ๋ผ์šฐํŠธ ์ปจํŠธ๋กค๋Ÿฌ (22๊ฐœ)
โ”‚   โ”œโ”€โ”€ middlewares/     # Express ๋ฏธ๋“ค์›จ์–ด (9๊ฐœ: ์ธ์ฆ, ๊ฒ€์ฆ, ์—…๋กœ๋“œ, UUID)
โ”‚   โ”œโ”€โ”€ models/          # Sequelize ๋ชจ๋ธ (32๊ฐœ)
โ”‚   โ”œโ”€โ”€ routes/          # API ๋ผ์šฐํŠธ (20๊ฐœ)
โ”‚   โ”œโ”€โ”€ services/        # ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๋ ˆ์ด์–ด (19๊ฐœ)
โ”‚   โ”œโ”€โ”€ utils/           # ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜ (7๊ฐœ)
โ”‚   โ”œโ”€โ”€ validations/     # ์š”์ฒญ ์œ ํšจ์„ฑ ๊ฒ€์ฆ ์Šคํ‚ค๋งˆ
โ”‚   โ”œโ”€โ”€ templates/       # ์ด๋ฉ”์ผ ํ…œํ”Œ๋ฆฟ
โ”‚   โ”œโ”€โ”€ migrations/      # DB ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ (13๊ฐœ)
โ”‚   โ””โ”€โ”€ app.js           # Express ์•ฑ ์„ค์ •
โ”œโ”€โ”€ tests/               # ํ…Œ์ŠคํŠธ ํŒŒ์ผ
โ”œโ”€โ”€ scripts/             # ์œ ํ‹ธ๋ฆฌํ‹ฐ ์Šคํฌ๋ฆฝํŠธ
โ”œโ”€โ”€ docs/                # ๋ฌธ์„œ
โ”œโ”€โ”€ index.js             # ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ง„์ž…์ 
โ””โ”€โ”€ package.json         # ์˜์กด์„ฑ ๋ฐ ์Šคํฌ๋ฆฝํŠธ

๐Ÿ“š API ๋ฌธ์„œ

๊ธฐ๋ณธ URL

  • ๊ฐœ๋ฐœ ํ™˜๊ฒฝ: http://localhost:8080
  • ํ”„๋กœ๋•์…˜: https://teamitakabackend.onrender.com

์ฃผ์š” ์—”๋“œํฌ์ธํŠธ

๐Ÿ” ์ธ์ฆ (Authentication)

POST   /api/auth/register              # ํšŒ์›๊ฐ€์ž…
POST   /api/auth/login                 # ๋กœ๊ทธ์ธ
GET    /api/auth/me                    # ํ˜„์žฌ ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ
POST   /api/auth/logout                # ๋กœ๊ทธ์•„์›ƒ
POST   /api/auth/send-verification     # ์ด๋ฉ”์ผ ์ธ์ฆ ์ฝ”๋“œ ์ „์†ก
POST   /api/auth/verify-code           # ์ด๋ฉ”์ผ ์ธ์ฆ ์ฝ”๋“œ ํ™•์ธ
GET    /api/auth/google                # ๊ตฌ๊ธ€ OAuth ๋กœ๊ทธ์ธ
POST   /api/auth/phone/verify          # Firebase ์ „ํ™”๋ฒˆํ˜ธ ์ธ์ฆ

๐Ÿ“ฑ SMS ์ธ์ฆ (SMS Verification)

POST   /api/sms/send                    # SMS ์ธ์ฆ ์ฝ”๋“œ ๋ฐœ์†ก
POST   /api/sms/verify                  # SMS ์ธ์ฆ ์ฝ”๋“œ ํ™•์ธ
GET    /api/sms/status/:sessionId       # ์ธ์ฆ ์ƒํƒœ ์กฐํšŒ

๐Ÿง  MBTI (MBTI Type)

POST   /api/users/mbti                  # MBTI ๊ฒฐ๊ณผ ์ €์žฅ

๐Ÿ‘ค ์‚ฌ์šฉ์ž (Users)

GET    /api/users/:id                  # ์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ์กฐํšŒ
PUT    /api/users/:id                  # ์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ์ˆ˜์ •
DELETE /api/users/:id                  # ์‚ฌ์šฉ์ž ๊ณ„์ • ์‚ญ์ œ

๐Ÿ“Š ํ”„๋กœ์ ํŠธ (Projects)

GET    /api/projects                   # ์ „์ฒด ํ”„๋กœ์ ํŠธ ๋ชฉ๋ก
GET    /api/projects/mine              # ๋‚ด ํ”„๋กœ์ ํŠธ ์กฐํšŒ
GET    /api/projects/:id               # ํ”„๋กœ์ ํŠธ ์ƒ์„ธ ์กฐํšŒ
POST   /api/projects                   # ์ƒˆ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ
POST   /api/projects/from-recruitment/:id  # ๋ชจ์ง‘๊ธ€์—์„œ ํ”„๋กœ์ ํŠธ ํ‚ฅ์˜คํ”„
PUT    /api/projects/:id               # ํ”„๋กœ์ ํŠธ ์ˆ˜์ •
DELETE /api/projects/:id               # ํ”„๋กœ์ ํŠธ ์‚ญ์ œ
POST   /api/projects/:id/favorite      # ํ”„๋กœ์ ํŠธ ์ฆ๊ฒจ์ฐพ๊ธฐ ํ† ๊ธ€

/api/projects/mine ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ:

ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž… ์„ค๋ช…
status string ongoing/active โ†’ ์ง„ํ–‰ ์ค‘, completed โ†’ ์™„๋ฃŒ
evaluation_status string PENDING, COMPLETED, NOT_REQUIRED
limit number ์กฐํšŒ ๊ฐœ์ˆ˜ ์ œํ•œ
offset number ํŽ˜์ด์ง€๋„ค์ด์…˜ ์˜คํ”„์…‹

๐Ÿ“ข ๋ชจ์ง‘๊ณต๊ณ  (Recruitments)

GET    /api/recruitments               # ์ „์ฒด ๋ชจ์ง‘๊ณต๊ณ  ๋ชฉ๋ก (์ง€์›์ž ์ˆ˜, ํ‚ค์›Œ๋“œ ํฌํ•จ)
GET    /api/recruitments/mine          # ๋‚ด ๋ชจ์ง‘๊ณต๊ณ  ์กฐํšŒ (ํ‚ค์›Œ๋“œ ํฌํ•จ)
GET    /api/recruitments/:id           # ๋ชจ์ง‘๊ณต๊ณ  ์ƒ์„ธ ์กฐํšŒ (์ž‘์„ฑ์ž ID, ์ง€์›์ž ์ˆ˜, ํ‚ค์›Œ๋“œ ํฌํ•จ)
POST   /api/recruitments               # ๋ชจ์ง‘๊ณต๊ณ  ์ž‘์„ฑ (ํ‚ค์›Œ๋“œ ๋ฐฐ์—ด ์ง€์›)
PUT    /api/recruitments/:id           # ๋ชจ์ง‘๊ณต๊ณ  ์ˆ˜์ • (ํ‚ค์›Œ๋“œ ์—…๋ฐ์ดํŠธ ์ง€์›)
DELETE /api/recruitments/:id           # ๋ชจ์ง‘๊ณต๊ณ  ์‚ญ์ œ

์‘๋‹ต ํ˜•์‹ ์˜ˆ์‹œ (Hashtags ํ•„๋“œ):

{
  "recruitment_id": "550e8400-e29b-41d4-a716-446655440000",
  "title": "ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž ๋ชจ์ง‘",
  "status": "OPEN",
  "applicationCount": 5,
  "Hashtags": [
    { "name": "React" },
    { "name": "TypeScript" },
    { "name": "Next.js" }
  ]
}

โš ๏ธ ์ฃผ์˜: Hashtags ํ•„๋“œ๋Š” ๋Œ€๋ฌธ์ž H๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค (Sequelize ์ž๋™ ์ƒ์„ฑ). ํ‚ค์›Œ๋“œ๊ฐ€ ์—†๋Š” ๋ชจ์ง‘๊ธ€์€ null ๋˜๋Š” []์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ ์ง€์›์„œ (Applications)

POST   /api/applications/:recruitment_id          # ์ง€์›์„œ ์ œ์ถœ (์ž๊ธฐ์†Œ๊ฐœ + ํฌํŠธํด๋ฆฌ์˜ค)
GET    /api/applications/:recruitment_id          # ์ง€์›์ž ๋ชฉ๋ก (ํฌํŠธํด๋ฆฌ์˜ค ํฌํ•จ)
POST   /api/applications/:application_id/approve  # ์ง€์› ์Šน์ธ
POST   /api/applications/:application_id/reject   # ์ง€์› ๊ฑฐ์ ˆ
GET    /api/applications/:recruitment_id/count    # ์ง€์›์ž ์ˆ˜ ์กฐํšŒ

๐Ÿ“ค ํŒŒ์ผ ์—…๋กœ๋“œ (Upload)

POST   /api/upload/recruitment-image   # ๋ชจ์ง‘๊ณต๊ณ  ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ (JWT ํ•„์ˆ˜)
POST   /api/upload/profile-image       # ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ (JWT ํ•„์ˆ˜)

๐Ÿ’ฌ ๋Œ“๊ธ€ (Comments)

GET    /api/comments/:projectId        # ํ”„๋กœ์ ํŠธ ๋Œ“๊ธ€ ์กฐํšŒ
POST   /api/comments                   # ๋Œ“๊ธ€ ์ž‘์„ฑ
PUT    /api/comments/:id               # ๋Œ“๊ธ€ ์ˆ˜์ •
DELETE /api/comments/:id               # ๋Œ“๊ธ€ ์‚ญ์ œ

๐Ÿ‘ค ํ”„๋กœํ•„ (Profile)

GET    /api/profile/me                 # ๋‚ด ํ”„๋กœํ•„ ์กฐํšŒ
PUT    /api/profile                    # ํ”„๋กœํ•„ ์ˆ˜์ •
GET    /api/profile/detail             # ํ”„๋กœํ•„ ์ƒ์„ธ ์กฐํšŒ
GET    /api/profile/verification       # ์ธ์ฆ ์ƒํƒœ ์กฐํšŒ

โญ ํ‰๊ฐ€ (Reviews)

POST   /api/reviews                        # ํŒ€์› ํ‰๊ฐ€ ์ƒ์„ฑ
GET    /api/reviews/user/:user_id          # ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐ›์€ ํ‰๊ฐ€ ์กฐํšŒ
GET    /api/reviews/project/:project_id    # ํ”„๋กœ์ ํŠธ ํ‰๊ฐ€ ๋ชฉ๋ก
GET    /api/reviews/project/:project_id/summary  # ํ”„๋กœ์ ํŠธ ํ‰๊ฐ€ ์š”์•ฝ
DELETE /api/reviews/:review_id             # ํ‰๊ฐ€ ์‚ญ์ œ

๐Ÿ“Œ ์Šคํฌ๋žฉ (Scraps)

GET    /api/scraps/recruitments            # ์Šคํฌ๋žฉํ•œ ๋ชจ์ง‘๊ณต๊ณ  ๋ชฉ๋ก
PUT    /api/scraps/recruitment/:id/scrap   # ์Šคํฌ๋žฉ ํ† ๊ธ€ (์ถ”๊ฐ€/์ œ๊ฑฐ)

๐Ÿ“… ์ผ์ • (Schedule) โš ๏ธ ๋ผ์šฐํŠธ ๋“ฑ๋ก ํ•„์š”

POST   /api/schedule/create            # ์ผ์ • ์ƒ์„ฑ
GET    /api/schedule/project/:project_id # ํ”„๋กœ์ ํŠธ๋ณ„ ์ผ์ • ์กฐํšŒ
PUT    /api/schedule/:schedule_id      # ์ผ์ • ์ˆ˜์ •
DELETE /api/schedule/:schedule_id      # ์ผ์ • ์‚ญ์ œ

๐Ÿ—ณ๏ธ ํˆฌํ‘œ (Vote) โš ๏ธ ๋ผ์šฐํŠธ ๋“ฑ๋ก ํ•„์š”

POST   /api/vote/create                # ํˆฌํ‘œ ์ƒ์„ฑ
GET    /api/vote/project/:project_id   # ํ”„๋กœ์ ํŠธ๋ณ„ ํˆฌํ‘œ ์กฐํšŒ
GET    /api/vote/:voteId               # ํˆฌํ‘œ ์ƒ์„ธ ์กฐํšŒ
POST   /api/vote/:voteId/submit        # ํˆฌํ‘œ ์ œ์ถœ

โš ๏ธ ์ฐธ๊ณ : Schedule, Vote API๋Š” ์ปจํŠธ๋กค๋Ÿฌ/์„œ๋น„์Šค๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ์œผ๋‚˜ app.js์— ๋ผ์šฐํŠธ ๋“ฑ๋ก์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ ํ”„๋กœ์ ํŠธ ๊ฒŒ์‹œํŒ (Project Posts)

POST   /api/:project_id/posts          # ๊ฒŒ์‹œ๋ฌผ ์ƒ์„ฑ
GET    /api/:project_id/posts          # ๊ฒŒ์‹œ๋ฌผ ๋ชฉ๋ก ์กฐํšŒ
GET    /api/posts/:post_id             # ๊ฒŒ์‹œ๋ฌผ ์ƒ์„ธ ์กฐํšŒ

๐Ÿ’พ ์ž„์‹œ์ €์žฅ (Drafts)

POST   /api/recruitment/draft          # ๋ชจ์ง‘๊ณต๊ณ  ์ž„์‹œ์ €์žฅ

๐Ÿ” ๊ฒ€์ƒ‰ (Search)

GET    /api/search/projects            # ํ”„๋กœ์ ํŠธ ๊ฒ€์ƒ‰
GET    /api/search/users               # ์‚ฌ์šฉ์ž ๊ฒ€์ƒ‰

๐Ÿ“ˆ ๋Œ€์‹œ๋ณด๋“œ (Dashboard)

GET    /api/dashboard/summary          # ๋Œ€์‹œ๋ณด๋“œ ์š”์•ฝ ์ •๋ณด

๐Ÿ›ก๏ธ ๊ด€๋ฆฌ์ž (Admin)

GET    /api/admin/users                # ์ „์ฒด ์‚ฌ์šฉ์ž ๋ชฉ๋ก
PUT    /api/admin/users/:id/role       # ์‚ฌ์šฉ์ž ์—ญํ•  ์ˆ˜์ •
DELETE /api/admin/users/:id            # ์‚ฌ์šฉ์ž ์‚ญ์ œ (๊ด€๋ฆฌ์ž)

โค๏ธ ์ƒํƒœ ํ™•์ธ (Health Check)

GET    /api/health                     # ์„œ๋ฒ„ ์ƒํƒœ ํ™•์ธ

์ž์„ธํ•œ API ๋ฌธ์„œ๋Š” API_DOCS.md๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

๐Ÿ—„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

์ง€์› ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

  • MySQL 8.0+ (๋กœ์ปฌ ๊ฐœ๋ฐœ)
  • PostgreSQL 14+ (Supabase ํ”„๋กœ๋•์…˜)

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ชจ๋ธ (32๊ฐœ)

์ŠคํŽ™ 26๊ฐœ ํ…Œ์ด๋ธ” ์ค‘ 19๊ฐœ ๊ตฌํ˜„ + ์ถ”๊ฐ€ 13๊ฐœ ๋ชจ๋ธ

ํ•ต์‹ฌ ๋ชจ๋ธ

๋ชจ๋ธ ์„ค๋ช… ์ŠคํŽ™ ๋งคํ•‘
User ์‚ฌ์šฉ์ž ๊ณ„์ • ๋ฐ ํ”„๋กœํ•„ users
Project ํ”„๋กœ์ ํŠธ ์ •๋ณด projects
ProjectMembers ํ”„๋กœ์ ํŠธ ํŒ€ ๋ฉค๋ฒ„ project_members
Recruitment ๋ชจ์ง‘ ๊ณต๊ณ  (์ด๋ฏธ์ง€, ํ•ด์‹œํƒœ๊ทธ ์ง€์›) recruitment_posts
Application ์ง€์›์„œ (์ž๊ธฐ์†Œ๊ฐœ + ํฌํŠธํด๋ฆฌ์˜ค) applications
ApplicationPortfolio ์ง€์›์„œ-ํฌํŠธํด๋ฆฌ์˜ค ์—ฐ๊ฒฐ (M:N) application_projects

๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ๋ชจ๋ธ

๋ชจ๋ธ ์„ค๋ช… ์ŠคํŽ™ ๋งคํ•‘
Hashtag ํ•ด์‹œํƒœ๊ทธ ๊ด€๋ฆฌ recruitment_hashtags
Comment ํ”„๋กœ์ ํŠธ ๋Œ“๊ธ€ - (์ถ”๊ฐ€)
Review ํŒ€์› ํ‰๊ฐ€ ์‹œ์Šคํ…œ peer_evaluations
Notification ์‚ฌ์šฉ์ž ์•Œ๋ฆผ notifications
Scrap ๋ถ๋งˆํฌ bookmarks
Todo ํ•  ์ผ ๊ด€๋ฆฌ todos

ํˆฌํ‘œ ์‹œ์Šคํ…œ ๋ชจ๋ธ

๋ชจ๋ธ ์„ค๋ช… ์ŠคํŽ™ ๋งคํ•‘
Vote ํˆฌํ‘œ ์ƒ์„ฑ votes
VoteOption ํˆฌํ‘œ ์„ ํƒ์ง€ vote_options
VoteResponse ํˆฌํ‘œ ์‘๋‹ต vote_responses

์ผ์ • ๋ฐ ํƒ€์ž„๋ผ์ธ ๋ชจ๋ธ

๋ชจ๋ธ ์„ค๋ช… ์ŠคํŽ™ ๋งคํ•‘
Schedule ์ผ์ • ๊ด€๋ฆฌ calendar_events
Timeline ํƒ€์ž„๋ผ์ธ ์ด๋ฒคํŠธ - (์ถ”๊ฐ€)
ProjectPost ํ”„๋กœ์ ํŠธ ํ”ผ๋“œ project_feeds

์‚ฌ์šฉ์ž ๊ด€๋ จ ๋ชจ๋ธ

๋ชจ๋ธ ์„ค๋ช… ์ŠคํŽ™ ๋งคํ•‘
University ๋Œ€ํ•™ ์ •๋ณด universities
College ๋‹จ๊ณผ๋Œ€ ์ •๋ณด - (์ถ”๊ฐ€)
Department ํ•™๊ณผ ์ •๋ณด - (์ถ”๊ฐ€)
EmailVerification ์ด๋ฉ”์ผ ์ธ์ฆ verification_codes
VerifiedEmail ์ธ์ฆ ์™„๋ฃŒ ์ด๋ฉ”์ผ - (์ถ”๊ฐ€)
Search ๊ฒ€์ƒ‰ ๊ธฐ๋ก search_history

ํŒ€ํ”Œ ์œ ํ˜• ๋ฐ ํ”ผ๋“œ๋ฐฑ ๋ชจ๋ธ

๋ชจ๋ธ ์„ค๋ช… ์ŠคํŽ™ ๋งคํ•‘
TeamiType ํŒ€ํ”Œ ์บ๋ฆญํ„ฐ ์œ ํ˜• - (์ถ”๊ฐ€)
UserTeamiType ์‚ฌ์šฉ์ž-์บ๋ฆญํ„ฐ ๋งคํ•‘ - (์ถ”๊ฐ€)
UserFeedback ์‚ฌ์šฉ์ž ํ”ผ๋“œ๋ฐฑ - (์ถ”๊ฐ€)
FeedbackItem ํ”ผ๋“œ๋ฐฑ ํ•ญ๋ชฉ - (์ถ”๊ฐ€)
Keyword ํ‚ค์›Œ๋“œ ๊ด€๋ฆฌ - (์ถ”๊ฐ€)

์‹œ์Šคํ…œ ๋ชจ๋ธ

๋ชจ๋ธ ์„ค๋ช… ์ŠคํŽ™ ๋งคํ•‘
Admin ๊ด€๋ฆฌ์ž ๊ณ„์ • - (์ถ”๊ฐ€)
RecruitmentView ์กฐํšŒ์ˆ˜ ์ถ”์  - (์ถ”๊ฐ€)

โŒ ๋ฏธ๊ตฌํ˜„ ํ…Œ์ด๋ธ” (7๊ฐœ)

์ŠคํŽ™ ํ…Œ์ด๋ธ” ์šฉ๋„ ์šฐ์„ ์ˆœ์œ„
user_stats ์‚ฌ์šฉ์ž ํ†ต๊ณ„ ์ง‘๊ณ„ ์ค‘
user_settings ์‚ฌ์šฉ์ž ์„ค์ • ์ค‘
popular_keywords ์ธ๊ธฐ ๊ฒ€์ƒ‰์–ด ํ•˜
project_invitations QR ์ดˆ๋Œ€ ์ค‘
draft_recruitment_posts ๋ชจ์ง‘๊ธ€ ์ž„์‹œ์ €์žฅ ํ•˜
meeting_notes ํšŒ์˜๋ก ์ค‘
team_chat_messages ํŒ€ ์ฑ„ํŒ… ํ•˜

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜

# ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์‹คํ–‰
npm run migrate:dev          # ๊ฐœ๋ฐœ ํ™˜๊ฒฝ
npm run migrate:prod         # ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ

# ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋กค๋ฐฑ
npm run rollback:dev         # ๋งˆ์ง€๋ง‰ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋กค๋ฐฑ
npm run undo-migrate:dev     # ๋ชจ๋“  ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋กค๋ฐฑ

# ๋ฐ์ดํ„ฐ ์‹œ๋”ฉ
npm run seed:dev             # ๊ฐœ๋ฐœ ๋ฐ์ดํ„ฐ ์‹œ๋”ฉ

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ดˆ๊ธฐํ™”

# ๋ชจ๋“  ํ…Œ์ด๋ธ”์„ ํฌํ•จํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ดˆ๊ธฐํ™”
npm run db:init:dev

# ๊ฐ„๋‹จํ•œ ์ดˆ๊ธฐํ™”
npm run db:init:simple:dev

# ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฆฌ์…‹
npm run db:reset

๐Ÿ”ง ๊ฐœ๋ฐœ ๊ฐ€์ด๋“œ

์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์Šคํฌ๋ฆฝํŠธ

# ๊ฐœ๋ฐœ
npm run dev                  # nodemon์œผ๋กœ ์‹œ์ž‘ (ํ•ซ ๋ฆฌ๋กœ๋“œ)
npm run dev:supabase        # Supabase ์„ค์ •์œผ๋กœ ์‹œ์ž‘

# ํ”„๋กœ๋•์…˜
npm start                    # ํ”„๋กœ๋•์…˜ ์„œ๋ฒ„ ์‹œ์ž‘
npm run start:supabase      # Supabase ์„ค์ •์œผ๋กœ ํ”„๋กœ๋•์…˜ ์‹œ์ž‘

# ํ…Œ์ŠคํŠธ
npm test                     # ๋ชจ๋“  ํ…Œ์ŠคํŠธ ์‹คํ–‰
npm run test:watch          # ์›Œ์น˜ ๋ชจ๋“œ๋กœ ํ…Œ์ŠคํŠธ ์‹คํ–‰

# ์ฝ”๋“œ ํ’ˆ์งˆ
npm run lint                 # ESLint ๋ฐ Prettier ์‹คํ–‰

# ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค
npm run migrate:dev         # ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์‹คํ–‰
npm run seed:dev            # ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‹œ๋”ฉ
npm run db:init:dev         # ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ดˆ๊ธฐํ™”

# ๊ฒ€์ฆ
npm run verify              # ๋ฐฐํฌ ๊ฒ€์ฆ
npm run verify:supabase     # Supabase ๋ฐฐํฌ ๊ฒ€์ฆ

๊ฐœ๋ฐœ ์›Œํฌํ”Œ๋กœ์šฐ

1๏ธโƒฃ ์ƒˆ ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ

git checkout -b feature/๊ธฐ๋Šฅ-์ด๋ฆ„

2๏ธโƒฃ ๋ณ€๊ฒฝ ์‚ฌํ•ญ ์ž‘์„ฑ

# ํŒŒ์ผ ์ˆ˜์ •
# ํ…Œ์ŠคํŠธ ์ž‘์„ฑ

3๏ธโƒฃ ํ…Œ์ŠคํŠธ ์‹คํ–‰

npm test

4๏ธโƒฃ ๋ณ€๊ฒฝ ์‚ฌํ•ญ ์ปค๋ฐ‹

git add .
git commit -m "feat: ๊ธฐ๋Šฅ ์„ค๋ช…"

5๏ธโƒฃ ์›๊ฒฉ ์ €์žฅ์†Œ์— ํ‘ธ์‹œ

git push origin feature/๊ธฐ๋Šฅ-์ด๋ฆ„

6๏ธโƒฃ Pull Request ์ƒ์„ฑ

GitHub์—์„œ Pull Request๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ฝ”๋“œ ์Šคํƒ€์ผ

์ด ํ”„๋กœ์ ํŠธ๋Š” ESLint์™€ Prettier๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:

# ๋ฆฐํ„ฐ ์‹คํ–‰
npm run lint

# ์ž๋™ ์ˆ˜์ •
npm run lint -- --fix

๐Ÿงช ํ…Œ์ŠคํŠธ

ํ…Œ์ŠคํŠธ ์‹คํ–‰

# ๋ชจ๋“  ํ…Œ์ŠคํŠธ ์‹คํ–‰
npm test

# ์ปค๋ฒ„๋ฆฌ์ง€์™€ ํ•จ๊ป˜ ํ…Œ์ŠคํŠธ ์‹คํ–‰
npm test -- --coverage

# ํŠน์ • ํ…Œ์ŠคํŠธ ํŒŒ์ผ ์‹คํ–‰
npm test -- tests/auth.test.js

# ์›Œ์น˜ ๋ชจ๋“œ
npm test -- --watch

ํ…Œ์ŠคํŠธ ๊ตฌ์กฐ

describe('์ธ์ฆ ์ปจํŠธ๋กค๋Ÿฌ', () => {
  it('์ƒˆ ์‚ฌ์šฉ์ž๋ฅผ ๋“ฑ๋กํ•ด์•ผ ํ•จ', async () => {
    // ํ…Œ์ŠคํŠธ ๊ตฌํ˜„
  });

  it('์œ ํšจํ•œ ์ž๊ฒฉ ์ฆ๋ช…์œผ๋กœ ๋กœ๊ทธ์ธํ•ด์•ผ ํ•จ', async () => {
    // ํ…Œ์ŠคํŠธ ๊ตฌํ˜„
  });
});

์ปค๋ฒ„๋ฆฌ์ง€ ๋ฆฌํฌํŠธ

์ปค๋ฒ„๋ฆฌ์ง€ ๋ฆฌํฌํŠธ๋Š” coverage/ ๋””๋ ‰ํ† ๋ฆฌ์— ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

๐Ÿš€ ๋ฐฐํฌ

Render ๋ฐฐํฌ

์ด ํ”„๋กœ์ ํŠธ๋Š” Render์— ๋ฐฐํฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค:

1๏ธโƒฃ Render ์„ค์ •

  1. Render ๊ณ„์ • ์ƒ์„ฑ ๋ฐ ๋กœ๊ทธ์ธ
  2. New + โ†’ Web Service ์„ ํƒ
  3. GitHub ์ €์žฅ์†Œ ์—ฐ๊ฒฐ
  4. ๋‹ค์Œ ์„ค์ • ์‚ฌ์šฉ:
    • Environment: Node
    • Build Command: npm install
    • Start Command: npm start

2๏ธโƒฃ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •

Render ๋Œ€์‹œ๋ณด๋“œ์˜ Environment ํƒญ์—์„œ ํ•„์š”ํ•œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์ถ”๊ฐ€:

  • NODE_ENV=production
  • PORT=3001
  • SUPABASE_DB_HOST (Shared Pooler ์‚ฌ์šฉ)
  • SUPABASE_DB_PORT=5432
  • SENDGRID_API_KEY
  • EMAIL_FROM=noreply@teamitaka.com
  • FIREBASE_PROJECT_ID, FIREBASE_PRIVATE_KEY, FIREBASE_CLIENT_EMAIL (์ „ํ™”๋ฒˆํ˜ธ ์ธ์ฆ)
  • ๊ธฐํƒ€ ํ•„์ˆ˜ ํ™˜๊ฒฝ ๋ณ€์ˆ˜

3๏ธโƒฃ ์ž๋™ ๋ฐฐํฌ

  • main ๋ธŒ๋žœ์น˜์— ํ‘ธ์‹œํ•˜๋ฉด ์ž๋™์œผ๋กœ ๋ฐฐํฌ๋ฉ๋‹ˆ๋‹ค
  • ๋ฐฐํฌ ๋กœ๊ทธ๋Š” Render ๋Œ€์‹œ๋ณด๋“œ์—์„œ ํ™•์ธ ๊ฐ€๋Šฅ

ํ™˜๊ฒฝ๋ณ„ ๋ฐฐํฌ

# ๊ฐœ๋ฐœ ํ™˜๊ฒฝ
npm run dev

# ํ”„๋กœ๋•์…˜ (Render)
npm start

๐Ÿ” ํ™˜๊ฒฝ ๋ณ€์ˆ˜

ํ•„์ˆ˜ ํ™˜๊ฒฝ ๋ณ€์ˆ˜

# Node ํ™˜๊ฒฝ
NODE_ENV=development                    # development, production, test

# ์„œ๋ฒ„ ์„ค์ •
PORT=8080                              # ์„œ๋ฒ„ ํฌํŠธ
HOST=0.0.0.0                          # ์„œ๋ฒ„ ํ˜ธ์ŠคํŠธ (๋ชจ๋“  ์ธํ„ฐํŽ˜์ด์Šค)

# ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค (MySQL)
DB_HOST=localhost
DB_USER=๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค_์‚ฌ์šฉ์ž
DB_PASSWORD=๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค_๋น„๋ฐ€๋ฒˆํ˜ธ
DB_NAME=teamitaka
DB_PORT=3306
DB_DIALECT=mysql

# ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค (PostgreSQL/Supabase Direct)
DB_DIALECT=postgres
DB_HOST=db.xxx.supabase.co
DB_USER=postgres
DB_PASSWORD=๋น„๋ฐ€๋ฒˆํ˜ธ
DB_NAME=postgres
DB_PORT=5432

# Supabase Shared Pooler (ํ”„๋กœ๋•์…˜ ๊ถŒ์žฅ)
SUPABASE_DB_HOST=aws-0-region.pooler.supabase.com
SUPABASE_DB_USER=postgres.xxx
SUPABASE_DB_PASSWORD=๋น„๋ฐ€๋ฒˆํ˜ธ
SUPABASE_DB_NAME=postgres
SUPABASE_DB_PORT=5432

# JWT ์„ค์ •
JWT_SECRET=JWT_์‹œํฌ๋ฆฟ_ํ‚ค
JWT_EXPIRES_IN=7d
JWT_REFRESH_SECRET=๋ฆฌํ”„๋ ˆ์‹œ_์‹œํฌ๋ฆฟ
JWT_REFRESH_EXPIRES_IN=30d

# ์ด๋ฉ”์ผ ์„œ๋น„์Šค (Resend)
RESEND_API_KEY=re_XXXXXXXXXXXX        # Resend API ํ‚ค
EMAIL_FROM=noreply@teamitaka.com      # ๋„๋ฉ”์ธ ์ธ์ฆ ํ•„์ˆ˜

# SMS ์„œ๋น„์Šค (Solapi)
SOLAPI_API_KEY=Solapi_API_ํ‚ค
SOLAPI_API_SECRET=Solapi_์‹œํฌ๋ฆฟ
SOLAPI_SENDER=๋ฐœ์‹ ๋ฒˆํ˜ธ                 # ๋“ฑ๋ก๋œ ๋ฐœ์‹ ๋ฒˆํ˜ธ

# iOS ํ‘ธ์‹œ ์•Œ๋ฆผ (APNs)
APNS_KEY_ID=ํ‚คID
APNS_TEAM_ID=ํŒ€ID
APNS_BUNDLE_ID=com.teamitaka.app

# ๊ตฌ๊ธ€ OAuth
GOOGLE_CLIENT_ID=๊ตฌ๊ธ€_ํด๋ผ์ด์–ธํŠธ_ID
GOOGLE_CLIENT_SECRET=๊ตฌ๊ธ€_ํด๋ผ์ด์–ธํŠธ_์‹œํฌ๋ฆฟ
GOOGLE_CALLBACK_URL=http://localhost:8080/api/auth/google/callback

# Firebase Phone Authentication
FIREBASE_PROJECT_ID=your-firebase-project-id
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
FIREBASE_CLIENT_EMAIL=firebase-adminsdk-xxxxx@your-project.iam.gserviceaccount.com
FIREBASE_API_KEY=your_web_api_key                    # Firebase Console โ†’ ํ”„๋กœ์ ํŠธ ์„ค์ • โ†’ ์›น API ํ‚ค

# CORS
CORS_ORIGIN=http://localhost:3000     # ํ”„๋ก ํŠธ์—”๋“œ URL
CORS_CREDENTIALS=true

# Supabase Storage (์ด๋ฏธ์ง€ ์—…๋กœ๋“œ)
SUPABASE_URL=https://xxx.supabase.co
SUPABASE_ANON_KEY=์ต๋ช…_ํ‚ค
SUPABASE_STORAGE_BUCKET=๋ฒ„ํ‚ท๋ช…          # ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ์šฉ ๋ฒ„ํ‚ท (์˜ˆ: recruitment-images)
SUPABASE_SERVICE_KEY=์„œ๋น„์Šค_ํ‚ค          # (์„ ํƒ์‚ฌํ•ญ)

ํ™˜๊ฒฝ ํŒŒ์ผ

  • .env.development - ๊ฐœ๋ฐœ ํ™˜๊ฒฝ
  • .env.production - ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ
  • .env.test - ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ
  • env.supabase - Supabase ์„ค์ •

โš ๏ธ ์ฃผ์˜: .env ํŒŒ์ผ์€ ์ ˆ๋Œ€ ๋ฒ„์ „ ๊ด€๋ฆฌ์— ์ปค๋ฐ‹ํ•˜์ง€ ๋งˆ์„ธ์š”!

๐Ÿ“– ๋ฌธ์„œ

docs/ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์ถ”๊ฐ€ ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

๐Ÿ› ๏ธ ์œ ํ‹ธ๋ฆฌํ‹ฐ ์Šคํฌ๋ฆฝํŠธ

scripts/ ๋””๋ ‰ํ† ๋ฆฌ์˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ ์Šคํฌ๋ฆฝํŠธ:

  • verify_hashtags.sql - ํ‚ค์›Œ๋“œ ๋ฐ์ดํ„ฐ ์ •ํ•ฉ์„ฑ ๊ฒ€์ฆ SQL

๐Ÿค ๊ธฐ์—ฌํ•˜๊ธฐ

๊ธฐ์—ฌ๋ฅผ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค! ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ๋”ฐ๋ผ์ฃผ์„ธ์š”:

๊ธฐ์—ฌ ํ”„๋กœ์„ธ์Šค

  1. ์ €์žฅ์†Œ ํฌํฌํ•˜๊ธฐ
  2. ๊ธฐ๋Šฅ ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ (git checkout -b feature/๋ฉ‹์ง„-๊ธฐ๋Šฅ)
  3. ๋ณ€๊ฒฝ ์‚ฌํ•ญ ์ปค๋ฐ‹ (git commit -m 'feat: ๋ฉ‹์ง„ ๊ธฐ๋Šฅ ์ถ”๊ฐ€')
  4. ๋ธŒ๋žœ์น˜์— ํ‘ธ์‹œ (git push origin feature/๋ฉ‹์ง„-๊ธฐ๋Šฅ)
  5. Pull Request ์—ด๊ธฐ

์ปค๋ฐ‹ ์ปจ๋ฒค์…˜

Conventional Commits ๋ช…์„ธ๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค:

ํƒ€์ž… ์„ค๋ช… ์˜ˆ์‹œ
feat: ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ feat: ์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ์ถ”๊ฐ€
fix: ๋ฒ„๊ทธ ์ˆ˜์ • fix: ๋กœ๊ทธ์ธ ์—๋Ÿฌ ์ˆ˜์ •
docs: ๋ฌธ์„œ ๋ณ€๊ฒฝ docs: README ์—…๋ฐ์ดํŠธ
style: ์ฝ”๋“œ ํฌ๋งทํŒ… style: ๋“ค์—ฌ์“ฐ๊ธฐ ์ˆ˜์ •
refactor: ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง refactor: ์ธ์ฆ ๋กœ์ง ๊ฐœ์„ 
test: ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€/์ˆ˜์ • test: ํšŒ์›๊ฐ€์ž… ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€
chore: ๊ธฐํƒ€ ๋ณ€๊ฒฝ์‚ฌํ•ญ chore: ์˜์กด์„ฑ ์—…๋ฐ์ดํŠธ

์ฝ”๋“œ ๋ฆฌ๋ทฐ

  • ๋ชจ๋“  Pull Request๋Š” ๋ฆฌ๋ทฐ๋ฅผ ๊ฑฐ์นฉ๋‹ˆ๋‹ค
  • ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค
  • ์ฝ”๋“œ ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ๋ฅผ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค

๐Ÿ“ ๋ผ์ด์„ ์Šค

์ด ํ”„๋กœ์ ํŠธ๋Š” ISC ๋ผ์ด์„ ์Šค๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

๐Ÿ‘ฅ ํŒ€

TeamItaka ๊ฐœ๋ฐœํŒ€

  • ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ
  • API ์„ค๊ณ„
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์•„ํ‚คํ…์ฒ˜
  • DevOps ๋ฐ ๋ฐฐํฌ

๐Ÿ› ๋ฒ„๊ทธ ๋ฆฌํฌํŠธ ๋ฐ ๊ธฐ๋Šฅ ์š”์ฒญ

๋ฒ„๊ทธ ๋ฆฌํฌํŠธ์™€ ๊ธฐ๋Šฅ ์š”์ฒญ์€ GitHub Issues๋ฅผ ์ด์šฉํ•ด ์ฃผ์„ธ์š”.

๋ฒ„๊ทธ ๋ฆฌํฌํŠธ ์ž‘์„ฑ ์‹œ ํฌํ•จํ•  ๋‚ด์šฉ

  • ๋ฒ„๊ทธ ์„ค๋ช…
  • ์žฌํ˜„ ๋‹จ๊ณ„
  • ์˜ˆ์ƒ ๋™์ž‘
  • ์‹ค์ œ ๋™์ž‘
  • ์Šคํฌ๋ฆฐ์ƒท (ํ•„์š”์‹œ)
  • ํ™˜๊ฒฝ ์ •๋ณด (OS, Node.js ๋ฒ„์ „ ๋“ฑ)

๊ธฐ๋Šฅ ์š”์ฒญ ์ž‘์„ฑ ์‹œ ํฌํ•จํ•  ๋‚ด์šฉ

  • ๊ธฐ๋Šฅ ์„ค๋ช…
  • ์‚ฌ์šฉ ์‚ฌ๋ก€
  • ์˜ˆ์ƒ๋˜๋Š” ์ด์ 
  • ์ถ”๊ฐ€ ์ปจํ…์ŠคํŠธ

๐Ÿ“ฎ ์—ฐ๋ฝ์ฒ˜

์งˆ๋ฌธ์ด๋‚˜ ์ง€์›์ด ํ•„์š”ํ•˜์‹  ๊ฒฝ์šฐ ๊ฐœ๋ฐœํŒ€์— ๋ฌธ์˜ํ•ด ์ฃผ์„ธ์š”.


๐ŸŒŸ ํ”„๋กœ์ ํŠธ ํ˜„ํ™ฉ

ํ•ญ๋ชฉ ์ƒํƒœ
๋ฒ„์ „ 1.7.1
๋งˆ์ง€๋ง‰ ์—…๋ฐ์ดํŠธ 2026-01-31
์œ ์ง€๋ณด์ˆ˜ ํ™œ๋ฐœํžˆ ์ง„ํ–‰ ์ค‘
๋ฌธ์„œํ™” ์™„๋ฃŒ
ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€ ์ง„ํ–‰ ์ค‘
Swagger ๋ฌธ์„œ API Docs

๐Ÿ“Š ๊ฐœ๋ฐœ ํ˜„ํ™ฉ (Development Status)

๋งˆ์ง€๋ง‰ ๋ถ„์„: 2026-01-31 | ์ „์ฒด ์™„๋ฃŒ์œจ: 97%

๐ŸŽฏ ์ „์ฒด ๊ฐœ๋ฐœ ์ง„ํ–‰๋ฅ 

๊ตฌ๋ถ„ ์™„๋ฃŒ ์ง„ํ–‰์ค‘ ๋ฏธ๊ตฌํ˜„ ์™„๋ฃŒ์œจ
API ์—”๋“œํฌ์ธํŠธ 90๊ฐœ 2๊ฐœ 2๊ฐœ 97%
๋ผ์šฐํŠธ ํŒŒ์ผ 20๊ฐœ 2๊ฐœ 0๊ฐœ 91%
์ปจํŠธ๋กค๋Ÿฌ 22๊ฐœ 0๊ฐœ 0๊ฐœ 100%
์„œ๋น„์Šค 19๊ฐœ 0๊ฐœ 0๊ฐœ 100%
๋ชจ๋ธ 32๊ฐœ 0๊ฐœ 0๊ฐœ 100%

๐Ÿ”ง ๊ธฐ๋Šฅ๋ณ„ ๊ตฌํ˜„ ํ˜„ํ™ฉ

๊ธฐ๋Šฅ ์ƒํƒœ ์—”๋“œํฌ์ธํŠธ ๋น„๊ณ 
๐Ÿ” ์ธ์ฆ (Auth) โœ… ์™„๋ฃŒ 8๊ฐœ JWT, OAuth, Firebase Phone
๐Ÿ“ฑ SMS ์ธ์ฆ โœ… ์™„๋ฃŒ 3๊ฐœ Solapi, sessionId ๊ธฐ๋ฐ˜
๐Ÿ“ง ์ด๋ฉ”์ผ ์ธ์ฆ โœ… ์™„๋ฃŒ 2๊ฐœ Resend, Rate Limiting
๐Ÿง  MBTI โœ… ์™„๋ฃŒ 1๊ฐœ ์œ ํ˜• ์ €์žฅ/์กฐํšŒ
๐Ÿ“ฒ ํ‘ธ์‹œ ์•Œ๋ฆผ โœ… ์™„๋ฃŒ - iOS APNs, ํŠธ๋ฆฌ๊ฑฐ ๊ธฐ๋ฐ˜
๐Ÿ“ข ๋ชจ์ง‘๊ณต๊ณ  โœ… ์™„๋ฃŒ 8๊ฐœ CRUD, ์Šคํฌ๋žฉ, ํ•ด์‹œํƒœ๊ทธ, ์กฐํšŒ์ˆ˜
๐Ÿ“ ์ง€์› ๊ด€๋ฆฌ โœ… ์™„๋ฃŒ 4๊ฐœ ์ง€์›, ์Šน์ธ/๊ฑฐ์ ˆ, ํฌํŠธํด๋ฆฌ์˜ค
๐Ÿ“Š ํ”„๋กœ์ ํŠธ โœ… ์™„๋ฃŒ 11๊ฐœ CRUD, ํ‚ฅ์˜คํ”„, ํŒ€์› ๊ด€๋ฆฌ, ์ฆ๊ฒจ์ฐพ๊ธฐ
โœ… ํ•  ์ผ (Todo) โœ… ์™„๋ฃŒ 4๊ฐœ ํ”„๋กœ์ ํŠธ๋ณ„ ํ•  ์ผ ๊ด€๋ฆฌ
๐Ÿ“… ํƒ€์ž„๋ผ์ธ โœ… ์™„๋ฃŒ 4๊ฐœ ํ”„๋กœ์ ํŠธ ํƒ€์ž„๋ผ์ธ
๐Ÿ‘ฅ ํŒ€์› ๊ด€๋ฆฌ โœ… ์™„๋ฃŒ 2๊ฐœ ์—ญํ•  ์กฐํšŒ/์ˆ˜์ •
โญ ํ‰๊ฐ€ (Review) โœ… ์™„๋ฃŒ 6๊ฐœ ํŒ€์› ์ƒํ˜ธํ‰๊ฐ€ (5๊ฐœ ํ•ญ๋ชฉ)
๐Ÿ‘ค ํ”„๋กœํ•„ โœ… ์™„๋ฃŒ 7๊ฐœ ์กฐํšŒ, ์ˆ˜์ •, ์ธ์ฆ ์ƒํƒœ, ํ‰์ 
๐Ÿ’ฌ ๋Œ“๊ธ€ โœ… ์™„๋ฃŒ 2๊ฐœ ๋ชจ์ง‘๊ณต๊ณ  ๋Œ“๊ธ€
๐Ÿ–ผ๏ธ ์—…๋กœ๋“œ โœ… ์™„๋ฃŒ 2๊ฐœ Supabase Storage
๐Ÿ“Œ ์Šคํฌ๋žฉ โœ… ์™„๋ฃŒ 2๊ฐœ ๋ชจ์ง‘๊ณต๊ณ  ์Šคํฌ๋žฉ
๐Ÿ›ก๏ธ ๊ด€๋ฆฌ์ž โœ… ์™„๋ฃŒ 3๊ฐœ ์ธ์ฆ ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ
๐Ÿ“ˆ ๋Œ€์‹œ๋ณด๋“œ โœ… ์™„๋ฃŒ 1๊ฐœ ํ†ต๊ณ„, ์•Œ๋ฆผ, ํƒ€์ž„๋ผ์ธ
๐Ÿ’พ ์ž„์‹œ์ €์žฅ ๐ŸŸก ๋ถ€๋ถ„ 1๊ฐœ ์ƒ์„ฑ๋งŒ ๊ตฌํ˜„
๐Ÿ“‹ ํ”„๋กœ์ ํŠธ ๊ฒŒ์‹œ๋ฌผ โœ… ์™„๋ฃŒ 3๊ฐœ ํ”„๋กœ์ ํŠธ ํ”ผ๋“œ
๐Ÿ” ๊ฒ€์ƒ‰ โœ… ์™„๋ฃŒ 1๊ฐœ ํ†ตํ•ฉ ๊ฒ€์ƒ‰
๐Ÿ—ณ๏ธ ํˆฌํ‘œ (Vote) โš ๏ธ ๋ฏธ๋“ฑ๋ก 4๊ฐœ ์ฝ”๋“œ ์™„์„ฑ, app.js ๋“ฑ๋ก ํ•„์š”
๐Ÿ“† ์ผ์ • (Schedule) โš ๏ธ ๋ฏธ๋“ฑ๋ก 4๊ฐœ ์ฝ”๋“œ ์™„์„ฑ, app.js ๋“ฑ๋ก ํ•„์š”

โš ๏ธ ํ•ด๊ฒฐ ํ•„์š” ์‚ฌํ•ญ

์šฐ์„ ์ˆœ์œ„ ์ด์Šˆ ์˜ํ–ฅ ๋ฒ”์œ„ ์˜ˆ์ƒ ์‹œ๊ฐ„
๐Ÿ”ด ๊ธด๊ธ‰ Vote ๋ผ์šฐํŠธ app.js ๋ฏธ๋“ฑ๋ก ํˆฌํ‘œ ๊ธฐ๋Šฅ ์ „์ฒด 5๋ถ„
๐Ÿ”ด ๊ธด๊ธ‰ Schedule ๋ผ์šฐํŠธ app.js ๋ฏธ๋“ฑ๋ก ์ผ์ • ๊ด€๋ฆฌ ์ „์ฒด 5๋ถ„
๐ŸŸก ๋ณดํ†ต /api/auth/logout ๋ฏธ๊ตฌํ˜„ ๋กœ๊ทธ์•„์›ƒ 1์‹œ๊ฐ„
๐ŸŸก ๋ณดํ†ต /api/auth/refresh ๋ฏธ๊ตฌํ˜„ ํ† ํฐ ๊ฐฑ์‹  2์‹œ๊ฐ„
๐ŸŸก ๋ณดํ†ต /api/auth/password/reset ๋ฏธ๊ตฌํ˜„ ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • 4์‹œ๊ฐ„
โœ… ์™„๋ฃŒ /api/applications/:id/cancel ์ง€์› ์ทจ์†Œ v1.5.5
โœ… ์™„๋ฃŒ ์•Œ๋ฆผ ์‹œ์Šคํ…œ API ์•Œ๋ฆผ ๊ธฐ๋Šฅ v1.5.5
๐ŸŸข ๋‚ฎ์Œ ํšŒ์˜๋ก API ๋ฏธ๊ตฌํ˜„ ํšŒ์˜ ๊ด€๋ฆฌ 1์ผ
๐ŸŸข ๋‚ฎ์Œ QR ์ดˆ๋Œ€ API ๋ฏธ๊ตฌํ˜„ ํ”„๋กœ์ ํŠธ ์ดˆ๋Œ€ 4์‹œ๊ฐ„

๐Ÿ—‚๏ธ ๋ ˆ์ด์–ด๋ณ„ ํ˜„ํ™ฉ

๋ ˆ์ด์–ด ํŒŒ์ผ ์ˆ˜ ๊ตฌํ˜„ ํ˜„ํ™ฉ
Routes 20๊ฐœ 18๊ฐœ ๋“ฑ๋ก, 2๊ฐœ ๋ฏธ๋“ฑ๋ก (vote, schedule)
Controllers 24๊ฐœ ์ „์ฒด ๊ตฌํ˜„ ์™„๋ฃŒ
Services 21๊ฐœ ์ „์ฒด ๊ตฌํ˜„ ์™„๋ฃŒ
Models 33๊ฐœ ์ „์ฒด ๊ตฌํ˜„ ์™„๋ฃŒ (DeviceToken ์ถ”๊ฐ€)
Middlewares 9๊ฐœ auth, admin, optional, error, validation, upload, rateLimit, uuidValidation ๋“ฑ

๐Ÿ“‹ ์ƒํƒœ ๋ฒ”๋ก€

์ƒํƒœ ์„ค๋ช…
โœ… ์™„๋ฃŒ ๊ธฐ๋Šฅ ์™„์ „ ๊ตฌํ˜„ ๋ฐ ๋™์ž‘ ํ™•์ธ
๐ŸŸก ๋ถ€๋ถ„ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ ๊ตฌํ˜„, ์ผ๋ถ€ ๊ธฐ๋Šฅ ๋ฏธ์™„์„ฑ
โš ๏ธ ๋ฏธ๋“ฑ๋ก ์ฝ”๋“œ ์™„์„ฑ๋˜์—ˆ์œผ๋‚˜ ๋ผ์šฐํŠธ ๋ฏธ๋“ฑ๋ก
โŒ ๋ฏธ๊ตฌํ˜„ ๊ตฌํ˜„ ํ•„์š”
๐Ÿ”ด ๊ธด๊ธ‰ ์ฆ‰์‹œ ํ•ด๊ฒฐ ํ•„์š” (5๋ถ„ ์ด๋‚ด)
๐ŸŸก ๋ณดํ†ต ๋‹จ๊ธฐ ํ•ด๊ฒฐ (1-2์ผ)
๐ŸŸข ๋‚ฎ์Œ ์ค‘๊ธฐ ํ•ด๊ฒฐ (1์ฃผ)

๐Ÿ”„ ๋ณ€๊ฒฝ ์ด๋ ฅ

v1.7.1 (2026-01-31)

  • ๐Ÿ“ ํ”„๋กœ์ ํŠธ ์ œ๋ชฉ 15์ž ์ œํ•œ ์ถ”๊ฐ€
    • POST /api/projects - ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ์‹œ ์ œ๋ชฉ 15์ž ์ œํ•œ
    • PUT /api/projects/:id - ํ”„๋กœ์ ํŠธ ์ˆ˜์ • ์‹œ ์ œ๋ชฉ 15์ž ์ œํ•œ
    • POST /api/projects/from-recruitment/:id - ํ‚ฅ์˜คํ”„ ์‹œ ์ œ๋ชฉ 15์ž ์ œํ•œ
  • โญ ํ‰๊ฐ€ API ๋‹ด๋‹น ์—…๋ฌด ํ•„๋“œ ์ถ”๊ฐ€
    • GET /api/evaluations/given ์‘๋‹ต์— target_member_task ํ•„๋“œ ์ถ”๊ฐ€
    • ํ‰๊ฐ€ ๋Œ€์ƒ์ž์˜ ํ”„๋กœ์ ํŠธ ๋‚ด ๋‹ด๋‹น ์—…๋ฌด ํ‘œ์‹œ ์ง€์›
  • ๐Ÿ“ Swagger ๋ฌธ์„œ ์—…๋ฐ์ดํŠธ
    • ํ”„๋กœ์ ํŠธ ์ œ๋ชฉ 15์ž ์ œํ•œ ๋ช…์‹œ
    • ํ‰๊ฐ€ API ์‘๋‹ต ์Šคํ‚ค๋งˆ ์ƒ์„ธํ™”

v1.7.0 (2026-01-26)

  • ๐Ÿ“ฑ SMS ์ธ์ฆ ์‹œ์Šคํ…œ ๊ตฌํ˜„
    • Solapi ํ†ตํ•ฉ์œผ๋กœ SMS ๋ฐœ์†ก
    • sessionId ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ์ธ์ฆ ํ”Œ๋กœ์šฐ
    • node-cache ๊ธฐ๋ฐ˜ ์ธ์ฆ ์ฝ”๋“œ ๊ด€๋ฆฌ
    • POST /api/sms/send, POST /api/sms/verify API ์ถ”๊ฐ€
  • ๐Ÿง  MBTI ์œ ํ˜• ์‹œ์Šคํ…œ
    • MBTI ๊ฒฐ๊ณผ ์ €์žฅ API ์ถ”๊ฐ€ (POST /api/users/mbti)
    • /api/auth/me ์‘๋‹ต์— mbtiType ํ•„๋“œ ์ถ”๊ฐ€
  • ๐Ÿ“ง ์ด๋ฉ”์ผ ์„œ๋น„์Šค ๋ณ€๊ฒฝ
    • SendGrid โ†’ Resend๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜
    • TimiTaka ๋ธŒ๋žœ๋”ฉ ์ด๋ฉ”์ผ ํ…œํ”Œ๋ฆฟ
    • ๋งˆ์Šค์ฝ”ํŠธ ์บ๋ฆญํ„ฐ ์ด๋ฏธ์ง€ ์ถ”๊ฐ€
  • ๐Ÿ“ฒ iOS ํ‘ธ์‹œ ์•Œ๋ฆผ
    • APNs (Apple Push Notification service) ์ง€์›
    • ์ดˆ๋Œ€/์ƒํƒœ๋ณ€๊ฒฝ/๋ฆฌ๋ทฐ ํ‘ธ์‹œ ํŠธ๋ฆฌ๊ฑฐ
    • DeviceToken ๋ชจ๋ธ๋กœ ํ† ํฐ ๊ด€๋ฆฌ
  • โญ ํ”„๋กœ์ ํŠธ ์ฆ๊ฒจ์ฐพ๊ธฐ API ์ถ”๊ฐ€ (POST /api/projects/:id/favorite)
  • ๐Ÿ” ๋น„๋ฐ€๋ฒˆํ˜ธ ๊ฒ€์ฆ ๊ทœ์น™ ๊ฐ„์†Œํ™”
    • ๊ธฐ์กด: ๋Œ€๋ฌธ์ž, ์†Œ๋ฌธ์ž, ์ˆซ์ž, ํŠน์ˆ˜๋ฌธ์ž ๊ฐ๊ฐ ํ•„์ˆ˜, 8~15์ž
    • ๋ณ€๊ฒฝ: ์˜๋ฌธ + ์ˆซ์ž ํฌํ•จ, 8์ž ์ด์ƒ์ด๋ฉด ๋ชจ๋“  ๋ฌธ์ž ํ—ˆ์šฉ
  • ๐Ÿ›ก๏ธ UUID ๊ฒ€์ฆ ๋ฏธ๋“ค์›จ์–ด ์ถ”๊ฐ€ (API ๋ผ์šฐํŠธ ๋ณด์•ˆ ๊ฐ•ํ™”)
  • ๐Ÿ› IPv6 ์—ฐ๊ฒฐ ์ด์Šˆ ์ˆ˜์ • (Render IPv4 ๊ฐ•์ œ)
  • ๐Ÿ“ Swagger ๋ฌธ์„œ์™€ ๊ฒ€์ฆ ์Šคํ‚ค๋งˆ ๋™๊ธฐํ™”

v1.6.0 (2025-12-28)

  • โœจ ํšŒ์˜๋ก API ์ „์ฒด ๊ตฌํ˜„ (5๊ฐœ ์—”๋“œํฌ์ธํŠธ)
    • GET /api/projects/:id/meetings - ํšŒ์˜๋ก ๋ชฉ๋ก ์กฐํšŒ (ํ”ผ๋“œ์šฉ)
    • GET /api/projects/:id/meetings/:meeting_id - ํšŒ์˜๋ก ์ƒ์„ธ ์กฐํšŒ
    • POST /api/projects/:id/meetings - ํšŒ์˜๋ก ์ƒ์„ฑ
    • PUT /api/projects/:id/meetings/:meeting_id - ํšŒ์˜๋ก ์ˆ˜์ •
    • DELETE /api/projects/:id/meetings/:meeting_id - ํšŒ์˜๋ก ์‚ญ์ œ
  • ๐Ÿ“ฆ MeetingNotes ๋ชจ๋ธ ์ถ”๊ฐ€
    • ํ•„๋“œ: meeting_id, project_id, created_by, title, content, meeting_date
    • ๊ด€๊ณ„: Project, User (Creator) ์—ฐ๊ฒฐ
  • ๐Ÿ“ Swagger ๋ฌธ์„œ ์—…๋ฐ์ดํŠธ
    • MeetingNotes ์Šคํ‚ค๋งˆ ๋ฐ ์—”๋“œํฌ์ธํŠธ ๋ฌธ์„œํ™”
    • ํ”ผ๋“œ ๊ธฐ๋Šฅ๊ณผ์˜ ์—ฐ๊ณ„ ์„ค๋ช… ์ถ”๊ฐ€

v1.5.5 (2025-12-21)

  • โœจ Notifications API ์ „์ฒด ๊ตฌํ˜„ (5๊ฐœ ์—”๋“œํฌ์ธํŠธ)
    • GET /api/notifications - ์•Œ๋ฆผ ๋ชฉ๋ก ์กฐํšŒ (ํŽ˜์ด์ง€๋„ค์ด์…˜, ๋ฏธ์ฝ์Œ ํ•„ํ„ฐ)
    • GET /api/notifications/unread-count - ์ฝ์ง€ ์•Š์€ ์•Œ๋ฆผ ๊ฐœ์ˆ˜
    • PUT /api/notifications/:id/read - ๊ฐœ๋ณ„ ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ
    • PUT /api/notifications/read-all - ๋ชจ๋“  ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ
    • DELETE /api/notifications/:id - ์•Œ๋ฆผ ์‚ญ์ œ
  • โœจ Application Cancel API ๊ตฌํ˜„ (3๊ฐœ ์—”๋“œํฌ์ธํŠธ)
    • POST /api/applications/:id/cancel - ์ง€์› ์ทจ์†Œ
    • DELETE /api/applications/:id - ์ง€์› ์ทจ์†Œ (DELETE ๋ฐฉ์‹)
    • GET /api/applications/mine - ๋‚ด ์ง€์› ๋ชฉ๋ก ์กฐํšŒ
  • ๐Ÿ› Notification ๋ชจ๋ธ PostgreSQL snake_case ๋งคํ•‘ ์ˆ˜์ •
    • isRead โ†’ is_read ์ปฌ๋Ÿผ ๋งคํ•‘ ๋ฒ„๊ทธ ์ˆ˜์ •
    • underscored: true ์˜ต์…˜ ์ถ”๊ฐ€
    • ํƒ€์ž„์Šคํƒฌํ”„ ํ•„๋“œ ๋ช…์‹œ์  ๋งคํ•‘ (created_at, updated_at)
  • ๐Ÿ—„๏ธ Application ์„œ๋น„์Šค ๊ฐœ์„ 
    • ์ง€์› ์ทจ์†Œ ์‹œ ํฌํŠธํด๋ฆฌ์˜ค ์—ฐ๊ฒฐ ์ž๋™ ์‚ญ์ œ
    • ์ทจ์†Œ ํ›„ ๋ชจ์ง‘๊ณต๊ณ  ์ƒํƒœ ์ž๋™ ์žฌํ™œ์„ฑํ™” (CLOSED โ†’ ACTIVE)
    • ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ๋กœ ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ ๋ณด์žฅ

v1.5.4 (2025-12-20)

  • โœจ ๋‚ด ํ”„๋กœ์ ํŠธ API ์ตœ์‹  ํ”ผ๋“œ ์‹œ๊ฐ„ ์ถ”๊ฐ€ (GET /api/projects/mine)
    • ์‘๋‹ต์— last_feed_at ํ•„๋“œ ์ถ”๊ฐ€ (ISO 8601 timestamp ๋˜๋Š” null)
    • ํ”„๋กœ์ ํŠธ ์นด๋“œ์— '2์‹œ๊ฐ„ ์ „' ํ˜•ํƒœ์˜ ์ƒ๋Œ€ ์‹œ๊ฐ„ ํ‘œ์‹œ ์ง€์›
    • project_posts ํ…Œ์ด๋ธ”์˜ ์ตœ์‹  ๊ฒŒ์‹œ๋ฌผ ์‹œ๊ฐ„ ๊ธฐ์ค€
  • ๐Ÿ› ๋‚ด ๋ชจ์ง‘๊ณต๊ณ  ๋ชฉ๋ก CLOSED ์ƒํƒœ ํ•„ํ„ฐ๋ง ๋ฒ„๊ทธ ์ˆ˜์ •
    • ํ”„๋กœ์ ํŠธ ํ‚ฅ์˜คํ”„ ํ›„ '๋ชจ์ง‘์ค‘' ํƒญ์—์„œ ์‚ฌ๋ผ์ง€๋„๋ก ์ˆ˜์ •
    • ACTIVE ์ƒํƒœ์˜ ๋ชจ์ง‘๊ณต๊ณ ๋งŒ ์กฐํšŒ๋˜๋„๋ก ์ฟผ๋ฆฌ ์ˆ˜์ •

v1.5.3 (2025-12-20)

  • โœจ ํ”„๋กœ์ ํŠธ ํ‚ฅ์˜คํ”„ API ๊ฐœ์„  (POST /api/projects/from-recruitment/:id)
    • ํ”„๋ก ํŠธ์—”๋“œ์—์„œ ์ง์ ‘ ํ”„๋กœ์ ํŠธ ์ œ๋ชฉ ์ž…๋ ฅ
    • ๋‹ค์ง(resolution) ํ•„๋“œ ์ถ”๊ฐ€
    • ์Šน์ธ๋œ ์ง€์›์ž ์ค‘ ํŒ€์› ์„ ํƒ ๊ธฐ๋Šฅ (memberUserIds ๋ฐฐ์—ด)
    • Recruitment์—์„œ project_type ์ž๋™ ๋ณต์‚ฌ (course/side)
  • ๐Ÿ—„๏ธ Project ๋ชจ๋ธ ์Šคํ‚ค๋งˆ ํ™•์žฅ
    • resolution: ํ”„๋กœ์ ํŠธ ๋‹ค์ง (TEXT)
    • project_type: ํ”„๋กœ์ ํŠธ ์œ ํ˜• (ENUM: 'course', 'side')
  • ๐Ÿ› ๋ฒ„๊ทธ ์ˆ˜์ •
    • Application status ๊ฒ€์ƒ‰ ๋ฒ„๊ทธ ์ˆ˜์ • (ACCEPTED โ†’ memberUserIds ์ง์ ‘ ์ „๋‹ฌ)

v1.5.2 (2025-12-18)

  • ๐Ÿ› Application API Sequelize alias ๋ฒ„๊ทธ ์ˆ˜์ •
    • as: "ProjectMembers" ๋ˆ„๋ฝ์œผ๋กœ ์ธํ•œ 500 ์—๋Ÿฌ ํ•ด๊ฒฐ
    • ํฌํŠธํด๋ฆฌ์˜ค ํ”„๋กœ์ ํŠธ ๊ฒ€์ฆ ๋กœ์ง ์ •์ƒํ™”
  • ๐Ÿ“ Swagger API ๋ฌธ์„œ ๋Œ€๊ทœ๋ชจ ์—…๋ฐ์ดํŠธ
    • Profile API 4๊ฐœ ์—”๋“œํฌ์ธํŠธ ์ถ”๊ฐ€ (/me, /detail, /verification, PUT /)
    • Vote API 4๊ฐœ ์—”๋“œํฌ์ธํŠธ ๋ฌธ์„œํ™”
    • Schedule API 4๊ฐœ ์—”๋“œํฌ์ธํŠธ ๋ฌธ์„œํ™”
    • Upload API /profile-image ์—”๋“œํฌ์ธํŠธ ์ถ”๊ฐ€
    • /projects/mine ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ์ƒ์„ธ ๋ฌธ์„œํ™” (status, evaluation_status, limit, offset)
    • /applications/{recruitment_id} portfolio_project_ids ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฌธ์„œํ™”
  • ๐Ÿ”ง API ๋ฌธ์„œ ํ’ˆ์งˆ ๊ฐœ์„ 
    • ์‘๋‹ต ์Šคํ‚ค๋งˆ ์ƒ์„ธํ™”
    • ์—๋Ÿฌ ์ฝ”๋“œ ๋ฐ ๋ฉ”์‹œ์ง€ ๋ฌธ์„œํ™”

v1.5.1 (2025-12-02)

  • ๐Ÿ”ง Sequelize ๋ชจ๋ธ PostgreSQL ํ˜ธํ™˜์„ฑ ๊ฐœ์„ 
    • 12๊ฐœ ๋ชจ๋ธ์— tableName ์†์„ฑ ์ถ”๊ฐ€ (PostgreSQL snake_case ํ…Œ์ด๋ธ”๋ช… ๋งคํ•‘)
    • ์˜ํ–ฅ๋ฐ›๋Š” ๋ชจ๋ธ: User, Project, ProjectMembers, Recruitment, Application, Review, Comment, Todo, Timeline, Vote, Schedule, Notification ๋“ฑ
  • ๐Ÿ› ๋ชจ๋ธ ์Šคํ‚ค๋งˆ ๋ฒ„๊ทธ ์ˆ˜์ •
    • ProjectMembers ๋ชจ๋ธ: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ์™€ ์ผ์น˜ํ•˜๋„๋ก ์ˆ˜์ •
    • Todo ๋ชจ๋ธ: ์ปฌ๋Ÿผ ์ •์˜๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ์— ๋งž๊ฒŒ ์ˆ˜์ •
    • Project ๋ชจ๋ธ: ์กด์žฌํ•˜์ง€ ์•Š๋Š” role ์ปฌ๋Ÿผ ์ œ๊ฑฐ
  • โšก ์ฟผ๋ฆฌ ์ตœ์ ํ™”
    • ProjectMembers include์—์„œ ๋ถˆํ•„์š”ํ•œ attributes ์ œ์•ฝ ์ œ๊ฑฐ

v1.5.0 (2025-11-24)

  • ๐Ÿ“ฑ Firebase ์ „ํ™”๋ฒˆํ˜ธ ์ธ์ฆ ๊ตฌํ˜„
    • Firebase Admin SDK ํ†ตํ•ฉ (firebase-admin@^12.0.0)
    • ์ „ํ™”๋ฒˆํ˜ธ ๊ธฐ๋ฐ˜ ์‚ฌ์šฉ์ž ์ธ์ฆ API ์ถ”๊ฐ€ (POST /api/auth/phone/verify)
    • Users ํ…Œ์ด๋ธ” ์Šคํ‚ค๋งˆ ํ™•์žฅ:
      • firebase_phone_uid: Firebase Phone Auth UID
      • phone_number: E.164 ํ˜•์‹ ์ „ํ™”๋ฒˆํ˜ธ ์ €์žฅ
      • phone_verified: ์ „ํ™”๋ฒˆํ˜ธ ์ธ์ฆ ์™„๋ฃŒ ์—ฌ๋ถ€
      • phone_verified_at: ์ธ์ฆ ์™„๋ฃŒ ์‹œ๊ฐ
    • ์‹ ๊ทœ ์‚ฌ์šฉ์ž ์ž๋™ ์ƒ์„ฑ ๋ฐ JWT ํ† ํฐ ๋ฐœ๊ธ‰
    • ๊ธฐ์กด ์‚ฌ์šฉ์ž ์ „ํ™”๋ฒˆํ˜ธ ์—…๋ฐ์ดํŠธ ์ง€์›
    • requirePhoneVerified ๋ฏธ๋“ค์›จ์–ด ์ถ”๊ฐ€ (์ „ํ™”๋ฒˆํ˜ธ ์ธ์ฆ ํ•„์ˆ˜ ๋ผ์šฐํŠธ์šฉ)
    • ๋กœ์ปฌ(MySQL) ๋ฐ ํ”„๋กœ๋•์…˜(Supabase PostgreSQL) ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์™„๋ฃŒ
    • ์ „ํ™”๋ฒˆํ˜ธ ์ธ์ฆ ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ ํฌํ•จ (test-phone-auth.js)
  • ๐Ÿ› User ๋ชจ๋ธ ๋ฒ„๊ทธ ์ˆ˜์ • ๋ฐ ํ™˜๊ฒฝ๋ณ„ ํ˜ธํ™˜์„ฑ ๊ฐœ์„ 
    • ์ค‘๋ณต๋œ user_type ํ•„๋“œ ์ œ๊ฑฐ (role ํ•„๋“œ์™€ ์ค‘๋ณต, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปฌ๋Ÿผ ์˜ค๋ฅ˜ ํ•ด๊ฒฐ)
    • ํ™˜๊ฒฝ๋ณ„ ํƒ€์ž„์Šคํƒฌํ”„ ์ปฌ๋Ÿผ๋ช… ์„ค์ • ์ถ”๊ฐ€:
      • Local (MySQL): camelCase (createdAt, updatedAt)
      • Production (PostgreSQL): snake_case (created_at, updated_at)
      • NODE_ENV์— ๋”ฐ๋ฅธ ์ž๋™ ์ „ํ™˜์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ˜ธํ™˜์„ฑ ๋ณด์žฅ
    • ์กด์žฌํ•˜์ง€ ์•Š๋Š” experience_years ํ•„๋“œ ์ œ๊ฑฐ
  • ๐Ÿ”ง Recruitment Status ํ†ต์ผ (Database ํ˜ธํ™˜์„ฑ ํ•ด๊ฒฐ)
    • Local๊ณผ Production DB ๊ฐ„ status ๊ฐ’ ๋ถˆ์ผ์น˜ ํ•ด๊ฒฐ:
      • Local (MySQL): ENUM('OPEN', 'CLOSED') โ†’ ENUM('ACTIVE', 'CLOSED', 'FILLED')
      • Production (PostgreSQL): CHECK('ACTIVE', 'CLOSED', 'FILLED') - ๊ธฐ์กด ์œ ์ง€
    • ์ฝ”๋“œ ์ „์ฒด ํ†ต์ผ: 'OPEN' โ†’ 'ACTIVE' ๋ณ€๊ฒฝ
      • Recruitment ๋ชจ๋ธ ENUM ์ •์˜ ์ˆ˜์ •
      • recruitmentService, applicationService, loadMockupData ์—…๋ฐ์ดํŠธ
    • Local MySQL ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ƒ์„ฑ ๋ฐ ์‹คํ–‰ ์™„๋ฃŒ
      • ๊ธฐ์กด 22๊ฐœ ๋ ˆ์ฝ”๋“œ ์ž๋™ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ (OPEN โ†’ ACTIVE)
    • Status ๊ฐ’ ์ •์˜:
      • ACTIVE: ๋ชจ์ง‘์ค‘ (๊ธฐ์กด OPEN)
      • CLOSED: ๋ชจ์ง‘๋งˆ๊ฐ
      • FILLED: ๋ชจ์ง‘์™„๋ฃŒ (Production ๊ธฐ์กด ๋ฐ์ดํ„ฐ)
  • ๐Ÿ“ ๋ฌธ์„œํ™”
    • Firebase ์ „ํ™”๋ฒˆํ˜ธ ์ธ์ฆ ๊ฐ€์ด๋“œ ์ถ”๊ฐ€
    • ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ • ๊ฐ€์ด๋“œ ์—…๋ฐ์ดํŠธ
    • API ์—”๋“œํฌ์ธํŠธ ๋ฌธ์„œ ์—…๋ฐ์ดํŠธ

v1.4.1 (2025-11-24)

  • ๐Ÿท๏ธ ๋ชจ์ง‘๊ธ€ ํ‚ค์›Œ๋“œ ๊ธฐ๋Šฅ ๊ฐœ์„ 
    • GET /api/recruitments ์‘๋‹ต์— Hashtags ํ•„๋“œ ์ถ”๊ฐ€
    • ๋ชจ์ง‘๊ธ€ ๋ชฉ๋ก ์กฐํšŒ ์‹œ ํ‚ค์›Œ๋“œ ์ •๋ณด ํฌํ•จ
    • ํ‚ค์›Œ๋“œ๊ฐ€ ์—†๋Š” ๋ชจ์ง‘๊ธ€ ์ฒ˜๋ฆฌ ๊ฐœ์„  (null ๋˜๋Š” ๋นˆ ๋ฐฐ์—ด)
    • ํ”„๋ก ํŠธ์—”๋“œ ํ†ตํ•ฉ ๊ฐ€์ด๋“œ ์ž‘์„ฑ (docs/api_changes_hashtags.md)
  • ๐Ÿ› ๋ฒ„๊ทธ ์ˆ˜์ •
    • ๋ชจ์ง‘๊ธ€ ์ƒ์„ฑ ์‹œ status ๊ฐ’ ํ†ต์ผ (ACTIVE โ†’ OPEN)
    • Sequelize ๋ชจ๋ธ ENUM๊ณผ ์ผ์น˜ํ•˜๋„๋ก ์ˆ˜์ •
  • ๐Ÿ“ ๋ฌธ์„œํ™”
    • SQL ๊ฒ€์ฆ ์Šคํฌ๋ฆฝํŠธ ์ถ”๊ฐ€ (scripts/verify_hashtags.sql)
    • ํ”„๋ก ํŠธ์—”๋“œ API ๋ณ€๊ฒฝ์‚ฌํ•ญ ๋ฌธ์„œ ์ž‘์„ฑ
    • React/Vue ์ปดํฌ๋„ŒํŠธ ์˜ˆ์‹œ ์ฝ”๋“œ ์ œ๊ณต
    • TypeScript ํƒ€์ž… ์ •์˜ ๊ฐ€์ด๋“œ ํฌํ•จ

v1.4.0 (2025-11-22)

  • ๐Ÿ“… ์ผ์ • ๊ด€๋ฆฌ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
    • ํ”„๋กœ์ ํŠธ๋ณ„ ์ผ์ • ์ƒ์„ฑ, ์กฐํšŒ, ์ˆ˜์ •, ์‚ญ์ œ API ๊ตฌํ˜„
  • ๐Ÿ“ ํ”„๋กœ์ ํŠธ ๊ฒŒ์‹œํŒ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
    • ํ”„๋กœ์ ํŠธ ๋‚ด ๊ฒŒ์‹œ๋ฌผ ์ž‘์„ฑ ๋ฐ ์กฐํšŒ ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • ๐Ÿ’พ ๋ชจ์ง‘๊ณต๊ณ  ์ž„์‹œ์ €์žฅ ๊ธฐ๋Šฅ
    • ์ž‘์„ฑ ์ค‘์ธ ๋ชจ์ง‘๊ณต๊ณ  ์ž„์‹œ์ €์žฅ API ์ถ”๊ฐ€

v1.3.1 (2025-11-20)

  • ๐ŸŽฏ ๋ชจ์ง‘๊ณต๊ณ  ์ƒ์„ธ ์กฐํšŒ API ๊ฐœ์„  (GET /api/recruitments/:id)
    • user_id ํ•„๋“œ ์ถ”๊ฐ€: ๋ชจ์ง‘๊ธ€ ์ž‘์„ฑ์ž ID ๋ฐ˜ํ™˜ (ํ”„๋ก ํŠธ์—”๋“œ ์†Œ์œ ์ž ํ™•์ธ์šฉ)
    • applicant_count ํ•„๋“œ ์ถ”๊ฐ€: ์‹ค์‹œ๊ฐ„ ์ง€์›์ž ์ˆ˜ ๊ณ„์‚ฐ (์„œ๋ธŒ์ฟผ๋ฆฌ)
    • created_at ํ•„๋“œ ํฌํ•จ: ๋ชจ์ง‘๊ธ€ ์ƒ์„ฑ ์‹œ๊ฐ„
    • ํ”„๋ก ํŠธ์—”๋“œ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ์ง€์› (์ž‘์„ฑ์ž: "์ง€์›์ž ๋ณด๊ธฐ", ์ผ๋ฐ˜ ์‚ฌ์šฉ์ž: "์ง€์›ํ•˜๊ธฐ")
  • ๐Ÿ› Hashtag ๋ชจ๋ธ ๋ฒ„๊ทธ ์ˆ˜์ •
    • ํ•ด์‹œํƒœ๊ทธ attributes ์ˆ˜์ •: content โ†’ name
    • ๋ชจ์ง‘๊ณต๊ณ  ์ƒ์„ธ ์กฐํšŒ ์‹œ ํ•ด์‹œํƒœ๊ทธ ์ •์ƒ ๋ฐ˜ํ™˜

v1.3.0 (2025-11-16)

  • ๐Ÿ“ ์ง€์›์„œ ์ œ์ถœ API ํฌํŠธํด๋ฆฌ์˜ค ์—ฐ๊ฒฐ ๊ธฐ๋Šฅ
    • ApplicationPortfolio ๋ชจ๋ธ ์ถ”๊ฐ€ (M:N ๊ด€๊ณ„)
    • introduction ํ•„๋“œ ์ถ”๊ฐ€ (ํ•„์ˆ˜, 1-500์ž)
    • ํฌํŠธํด๋ฆฌ์˜ค ํ”„๋กœ์ ํŠธ ์„ ํƒ ๋ฐ ์†Œ์œ ๊ถŒ ๊ฒ€์ฆ
    • ๋ณธ์ธ ๋ชจ์ง‘๊ธ€ ์ง€์› ๋ฐฉ์ง€, ๋งˆ๊ฐ ์—ฌ๋ถ€ ๊ฒ€์ฆ
  • ๐Ÿ–ผ๏ธ ๋ชจ์ง‘๊ณต๊ณ  ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ (Supabase Storage)
    • photo_url ํ•„๋“œ ์ถ”๊ฐ€
    • ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ API (/api/upload/recruitment-image)
    • ํŒŒ์ผ ๊ฒ€์ฆ (jpeg/png/webp, ์ตœ๋Œ€ 5MB)
    • UUID ๊ธฐ๋ฐ˜ ํŒŒ์ผ๋ช… ์ƒ์„ฑ
    • RLS ์ •์ฑ… ์ ์šฉ
  • ๐Ÿ” ์ง€์›์„œ ์ œ์ถœ ๋ณด์•ˆ ๊ฐ•ํ™”
    • ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ๋กœ ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ ๋ณด์žฅ
    • ํฌํŠธํด๋ฆฌ์˜ค ์†Œ์œ ๊ถŒ ๊ฒ€์ฆ (ProjectMembers ํ™•์ธ)
    • 9๊ฐ€์ง€ ์—๋Ÿฌ ์ฝ”๋“œ ์ฒด๊ณ„ ๊ตฌํ˜„
      • INVALID_INPUT, SELF_APPLICATION, RECRUITMENT_CLOSED
      • INVALID_PORTFOLIO, UNAUTHORIZED, RECRUITMENT_NOT_FOUND
      • ALREADY_APPLIED
  • ๐Ÿ“Š ์ง€์›์ž ๋ชฉ๋ก ์กฐํšŒ ๊ฐœ์„ 
    • ํฌํŠธํด๋ฆฌ์˜ค ํ”„๋กœ์ ํŠธ ์ •๋ณด ํฌํ•จ (์ œ๋ชฉ, ์„ค๋ช…)
    • User ํ”„๋กœํ•„ ์ •๋ณด ํฌํ•จ

v1.2.0 (2025-11-09)

  • ๐ŸŽฏ ๋Œ€์‹œ๋ณด๋“œ ์š”์•ฝ API ๊ตฌํ˜„ (/api/dashboard/summary)
    • ํ”„๋กœ์ ํŠธ ํ†ต๊ณ„, ์ง€์›์„œ ์ถ”์ , ํ‰๊ฐ€ ๋Œ€๊ธฐ ํ”„๋กœ์ ํŠธ, ์ตœ๊ทผ ํ™œ๋™ ํƒ€์ž„๋ผ์ธ
  • ๐Ÿ‘ค ํ˜„์žฌ ์‚ฌ์šฉ์ž ์ •๋ณด API ์ถ”๊ฐ€ (/api/auth/me)
    • ๋กœ๊ทธ์ธ ์‘๋‹ต์— user ๊ฐ์ฒด ํฌํ•จ์œผ๋กœ ํ”„๋ก ํŠธ์—”๋“œ ํ†ตํ•ฉ ๊ฐ„์†Œํ™”
  • ๐Ÿ“Š ๋‚ด ํ”„๋กœ์ ํŠธ ์กฐํšŒ API ๊ฐœ์„  (/api/projects/mine)
    • evaluation_status ํ•„๋“œ ์ง€์› (COMPLETED, PENDING, NOT_REQUIRED)
    • ํŒ€์› ํ‰๊ฐ€ ์ƒํƒœ ์ž๋™ ๊ณ„์‚ฐ ๋ฐ ํ•„ํ„ฐ๋ง ์ง€์›
  • ๐Ÿ”” Notifications ํ…Œ์ด๋ธ” ์ถ”๊ฐ€
    • ์•Œ๋ฆผ ์‹œ์Šคํ…œ ๊ธฐ๋ฐ˜ ๊ตฌ์ถ• (์ฝ์Œ/์•ˆ์ฝ์Œ ์ƒํƒœ ๊ด€๋ฆฌ)
  • ๐Ÿ—„๏ธ PostgreSQL Raw SQL ์ „ํ™˜
    • Sequelize ORM ๋Œ€์†Œ๋ฌธ์ž ์ด์Šˆ ํ•ด๊ฒฐ (ProjectMembers โ†’ project_members)
    • ํ”„๋กœ๋•์…˜ ์•ˆ์ •์„ฑ ๋ฐ ์„ฑ๋Šฅ ํ–ฅ์ƒ
  • โšก Recruitments ์Šคํ‚ค๋งˆ ๊ฐœ์„ 
    • user_id ์ปฌ๋Ÿผ ์ถ”๊ฐ€๋กœ ๋ชจ์ง‘๊ณต๊ณ  ์ž‘์„ฑ์ž ์ถ”์  ๊ธฐ๋Šฅ ๊ฐ•ํ™”
  • ๐Ÿ” JWT ํ˜ธํ™˜์„ฑ ๋ ˆ์ด์–ด ๊ตฌํ˜„
    • Edge Function JWT (sub ํ•„๋“œ) + Render JWT (userId ํ•„๋“œ) ๋™์‹œ ์ง€์›
    • ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ธฐ๊ฐ„ ์ค‘ ์›ํ™œํ•œ ์ „ํ™˜ ์ง€์›

v1.1.0 (2025-11-07)

  • โœ… SendGrid ๋„๋ฉ”์ธ ์ธ์ฆ ์™„๋ฃŒ (teamitaka.com)
  • ๐Ÿš€ Render ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ ์™„๋ฃŒ
  • โšก Nodemailer SMTP ํด๋ฐฑ ์ œ๊ฑฐ (์„ฑ๋Šฅ ๊ฐœ์„ : 120์ดˆ โ†’ 2์ดˆ)
  • ๐Ÿ—„๏ธ Supabase Shared Pooler ์ ์šฉ (IPv4 ํ˜ธํ™˜์„ฑ)
  • ๐Ÿ”ง ์ด๋ฉ”์ผ ๋ฐœ์†ก ์‹œ์Šคํ…œ ์ตœ์ ํ™” (SendGrid Web API ์ „์šฉ)
  • ๐Ÿ› ๏ธ GitHub Actions ์›Œํฌํ”Œ๋กœ์šฐ ์ •๋ฆฌ
  • ๐Ÿ“ ํ”„๋ก ํŠธ์—”๋“œ ํ†ตํ•ฉ ๋ฌธ์„œ ์ž‘์„ฑ

v1.0.0 (2025-11-01)

  • โœจ ์ดˆ๊ธฐ ๋ฆด๋ฆฌ์ฆˆ
  • ๐Ÿ” ์ด๋ฉ”์ผ ์ธ์ฆ ์‹œ์Šคํ…œ ๊ตฌํ˜„
  • ๐Ÿ”‘ JWT ๊ธฐ๋ฐ˜ ์ธ์ฆ ๊ตฌํ˜„
  • ๐Ÿ“Š ํ”„๋กœ์ ํŠธ ๊ด€๋ฆฌ CRUD
  • ๐Ÿ’ฌ ๋Œ“๊ธ€ ์‹œ์Šคํ…œ ๊ตฌํ˜„
  • ๐Ÿ” ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • ๐Ÿš€ Supabase ๋ฐฐํฌ ์ง€์›

๊ฐœ๋ฐœ: TeamItaka Development Team ๋ฌธ์˜: GitHub Issues๋ฅผ ํ†ตํ•ด ์—ฐ๋ฝ ์ฃผ์„ธ์š”

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors