Skip to content

whileTrueDev/tp-mvp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

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

Repository files navigation

tp-mvp

pilot project for True point

์ฝ”๋“œ ํ’ˆ์งˆ ๊ด€๋ฆฌ

Truepoint์˜ ๋Œ€๋ถ€๋ถ„์˜ ์„œ๋น„์Šค๋Š” typescript๋กœ ์ž‘์„ฑ๋ฉ๋‹ˆ๋‹ค.
๋Œ€๋ถ€๋ถ„์˜ javascript(typescript ์—ญ์‹œ) ํ”„๋กœ์ ํŠธ์—์„œ ์ฝ”๋“œ์˜ ๊ทœ์น™์„ ์ง€์ •ํ•˜๊ณ  ์˜ฌ๋ฐ”๋ฅธ ๊ทœ์น™์— ๋งž๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก Eslint๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
prettier๋ฅผ ํ†ตํ•ด ์ฝ”๋“œ ์ €์žฅ ์‹œ ์˜ฌ๋ฐ”๋ฅธ ์ฝ”๋”ฉ ๋ฐฉ์‹์œผ๋กœ์˜ ์ž๋™ ์ˆ˜์ •๊ธฐ๋Šฅ์„ ๋ง๋ถ™์—ฌ ์‚ฌ์šฉํ•˜์—ฌ ๋”์šฑ ์‰ฝ๊ณ  ๋น ๋ฅด๊ฒŒ ์ฝ”๋”ฉํ‘œ์ค€์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Truepoint๋Š” Vscode์—์„œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ์•ž์„œ ๋งํ•œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ ํ’ˆ์งˆ ๊ด€๋ฆฌ ํˆด์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.
Eslint Vscode Extension์„ ์„ค์น˜ํ•ด ์ฃผ์„ธ์š”. ( Extensions => eslint ๊ฒ€์ƒ‰ => install and enable )

์ดํ›„ Cmd + , (windows: ctrl + ,) ๋‹จ์ถ•์–ด๋ฅผ ์ž…๋ ฅํ•˜์—ฌ vscode setting ํŒŒ์ผ์„ ์—ด๊ณ , ์šฐ์ธก ์ƒ๋‹จ์˜ open settings(JSON) ๋ฒ„ํŠผ์„ ํด๋ฆญ ํ•ด settings.json ํŒŒ์ผ์„ ์—ด์–ด ์•„๋ž˜์˜ ๋‚ด์šฉ์„ ์ตœํ•˜๋‹จ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

// typescript semantic highlighting
"editor.semanticHighlighting.enabled": true,
// These are all my auto-save configs
"editor.formatOnSave": true,
// turn it off for JS and JSX, we will do this via eslint
"[javascript]": {
    "editor.formatOnSave": false,
    "editor.tabSize": 2
},
"[javascriptreact]": {
    "editor.formatOnSave": false,
    "editor.tabSize": 2
},
"[typescript]": {
    "editor.formatOnSave": false,
    "editor.tabSize": 2
},
"[typescriptreact]": {
    "editor.formatOnSave": false,
    "editor.tabSize": 2
},
// eslint config
"eslint.packageManager": "yarn",
"eslint.codeAction.showDocumentation": {
    "enable": true
}

์ถ”๊ฐ€์ ์œผ๋กœ vscode์—์„œ ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ ํ–ฅ์ƒ์„ ์œ„ํ•ด ๋‹ค์Œ์˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. vscode์˜ Explorer์—์„œ ๊ฒ€์ƒ‰ ์‹œ ํฌํ•จ๋˜์ง€ ์•Š์„ ํŒŒ์ผ ๋˜๋Š” ํด๋”๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

// ๊ฒ€์ƒ‰์‹œ ๊ฒ€์ƒ‰๋˜์ง€ ์•Š์„ ํŒŒ์ผ ๋ฐ ๋””๋ ‰ํ† ๋ฆฌ ์„ค์ •
"search.exclude": {
    "**/.git": true,
    "**/node_modules": true,
    "**/bower_components": true,
    "**/tmp": true,
    "**/build": true,
    "**/dist": true,
    "**/yarn.lock": true,
    "**/*.log": true,
},

