Skip to content

spec-together/spectogether-api-server-v2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

spectogether API v2

How To ?

Conventions & Template

  • GitHub Issue Template
  • Git ์ „๋žต : Git Flow, GitHub Flow
  • Code ์ž‘์„ฑ ์ปจ๋ฒค์…˜ : ๋ณ€์ˆ˜, ํ•จ์ˆ˜, ํŒŒ์ผ, ํด๋” ๋ช…๋ช…๋ฒ•
  • docker ๋ฐ docker-compose ํŒŒ์ผ : ๋น ๋ฅด๊ณ  ์‰ฌ์šด ๋ฐฐํฌ
  • CI/CD (GitHub Actions) : ๊ฐœ์ธ์„œ๋ฒ„ ์šฉ CI/CD (SSH ์ด์šฉ), AWS ์šฉ CI/CD
  • ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ preset : ๋กœ๊ทธ์ธ, ์ฑ„ํŒ…, ๊ฒŒ์‹œํŒ
  • .gitignore : Windows, macOS, Linux, node, dotenv ๊ธฐ์ค€ + config.json, *.pem

๋Œ€์ค‘์ ์ธ ๊ตฌ์กฐ๋Š” ์žˆ์ง€๋งŒ, ์„ธ๋ถ€์ ์ธ ๋ถ€๋ถ„์€ ๊ฐœ๋ฐœ์ž ๊ฐœ์ธ์˜ ์ทจํ–ฅ์ž…๋‹ˆ๋‹ค.
๊ฐœ์ธ์ ์œผ๋กœ ํ”„๋กœ์ ํŠธ๋‚˜ ํ•ด์ปคํ†ค์—์„œ ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ž‘์„ฑํ•˜์˜€๊ธฐ์—,
์ œ ๊ฐœ์ธ์˜ ์ทจํ–ฅ์— ๋งž๊ฒŒ ์ ์šฉ๋˜์–ด ์žˆ๊ณ , ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋งž๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋€Œ๋ฉฐ
ํ…œํ”Œ๋ฆฟ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ…œํ”Œ๋ฆฟ์€ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ทจํ–ฅ์— ๋งž๊ฒŒ ์ˆ˜์ •ํ•˜์—ฌ ์‚ฌ์šฉํ•ด์ฃผ์‹œ๊ณ , ๋„์›€์ด ๋˜์…จ๋‹ค๋ฉด โญ ํ•œ๋ฒˆ๋งŒ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.
preset ์ฝ”๋“œ์— ๋ฒ„๊ทธ๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ issue ์ƒ์„ฑํ•˜์‹œ์–ด ๋‚จ๊ฒจ์ฃผ์‹œ๋ฉด ํ™•์ธ ํ›„ ๋ฐ˜์˜ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

made and owned by @kyeoungwoon | Naver Blog

Git Convention : Strategy

Strategy #1 : Git Flow

  • ๊ทœ๋ชจ๊ฐ€ ํฐ ํ”„๋กœ์ ํŠธ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.
  • ๋ธŒ๋žœ์น˜ ์ข…๋ฅ˜ : main, develop, feature, release, hotfix
  1. main :
  2. develop :
  3. feature :
  4. release :
  5. hotfix :

Strategy #2 : GitHub Flow

  • ๊ทœ๋ชจ๊ฐ€ ์ž‘๊ณ  ์žฆ์€ ๊ธฐ๋Šฅ์ˆ˜์ •๊ณผ ๋ฐฐํฌ๊ฐ€ ์žˆ๋Š” ํ”„๋กœ์ ํŠธ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.
  • ๋ธŒ๋žœ์น˜ ์ข…๋ฅ˜ : main, develop, feature

