Polaryx๋ ๊ต์ก๊ธฐ๊ด์ ์ํ ๋ฉํฐํ ๋ํธ ํ์ต๊ด๋ฆฌ์์คํ (Learning Management System)์ ๋๋ค. Slack๊ณผ ์ ์ฌํ ์ง๊ด์ ์ธ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ฉฐ, ๊ต์ก๊ธฐ๊ด๋ณ ๋ ๋ฆฝ์ ์ธ ๋ฐ์ดํฐ ๊ด๋ฆฌ์ ํ์ฅ ๊ฐ๋ฅํ ์ํคํ ์ฒ๋ฅผ ํตํด ํจ์จ์ ์ธ ์จ๋ผ์ธ ๊ต์ก ํ๊ฒฝ์ ๊ตฌ์ถํฉ๋๋ค.
์๋น์ค ์ฃผ์: https://polaryx.net๊ธฐ์ ๋ฌธ์: ๐ ๊ธฐ์ ๋ฌธ์ ์ฐธ์กฐ
- ๋ฉํฐํ ๋ํธ ์ํคํ ์ฒ: ๊ต์ก๊ธฐ๊ด๋ณ ๋น์ฆ๋์ค ๋ก์ง, ๋ฐ์ดํฐ ๋ถ๋ฆฌ
- ์ญํ ๊ธฐ๋ฐ ์ ๊ทผ ์ ์ด(RBAC): ๊ฐ์ธ/๊ทธ๋ฃน ๋จ์์ ์ธ๋ถํ๋ ๊ถํ ๊ด๋ฆฌ
- ํ์ฅ ๊ฐ๋ฅํ ์์คํ ์ค๊ณ: DDD ๊ธฐ๋ฐ ๋ ์ด์ด๋ ์ํคํ ์ฒ ์ ์ฉ
- ์ค์๊ฐ ํ์ : Slack ์คํ์ผ์ ์ง๊ด์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ
- ์๋ํ๋ ๋ฐฐํฌ: CI/CD ํ์ดํ๋ผ์ธ์ ํตํ ์์ ์ ์ธ ์๋น์ค ์ด์
- ์ํฌ์คํ์ด์ค: ๊ต์ก๊ธฐ๊ด๋ณ ๋ ๋ฆฝ์ ์ธ ํ์ต ๊ณต๊ฐ
- ํญ: ์นดํ ๊ณ ๋ฆฌ (Anouncements / Courses / Channels / DirectMessage)๋ณ ๊ตฌ๋ถ ๋จ์
- ์๋ธํญ: ํญ ๋ด ์ธ๋ถ ๋ถ๋ฅ (์ถํ ๋์ ์์ )
- ์ค์๊ฐ ์ฑํ : WebSocket ๊ธฐ๋ฐ ์ค์๊ฐ ๋ฉ์์ง ์ ์ก/์์
- ๋ฆฌ์น ํ ์คํธ ์๋ํฐ: TipTap ๊ธฐ๋ฐ ๋ค์ํ ํ์ ์ง์ (๊ตต๊ฒ, ๊ธฐ์ธ์, ๋งํฌ ๋ฑ)
- ํ์ผ ์ ๋ก๋: ์ด๋ฏธ์ง, ๋ฌธ์ ์ฒจ๋ถ ๊ธฐ๋ฅ (AWS S3 ์ฐ๋)
- ์ด๋ชจ์ง ๋ฐ์: ์ฒดํฌ, ๋ฐ์, ์ข์์, ๊ธฐ๋, ๋ฐ์ง ์ด๋ชจ์ง๋ก ๋น ๋ฅธ ํผ๋๋ฐฑ
- ๋ฉ์์ง ํธ์ง/์ญ์ : ์ค์๊ฐ ๋ฉ์์ง ์์ ๋ฐ ์ญ์ ๊ธฐ๋ฅ
- ๋ฌดํ ์คํฌ๋กค: ํ์ด์ง๋ค์ด์ ๊ธฐ๋ฐ ๋ฉ์์ง ํ์คํ ๋ฆฌ ๋ก๋ฉ
- 4๋จ๊ณ ๊ถํ ์ฒด๊ณ:
- Admin: ์์คํ ์ ๋ฐ์ ๋ํ ๊ด๋ฆฌ ๋ฐ ์ค์
- Instructor: ๊ณต์ง, ํ์ต์๋ฃ ๊ด๋ฆฌ ๋ฐ ํ์ ํ๋
- Student: ํ์ต์๋ฃ ์ด๋, ๊ณผ์ ์ ์ถ ๋ฐ ํ์ ํ๋
- Guest: ๋ฏธ๋ฑ๋ก ์ฌ์ฉ์์ ๋ํ ์ ํ์ ์ ๊ทผ
- ๊ทธ๋ฃน ๊ด๋ฆฌ: ๊ทธ๋ฃน๋ณ ๊ถํ ์ค์
- ์ธ๋ถํ๋ ์ ๊ทผ ์ ์ด: ํ์ด์ง/๊ธฐ๋ฅ๋ณ ๊ถํ ์ค์
- ์ฌ์ฉ์ ๊ด๋ฆฌ: ํ์ ๋ฑ๋ก, ์ญํ ํ ๋น, ํ๋กํ ๊ด๋ฆฌ
- ๊ทธ๋ฃน ๊ด๋ฆฌ: ๊ต์ก์ ๋ฑ๋ก, ํญ ์ด๋ ๋ฑ ๊ทธ๋ฃน ๋จ์ ๊ด๋ฆฌ ๊ฐ๋ฅ
- ์ญํ ๊ด๋ฆฌ: ์ปค์คํ ์ญํ ์์ฑ ๋ฐ ๊ถํ ์ค์
- Excel ์ผ๊ด ์ ๋ก๋: ์ฌ์ฉ์ ์ ๋ณด ๋๋ ๋ฑ๋ก ๊ธฐ๋ฅ
- Canvas (Notion ์ฐ๋): ์ธ๋ถ Notion ํ์ด์ง ์๋ฒ ๋ฉ
- ๋งํฌ ์ ์ฅ์: ์ค์ ๋งํฌ ์์ง ๋ฐ ๊ณต์
- ๊ฒ์ ๊ธฐ๋ฅ: ๋ฉ์์ง, ์ฌ์ฉ์, ์ฝํ ์ธ ํตํฉ ๊ฒ์
- ์ ์ฅ๋ ๋ฉ์์ง: ์ค์ ๋ฉ์์ง ๋ถ๋งํฌ ๊ธฐ๋ฅ (์ถํ ๋์ ์์ )
- ์ค์๊ฐ ์๋ฆผ: SSE(Server-Sent Events) ๊ธฐ๋ฐ ์ํฌ์คํ์ด์ค๋ณ/ํญ๋ณ ์ ๊ท ๋ฉ์ธ์ง ์ฆ์ ์๋ฆผ
- ํธ์ ์๋ฆผ: PWA ๊ธฐ๋ฐ ๋ธ๋ผ์ฐ์ ํธ์ ์๋ฆผ
- ํ๋ ๋ถ์: ์ฌ์ฉ์๋ณ ์ฐธ์ฌ๋ ๋ฐ ๋ฉ์์ง ํต๊ณ
- ์ํฌ์คํ์ด์ค ํํฉ: ์ ์ฒด ํ๋ ํํฉ ๋์๋ณด๋
- WebSocket ์ฐ๊ฒฐ: ์ค์๊ฐ ๋ฉ์์ง ์ก์์
- ์๋ ์ฌ์ฐ๊ฒฐ: ์ฐ๊ฒฐ ๋๊น ์ ์๋ ์ฌ์ฐ๊ฒฐ
- ์ถ์ ์ํ: ์ถ์ ์ ์ปฌ๋ฌ ํ๋ฉด์ผ๋ก ํ์ฑํ (์ถํ ๋์ ์์ )
- ์จ๋ผ์ธ ์ํ: ์ฌ์ฉ์ ์ ์ ์ํ ํ์ (์ถํ ๋์ ์์ )
Frontend
TypeScript- ํ์ ์์ ์ฑ ๋ณด์ฅNext.js- Node.js ๋ฐฑ์๋ ์์ด FastAPI ์ง์ ์ฐ๋, App Router ๊ธฐ๋ฐ ํ์ผ ์์คํ ๋ผ์ฐํ ์ผ๋ก ๊ฐ๋ฐ ์์ฐ์ฑ ํฅ์Tailwind CSS- ์ผ๊ด๋ ๋์์ธ ์์คํ ๊ณผ ๋น ๋ฅธ UI ๊ฐ๋ฐZustand- ์ํฌ์คํ์ด์ค, ํญ ์ํ์ ์ค์๊ฐ ๋ฉ์์ง ์ํ์ ๋ํ ํจ์จ์ ๊ด๋ฆฌ
Backend
Python- ๋น ๋ฅธ ํ๋กํ ํ์ดํ์ ์ต์ ํFastAPI- WebSocket ์ค์๊ฐ ํต์ ๋ฐ ๋น๋๊ธฐ ์ฒ๋ฆฌ ์ง์Redis- Pub/Sub ๊ธฐ๋ฐ ๋ฉ์์ง ํ, ๋ฉํฐ ์๋ฒ ํ๊ฒฝ์์ ์ค์๊ฐ ๋ฉ์์ง ๋๊ธฐํ ๋ฐ ์ธ์ ๊ด๋ฆฌ
Database
MySQL- ACID ํธ๋์ญ์ ๋ณด์ฅ์ผ๋ก ๋ฉํฐํ ๋ํธ ํ๊ฒฝ์์ ๋ฐ์ดํฐ ์ ํฉ์ฑ ํ๋ณด, JOIN ๊ธฐ๋ฐ ๋ณต์กํ ๊ด๊ณํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ์ ์ต์ ํ
Infrastructure & DevOps
Docker&Docker Compose- ๋ฉํฐ ์๋น์ค ์ปจํ ์ด๋ํ๋ฅผ ํตํ ๋ก์ปฌ ๊ฐ๋ฐํ๊ฒฝ๊ณผ ํ๋ก๋์ ํ๊ฒฝ ์ผ๊ด์ฑ ๋ณด์ฅ- AWS
EC2- ECS ๋์ ์ง์ ์๋ฒ๋ฅผ ๊ด๋ฆฌํ๋ฉฐ ์ธํ๋ผ ์ ๋ฐ์ ๋ํ ํ์ตECR- ๋์ปค ์ด๋ฏธ์ง ๋ฒ์ ๊ด๋ฆฌ ๋ฐ ์ ์ฅ์ALB- HTTP/HTTPS ํธ๋ํฝ ์ฒ๋ฆฌ์ ์ต์ ํ๋ L7 ๋ก๋๋ฐธ๋ฐ์ASG- ์คํ ์ค์ผ์ผ๋ง ์ ์ฑ ๊ธฐ๋ฐ ๋ฆฌ์์ค ๊ด๋ฆฌS3- ์ ์ ํ์ผ ์ ์ฅ์
GitHub Actions- ๋ธ๋์น ์ ๋ต ๊ธฐ๋ฐ ์๋ํ๋ CI/CD ํ์ดํ๋ผ์ธ
โโโ BE/ # ๋ฐฑ์๋ (FastAPI)
โ โโโ app/
โ โ โโโ core/ # ํต์ฌ ์ค์ ๋ฐ ์ ํธ๋ฆฌํฐ
โ โ โโโ domain/ # ๋๋ฉ์ธ ๋ชจ๋ธ (DDD)
โ โ โโโ repository/ # ๋ฐ์ดํฐ ์ ๊ทผ ๊ณ์ธต
โ โ โโโ service/ # ๋น์ฆ๋์ค ๋ก์ง ๊ณ์ธต
โ โ โโโ router/ # API ๋ผ์ฐํฐ (์ธํฐํ์ด์ค ๊ณ์ธต)
โ โ โโโ schema/ # API ์คํค๋ง ์ ์
โ โโโ sql/ # ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง
โโโ FE/ # ํ๋ก ํธ์๋ (Next.js)
โ โโโ app/ # App Router
โ โโโ components/ # ์ฌ์ฌ์ฉ ์ปดํฌ๋ํธ
โ โโโ hooks/ # ์ปค์คํ
ํ
โ โโโ store/ # ์ํ ๊ด๋ฆฌ
โ โโโ apis/ # API ํด๋ผ์ด์ธํธ
โโโ .github/workflows/ # CI/CD ํ์ดํ๋ผ์ธ
๐ 2. API ๋ช ์ธ์ ๋งํฌ
๐ 3. ์ํ์ค ๋ค์ด์ด๊ทธ๋จ (BE/docs/sequence/)
- WebSocket ํธ๋์ ฐ์ดํฌ: ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ ๋ฐ ์ธ์ ๋ฑ๋ก ๊ณผ์
- ๋ฉ์์ง ๋ธ๋ก๋์บ์คํธ: Redis Pub/Sub ๊ธฐ๋ฐ ๋ค์ค ์๋ฒ ๋ฉ์์ง ๋๊ธฐํ
๐งช 4. WebSocket ์ฑ๋ฅ ํ ์คํธ ๊ฒฐ๊ณผ (BE/docs/test/)
- ํ ์คํธ ๋๊ตฌ: K6
- ํ๋กํ ์ฝ: WebSocket (์ค์๊ฐ ๋ฉ์์ง)
- ์๋ฒ ๊ตฌ์ฑ: Redis Pub/Sub ๊ธฐ๋ฐ ๋ฉํฐ ์๋ฒ ์ํคํ ์ฒ
-
1๏ธโฃ Smoke ํ ์คํธ
- ๋์ ์ฌ์ฉ์: 20 VUS
- ์ด ์ธ์ ์: 39๊ฐ
- ์ฐ๊ฒฐ ์ฑ๊ณต๋ฅ : 100% (39/39)
- ํ๊ท ์ฐ๊ฒฐ ์ง์ฐ์๊ฐ: 64ms
- ๋ฉ์์ง ์ฒ๋ฆฌ: 756๊ฐ ์ก์ , 10,419๊ฐ ์์
- ๊ฒ์ฆ ๋ชฉ์ : ๊ธฐ๋ณธ์ ์ธ WebSocket ์ฐ๊ฒฐ ๋ฐ ๋ฉ์์ง ์ก์์ ์์ ์ฑ
- ํ ์คํธ ๊ฒฐ๊ณผ
-
2๏ธโฃ Load ํ ์คํธ
- ๋์ ์ฌ์ฉ์: 400 VUS
- ์ด ์ธ์ ์: 15,598๊ฐ
- ์ฐ๊ฒฐ ์ฑ๊ณต๋ฅ : 99.9% (15,587/15,598)
- ํ๊ท ์ฐ๊ฒฐ ์ง์ฐ์๊ฐ: 1,083ms
- ๊ฒ์ฆ ๋ชฉ์ : ์ผ๋ฐ์ ์ธ ์ฌ์ฉ์ ๋ถํ๋ฅผ ๊ฐ์ ํ์ฌ ๋น๋ฒํ ์ฐ๊ฒฐ/ํด์ ์ํฉ์์์ ์์คํ ์์ ์ฑ
- ํ ์คํธ ๊ฒฐ๊ณผ
-
3๏ธโฃ Soak ํ ์คํธ
- ๋์ ์ฌ์ฉ์: 1,200 VUS
- ์ด ์ธ์ ์: 9,636๊ฐ
- ํ ์คํธ ์๊ฐ: 842์ด (์ฝ 14๋ถ)
- ์ฐ๊ฒฐ ์ฑ๊ณต๋ฅ : 100% (9,636/9,636)
- ๋ฉ์์ง ์ฒ๋ฆฌ: 278,118๊ฐ ์ก์ , 5,435,263๊ฐ ์์
- ๊ฒ์ฆ ๋ชฉ์ : ๊ณ ๋ถํ ์ํฉ์์์ ์ฅ์๊ฐ ์์ ์ฑ ๊ฒ์ฆ
- ํ ์คํธ ๊ฒฐ๊ณผ
| ์ ํ | ๋์ ์ฌ์ฉ์ (VUS) |
์ฐ๊ฒฐ ์ฑ๊ณต๋ฅ |
ํ๊ท ์ง์ฐ์๊ฐ |
p(95) ์ง์ฐ์๊ฐ |
๋ฉ์์ง ์ฒ๋ฆฌ๋ |
|---|---|---|---|---|---|
| Smoke | 20 | 100% | 64ms | 187ms | ์ก์ : 756 ์์ : 10,419 |
| Load | 400 | 99.9% | 61ms | 89ms | ์ก์ : 15,695 ์์ : - |
| Soak | 1,200 | 100% | 3,020ms | 9,790ms | ์ก์ : 278,118 ์์ : 5,435,263 |
- Domain-Driven Design ์์น์ ์ ์ฉํ ๋ชจ๋ํ๋ ๋ฐฑ์๋ ๊ตฌ์กฐ ์ค๊ณ
- Router, Service, Domain, Repository ๊ณ์ธต ๋ถ๋ฆฌ๋ก ๊ด์ฌ์ฌ ๋ถ๋ฆฌ ๋ฐ ์ ์ง๋ณด์์ฑ ํฅ์
- ํ ๊ณตํต ๊ฐ๋ฐ ๋ฐฉ์ ํ์คํ๋ฅผ ์ํ ์ฝ๋ ํ ํ๋ฆฟ ๋ฐ ์ปจ๋ฒค์ ๊ตฌ์ถ
- Docker ์ปจํ ์ด๋ํ๋ฅผ ํตํ ํ๊ฒฝ ์ผ๊ด์ฑ ๋ณด์ฅ
- ๋ก๋ ๋ฐธ๋ฐ์ฑ ๋ฐ ์คํ ์ค์ผ์ผ๋ง ๊ณ ๋ คํ ์ธํ๋ผ ์ค๊ณ
- GitHub Actions๋ฅผ ํ์ฉํ ๋น๋/๋ฐฐํฌ ์๋ํ
- ์ํฌ์คํ์ด์ค๋ณ ๋ฐ์ดํฐ ๋ฐ ๋น์ฆ๋์ค๋ก์ง ๋ถ๋ฆฌ ๊ตฌํ
- ๊ต์ก๊ธฐ๊ด ์ฆ๊ฐ์ ๋ฐ๋ฅธ ์ํ์ ํ์ฅ ๊ฐ๋ฅํ ๊ตฌ์กฐ ์ค๊ณ
- RBAC(Role-Based Access Control) ๋ชจ๋ธ ๊ธฐ๋ฐ ๊ฐ์ธ ๋ฐ ๊ทธ๋ฃน๋ณ ์ธ๋ถํ๋ ๊ถํ ์ฒด๊ณ ์ค๊ณ
- ํ์ด์ง ๋จ์ ์ ๊ทผ ์ ์ด ์์คํ ๊ตฌ์ถ
- ๋์ ๊ถํ ํ ๋น
- ๋ฐฑ์๋ API์ ํ๋ก ํธ์๋ ์ฐ๋ ์ด์ ํด๊ฒฐ