Vscode Explorer ์•„์ด์ฝ˜ ์„ค์ •

truepoint์˜ REST API ์„œ๋น„์Šค๋Š” nestjs ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. nestjs๋Š” ์ผ๊ด€ํ™”๋œ ๋ฐฉ์‹์œผ๋กœ Nodejs Backend ์•ฑ์„ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ค๋‹ˆ๋‹ค.
nestjs๋Š” Angular์˜ ์ฒ ํ•™๊ณผ ๊ฐœ๋…์„ ๋งŽ์€ ๋ถ€๋ถ„ ์ฐจ์šฉํ•˜์˜€๊ณ , ๊ทธ์— ๋”ฐ๋ฅด๋Š” ์—ฌ๋Ÿฌ ๊ฐœ๋…๊ณผ ๊ทธ์— ๋”ฐ๋ฅด๋Š” ํŒŒ์ผ ๋„ค์ด๋ฐ ๋ฃฐ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
vscode์˜ material-icon-theme ํ™•์žฅํ”„๋กœ๊ทธ๋žจ์„ ์‚ฌ์šฉํ•˜๋ฉด ํƒ์ƒ‰๊ธฐ์—์„œ ๋”์šฑ ์‰ฝ๊ณ  ๋ช…ํ™•ํ•˜๊ฒŒ ํŒŒ์ผ๊ณผ ํด๋”๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

vscode์˜ Material Icon Theme๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. ( Extensions => material-icon-theme ๊ฒ€์ƒ‰ => intsall and enable )
๊ธฐ๋ณธ์ ์œผ๋กœ material-icon-theme๋Š” nestjs ๋ฐฉ์‹์˜ ํŒŒ์ผ๋“ค์„ Angular ์•„์ด์ฝ˜์œผ๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. nestjs ์•„์ด์ฝ˜์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ์˜ ๊ณผ์ •์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

Cmd + , (windows: ctrl + , )=> ์šฐ์ธก ์ƒ๋‹จ Open Settings(JSON) ๋ฒ„ํŠผ์œผ๋กœ ์„ค์ •ํŒŒ์ผ์„ ์—ด์–ด ๋‹ค์Œ ๋‚ด์šฉ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
์ด๋ฅผ ํ†ตํ•ด vscode Explorer์—์„œ Nest์™€ ๊ด€๋ จ๋œ ํŒŒ์ผ, ํด๋”๋“ค์ด ๋” ๋ช…ํ™•ํ•œ ์•„์ด์ฝ˜์œผ๋กœ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

// material-icon-theme config
"material-icon-theme.files.associations": {
    "*.pipe.ts": "nest-pipe",
    "*.guard.ts": "nest-guard",
    "*.controller.ts": "nest-controller",
    "*.module.ts": "nest-module",
    "*.service.ts": "nest-service",
    "*.middleware.ts": "nest-middleware",
    "*.filter.ts": "nest-filter",
    "*.interface.ts": "typescript-def",
    "*.dto.ts": "nest-resolver",
    "*.strategy.ts": "key",
    "*.entity.ts": "sequelize",
    "*.config.ts": "settings",
    "*.style.ts": "css",
    "*.roles.ts": "nest-decorator",
    "*.decorator.ts": "nest-decorator",
},
"material-icon-theme.folders.associations": {
    "interfaces": "typescript",
    "atoms": "react-components",
    "organisms": "core",
    "dto": "delta",
    "strategies": "keys",
    "entities": "database"
}

์„ค์น˜ ๋ฐ ์‹คํ–‰

truepoint์˜ ๋ชจ๋“  ์„œ๋น„์Šค๋Š” ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €๋กœ yarn์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋จผ์ € yarn์„ ์„ค์น˜ํ•œ ์ดํ›„, yarn์„ ํ†ตํ•ด ๊ฐ ์„œ๋น„์Šค ํด๋”์˜ ์˜์กด๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. yarn ๊ณต์‹ ํ™ˆํŽ˜์ด์ง€ - ์„ค์น˜