1. main

  • Production ํ™˜๊ฒฝ์— ์–ธ์ œ ๋ฐฐํฌํ•ด๋„ ๋ฌธ์ œ ์—†๋Š” stable branch ์ž…๋‹ˆ๋‹ค.
  • ์žฅ์•  ํ˜น์€ ๋ฒ„๊ทธ ๋ฐœ์ƒ ์‹œ main branch๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋น ๋ฅด๊ฒŒ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.
  • Initial commit์„ ์ œ์™ธํ•˜๊ณ , main branch์— commit์ด ์ง์ ‘์ ์œผ๋กœ ๋ฐœ์ƒํ•˜๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค.

2. develop

  • ์ƒˆ๋กœ์šด feature๋“ค์„ ๊ฐœ๋ฐœํ•  ๊ฒฝ์šฐ main์„ ๊ธฐ์ค€์œผ๋กœ develop branch๋ฅผ ์ƒ์„ฑ ํ•ฉ๋‹ˆ๋‹ค.
  • feature branch๋“ค์„ merge ํ•˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค.
  • feature๋“ค์„ ๋ชจ๋‘ mergeํ•œ ํ›„ ๋ฐœ์ƒ๋˜๋Š” bug fix๋ฅผ ๋ชจ๋‘ ๋งˆ์นœ ํ›„, main branch๋กœ PR์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • ๋‹ค์‹œ ํ•œ๋ฒˆ ๊ฐ•์กฐํ•˜์ง€๋งŒ, main branch๋Š” ๋ชจ๋“  ์ž‘์—…์˜ ์‹œ์ž‘์ ์ด๋ฉฐ, ์ ˆ๋Œ€์ ์œผ๋กœ stable ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ถˆ์™„์ „ํ•œ ์‚ฌํ•ญ๋“ค์€ develop branch ๋‚ด์—์„œ ํ•ด๊ฒฐ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

3. feature

  • develop branch๋ฅผ ๊ธฐ์ค€์œผ๋กœ, ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ๊ฐœ๋ฐœํ•˜๋Š” branch ์ž…๋‹ˆ๋‹ค.
  • ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ bug fix๋Š” feature branch ๋‚ด์—์„œ ๋งˆ์นœ ํ›„ develop branch๋กœ PR์„ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Merge ๋ฐ Conflict ๊ด€๋ จ tip

ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1. GitHub Web ์ด์šฉํ•˜๊ธฐ

feature/login branch๋ฅผ develop/user branch์— merge ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ด…์‹œ๋‹ค.

  • feature/login branch๋ฅผ push ํ•ฉ๋‹ˆ๋‹ค.
  • GitHub ๋ ˆํฌ์ง€ํ† ๋ฆฌ ํŽ˜์ด์ง€์—์„œ Compare & Create Pull Request ๋ฒ„ํŠผ์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
  • ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ํด๋ฆญํ•œ ํ›„, base์™€ compare branch๋ฅผ ๊ฐ๊ฐ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ณด์ด๊ฒŒ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • base: develop/user <- compare: featture/login๊ณผ ๊ฐ™์ด ์„ค์ • ํ›„ ์‚ฌ์šฉํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

2. CLI ์ด์šฉํ•˜๊ธฐ

1๋ฒˆ๊ณผ ๋™์ผํ•œ ์ƒํ™ฉ์„ ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

  • git switch develop/user ๋ฅผ ํ†ตํ•ด ์ด๋™ํ•˜๊ณ  git pull origin develop/user๋ฅผ ํ†ตํ•ด ์ตœ์‹  ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • git merge feature/login์„ ํ†ตํ•ด merge๋ฅผ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค.
  • ์ž๋™ ๋ณ‘ํ•ฉ์— ์„ฑ๊ณตํ•˜๋ฉด ๊ทธ๋Œ€๋กœ Merge: branch 'feature/login'๊ณผ ๊ฐ™์ด commit์„ ๋‚จ๊ธฐ๊ณ  push ํ•ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  • ์ž๋™ ๋ณ‘ํ•ฉ์— ์‹คํŒจํ•œ ๋ถ€๋ถ„์€ ์ˆ˜๋™์œผ๋กœ conflict ํ•ด๊ฒฐํ•ด ์ฃผ์‹œ๊ณ ,
  • ๊ฐ€๋Šฅํ•˜๋ฉด ํ•ด๊ฒฐํ•œ ๋ถ€๋ถ„์— ์ฃผ์„์œผ๋กœ ์–ด๋–ค ๋ถ€๋ถ„์— conflict๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๊ณ , ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ํ•ด๊ฒฐํ•˜์˜€๋Š”์ง€ ์ž‘์„ฑํ•ด์ฃผ์‹œ๋ฉด ์ข‹์Šต๋‹ˆ๋‹ค.
