|
| 1 | +# Denamu Project - GitHub Copilot Instructions |
| 2 | + |
| 3 | +## ํ๋ก์ ํธ ๊ฐ์ |
| 4 | + |
| 5 | +**๋ฐ๋๋ฌด(Denamu)** - RSS ๊ธฐ๋ฐ ๊ธฐ์ ๋ธ๋ก๊ทธ ํ๋ ์ด์
ํ๋ซํผ |
| 6 | + |
| 7 | +๊ฐ๋ฐ์๋ค์ด ๋ถ์ฐ๋ ๊ธฐ์ ๋ธ๋ก๊ทธ ์ฝํ
์ธ ๋ฅผ ํ ๊ณณ์์ ํธ๋ฆฌํ๊ฒ ๊ตฌ๋
ํ๊ณ , ์ค์๊ฐ ํธ๋ ๋๋ฅผ ํ์ธํ๋ฉฐ, ์ปค๋ฎค๋ํฐ๋ฅผ ํตํด ์ํตํ ์ ์๋ ์๋น์ค์
๋๋ค. |
| 8 | + |
| 9 | +## ํ๋ก์ ํธ ๊ตฌ์กฐ |
| 10 | + |
| 11 | +### `/server` |
| 12 | + |
| 13 | +- **NestJS ๊ธฐ๋ฐ WAS(Web Application Server)** |
| 14 | +- TypeORM์ ์ฌ์ฉํ MySQL ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๋ |
| 15 | +- Redis๋ฅผ ํ์ฉํ ์บ์ฑ ๋ฐ ์ธ์
๊ด๋ฆฌ |
| 16 | +- Socket.IO ๊ธฐ๋ฐ ์ค์๊ฐ ์ฑํ
๊ธฐ๋ฅ |
| 17 | +- JWT ์ธ์ฆ ๋ฐ OAuth(Google, GitHub) ์์
๋ก๊ทธ์ธ |
| 18 | +- Prometheus๋ฅผ ํตํ ๋ชจ๋ํฐ๋ง |
| 19 | +- Winston์ ํ์ฉํ ๊ตฌ์กฐํ๋ ๋ก๊น
|
| 20 | + |
| 21 | +### `/feed-crawler` |
| 22 | + |
| 23 | +- **RSS ํผ๋ ํฌ๋กค๋ฌ ์๋น์ค** |
| 24 | +- ๋ฑ๋ก๋ RSS ํผ๋๋ฅผ ์ฃผ๊ธฐ์ ์ผ๋ก ์์ง |
| 25 | +- AI(Anthropic Claude) ๊ธฐ๋ฐ ์ฝํ
์ธ ๋ถ์ ๋ฐ ํ๊ทธ ์์ฑ |
| 26 | +- MySQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์์ง ๋ฐ์ดํฐ ์ ์ฅ |
| 27 | +- ์์กด์ฑ ์ฃผ์
(tsyringe) ๊ธฐ๋ฐ ์ํคํ
์ฒ |
| 28 | + |
| 29 | +### `/client` |
| 30 | + |
| 31 | +- **React + TypeScript ๊ธฐ๋ฐ ํ๋ก ํธ์๋** |
| 32 | +- Vite ๋น๋ ๋๊ตฌ ์ฌ์ฉ |
| 33 | +- TanStack Query๋ฅผ ํตํ ์๋ฒ ์ํ ๊ด๋ฆฌ |
| 34 | +- Zustand๋ฅผ ํตํ ํด๋ผ์ด์ธํธ ์ํ ๊ด๋ฆฌ |
| 35 | +- Radix UI + Tailwind CSS ๊ธฐ๋ฐ ์ปดํฌ๋ํธ ์์คํ
|
| 36 | +- Socket.IO Client๋ก ์ค์๊ฐ ์ฑํ
์ฐ๋ |
| 37 | + |
| 38 | +### `/docker-compose` |
| 39 | + |
| 40 | +- **์ธํ๋ผ ๊ตฌ์ฑ ํ์ผ** |
| 41 | +- ๋ก์ปฌ ๊ฐ๋ฐ ํ๊ฒฝ (docker-compose.local.yml) |
| 42 | +- ๊ฐ๋ฐ ์๋ฒ ํ๊ฒฝ (docker-compose.dev.yml) |
| 43 | +- ํ๋ก๋์
ํ๊ฒฝ (docker-compose.prod.yml) |
| 44 | +- ์ธํ๋ผ ์๋น์ค (MySQL, Redis, Prometheus, Grafana) |
| 45 | + |
| 46 | +--- |
| 47 | + |
| 48 | +## ์ฝ๋ ๋ฆฌ๋ทฐ ๊ฐ์ด๋๋ผ์ธ |
| 49 | + |
| 50 | +### ๋ฆฌ๋ทฐ ์ธ์ด |
| 51 | + |
| 52 | +์ฝ๋ ๋ฆฌ๋ทฐ์์๋ ๋ฐ๋์ ํ๊ตญ์ด๋ฅผ ์ฌ์ฉํ์ธ์. |
| 53 | + |
| 54 | +### ๋ฆฌ๋ทฐ ์ฐ์ ์์ (Pn ๋ฃฐ ์ ์ฉ) |
| 55 | + |
| 56 | +์ฝ๋ ๋ฆฌ๋ทฐ ์ ์๋ ์ฐ์ ์์๋ฅผ ๋ฐ๋์ ๋ช
์ํ์ฌ ํผ๋๋ฐฑ์ ์ ๊ณตํ์ธ์: |
| 57 | + |
| 58 | +- **P1 (์ต์ฐ์ )**: ์ฆ๊ฐ ์์ ์ด ํ์ํ ์ค๋ํ ๋ฌธ์ (๋ณด์ ์ทจ์ฝ์ , ํฌ๋ฆฌํฐ์ปฌ ๋ฒ๊ทธ, ๋น์ฆ๋์ค ๋ก์ง ์ค๋ฅ) |
| 59 | +- **P2 (๋งค์ฐ ์ค์)**: ๋ฐ๋์ ๋ฐ์ํด์ผ ํ๋ ์ฝ๋ ํ์ง/๊ธฐ๋ฅ ์ด์ |
| 60 | +- **P3 (์ค์)**: ์ ์ฌ์ ๋ฒ๊ทธ ์ํ์ด๋ ์ค์ํ ๊ฐ์ ์ฌํญ |
| 61 | +- **P4 (๊ฐ๋ฒผ์ด ์ ์)**: ๊ฐ๋
์ฑ/์ ์ง๋ณด์์ฑ ๊ฐ์ ๊ถ์ฅ ์ฌํญ |
| 62 | +- **P5 (์ง๋ฌธ ๋ฐ ์ถ์ฒ)**: ์ ํ์ ์ ์ ๋ฐ ์ง๋ฌธ |
| 63 | + |
| 64 | +### ๋ฐฑ์๋ ์ฝ๋ ๋ฆฌ๋ทฐ ์ค์ ์ฌํญ |
| 65 | + |
| 66 | +#### 1. ๋ณด์ ๋ฐ ์ ์ฌ ๋ฒ๊ทธ ์ํ (P1-P2) |
| 67 | + |
| 68 | +- **SQL Injection**: TypeORM ์ฟผ๋ฆฌ ๋น๋ ์ฌ์ฉ ์ raw query ๊ฒ์ฆ |
| 69 | +- **์ธ์ฆ/์ธ๊ฐ**: JWT ํ ํฐ ๊ฒ์ฆ, refresh token ๊ฐฑ์ ๋ก์ง ํ์ธ |
| 70 | +- **์
๋ ฅ ๊ฒ์ฆ**: class-validator DTO ๊ฒ์ฆ ๋๋ฝ ์ฌ๋ถ |
| 71 | +- **XSS ๋ฐฉ์ง**: ์ฌ์ฉ์ ์
๋ ฅ sanitization ํ์ธ |
| 72 | +- **Race Condition**: Redis ๋์์ฑ ์ ์ด (๋ฝ, ํธ๋์ญ์
) |
| 73 | +- **์๋ฌ ํธ๋ค๋ง**: try-catch ๋๋ฝ, ์ ์ ํ HTTP ์ํ ์ฝ๋ ๋ฐํ |
| 74 | +- **ํ์ผ ์
๋ก๋**: ํ์ผ ํฌ๊ธฐ ์ ํ, MIME ํ์
๊ฒ์ฆ |
| 75 | +- **๋ฆฌ์์ค ๋์**: DB ์ปค๋ฅ์
, ํ์ผ ํธ๋ค๋ฌ ์ ๋ฆฌ ํ์ธ |
| 76 | + |
| 77 | +#### 2. ๋น์ฆ๋์ค ๋ก์ง ๊ฒ์ฆ (P1-P3) |
| 78 | + |
| 79 | +- **๋ฐ์ดํฐ ์ผ๊ด์ฑ**: ํธ๋์ญ์
๋ฒ์ ์ ์ ์ฑ |
| 80 | +- **์ํ ์ ์ด**: ์ํฐํฐ ์ํ ๋ณํ ๋ก์ง์ ์ ํฉ์ฑ |
| 81 | +- **์ฃ์ง ์ผ์ด์ค**: ๊ฒฝ๊ณ๊ฐ, null/undefined ์ฒ๋ฆฌ |
| 82 | +- **์ค๋ณต ๋ฐฉ์ง**: ์กฐํ์ ์ฆ๊ฐ, ์ข์์ ๋ฑ ์ค๋ณต ๋ฐฉ์ง ๋ก์ง |
| 83 | +- **๋๋ฉ์ธ ๊ท์น**: ๋น์ฆ๋์ค ์ ์ฝ ์กฐ๊ฑด ์ค์ ์ฌ๋ถ |
| 84 | + |
| 85 | +#### 3. ์ฑ๋ฅ ์ต์ ํ (P2-P4) |
| 86 | + |
| 87 | +- **N+1 ์ฟผ๋ฆฌ**: TypeORM relations eager loading ํ์ธ |
| 88 | +- **์ธ๋ฑ์ค ํ์ฉ**: WHERE, JOIN ์กฐ๊ฑด์ ์ธ๋ฑ์ค ์ฌ์ฉ |
| 89 | +- **์บ์ฑ ์ ๋ต**: Redis ์บ์ TTL ์ ์ ์ฑ, ์บ์ ๋ฌดํจํ ๋ก์ง |
| 90 | +- **ํ์ด์ง๋ค์ด์
**: offset ๋์ cursor ๊ธฐ๋ฐ ํ์ด์ง๋ค์ด์
๊ณ ๋ ค |
| 91 | +- **๋ถํ์ํ ์ฟผ๋ฆฌ**: ์ค๋ณต DB ํธ์ถ ์ ๊ฑฐ |
| 92 | +- **๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ**: ๋์ฉ๋ ๋ฐ์ดํฐ ์คํธ๋ฆฌ๋ฐ ์ฒ๋ฆฌ |
| 93 | + |
| 94 | +#### 4. ์ฝ๋ ํ์ง (P3-P5) |
| 95 | + |
| 96 | +- **SOLID ์์น**: ๋จ์ผ ์ฑ
์, ์์กด์ฑ ์ญ์ ์ค์ |
| 97 | +- **์ค๋ณต ์ ๊ฑฐ**: DRY ์์น, ๊ณตํต ๋ก์ง ์ถ์ถ |
| 98 | +- **๋ช
๋ช
๊ท์น**: ๋ช
ํํ๊ณ ์ผ๊ด๋ ๋ณ์/ํจ์๋ช
|
| 99 | +- **ํ์
์์ ์ฑ**: any ํ์
๋จ์ฉ ๋ฐฉ์ง, ์ ์ ํ ํ์
์ ์ |
| 100 | +- **ํ
์คํธ ์ปค๋ฒ๋ฆฌ์ง**: ์ฃผ์ ๋น์ฆ๋์ค ๋ก์ง ๋จ์ ํ
์คํธ |
| 101 | + |
| 102 | +--- |
| 103 | + |
| 104 | +## ๊ธฐ์ ์คํ๋ณ ๊ถ์ฅ ์ฌํญ |
| 105 | + |
| 106 | +### NestJS (Server) |
| 107 | + |
| 108 | +- ๋ชจ๋ํ๋ ๊ตฌ์กฐ ์ ์ง (๊ฐ ๊ธฐ๋ฅ๋ณ Module, Controller, Service ๋ถ๋ฆฌ) |
| 109 | +- Dependency Injection ์ ๊ทน ํ์ฉ |
| 110 | +- Global Exception Filter๋ก ์ผ๊ด๋ ์๋ฌ ์๋ต |
| 111 | +- Pipe๋ฅผ ํตํ ์
๋ ฅ ๊ฒ์ฆ ๋ฐ ๋ณํ |
| 112 | +- Interceptor๋ก ๋ก๊น
, ์๋ต ๋ณํ ์ฒ๋ฆฌ |
| 113 | +- Guard๋ฅผ ํตํ ์ธ์ฆ/์ธ๊ฐ ๊ตฌํ |
| 114 | + |
| 115 | +### TypeScript ๊ณตํต |
| 116 | + |
| 117 | +- strict ๋ชจ๋ ํ์ฑํ ์ ์ง |
| 118 | +- enum ๋์ union type ์ฌ์ฉ ๊ณ ๋ ค |
| 119 | +- ํ์
์ถ๋ก ํ์ฉ, ๋ถํ์ํ ํ์
๋ช
์ ์ง์ |
| 120 | +- ์ ํธ๋ฆฌํฐ ํ์
์ ๊ทน ํ์ฉ (Pick, Omit, Partial ๋ฑ) |
| 121 | + |
| 122 | +### React (Client) |
| 123 | + |
| 124 | +- ์ปดํฌ๋ํธ ๋จ์ผ ์ฑ
์ ์์น ์ค์ |
| 125 | +- Custom Hooks๋ก ๋ก์ง ์ฌ์ฌ์ฉ |
| 126 | +- useCallback, useMemo๋ก ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง ๋ฐฉ์ง |
| 127 | +- TanStack Query์ staleTime, cacheTime ์ ์ ํ ์ค์ |
| 128 | +- ์ ๊ทผ์ฑ(a11y) ๊ณ ๋ ค (ARIA ๋ ์ด๋ธ, ํค๋ณด๋ ๋ค๋น๊ฒ์ด์
) |
| 129 | + |
| 130 | +--- |
| 131 | + |
| 132 | +## ๋ฆฌ๋ทฐ ์์ |
| 133 | + |
| 134 | +### ์ข์ ๋ฆฌ๋ทฐ ์์ |
| 135 | + |
| 136 | +``` |
| 137 | +P1) [๋ณด์] JWT ํ ํฐ ๊ฒ์ฆ ์ ๋ง๋ฃ ์๊ฐ(exp) ์ฒดํฌ๊ฐ ๋๋ฝ๋์์ต๋๋ค. |
| 138 | +๋ง๋ฃ๋ ํ ํฐ์ผ๋ก๋ ์ธ์ฆ์ด ํต๊ณผ๋ ์ ์์ด ์ฆ์ ์์ ์ด ํ์ํฉ๋๋ค. |
| 139 | +
|
| 140 | +P2) [์ฑ๋ฅ] findAll() ๋ฉ์๋์์ ์ ์ฒด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์จ ํ ํํฐ๋งํ๊ณ ์์ต๋๋ค. |
| 141 | +WHERE ์ ๋ก DB ๋ ๋ฒจ์์ ํํฐ๋งํ๋ ๊ฒ์ด ์ฑ๋ฅ์ ์ ๋ฆฌํฉ๋๋ค. |
| 142 | +
|
| 143 | +P3) [๋ฒ๊ทธ ๊ฐ๋ฅ์ฑ] Redis ์บ์ ์กฐํ ์คํจ ์ ์๋ฌ ํธ๋ค๋ง์ด ์์ต๋๋ค. |
| 144 | +Redis ์ฅ์ ์ ์๋น์ค ์ ์ฒด๊ฐ ์ค๋จ๋ ์ ์์ผ๋ fallback ๋ก์ง์ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข๊ฒ ์ต๋๋ค. |
| 145 | +
|
| 146 | +P4) [๊ฐ๋
์ฑ] ์ค์ฒฉ๋ if๋ฌธ์ด ๋ง์ ๋ก์ง ์ดํด๊ฐ ์ด๋ ต์ต๋๋ค. |
| 147 | +Early return ํจํด์ด๋ Guard clause๋ฅผ ํ์ฉํ๋ฉด ๋ ๋ช
ํํด์ง ๊ฒ ๊ฐ์ต๋๋ค. |
| 148 | +
|
| 149 | +P5) [์ ์] lodash ๋์ native array ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ์ค์ผ ์ ์์ต๋๋ค. |
| 150 | +์ฑ๋ฅ ์ฐจ์ด๊ฐ ํฌ์ง ์๋ค๋ฉด ๊ณ ๋ คํด๋ณด์๋ฉด ์ข์ ๊ฒ ๊ฐ์์. |
| 151 | +``` |
| 152 | + |
| 153 | +--- |
| 154 | + |
| 155 | +## ์ฃผ์์ฌํญ |
| 156 | + |
| 157 | +- **๋ฐฐํฌ ์ ์ฒดํฌ๋ฆฌ์คํธ**: ํ๊ฒฝ๋ณ์ ์ค์ , ๋ง์ด๊ทธ๋ ์ด์
์คํ, ํ
์คํธ ํต๊ณผ ํ์ธ |
| 158 | +- **๋ก๊น
**: ๋ฏผ๊ฐ ์ ๋ณด(๋น๋ฐ๋ฒํธ, ํ ํฐ) ๋ก๊ทธ ์ถ๋ ฅ ๊ธ์ง |
| 159 | +- **์๋ฌ ๋ฉ์์ง**: ํ๋ก๋์
์์๋ ์์ธ ์๋ฌ ์คํ ๋
ธ์ถ ๋ฐฉ์ง |
| 160 | +- **API ๋ฒ์ ๊ด๋ฆฌ**: Breaking change ์ API ๋ฒ์ ์
๊ณ ๋ ค |
| 161 | +- **DB ๋ง์ด๊ทธ๋ ์ด์
**: ๋ฐ์ดํฐ ์์ค ๋ฐฉ์ง๋ฅผ ์ํ ๋กค๋ฐฑ ๊ณํ ์๋ฆฝ |
0 commit comments