๋‹ค์Œ์˜ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ์˜์กด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ ํ•ฉ๋‹ˆ๋‹ค.

cd client
yarn
cd server
yarn

๋‹ค์Œ์˜ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ๊ฐ ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค

  • ํ”„๋ก ํŠธ ์—”๋“œ
# ์œˆ๋„์šฐ์ฆˆ OS
yarn start
# ๋งฅOS
yarn start:mac
  • ๋ฐฑ์—”๋“œ
# OS ๊ตฌ๋ถ„ ์—†์ด ์‹คํ–‰ ์Šคํฌ๋ฆฝํŠธ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

# devํ™˜๊ฒฝ ( hot reloading )
yarn start:dev

repository ๊ตฌ์„ฑ ๋ณ€๊ฒฝ (2020.10.14 ~)

monorepo

monorepo๋ž€ ๋‹ค์–‘ํ•œ ๋ชจ๋“ˆ์„ ์—ฌ๋Ÿฌ ๋ฆฌํŒŒ์ง€ํ† ๋ฆฌ๋กœ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๊ณ , ํ•˜๋‚˜์˜ ๋ฆฌํŒŒ์ง€ํ† ๋ฆฌ์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. monorepo๋กœ์„œ ์—ฌ๋Ÿฌ ๋ชจ๋“ˆ์„ ํ•จ๊ป˜ ๊ด€๋ฆฌํ•˜๊ฒŒ ๋˜๋ฉด ์ „์—ญ์ ์œผ๋กœ eslint๋‚˜ husky, tsconfig ๋“ฑ์— ๋Œ€ํ•ด ์„ค์ • ํ•˜์—ฌ ํ†ต์ผ์„ฑ์žˆ๋Š” ํ”„๋กœ์ ํŠธ ๊ด€๋ฆฌ์— ์šฉ์ดํ•˜๋ฉฐ, ๊ฐ ๋ชจ๋“ˆ ๊ฐ„ ์˜์กด์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์— ์šฉ์ดํ•ฉ๋‹ˆ๋‹ค.

tp-mvp ํ”„๋กœ์ ํŠธ์—์„œ๋Š” monorepo๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. ์ด๋กœ์ธํ•ด ๋ณ€๊ฒฝ๋˜๋Š” ํด๋” ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค

  • ํ˜„์žฌ
tp-mvp
  client
    web
      package.json
      node_modules
      yarn.lock
      .eslintrc
    admin
      package.json
      node_modules
      yarn.lock
      .eslintrc
  server
    package.json
    node_modules
    yarn.lock
    .eslintrc
  • ์ดํ›„
tp-mvp
  client
    web
      package.json
    admin
      package.json
  server
    package.json
  shared
    package.json
  node_modules
  yarn.lock
  .eslintrc

tp-mvp์˜ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ ๋ณ€๊ฒฝ์ 