Git ์ „๋žต๋“ค์— ๋Œ€ํ•ด์„œ ๋” ์•Œ์•„๋ณด๊ณ  ์‹ถ๋‹ค๋ฉด : ์ž˜ ์ •๋ฆฌํ•ด๋†“์œผ์‹  ๋ถ„์ด ์žˆ์Šต๋‹ˆ๋‹ค

Git Convention : Commit

์ œ๋ชฉ, ๋ณธ๋ฌธ, ๊ผฌ๋ฆฌ๋ง ์„ธ ๋ถ€๋ถ„์œผ๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค.
๊ฐ ๋ถ€๋ถ„์€ ๋นˆ ์ค„๋กœ ๊ตฌ๋ถ„๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ œ๋ชฉ

Tag: Title ์˜ ํ˜•์‹์„ ์‚ฌ์šฉํ•ด ์ฃผ์„ธ์š”.

  • Tag์˜ ์ฒซ ๋ฌธ์ž๋Š” ๋Œ€๋ฌธ์ž๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • ์ฝœ๋ก ์€ Tag์— ๋ถ™์—ฌ์„œ ์ž‘์„ฑํ•˜๊ณ , ์ฝœ๋ก  ์ดํ›„ 1์นธ ๋’ค์— title์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
    • (X)
      • feat:title feat: title feat :title feat : title
      • Feat :title Feat : title
    • (O)
      • Feat: title

Tag์˜ ์ข…๋ฅ˜์™€ ๊ทธ ๊ตฌ๋ถ„์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • Feat : ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋˜์—ˆ์„ ๋•Œ
  • Fix : ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •ํ•˜์˜€์„ ๋•Œ
  • Docs : README.md๋‚˜ ์ฃผ์„ ๋“ฑ ๋ฌธ์„œ๋ฅผ ์ˆ˜์ •ํ•˜์˜€์„ ๋•Œ
  • Style : ์ฝ”๋“œ ๊ตฌ์กฐ์— ๋ณ€๊ฒฝ ์—†์ด ๋ณ€์ˆ˜๋ช… ๋“ฑ์„ ์ˆ˜์ •ํ•˜์˜€์„ ๋•Œ
  • Refactor : ์ฝ”๋“œ ๋™์ž‘ ๋ฐฉ์‹์„ ์ˆ˜์ •ํ•˜์˜€์„ ๋•Œ, ๋˜๋Š” Style์„ ๋Œ€๊ทœ๋ชจ๋กœ ๋ณ€๊ฒฝํ•˜์˜€์„ ๋•Œ์—๋„ ํ™œ์šฉ.
  • Test : ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์˜€์„ ๋•Œ
  • Chore : package.json์„ ์ˆ˜์ •ํ•˜์˜€๊ฑฐ๋‚˜ dockerfile ๋“ฑ ๋ถ„๋ฅ˜ํ•˜๊ธฐ ์• ๋งคํ•œ ์ƒํ™ฉ์—์„œ ์‚ฌ์šฉ
  • Merge : branch๋ฅผ mergeํ•˜์˜€์„ ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋ณธ๋ฌธ

  • ๋ณธ๋ฌธ์€ ํ•œ ์ค„ ๋‹น 72์ž ๋‚ด๋กœ ์ž‘์„ฑํ•ด ์ฃผ์„ธ์š”. (๋‹ค์–‘ํ•œ ํ™˜๊ฒฝ์—์„œ์˜ ๊ฐ€๋…์„ฑ์„ ์œ„ํ•˜์—ฌ)
  • ๋ณธ๋ฌธ ๋‚ด์šฉ์€ ์–‘์— ๊ตฌ์• ๋ฐ›์ง€ ์•Š๊ณ  ์ตœ๋Œ€ํ•œ ์ƒ์„ธํžˆ ์ž‘์„ฑํ•ด ์ฃผ์„ธ์š”.
  • ๋ณธ๋ฌธ ๋‚ด์šฉ์€ ์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝํ–ˆ๋Š”์ง€ ๋ณด๋‹จ, ๋ฌด์—‡์„ ๋ณ€๊ฒฝํ–ˆ๋Š”์ง€ ๋˜๋Š” ์™œ ๋ณ€๊ฒฝํ–ˆ๋Š”์ง€๋ฅผ ์„ค๋ช…ํ•ด ์ฃผ์„ธ์š”.