๊ธฐ์กด UI ๋ฐ ์›น ํŽ˜์ด์ง€ ๋ฆฌ์•กํŠธ ์„œ๋ฒ„๋Š” client/web, Nest API ์„œ๋ฒ„๋Š” server ํด๋”์— ๊ด€๋ฆฌ๋˜์–ด ์™”์œผ๋ฉฐ, HTTP/S ์—ฐ๊ฒฐ๋กœ ์„œ๋กœ ํ†ต์‹ ํ•˜๋ฉฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›๋Š” ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค. useAxios hook์„ ํ†ตํ•ด ๋ฐฑ์—”๋“œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๊ณ , ์ €ํฌ๋Š” ๋ฐฑ์—”๋“œ๋กœ ๋ถ€ํ„ฐ ์‘๋‹ต๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์™€ ๋ฆฌ์•กํŠธ ๋‚ด๋ถ€์—์„œ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ๋ Œ๋”๋ง ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์˜ ๊ณผ์ •์—์„œ ํ”„๋ก ํŠธ์—”๋“œ๋Š” ๋ฐฑ์—”๋“œ๋กœ๋ถ€ํ„ฐ ์‘๋‹ต๋˜๋Š” ๋ฐ์ดํ„ฐ์˜ ํ˜•ํƒœ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋˜๋Š” ์ง€ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ axios์—์„œ ๋ฐฑ์—”๋“œ๋กœ๋ถ€ํ„ฐ ๋ฐ˜ํ™˜๋˜๋Š” ๋ฐ์ดํ„ฐ ๊ฐ์ฒด์ธres.data์˜ ํƒ€์ž…์€ any๋กœ ์„ค์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. res.data๋ฅผ any๊ฐ€ ์•„๋‹Œ ์•Œ๋งž์€ ํƒ€์ž… ๋˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ–๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” axios ์š”์ฒญ์‹œ generic์„ ํ†ตํ•ด res.data์˜ ํƒ€์ž…์„ ๋ช…์‹œํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ๋ฐฑ์—”๋“œ๋Š” ํ”„๋ก ํŠธ์—”๋“œ๋กœ๋ถ€ํ„ฐ API ์š”์ฒญ์‹œ ์ „์†ก๋  ์ •ํ™•ํ•œ ๋ฐ์ดํ„ฐ์˜ ํ˜•ํƒœ(data transfer object, DTO)๋ฅผ ์ •์˜ํ•ด ๋‘์–ด์•ผ ํ•˜๋ฉฐ, ๊ทธ ์ •์˜๋œ ๋ฐ์ดํ„ฐ ํ˜•ํƒœ์— ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋งž๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜์˜€๋Š”๊ฐ€๋ฅผ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋”๋ถˆ์–ด ํ”„๋ก ํŠธ์—”๋“œ๋กœ ์‘๋‹ตํ•  ๋ฐ์ดํ„ฐ์˜ ํ˜•ํƒœ๋ฅผ ์ •์˜ํ•ด ๋‘์–ด์•ผ ํ•˜๋ฉฐ, ํ”„๋ก ํŠธ์—”๋“œ์™€๋Š” ํ•ด๋‹น ๋ฐ˜ํ™˜๋  ํƒ€์ž…์ •๋ณด๋ฅผ ๊ณต์œ ํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ์กด์˜ tp ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋ฐฑ์—”๋“œ์˜ ๊ฒฝ์šฐ DTO๋ฅผ ์ •์˜ํ•˜๊ณ , ์‘๋‹ตํ•  ๋ฐ์ดํ„ฐ ํ˜•ํƒœ์—ญ์‹œ ์ •์˜ํ•ด์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ”„๋ก ํŠธ์—”๋“œ์—์„œ๋Š” ๋Œ€๊ฐœ์˜ ๊ฒฝ์šฐ ๋ฐฑ์—”๋“œ๋กœ๋ถ€ํ„ฐ ์‘๋‹ต๋ฐ›์€ ๋ฐ์ดํ„ฐ์˜ ํ˜•ํƒœ๋ฅผ ๋ชจ๋ฅธ์ฑ„(any๋กœ ๋‘” ์ฑ„) ์ž‘์—…์„ ์ง„ํ–‰ํ•ด์™”์Šต๋‹ˆ๋‹ค. ์ด ์ž‘์—…์ด ๊ฐ•์ œ๋˜์ง€ ์•Š์•˜์œผ๋ฉฐ ๊ท€์ฐฎ๊ธฐ๋„ ํ–ˆ์ฃ .

์ด์ œ๋Š” ๋ฐฑ์—”๋“œ์™€ ํ”„๋ก ํŠธ์—”๋“œ๊ฐ„ ๋™์‹œ์— ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ shared ๋ผ๋Š” ์ƒˆ๋กœ์šด ๋ชจ๋“ˆ์—์„œ ์ •์˜ํ•˜๊ณ  ๋ฐฑ์—”๋“œ์™€ ํ”„๋ก ํŠธ์—์„œ shared๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

shared ๋ชจ๋“ˆ์€ ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ์ข…๋ฅ˜์˜ ํŒŒ์ผ์„ ์ •์˜ํ•ด ๋‘๋Š” ๊ณณ์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  1. ๋ฐ์ดํ„ฐ ์ „์†ก ๊ฐ์ฒด์ธ DTO - class-validator ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  2. ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ ๋ฐฑ์—”๋“œ๋กœ๋ถ€ํ„ฐ ๋ฐ˜ํ™˜๋ฐ›๋Š” ๋ฐ์ดํ„ฐ ( ๋ฐฑ์—”๋“œ์˜ ํŠน์ • ๋ผ์šฐํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐ์ดํ„ฐ )์˜ ํƒ€์ž… - typescript interface 2-1. ์‘๋‹ตํ•˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์—”ํ„ฐํ‹ฐ์™€ ๊ด€๊ณ„๊ฐ€ ๊นŠ์€ ๊ฒฝ์šฐ, ์ด interface ๋Š” ๊ฐ ๋ฆฌ์†Œ์Šค Entity ์—์„œ implement ํ•˜๋Š” ๋“ฑ ํ•ด๋‹น entity์˜ ๋ชจ์ฒด๋กœ์„œ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)

ํ•ด๋‹น ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์ ์šฉ ๋œ ์ดํ›„ ์ฝ”๋”ฉ ๋ฐฉ๋ฒ•

Frontend

  1. ๋ชจ๋“  useAxios ์š”์ฒญ์—์„œ useAxios<SomeResponseType> ์™€ ๊ฐ™์ด generic์œผ๋กœ ๋ฐ˜ํ™˜๋ฐ›๋Š” ๋ฐ์ดํ„ฐ ํ˜•ํƒœ๋ฅผ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ชจ๋“  useAxios ์š”์ฒญ์—์„œ ํ•จ๊ป˜ ๋ณด๋‚ด๋Š” ๋ฐ์ดํ„ฐ (GET method ์˜ ๊ฒฝ์šฐ params, POST,PATCH,DELETE์˜ ๊ฒฝ์šฐ data ๊ฐ์ฒด) ํ˜•ํƒœ๋ฅผ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.
  3. ์œ„์—์„œ ๋ช…์‹œํ•˜๋Š” ๋ชจ๋“  ํƒ€์ž…(DTO, interface, type)์€ shared ๋ชจ๋“ˆ ์—์„œ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  • ์˜ˆ์‹œ1) shared์˜ Notice entity ์˜ ๋ชจ์ฒด๊ฐ€ ๋˜๋Š” interface
export interface Notice {
  id: number;

  category: string;
}
  • ์˜ˆ์‹œ1-1) client์˜ ๋ฐ์ดํ„ฐ ์š”์ฒญ์ด ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ
import { Notice } from '@truepoint/shared/dist/interface/Notice.interface';
import { NoticeGetDto } from '@truepoint/shared/dist/dto/NoticeGet.dto';

export function SomeComponent() {
  const dto: NoticeGetDto = { userId: 'userId1' };
  const [{data, loading}] = useAxios<Notice>(
    { url: '/notice', method: 'get', params: dto }
  )
  return (<div>์นดํ…Œ๊ณ ๋ฆฌ: {loading ? 'loading...' : data.category}</div>)
}

Backend

  1. ๋ชจ๋“  POST, PATCH, PUT, DELETE ์š”์ฒญ ํ•ธ๋“ค๋Ÿฌ์—๋Š” DTO ๋ฅผ ์ •์˜ํ•˜๊ณ , ValidationPipe๋กœ ์š”์ฒญ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•ด ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค.
    (GET ์š”์ฒญ ํ•ธ๋“ค๋Ÿฌ์—๋Š” DTO๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.)
  2. ๋ชจ๋“  ๋ผ์šฐํ„ฐ์˜ ์‘๋‹ต ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ํ˜•ํƒœ๋ฅผ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, controller์˜ ๊ฐ ๋ฉ”์†Œ๋“œ(์š”์ฒญ ํ•ธ๋“ค๋Ÿฌ)์— ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ชจ๋“  Entity ์ •์˜ ์‹œ, ํ•ด๋‹น Entity์˜ ๋ชจ์ฒด๊ฐ€ ๋˜๋Š” interface๋ฅผ implements ํ•˜์—ฌ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
  4. ์œ„์—์„œ ๋ช…์‹œํ•œ ๋ชจ๋“  ํƒ€์ž…(DTO, ์‘๋‹ต ๋ฐ์ดํ„ฐ)์€ shared ๋ชจ๋“ˆ์—์„œ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  • ์˜ˆ์‹œ2) shared์˜ Notice entity ์˜ ๋ชจ์ฒด๊ฐ€ ๋˜๋Š” interface