๊ผฌ๋ฆฌ๋ง

Type: #issue_number ์˜ ํ˜•์‹์„ ์‚ฌ์šฉํ•ด ์ฃผ์„ธ์š”.

  • Footer๋Š” ํ•„์ˆ˜์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๋‹ค๋งŒ, issue์— ์—ฐ๊ด€๋˜์–ด ์ƒ์„ฑ๋œ commit์ด๋ผ๋ฉด ๋„ฃ์–ด์ฃผ์‹œ๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค.
  • ์ œ๋ชฉ์„ ์“ธ ๋•Œ์™€ ํ˜•์‹์€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.
    • eg. Fixes: something

Type์˜ ์ข…๋ฅ˜์™€ ๊ตฌ๋ถ„์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • Fixes : ์ด์Šˆ ์ˆ˜์ •์ค‘ (์•„์ง ํ•ด๊ฒฐ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ)
  • Resolves : ์ด์Šˆ๋ฅผ ํ•ด๊ฒฐํ–ˆ์„ ๋•Œ ์‚ฌ์šฉ
  • Ref : ์ฐธ๊ณ ํ•  ์ด์Šˆ๊ฐ€ ์žˆ์„ ๋•Œ ์‚ฌ์šฉ
  • Related to : ํ•ด๋‹น ์ปค๋ฐ‹์— ๊ด€๋ จ๋œ ์ด์Šˆ๋ฒˆํ˜ธ (์•„์ง ํ•ด๊ฒฐ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ)

Code Convention

ํ•จ์ˆ˜๋ช…

  • Camel Case๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    • eg. getUserByUserId, getEventByDateAndUserId
  • ๊ธธ์ด๊ฐ€ ๊ธธ์–ด์ง€๋”๋ผ๋„ ๊ธฐ๋Šฅ์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ช…์‹œํ•ด ์ฃผ์„ธ์š”.
  • ํ•จ์ˆ˜๋ช…์€ ๊ฒน์ณ๋„ ๋ฉ๋‹ˆ๋‹ค.
    • ํ•˜๋‹จ์— import/export ๊ด€๋ จ ์ปจ๋ฒค์…˜ ์„ค๋ช…์—์„œ ๋” ์ž์„ธํžˆ ์•Œ ์ˆ˜ ์žˆ์ง€๋งŒ, ์•„๋ž˜์˜ ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.
    • user.service.js ์— createNewUser ๊ณผ user.repository.js์— createNewUser์ด ๋™์‹œ์— ์กด์žฌํ•˜์—ฌ๋„ ๋ฉ๋‹ˆ๋‹ค.
    • service์—์„œ ์‚ฌ์šฉ ์‹œ์—๋Š” userRepository.createNewUser
    • controller์—์„œ ์‚ฌ์šฉํ•  ๋–„๋Š” userController.createNewUser์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • routes ํด๋”์—์„œ express.Router()๋กœ ์ •์˜ํ•˜๋Š” ๋ณ€์ˆ˜๋ช…์€ ํ•ด๋‹น ํŒŒ์ผ๋ช…๊ณผ ์ผ์น˜ํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • eg. auth.router.js ํŒŒ์ผ์˜ ๊ฒฝ์šฐ์—๋Š” const authRouter = express.Router(); ์™€ ๊ฐ™์ด!
    • authRouter.get("/", handleXX), userRouter.get("/", handleYY)