export interface Notice {
  id: number;

  category: string;
}
  • ์˜ˆ์‹œ2-1) server/resources/notice/entities/notice.entity.ts
import { Notice } from '@truepoint/shared/dist/interfaces/Notice.interface';
import {
  Column, Entity, PrimaryGeneratedColumn,
} from 'typeorm';

@Entity('Notice')
export class NoticeEntity implements Notice { // shared์˜ Notice ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ชจ์ฒด๋กœ ์‚ฌ์šฉ.
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ comment: '๊ณต์ง€์‚ฌํ•ญ ๊ตฌ๋ถ„' })
  category: string;
}
  • ์˜ˆ์‹œ2-2) server/resources/notice/notice.controller.ts
import { Notice } from '@truepoint/shared/dist/interfaces/Notice.interface';
import { NoticeGetDto } from '@truepoint/shared/dist/dto/NoticeGet.dto';
import { Controller, Get } from '@nestjs/common';

@Controller('notice')
export class NoticeController {
  constructor(private readonly noticeService: NoticeService) {}

  @Post()
  async create(
    @Body() dto: NoticeGetDto,
  ): Promise<Notice[]> {
    return this.noticeService.create(dto);
  }

shared ๋ชจ๋“ˆ์„ ์ฐธ์กฐํ•˜๋Š” ๋ฐฉ๋ฒ•

  • dto import { SomethingDto } from '@truepoint/shared/dist/dto/Something.dto';
  • ๋ฐ˜ํ™˜ ๋ฐ์ดํ„ฐ ํƒ€์ž… ๋˜๋Š” entity ๋ชจ์ฒด ํƒ€์ž… import { SomeResponseType } from '@truepoint/shared/dist/interfaces/Something.dto';

์˜ˆ์™ธ์  ์ƒํ™ฉ

  • Backend ์˜ Entity์™€๋Š” ์•„๋ฌด ์ƒ๊ด€์—†๋Š” ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์‘๋‹ตํ•  ๋•Œ shared/res ํด๋”์— ํ•ด๋‹น์‘๋‹ต์˜ interface๋ฅผ ์ •์˜ํ•œ ํ›„ client์˜ useAxios ์š”์ฒญ, ๋ฐฑ์—”๋“œserver์˜ ๋ผ์šฐํŠธ ํ•ธ๋“ค๋Ÿฌ ์—์„œ ๊ฐ™์€ ํƒ€์ž…์„ ๊ณต์œ 

์„ค์น˜ ๋ฐ ์‹คํ–‰

์„ค์น˜

  • ์ด์ œ ๊ฐ ํด๋”์— server, client/web, client/admin, shared ์—์„œ ๊ฐ๊ฐ yarn install ์„ ํ†ตํ•ด dependencies๋ฅผ ์„ค์น˜ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค. ๊ฐ ํด๋” ๋˜๋Š” ์ตœ์ƒ์œ„ ํด๋”์—์„œ yarn install(yarn)์„ ํ•œ ๋ฒˆ๋งŒ ์ง„ํ–‰ํ•˜๋ฉด ์•Œ์•„์„œ server, client/web, client/admin ๋“ฑ์— dependencies๊ฐ€ ๋ชจ๋‘ ์„ค์น˜๋ฉ๋‹ˆ๋‹ค.

์‹คํ–‰