๋ณ€์ˆ˜๋ช…

  • Snake Case๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    • eg. user_id, event_id
  • ํŒ€์›๊ฐ„ ํ˜‘์˜ ํ›„ Camel Case ๋˜ํ•œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ค‘์š”ํ•œ ๋ถ€๋ถ„์€ ์ปจ๋ฒค์…˜์˜ ํ†ต์ผ์ž…๋‹ˆ๋‹ค.
    • ๋‹ค๋งŒ, Database์˜ ์ปฌ๋Ÿผ๋ช…๋“ค์ด Snake Case๋กœ ์ž‘์„ฑ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— Query๋ฌธ ์ž‘์„ฑ ์‹œ ์œ ์˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  • JSON ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋–„๋Š”, { user_id : user_id } (X) { user_id } (O) ์™€ ๊ฐ™์ด ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”.
    • JSON ๊ฐ์ฒด ์ƒ์„ฑ ์‹œ ๋ณ€์ˆ˜๋ช…๋งŒ ์ž…๋ ฅํ•˜๋ฉด, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์ž๋™์œผ๋กœ { ๋ณ€์ˆ˜๋ช…: ๋ณ€์ˆ˜๊ฐ’ } ํ˜•ํƒœ๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ ์„ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค. (๊ฐ์ฒด ์ถ•์•ฝ ํ‘œ๊ธฐ๋ฒ•)
  • ์ƒ์ˆ˜๊ฐ’์— ํ•ด๋‹นํ•˜๋Š” ๋ณ€์ˆ˜๋ช…์€ ์ „๋ถ€ ๋Œ€๋ฌธ์ž ๋ฐ snake case๋กœ ์ž‘์„ฑ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋“ฑ์ด ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค. eg. AWS_SECRET_KEY, API_KEY ๋“ฑ

ํŒŒ์ผ๋ช…

  • ์ „๋ถ€ ์†Œ๋ฌธ์ž๋ฅผ ์‚ฌ์šฉํ•˜์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ƒ์œ„ ํด๋”๋ช…์„ ํฌํ•จํ•˜์—ฌ ๊ธฐ๋Šฅ์„ ๋ช…์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์—ฌ๋Ÿฌ ๋‹จ์–ด๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ . ์œผ๋กœ ๋‹จ์–ด๋ฅผ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค
  • eg. user.repository.js, chat.service.js

ํด๋”๋ช…

  • ํด๋”๋ช…์€ ๊ธธ์–ด์งˆ ๊ฒฝ์šฐ -๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. (kebab case)
  • eg. my-page, user-info