  • ์‹คํ–‰์€ ๊ธฐ์กด๊ณผ ๊ฐ™์ด server -> yarn start:dev, client/web -> yarn start, client/admin -> yarn start ๋กœ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • shared ๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰ํ•  ์ผ์€ ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€์‹ , server, client/web, client/admin์—์„œ shared ์— ์ •์˜๋œ DTO ๋˜๋Š” interface ๋“ฑ์„ ์ฐธ์กฐ ํ•˜๋Š” ๊ฒฝ์šฐ, shared/dist ์˜ ์ปดํŒŒ์ผ๋œ js ํŒŒ์ผ์„ ํ•„์š”๋กœ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์žˆ๋Š” ๊ฒฝ์šฐ yarn build ๋ฅผ ํ†ตํ•ด ts -> js ์ปดํŒŒ์ผ์„ ์ง„ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŽธํ•˜๊ฒŒ ๊ฐœ๋ฐœ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์žˆ์„ ๋•Œ๋งˆ๋‹ค ๋นŒ๋“œ๊ฐ€ ์ง„ํ–‰๋˜๋„๋ก ํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. yarn start:dev ์Šคํฌ๋ฆฝํŠธ๋กœ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์žˆ์„ ๋•Œ๋งˆ๋‹ค ์ปดํŒŒ์ผ ํ•˜๋Š” ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ•ด ๋‘์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๊ฐ„๋‹จํžˆ ๋งํ•ด shared ์—ญ์‹œ yarn start:dev๋กœ ์‹คํ–‰ํ•ด ๋‘” ์ฑ„ ์ž‘์—…์„ ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ํŽธํ•ฉ๋‹ˆ๋‹ค.

eslint ๋ฐ ๊ด€๋ฆฌ ๊ด€๋ จ ๋ณ€๊ฒฝ์‚ฌํ•ญ

  • ์ปค๋ฐ‹ ๋‹จ๊ณ„ lint ์ œํ•œ husky์™€ lint-staged ๋ฅผ ํ†ตํ•ด git ์ปค๋ฐ‹์‹œ, ํ˜„์žฌ staged ์ƒํƒœ์ธ ํŒŒ์ผ๋“ค์— ๋Œ€ํ•ด eslint ๊ฒ€์‚ฌํ•˜๊ณ , ํ•ด๋‹น ๊ฒ€์‚ฌ์—์„œ eslint๋ฅผ ํ†ต๊ณผํ•˜์ง€ ๋ชปํ•˜๋ฉด (error ๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ๋‹ค๋ฉด) ์ปค๋ฐ‹์ด ์ง„ํ–‰๋˜์ง€ ์•Š๋„๋ก ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.
  • PR ๋‹จ๊ณ„ lint ์ œํ•œ github actions๋ฅผ ํ†ตํ•ด PR์‹œ, ๋ณ€๊ฒฝํ•œ ํŒŒ์ผ ๋งŒ์„ ํฌํ•จํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ๊ฐ ๋ชจ๋“ˆ์˜ ๋ชจ๋“  ํŒŒ์ผ์— ๋Œ€ํ•ด eslint ๊ฒ€์‚ฌ ์ง„ํ–‰ํ•˜์—ฌ ๋ฏธ ํ†ต๊ณผ ์‹œ merge๊ฐ€ ๋ถˆ๊ฐ€ํ•˜๋„๋ก ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์‹œ1.) server์™€, client/web์—์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์žˆ๋Š” PR์ด๋ฉด, server ํด๋”์™€ client/web ํด๋”์˜ ๋ชจ๋“  ํŒŒ์ผ์„ eslint ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์‹œ2.) server ์—์„œ๋งŒ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ณ€๊ฒฝํ•œ ๊ฒฝ์šฐ, server ํด๋”์˜ ๋ชจ๋“  ํŒŒ์ผ์— ๋Œ€ํ•ด์„œ eslint ๊ฒ€์‚ฌ๋ฅผ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • PR ๋‹จ๊ณ„ ํ…Œ์ŠคํŠธ ์ œํ•œ ( ํ–ฅํ›„ ์—…๋ฐ์ดํŠธ ์‚ฌํ•ญ ) github actions๋ฅผ ํ†ตํ•ด PR์‹œ, jest ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ง„ํ–‰ํ•˜์—ฌ coverage๊ฐ€ ํŠน์ • ์ˆ˜์ค€ ์ดํ•˜์ธ ๊ฒฝ์šฐ merge๊ฐ€ ๋ถˆ๊ฐ€ํ•˜๋„๋ก ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.

About

pilot project for True point (minimum viable product)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 9