Error Handling

  • class CustomError extends Error์™€ ๊ฐ™์ด, JavaScript ๊ธฐ๋ณธ Error ๊ฐ์ฒด๋ฅผ extend ํ•˜์—ฌ Custom Error๋ฅผ ์ž‘์„ฑํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • Error๋Š” ์„ธ๋ถ„ํ™”ํ•˜์—ฌ ๊ฐ๊ฐ ์—๋Ÿฌ๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ๋Œ€๋ถ„๋ฅ˜๋กœ ๊ด€๋ฆฌํ•˜์—ฌ reason์œผ๋กœ ์„ธ๋ถ€์‚ฌํ•ญ์„ ์•Œ ์ˆ˜ ์žˆ๋„๋ก ํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • Error ๋ช…์€ Pascal Case๋กœ ์ž‘์„ฑํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • UserNotExistError UserAuthorizationError IdNotProvidedError ๋“ฑ๊ณผ ๊ฐ™์ด ์„ธ๋ถ„ํ™” ๋œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ,
    • NotExistError InvalidInputError ์ฒ˜๋Ÿผ ์ตœ๋Œ€ํ•œ ํฌ๊ด„์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • ์„ธ๋ถ„ํ™”ํ•  ํ•„์š”๊ฐ€ ์ƒ๊ธด๋‹ค๋ฉด, UserIdNotExist UserNameNotExist ์ˆ˜์ค€์œผ๋กœ ์„ธ๋ถ„ํ™” ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, InvalidUserDataInput ๊ณผ ๊ฐ™์ด ์นดํ…Œ๊ณ ๋ฆฌ๊นŒ์ง€๋งŒ ํฌํ•จํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ˆ˜์ •์€ ์ž์œ ์ด๋‚˜, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‚ฌํ•ญ์„ ํฌํ•จํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • error code
      • string ์ด์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
      • U001๊ณผ ๊ฐ™์ด ๋”ฐ๋กœ ์ •์˜ํ•ด๋‘์…”๋„ ๋˜๊ณ , ALREADY_EXIST์™€ ๊ฐ™์ด ํ•œ๋‘ ๋‹จ์–ด ์ •๋„๋กœ ๊ฐ„๋žตํ•˜๊ฒŒ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”.
      • U001๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๊ฐ’์œผ๋กœ ๊ด€๋ฆฌํ•˜์‹ค ์˜ˆ์ •์ด๋ฉด, ๋ฌธ์„œํ™” ํ•˜์—ฌ ํŒ€์›๋“ค ์‚ฌ์ด์— ๊ณต์œ ํ•ด ์ค‘๋ณต๋œ ์—๋Ÿฌ๊ฐ€ ์ž‘์„ฑ๋˜์ง€ ์•Š๋„๋ก ์œ ์˜ํ•ด์ฃผ์„ธ์š”.
    • status code
      • http status code ๊ฐ’ ์ž…๋‹ˆ๋‹ค.
      • ํ•ด๋‹น ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์ „์†กํ•  status code๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.
    • reason
      • ํ•ด๋‹น ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค.
      • debug ์‹œ์— reason๋งŒ ๋ณด๊ณ  ์•Œ ์ˆ˜ ์žˆ๋„๋ก ๊ฐ„๊ฒฐํ•˜๋˜, ๋ชจ๋“  ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๋„๋ก ์ž‘์„ฑํ•ด ์ฃผ์„ธ์š”.

class AlreadyExistError extends Error {
  errorCode = "ALREADY_EXIST";
  statusCode = 409;

  constructor(reason, data) {
    super(reason);
    this.reason = reason;
    this.data = data;
  }
}

Database

MySQL์„ ๊ธฐ์ค€์œผ๋กœ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

  • ํ…Œ์ด๋ธ”๋ช…๊ณผ ์ปฌ๋Ÿผ๋ช… ๋“ฑ ๋ชจ๋“  ๋ณ€์ˆ˜๋ช…์€ ๋ฐ˜๋“œ์‹œ snake case๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • PK๊ฐ’์€ {table๋ช…}_id ์™€ ๊ฐ™์€ ํ˜•์‹์ด์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • eg. user_oauth ํ…Œ์ด๋ธ”์˜ PK ์ปฌ๋Ÿผ ๋ช…์€ user_oauth_id
    • bigint ์ž๋ฃŒํ˜•์„ ์‚ฌ์šฉํ•˜๊ณ , auto increment์„ ์‚ฌ์šฉํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • ๋ฐ˜์ •๊ทœํ™” (๋น„์ •๊ทœํ™”, denormailzation)๋กœ ์ธํ•ด ํ…Œ์ด๋ธ”์ด ๋ถ„ํ• ๋œ ๊ฒฝ์šฐ์—๋„, id๊ฐ’์„ ๋”ฐ๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค.
  • ๋ชจ๋“  ํ…Œ์ด๋ธ”์—๋Š” created_at๊ณผ updated_at์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • DataType์€ TIMESTAMP(6) ์ž…๋‹ˆ๋‹ค.
    • created_at๊ณผ updated_at์€ default expression์— current_timestamp(6)์„ ์ ์šฉํ•ด๋‘์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • updated_at์€ on_update์— current_timestamp(6)์ด ์ ์šฉ๋˜์–ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ •๊ทœํ™” ๊ทœ์น™์„ ๋˜๋„๋ก์ด๋ฉด ๋”ฐ๋ฅด๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐ™์€ ๋‚ด์šฉ์˜ Query๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ๋‚ ๋ฆฌ๋Š” ๊ฒƒ ๋ณด๋‹ค๋Š”, JOIN์ด๋‚˜ BETWEEN ๋“ฑ์œผ๋กœ ํ•œ๋ฒˆ์— ๊ฐ€์ ธ์™€์„œ Node.js๋‹จ์—์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๊ถŒํ•ฉ๋‹ˆ๋‹ค.
  • image๋“ฑ ํŒŒ์ผ์€ url๋งŒ์„ ์ €์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. binary data๋ฅผ ์ง์ ‘์ ์œผ๋กœ ์ €์žฅํ•˜๋Š” ํ–‰์œ„๋Š” ์ง€์–‘ํ•ด์•ผ ํ•  1์ˆœ์œ„ ์ž…๋‹ˆ๋‹ค.

import / export

ES6์™€ commonJS ๋ชจ๋‘ ๋™์ผํ•˜๊ฒŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

  • default export์˜ ์‚ฌ์šฉ์„ ์ง€์–‘ํ•˜๊ณ ,
  • named export์˜ ์‚ฌ์šฉ์„ ์ง€ํ–ฅํ•ฉ๋‹ˆ๋‹ค.
// ์ง€์–‘ : ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ import ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ
import { createNewUser } from "./user.service";

const result = createNewUser();
// user.repository์—๋„ createNewUser ์กด์žฌํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๊ธฐ์—, ์ถฉ๋Œํ•  ์šฐ๋ ค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

// ์ง€ํ–ฅ : ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๊ตฌ์กฐํ™” ํ•ฉ๋‹ˆ๋‹ค.
// eg. Java, C++

import userService from "./sample.service.js";

const result = userService.createNewUser();

์ปจ๋ฒค์…˜์„ ๋ชจ๋‘ ์ง€ํ‚จ, router - controller - service - repository ๊ฐ„์˜ ํ˜ธ์ถœ๊ตฌ์กฐ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

// user.router.js
import userController from "./user.controller";

const userRouter = express.Router();
userRouter.get("/", userController.createNewUser);

// user.controller.js
import userService from "./user.service";

export const createNewUser = async (req, res, next) => {
  const { id, password } = req.body;
  // ์ด๋ ‡๊ฒŒ๋„ ๋˜๊ณ 
  await userService.createNewUser({ id, password }); // RORO
  // ์ด๋ ‡๊ฒŒ ํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค.
  const data = { id, password };
  userService.createNewUser(data);

  return res.status(200).success();
};

// user.service.js
import userRepository from "./user.repository";

export const createNewUser = async (data) => {
  const result = await userRepository.createNewUser(data);

  return { message: "OK", result };
};

// user.repository.js
export const createNewUser = async (data) => {
  const result = await User.create(data);

  return result;
};

Project Architecture

controllers

  • ๊ฐ ์—”๋“œํฌ์ธํŠธ์˜ ์‘๋‹ต์„ ํ•ธ๋“ค๋งํ•ฉ๋‹ˆ๋‹ค.
  • service์— ์˜์กด์ ์ž…๋‹ˆ๋‹ค.

service

  • controllers์—์„œ ํ™œ์šฉํ•  ๊ธฐ๋Šฅ ๋“ฑ์„ ์œ„ํ•œ ํด๋”์ž…๋‹ˆ๋‹ค.
  • ์ž…๋ ฅ๊ฐ’ validation์ด๋‚˜ error handling ๋“ฑ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

repositories

  • Database ์ž…์ถœ๋ ฅ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค.
  • ํ•œ ํ•จ์ˆ˜๋Š” ํ•œ Query๋งŒ์„ ๋‹ด๋‹นํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • try-catch๋Š” ๋˜๋„๋ก ์ ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • request/response ํ˜•์‹ ํ†ต์ผ ๋ถ€๋ถ„์„ ์ฐธ๊ณ ํ•˜์—ฌ, error ๋ฐœ์ƒ ์‹œ next(err) ๋“ฑ์œผ๋กœ middleware๊ฐ€ ์—๋Ÿฌ๋ฅผ ์บ์น˜ํ•˜๋Š” ๋กœ์ง์œผ๋กœ ๊ตฌํ˜„ํ•˜์—ฌ์•ผ ํ•˜๋ฉฐ, DB ์ ‘์† ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹Œ ์ด์ƒ repositories๋‹จ์—์„œ ์—๋Ÿฌ๊ฐ€ ๋‚˜์ง€ ์•Š๋„๋ก ์ถฉ๋ถ„ํ•œ ์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ ํ›„์— ํ˜ธํ’€ํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • sequelize์™€ ๊ฐ™์€ ORM์„ ์‚ฌ์šฉํ•  ๋•Œ์—๋Š” repositories์—์„œ ๋ฆฌํ„ด๊ฐ’์„ ๊ฐ€๊ณตํ•˜์ง€ ์•Š๊ณ , attributes์„ค์ • ๋“ฑ์œผ๋กœ query๋‹จ์—์„œ ๊ฐ€๊ณตํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • eg.
    const getUserIdByLoginId async (login_id) => {
      return await User.findOne({
        where : {
          login_id : login_id
          },
        attributes: ["user_id"]
        })
      }

models

  • ORM ์‚ฌ์šฉ ์‹œ model ์ •์˜๋ฅผ ์œ„ํ•œ ํด๋”์ž…๋‹ˆ๋‹ค.
  • sequelize ๊ธฐ์ค€์œผ๋กœ, sequelize.define์ด ์•„๋‹Œ class User Extends Model ๊ณผ ๊ฐ™์€ class ํ˜•์‹์œผ๋กœ ์ž‘์„ฑํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
class User extends Model {
  static init(sequelize) {
    5;
    super.init(
      {
        user_id: {
          type: DataTypes.INTEGER,
          autoIncrement: true,
          primaryKey: true,
        },

        // ๊ธฐํƒ€ ์ปฌ๋Ÿผ๋“ค ...

        created_at: {
          type: DataTypes.DATE(6),
          defaultValue: DataTypes.NOW,
          allowNull: false,
        },
        updated_at: {
          type: DataTypes.DATE(6),
          defaultValue: DataTypes.NOW,
          allowNull: false,
        },
      },
      {
        sequelize,
        tableName: "user",
        timestamps: false,
      }
    );
  }

  static associate(models) {
    // ๊ด€๊ณ„ํ˜• ์ •์˜ ํ•„์š”
    User.hasMany(models.Question, { foreignKey: "questioned_user_id" });
  }
}

presets

  • ์ž์ฃผ ์“ฐ์ด๋Š” ๊ธฐ๋Šฅ๋“ค์— ๋Œ€ํ•œ ์ฝ”๋“œ preset ์ž…๋‹ˆ๋‹ค.
  • ์ž์œ ๋กญ๊ฒŒ ๋ณ€ํ˜•ํ•ด์„œ ์“ฐ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

About

Backend Server v2 for spectogether service

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •