| name | ceo-standards |
| description | CEO Standards โ Security policy, coding standards, performance patterns. Load this when reviewing security, writing code, or enforcing quality gates.
|
1. ์ธ์ฆ / ์ธ๊ฐ (Authentication & Authorization)
1-1. ์ธ์ฆ ํ์ ์์น
- ๋ชจ๋ API ์๋ํฌ์ธํธ๋ ์๋ฒ์ฌ์ด๋ ์ธ์ฆ ๋ฏธ๋ค์จ์ด๋ฅผ ํต๊ณผํด์ผ ํจ
- ํผ๋ธ๋ฆญ ์๋ํฌ์ธํธ๋ ๋ช
์์ ํ์ดํธ๋ฆฌ์คํธ๋ก๋ง ํ์ฉ (PUBLIC_ROUTES ๋ฐฐ์ด ๊ด๋ฆฌ)
- ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ์ธ์ฆ ์ฒดํฌ๋ UX ์ฉ๋์ผ ๋ฟ, ๋ณด์ ํ๋จ ๊ทผ๊ฑฐ๋ก ์ฌ์ฉ ๊ธ์ง
1-2. ํ ํฐ ๊ด๋ฆฌ
- JWT๋ httpOnly + Secure + SameSite=Strict ์ฟ ํค๋ก๋ง ์ ๋ฌ
- localStorage, sessionStorage์ ํ ํฐ ์ ์ฅ ์ ๋ ๊ธ์ง
- Access Token ๋ง๋ฃ: 15๋ถ ์ดํ
- Refresh Token: DB ์ ์ฅ + ๋จ์ผ ์ฌ์ฉ ํ ์ฆ์ rotation
- Refresh Token ๋ง๋ฃ: 7์ผ ์ดํ, ์ ๋์ ๋ง๋ฃ(absolute expiry) 30์ผ
1-3. ๋น๋ฐ๋ฒํธ
- ํด์ฑ: argon2id ์ฐ์ , ์ฐจ์ bcrypt (cost factor >= 12)
- SHA-256, MD5, ํ๋ฌธ ์ ์ฅ ์ ๋ ๊ธ์ง
- ๋น๋ฐ๋ฒํธ ์ต์ ์๊ตฌ์ฌํญ: 8์ ์ด์, ์ ์ถ DB(HaveIBeenPwned API) ๋์กฐ ๊ถ์ฅ
1-4. OAuth / SSO
- state ํ๋ผ๋ฏธํฐ ํ์ ์์ฑ ๋ฐ ๊ฒ์ฆ (CSRF ๋ฐฉ์ง)
- PKCE (Proof Key for Code Exchange) ์ ์ฉ ๊ถ์ฅ
- ์ฝ๋ฐฑ URL์ ํ๊ฒฝ๋ณ์๋ก ๊ด๋ฆฌ, ํ๋์ฝ๋ฉ ๊ธ์ง
1-5. RBAC (Role-Based Access Control)
- ๋ชจ๋ ์๋ํฌ์ธํธ์ ์ญํ ๊ฒ์ฆ ๋ฏธ๋ค์จ์ด ์ ์ฉ
- ์ญํ ์ฒดํฌ๋ DB ๊ธฐ์ค ์ค์๊ฐ ์กฐํ (์บ์ ์ TTL <= 5๋ถ)
- ๋ฆฌ์์ค ์์ ๊ถ ๊ฒ์ฆ ๋ณ๋ ์ํ (์๊ธฐ ๋ฐ์ดํฐ๋ง ์ ๊ทผ)
1-6. Rate Limiting
| ๋์ | ์ ํ |
|---|
| ๋ก๊ทธ์ธ ์๋ | 5ํ/๋ถ/IP |
| ์ธ์ฆ์ฝ๋ (OTP) | 3ํ/10๋ถ/๊ณ์ |
| ๋น๋ฐ๋ฒํธ ์ฌ์ค์ | 3ํ/์๊ฐ/๊ณ์ |
| ์ผ๋ฐ API | 60ํ/๋ถ/์ ์ |
| Webhook ์์ | 300ํ/๋ถ/์๋ํฌ์ธํธ |
| ํ์ผ ์
๋ก๋ | 10ํ/๋ถ/์ ์ |
2. ์
๋ ฅ ๊ฒ์ฆ (Input Validation)
2-1. ์์น
- ๋ชจ๋ ์
๋ ฅ์ ์๋ฒ์์ ์ฌ๊ฒ์ฆ โ ํด๋ผ์ด์ธํธ ๊ฒ์ฆ์ UX ์ ์ฉ
- ๊ฒ์ฆ ๋ผ์ด๋ธ๋ฌ๋ฆฌ: zod (TypeScript) ์ฌ์ฉ, ์คํค๋ง๋ฅผ src/schemas/์ ์ง์ค ๊ด๋ฆฌ
- ๊ฒ์ฆ ์คํจ ์ 400 Bad Request + ์ ๋ค๋ฆญ ์๋ฌ ๋ฉ์์ง ๋ฐํ (๋ด๋ถ ์์ธ๋ ๋ก๊ทธ์๋ง)
2-2. Injection ๋ฐฉ์ง
- SQL Injection: ORM ์ฌ์ฉ, raw query ์ parameterized query๋ง ํ์ฉ
- NoSQL Injection: ์ฟผ๋ฆฌ ๊ฐ์ฒด์ $ ์ฐ์ฐ์ ํฌํจ ์ฌ๋ถ ๊ฒ์ฌ
- XSS: ์ฌ์ฉ์ ์
๋ ฅ HTML ๋ ๋๋ง ๊ธ์ง, dangerouslySetInnerHTML ์ฌ์ฉ ๊ธ์ง
- Command Injection: child_process.exec ๊ธ์ง, ํ์ ์ execFile + ์ธ์ ๋ฐฐ์ด๋ง ํ์ฉ
- Path Traversal: ํ์ผ๋ช
/๊ฒฝ๋ก์ ../, ..\ ํฌํจ ์ ์ฆ์ reject
- SSRF: ๋ด๋ถ URL(127.0.0.1, 10.x, 172.16-31.x, 192.168.x, metadata ์๋ํฌ์ธํธ) ์ฐจ๋จ
2-3. ํ์ผ ์
๋ก๋
- ํ์ฅ์ ํ์ดํธ๋ฆฌ์คํธ (๋ธ๋๋ฆฌ์คํธ ๊ธ์ง)
- ์๋ฒ์์ MIME ํ์
๊ฒ์ฆ (๋งค์ง ๋ฐ์ดํธ ํ์ธ)
- ์ต๋ ํ์ผ ํฌ๊ธฐ ์ ํ (๊ธฐ๋ณธ 10MB, ์ฉ๋๋ณ ์กฐ์ )
- ์
๋ก๋ ํ์ผ๋ช
์ UUID๋ก ์ฌ์์ฑ, ์๋ณธ ํ์ผ๋ช
์ ๋ฉํ๋ฐ์ดํฐ๋ก๋ง ์ ์ฅ
- ์
๋ก๋ ๋๋ ํ ๋ฆฌ๋ ์น ๋ฃจํธ ์ธ๋ถ ๋๋ ์ค๋ธ์ ํธ ์คํ ๋ฆฌ์ง(S3)
3. ๊ฒฐ์ / ๋น๋ง ๋ณด์ (Billing Security)
3-1. ํต์ฌ ์์น
- ๊ฐ๊ฒฉ/ํ ์ธ/์ธ๊ธ ๊ณ์ฐ์ 100% ์๋ฒ์ฌ์ด๋ โ ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ ๊ธ์ก ์ ๋ ์ ๋ขฐ ๊ธ์ง
- ๊ตฌ๋
์ํ ํ๋จ์ DB ๋ ์ฝ๋ ๊ธฐ์ค๋ง ์ฌ์ฉ
- ํ๋ก ํธ์์ ๋ฐ์ planId, priceId๋ ์๋ฒ์์ ์ ํจ์ฑ ์ฌ๊ฒ์ฆ
3-2. Webhook ๋ณด์
- Webhook ์๋ช
(signature) ๊ฒ์ฆ ํ์ โ ๋ฏธ๊ฒ์ฆ ์ ์ฆ์ 400 ๋ฐํ
- IP ํ์ดํธ๋ฆฌ์คํธ ์ถ๊ฐ ์ ์ฉ ๊ถ์ฅ
- ๋ฉฑ๋ฑ์ฑ(Idempotency): event_id ๊ธฐ๋ฐ ์ค๋ณต ์ฒ๋ฆฌ ๋ฐฉ์ง
- Webhook ์ฒ๋ฆฌ ์คํจ ์ ์ฌ์๋ ํ(dead letter queue) ์ด์ฉ
3-3. ๊ฐ์ฌ ๋ก๊ทธ (Audit Log)
- ๊ฒฐ์ ์์ฑ/๋ณ๊ฒฝ/์ทจ์/ํ๋ถ ๋ชจ๋ ์ด๋ฒคํธ ๊ธฐ๋ก
- ๋ก๊ทธ ํ์ ํ๋: userId, action, amount, currency, timestamp, ip, eventId
- ๊ฐ์ฌ ๋ก๊ทธ๋ ์์ /์ญ์ ๋ถ๊ฐ (append-only)
3-4. ํฌ๋ ๋ง/์ ๋ถ ์์คํ
- ์์ก ์ฐจ๊ฐ์ DB ํธ๋์ญ์
๋ด ์์์ (atomic) ์ฒ๋ฆฌ
- ์์ ์์ก ํ์ฉ ๊ธ์ง โ CHECK (balance >= 0) ๋๋ ์ ํ๋ฆฌ์ผ์ด์
๋ ๋ฒจ ๊ฒ์ฆ
- ๋์์ฑ ์ ์ด: SELECT ... FOR UPDATE ๋๋ optimistic locking
4. API ์ค๊ณ / ๋ณด์
4-1. CORS
- ํ์ฉ ๋๋ฉ์ธ ๋ช
์์ ํ์ดํธ๋ฆฌ์คํธ,
origin: '*' ์ ๋ ๊ธ์ง
- credentials: true ์ฌ์ฉ ์ ์์ผ๋์นด๋ origin ๋ถ๊ฐ (๋ธ๋ผ์ฐ์ ๊ฐ ์ฐจ๋จ)
4-2. CSRF
- ์ํ ๋ณ๊ฒฝ ์์ฒญ (POST/PUT/PATCH/DELETE)์ CSRF ํ ํฐ ํ์
- SameSite ์ฟ ํค + CSRF ํ ํฐ ์ด์ค ๋ฐฉ์ด
4-3. HTTP ๋ณด์ ํค๋ (ํ์)
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
4-4. ์๋ต ๋ณด์
- ์๋ฌ ์๋ต์ ์คํํธ๋ ์ด์ค, DB ์คํค๋ง, ๋ด๋ถ ๊ฒฝ๋ก ๋
ธ์ถ ์ ๋ ๊ธ์ง
- ํ๋ก๋์
์์ NODE_ENV=production ํ์
- ์กด์ฌํ์ง ์๋ ๋ฆฌ์์ค: 404 (id ๋
ธ์ถ ๊ธ์ง, ์ด๊ฑฐ ๊ณต๊ฒฉ ๋ฐฉ์ง)
- ์ธ์ฆ ์คํจ: 401, ์ธ๊ฐ ์คํจ: 403 โ ๋ฉ์์ง๋ ์ ๋ค๋ฆญ
4-5. API ๋ฒ์ ๊ด๋ฆฌ
- URL prefix ๋ฐฉ์: /api/v1/...
- ๋ฒ์ ๊ฐ ํ์ ํธํ์ฑ ์ ์ง, ๊ฐ์ ๋ง์ด๊ทธ๋ ์ด์
์ ์ต์ 6๊ฐ์ ์ ์
5. ๋ฐ์ดํฐ ๋ณดํธ
5-1. ์ํธํ
- PII(๊ฐ์ธ์ ๋ณด) ์ ์ฅ: AES-256-GCM ์ํธํ
- ์ํธํ ํค: ํ๊ฒฝ๋ณ์ ๋๋ KMS(AWS KMS, GCP KMS ๋ฑ)์์ ๊ด๋ฆฌ
- DB ์ ์: SSL/TLS ํ์ (?sslmode=require)
- ์ ์ก ๊ตฌ๊ฐ: HTTPS only, HTTP ๋ฆฌ๋ค์ด๋ ํธ ๊ฐ์
5-2. ์ํฌ๋ฆฟ ๊ด๋ฆฌ
- API Key, ํ ํฐ: ํด์ฑ ์ ์ฅ (์๋ฌธ ๋ณต์ ๋ถํ์ํ ๊ฒฝ์ฐ)
- ๋ณต์ ํ์ ์: AES ์ํธํ ์ ์ฅ
- ํ๋ฌธ ์ ์ฅ ์ ๋ ๊ธ์ง
- .env ํ์ผ์ .gitignore์ ๋ฐ๋์ ํฌํจ
- .env.example ์ ์ง: ํ์ ํค ๋ชฉ๋ก ๋ฌธ์ํ (๊ฐ์ ๋น์)
- ํ๋ก๋์
: Vault / Secret Manager / ํ๊ฒฝ๋ณ์
5-3. ๋ก๊ทธ ๋ณด์
- ๋ก๊ทธ์ ์ถ๋ ฅ ๊ธ์ง ํญ๋ชฉ: ๋น๋ฐ๋ฒํธ, ์นด๋๋ฒํธ, API ํค, ํ ํฐ, PII
- ๋ฏผ๊ฐ ํ๋๋ ๋ง์คํน ์ฒ๋ฆฌ (email: j***@example.com)
- ๋ก๊ทธ ๋ณด์กด ๊ธฐ๊ฐ ์ ์ฑ
์๋ฆฝ (๊ธฐ๋ณธ 90์ผ, ๊ฐ์ฌ ๋ก๊ทธ๋ 3๋
)
5-4. ์ญ์ ์ ์ฑ
- ์ํํธ ๋๋ฆฌํธ ๊ธฐ๋ณธ (deletedAt ์ปฌ๋ผ)
- ํ๋ ๋๋ฆฌํธ๋ ๋ฐฐ์น ์์
์ผ๋ก๋ง, ๊ฐ์ฌ ๋ก๊ทธ ํ์
- GDPR/๊ฐ์ธ์ ๋ณด๋ณดํธ๋ฒ ๋์: ์ฌ์ฉ์ ์์ฒญ ์ 30์ผ ์ด๋ด ์์ ์ญ์ ํ๋ก์ธ์ค
6. ๋ฐฑ์๋ ์ํคํ
์ฒ ํ์ ํจํด
6-1. ์๋ฌ ์ฒ๋ฆฌ
- ๊ธ๋ก๋ฒ ์๋ฌ ํธ๋ค๋ฌ ๋ฏธ๋ค์จ์ด ํ์
- ์ปค์คํ
์๋ฌ ํด๋์ค ๊ณ์ธต ๊ตฌ์กฐ: AppError (base) โ ValidationError, AuthError, NotFoundError, ForbiddenError, ConflictError
- try-catch์์ ์๋ฌ ์ผํค๊ธฐ(swallow) ๊ธ์ง โ ๋ฐ๋์ ๋ก๊น
๋๋ ์ฌthrow
- ๋น๋๊ธฐ ์๋ฌ: express-async-errors ๋๋ ๋ํผ ํจ์๋ก ํฌ์ฐฉ
6-2. ๋ก๊น
- ๊ตฌ์กฐํ ๋ก๊น
(structured logging): JSON ํํ, pino ๋๋ winston ์ฌ์ฉ
- ํ์ ํ๋: timestamp, level, requestId, userId, action, duration
- Request ID: ๋ชจ๋ ์์ฒญ์ UUID ํ ๋น, ๋ก๊ทธ ์ ์ฒด์ ์ ํ
- ๋ก๊ทธ ๋ ๋ฒจ: error > warn > info > debug โ ํ๋ก๋์
์ info ์ด์๋ง
6-3. DB ์ค๊ณ ์์น
- ๋ชจ๋ ํ
์ด๋ธ ํ์ ์ปฌ๋ผ: id (UUID), createdAt, updatedAt, deletedAt
- ๋ฉํฐํ
๋ํธ: organizationId ๊ธฐ๋ฐ row-level ๊ฒฉ๋ฆฌ
- ์ธ๋ฑ์ค: WHERE ์ , JOIN ํค, ORDER BY ๋์์ ๋ฐ๋์ ์ค์
- N+1 ์ฟผ๋ฆฌ ๊ธ์ง โ include/select ๋ช
์์ ์ฌ์ฉ
- ๋ง์ด๊ทธ๋ ์ด์
: ORM migration๋ง ์ฌ์ฉ, ์๋ DDL ๊ธ์ง
- ํธ๋์ญ์
: ๋ณต์ ํ
์ด๋ธ ๋ณ๊ฒฝ ์ ๋ฐ๋์ ์ฌ์ฉ
6-4. ์บ์ฑ ์ ๋ต
- ์บ์ ํค ๋ค์ด๋ฐ: {service}:{entity}:{id}
- TTL ํ์ ์ค์ โ ๋ฌด๊ธฐํ ์บ์ ๊ธ์ง
- ์บ์ ๋ฌดํจํ: ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์ ๊ด๋ จ ์บ์ ์ฆ์ ์ญ์
- ๋ฏผ๊ฐ ๋ฐ์ดํฐ ์บ์ฑ ๊ธ์ง (ํ ํฐ, PII, ๊ฒฐ์ ์ ๋ณด)
6-5. ํ / ๋น๋๊ธฐ ์์
- ์ด๋ฉ์ผ ๋ฐ์ก, Webhook ์ฌ์๋, ๋์ฉ๋ ์ฒ๋ฆฌ โ ํ ์ฌ์ฉ
- ๋๊ธฐ API ์๋ต์์ 30์ด ์ด์ ๊ฑธ๋ฆฌ๋ ์์
์ฒ๋ฆฌ ๊ธ์ง
- ํ ์์
ํ์ ์์: ์ฌ์๋ ํ์ ์ ํ, ํ์์์, dead letter queue
- ๋ฉฑ๋ฑ์ฑ ํค๋ก ์ค๋ณต ์คํ ๋ฐฉ์ง
6-6. ํฌ์ค์ฒดํฌ / ๋ชจ๋ํฐ๋ง
- GET /api/health ์๋ํฌ์ธํธ ํ์ (์ธ์ฆ ๋ถํ์) โ ์๋ต: DB ์ฐ๊ฒฐ ์ํ, ์บ์ ์ฐ๊ฒฐ ์ํ, ๋ฒ์ , uptime
- GET /api/health/ready โ ํธ๋ํฝ ์์ ๊ฐ๋ฅ ์ฌ๋ถ (readiness probe)
- ์๋ฌ์จ ๊ธ์ฆ ์ ์๋ฆผ ์ค์
7. ๋ฏธ๋ค์จ์ด ์คํ ์์ (๊ถ์ฅ)
1. Request ID ์์ฑ
2. ๋ก๊น
(์์ฒญ ์์)
3. CORS
4. ๋ณด์ ํค๋ (helmet)
5. Rate Limiter
6. Body Parser (ํฌ๊ธฐ ์ ํ ํฌํจ)
7. CSRF ๊ฒ์ฆ
8. ์ธ์ฆ (JWT ๊ฒ์ฆ)
9. ์ธ๊ฐ (RBAC)
10. ์
๋ ฅ ๊ฒ์ฆ (zod)
11. ๋น์ฆ๋์ค ๋ก์ง (๋ผ์ฐํฐ/์ปจํธ๋กค๋ฌ)
12. ์๋ฌ ํธ๋ค๋ฌ
13. ๋ก๊น
(์์ฒญ ์๋ฃ + duration)
8. ์ฝ๋ ๋ ๋ฒจ ๊ธ์ง ์ฌํญ
| ๊ธ์ง ํญ๋ชฉ | ์ด์ |
|---|
| eval(), new Function() | ์ฝ๋ ์ธ์ ์
|
| dangerouslySetInnerHTML | XSS |
| child_process.exec() | ์ปค๋งจ๋ ์ธ์ ์
|
| console.log (ํ๋ก๋์
) | ๊ตฌ์กฐํ ๋ก๊ฑฐ ์ฌ์ฉ |
| ๋์ import์ ์ฌ์ฉ์ ์
๋ ฅ | ์์ ๋ชจ๋ ๋ก๋ฉ |
| any ํ์
๋จ์ฉ | ํ์
์์ ์ฑ ๋ถ๊ดด |
| // @ts-ignore ๋ฌด๋ถ๋ณ ์ฌ์ฉ | ํ์
์๋ฌ ์ํ |
| ํ๋์ฝ๋ฉ๋ ์ํฌ๋ฆฟ | ์ ์ถ ์ํ |
| SELECT * | ๊ณผ๋ค ๋ฐ์ดํฐ ๋
ธ์ถ + ์ฑ๋ฅ |
| ๋๊ธฐ ํ์ผ I/O (fs.readFileSync) | ์ด๋ฒคํธ ๋ฃจํ ๋ธ๋กํน |
9. ์ธํ๋ผ / ๋ฐฐํฌ
9-1. ํ๊ฒฝ ๋ถ๋ฆฌ
- development / staging / production ํ๊ฒฝ ์์ ๋ถ๋ฆฌ
- ํ๋ก๋์
DB์ ๊ฐ๋ฐ ํ๊ฒฝ์์ ์ง์ ์ ๊ทผ ์ ๋ ๊ธ์ง
- ํ๊ฒฝ๋ณ ํ๊ฒฝ๋ณ์ ๋
๋ฆฝ ๊ด๋ฆฌ
9-2. CI/CD ๋ณด์
- npm audit / pnpm audit CI์์ ์๋ ์คํ
- critical/high ์ทจ์ฝ์ ๋ฐ๊ฒฌ ์ ๋น๋ ์คํจ ์ฒ๋ฆฌ
- ์ํฌ๋ฆฟ์ CI/CD ์ํฌ๋ฆฟ ์คํ ์ด์๋ง ์ ์ฅ (GitHub Secrets ๋ฑ)
- ๋น๋ ์ํฐํฉํธ์ .env, node_modules ํฌํจ ๊ธ์ง
9-3. Docker
- non-root ์ ์ ์คํ (USER node)
- ์ต์ ์ด๋ฏธ์ง ์ฌ์ฉ (node:xx-alpine)
- .dockerignore์ .env, .git, node_modules ํฌํจ
- ๋ฉํฐ์คํ
์ด์ง ๋น๋๋ก ๋น๋ ์์กด์ฑ ์ ๊ฑฐ
9-4. HTTPS / TLS
- ์ ๊ตฌ๊ฐ HTTPS ๊ฐ์ โ HTTP โ HTTPS 301 ๋ฆฌ๋ค์ด๋ ํธ
- TLS 1.2 ์ด์๋ง ํ์ฉ
- ์ธ์ฆ์ ์๋ ๊ฐฑ์
10. PR ๋ณด์ ์ฒดํฌ๋ฆฌ์คํธ
โก ์ ์๋ํฌ์ธํธ์ ์ธ์ฆ ๋ฏธ๋ค์จ์ด ์ ์ฉํ๋๊ฐ?
โก ์
๋ ฅ ๊ฒ์ฆ ์คํค๋ง(zod) ์์ฑํ๋๊ฐ?
โก RBAC + ๋ฆฌ์์ค ์์ ๊ถ ๊ฒ์ฆ ์ ์ฉํ๋๊ฐ?
โก ์๋ฌ ์๋ต์ ๋ด๋ถ ์ ๋ณด ๋
ธ์ถ์ด ์๋๊ฐ?
โก ์ ํ๊ฒฝ๋ณ์๋ฅผ .env.example์ ์ถ๊ฐํ๋๊ฐ?
โก ๊ธ์ง ํจ์(eval, exec ๋ฑ)๋ฅผ ์ฌ์ฉํ์ง ์์๋๊ฐ?
โก ๋ฏผ๊ฐ ๋ฐ์ดํฐ๊ฐ ๋ก๊ทธ์ ๋
ธ์ถ๋์ง ์๋๊ฐ?
โก DB ์ฟผ๋ฆฌ์ N+1 ๋ฌธ์ ๊ฐ ์๋๊ฐ?
โก ์บ์ ํค์ TTL์ด ์ค์ ๋์๋๊ฐ?
โก ๊ฒฐ์ ๊ด๋ จ ๋ก์ง์ด ์๋ฒ์ฌ์ด๋์์๋ง ์ฒ๋ฆฌ๋๋๊ฐ?
์ฝ๋ฉ ํ์ค (Language-Agnostic Core)
๋ถ๋ณ์ฑ (CRITICAL)
ํญ์ ์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ , ๊ธฐ์กด ๊ฐ์ฒด๋ฅผ ์ ๋ ๋ณ๊ฒฝํ์ง ์์ต๋๋ค:
// ์์ฌ ์ฝ๋
์๋ชป: modify(original, field, value) โ original์ ์ง์ ๋ณ๊ฒฝ
์ฌ๋ฐ๋ฆ: update(original, field, value) โ ๋ณ๊ฒฝ๋ ์ ๋ณต์ฌ๋ณธ ๋ฐํ
ํต์ฌ ์์น
- KISS: ์ค์ ๋ก ๋์ํ๋ ๊ฐ์ฅ ๋จ์ํ ํด๊ฒฐ์ฑ
์ ํ. ์กฐ๊ธฐ ์ต์ ํ ๊ธ์ง. ์๋ฆฌํจ๋ณด๋ค ๋ช
ํํจ.
- DRY: ๋ฐ๋ณต ๋ก์ง์ ๊ณต์ ํจ์๋ก ์ถ์ถ. ๋ณต์ฌ-๋ถ์ฌ๋ฃ๊ธฐ ๋๋ฆฌํํธ ๋ฐฉ์ง. ๋ฐ๋ณต์ด ์ค์ ์ผ ๋๋ง ์ถ์ํ ๋์
.
- YAGNI: ํ์ํ๊ธฐ ์ ์ ๊ธฐ๋ฅ์ด๋ ์ถ์ํ๋ฅผ ๋ง๋ค์ง ์์. ํฌ๊ธฐ์ ์ผ๋ฐํ ๊ธ์ง. ๋จ์ํ๊ฒ ์์ ํ ์๋ ฅ์ด ์ค์ฌํ ๋ ๋ฆฌํฉํ ๋ง.
ํ์ผ ์กฐ์ง
๋ง์ ์์ ํ์ผ > ์ ์ ํฐ ํ์ผ
- ๋์ ์์ง๋, ๋ฎ์ ๊ฒฐํฉ๋
- 300์ค ์ดํ ์์ (GATE-1 ์๋ ์ฐจ๋จ)
- ์ด๊ณผ ์ฆ์ ๋ชจ๋ ๋ถ๋ฆฌ โ ๋ฆฌํฉํ ๋ง ํ ์ฌ์ ์ถ
- ๊ธฐ๋ฅ/๋๋ฉ์ธ ๊ธฐ์ค ์กฐ์ง (ํ์
๊ธฐ์ค ์๋)
300์ค ๊ท์น์ ํ์ ๋ถ๊ฐ (GATE-1 ๋ฑ๋ก ํจํด)
- Worker๊ฐ 300์ค ์ด๊ณผ ํ์ผ ์์ฑ ์ โ GATE-1์์ ์ฆ์ ์ฐจ๋จ
- CEO๊ฐ ๋ถ๋ฆฌ ์ง์ โ Worker๊ฐ ๋ชจ๋ ๋ถ๋ฆฌ ํ ์ฌ์ ์ถ
- ์์ธ ์์ (์ค์ ํ์ผ, ์๋ ์์ฑ ํ์ผ ์ ์ธ)
ํจ์ ํฌ๊ธฐ
- 50์ค ์ํ
- ํ ๊ฐ์ง ์ฑ
์๋ง ๋ด๋น
- ํฌ๋ฉด ๋ถํ
์ค์ฒฉ ๊น์ด
- 4๋จ๊ณ ์ํ
- ์กฐ๊ฑด์ด ์์ด๋ฉด early return ์ฌ์ฉ
์๋ฌ ์ฒ๋ฆฌ
- ๋ชจ๋ ๋ ๋ฒจ์์ ๋ช
์์ ์ฒ๋ฆฌ
- UI ์ฝ๋: ์ฌ์ฉ์ ์นํ์ ๋ฉ์์ง
- ์๋ฒ ์ฝ๋: ์์ธ ๋ก๊น
- ์๋ฌ ์ผํค๊ธฐ ์ ๋ ๊ธ์ง
์
๋ ฅ ๊ฒ์ฆ
- ์์คํ
๊ฒฝ๊ณ์์ ํญ์ ๊ฒ์ฆ
- ์คํค๋ง ๊ธฐ๋ฐ ๊ฒ์ฆ (Zod ๋ฑ)
- ๋น ๋ฅธ ์คํจ + ๋ช
ํํ ์๋ฌ
- ์ธ๋ถ ๋ฐ์ดํฐ ์ ๋ ์ ๋ขฐ ๊ธ์ง
๋ค์ด๋ฐ ๊ท์น
| ๋์ | ๊ท์น |
|---|
| ๋ณ์, ํจ์ | camelCase |
| Boolean | is/has/should/can prefix |
| ์ธํฐํ์ด์ค, ํ์
, ์ปดํฌ๋ํธ | PascalCase |
| ์์ | UPPER_SNAKE_CASE |
| Custom Hooks | use prefix |
TypeScript/JavaScript ๊ท์น
- ํผ๋ธ๋ฆญ API์ ๋ช
์์ ํ์
โ ๋ก์ปฌ ๋ณ์๋ ์ถ๋ก ํ์ฉ
- ํ์ฅ ๊ฐ๋ฅํ ํ์: interface โ ์ ๋์จ/์ธํฐ์น์
/๋งคํ: type
- ์ ํ๋ฆฌ์ผ์ด์
์ฝ๋์์ any ๊ธ์ง โ ์ธ๋ถ ์
๋ ฅ์ unknown + ํ์
๋ด๋ก์
- React: props์ named interface, React.FC ๊ธ์ง, ์ฝ๋ฐฑ ํ์
๋ช
์
- ๋ถ๋ณ์ฑ: spread operator, Readonly
- ์๋ฌ ์ฒ๋ฆฌ: async/await + try-catch + unknown ๋ด๋ก์
- ์
๋ ฅ ๊ฒ์ฆ: Zod + z.infer ํ์
์ถ๋ก
- ํ๋ก๋์
์์ console.log ๊ธ์ง (hook์ผ๋ก ๊ฐ์ )
์น/ํ๋ก ํธ์๋ ๊ท์น
Anti-Template ์ ์ฑ
๋ชจ๋ ์๋ฏธ ์๋ ํ๋ก ํธ์๋ ํ๋ฉด์ ์๋ 10๊ฐ์ง ์ค ์ต์ 4๊ฐ์ง๋ฅผ ๋ณด์ฌ์ผ ํฉ๋๋ค:
- ์ค์ผ์ผ ๋๋น๋ฅผ ํตํ ๋ช
ํํ ๊ณ์ธต
- ๊ท ์ผ ํจ๋ฉ์ด ์๋ ์๋์ ๋ฆฌ๋ฌ
- ์ค๋ฒ๋ฉ, ๊ทธ๋ฆผ์, ํ๋ฉด, ๋ชจ์
์ ํตํ ๊น์ด/๋ ์ด์ด๋ง
- ์บ๋ฆญํฐ์ ํ์ด๋ง ์ ๋ต์ด ์๋ ํ์ดํฌ๊ทธ๋ํผ
- ์ฅ์์ด ์๋ ์๋ฏธ๋ก ์ ์์ ์ฌ์ฉ
- ๋์์ธ๋ hover/focus/active ์ํ
- ์ ์ ํ ๊ณณ์์ ๊ทธ๋ฆฌ๋ ๊นจ๋ ์๋ํ ๋ฆฌ์ผ/๋ฒคํ ๊ตฌ์ฑ
- ์๊ฐ์ ๋ฐฉํฅ์ ๋ง๋ ํ
์ค์ฒ, ๊ทธ๋ ์ธ, ๋ถ์๊ธฐ
- ์ฐ๋งํจ์ด ์๋ ํ๋ฆ ๋ช
ํํ ๋ชจ์
- ๋์์ธ ์์คํ
์ ์ผ๋ถ๋ก ์ทจ๊ธ๋๋ ๋ฐ์ดํฐ ์๊ฐํ
CSS Custom Properties
๋ชจ๋ ๋์์ธ ํ ํฐ์ ๋ณ์๋ก ์ ์ํฉ๋๋ค. ํ๋ ํธ, ํ์ดํฌ๊ทธ๋ํผ, ๊ฐ๊ฒฉ์ ๋ฐ๋ณต ํ๋์ฝ๋ฉํ์ง ์์ต๋๋ค.
Semantic HTML
<header>
<nav aria-label="Main navigation">...</nav>
</header>
<main>
<section aria-labelledby="hero-heading">
<h1 id="hero-heading">...</h1>
</section>
</main>
<footer>...</footer>
generic div ์คํ ๋์ semantic element ์ฌ์ฉ.
Animation
- Compositor-friendly property๋ง ์ฌ์ฉ: transform, opacity, clip-path, filter
- Layout-bound property animation ๊ธ์ง: width, height, top, left, margin, padding, border, font-size
์ฑ๋ฅ ๋ชฉํ
| Metric | Target |
|---|
| LCP | < 2.5s |
| INP | < 200ms |
| CLS | < 0.1 |
| FCP | < 1.5s |
| TBT | < 200ms |
| Page Type | JS Budget (gzipped) | CSS Budget |
|---|
| Landing page | < 150kb | < 30kb |
| App page | < 300kb | < 50kb |
| Microsite | < 80kb | < 15kb |
ํ๋ก ํธ์๋ ๊ธ์ง ์ฌํญ
- localStorage/sessionStorage์ ํ ํฐ ์ ์ฅ ๊ธ์ง โ httpOnly ์ฟ ํค๋ง
- React์์ HTML
<form> ํ๊ทธ ๊ธ์ง
- dangerouslySetInnerHTML ๊ธ์ง
- ๊ธฐ๋ณธ ํ
ํ๋ฆฟ UI ์ถ๋ ฅ ๊ธ์ง โ ์๋์ ์ด๊ณ opinionatedํ ๋์์ธ
ํ
์คํธ ์๊ตฌ์ฌํญ
์ต์ ์ปค๋ฒ๋ฆฌ์ง: 80%
TDD ํ์ ์ํฌํ๋ก์ฐ
1. ํ
์คํธ ๋จผ์ ์์ฑ (RED)
2. ํ
์คํธ ์คํ โ ์คํจํด์ผ ํจ
3. ์ต์ ๊ตฌํ ์์ฑ (GREEN)
4. ํ
์คํธ ์คํ โ ํต๊ณผํด์ผ ํจ
5. ๋ฆฌํฉํ ๋ง (IMPROVE)
6. ์ปค๋ฒ๋ฆฌ์ง ๊ฒ์ฆ (80%+)
ํ
์คํธ ์ ํ (์ ๋ถ ํ์)
- Unit Tests โ ๊ฐ๋ณ ํจ์, ์ ํธ๋ฆฌํฐ, ์ปดํฌ๋ํธ
- Integration Tests โ API ์๋ํฌ์ธํธ, DB ์์
- E2E Tests โ ํต์ฌ ์ฌ์ฉ์ ํ๋ก์ฐ
AAA ํจํด (Arrange/Act/Assert)
test('calculates similarity correctly', () => {
const vector1 = [1, 0, 0]
const vector2 = [0, 1, 0]
const similarity = calculateCosineSimilarity(vector1, vector2)
expect(similarity).toBe(0)
})
ํ
์คํธ ๋ค์ด๋ฐ
test('returns empty array when no items match query', () => {})
test('throws error when API key is missing', () => {})
test('falls back to default when cache is unavailable', () => {})
Integration Test ๊ท์น
- DB๋ฅผ ๋ชจํนํ์ง ์์ โ ์ค์ ํ
์คํธ DB ์ฌ์ฉ
- ํ
์คํธ ๊ฐ ๊ฒฉ๋ฆฌ ๋ณด์ฅ
์ต์ด ํ๋ก์ ํธ ์
์
์ ์ฐจ
CEO๊ฐ ์ ํ๋ก์ ํธ์์ ์ฒซ ๋ฒ์งธ ์ง์๋ฅผ ์์ ํ์ ๋:
[FIRST-TIME PROJECT SETUP]
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Step 1: gstack ์คํฌ ํ์ธ
โ https://github.com/garrytan/gstack ์คํฌ ์ค์น ์ฌ๋ถ ํ์ธ
โ ๋ฏธ์ค์น ์ ์ค์น โ ์ด๋ฏธ ์ค์น๋์์ผ๋ฉด ํจ์ค
Step 2: ๋ ์ง์คํธ๋ฆฌ ์ด๊ธฐํ
โ ~/.claude/error-registry.md ์์ฑ (์์ผ๋ฉด)
โ ~/.claude/skill-registry.md ์์ฑ (์์ผ๋ฉด)
โ ~/.claude/project-registry.md ์์ฑ (์์ผ๋ฉด)
โ ~/.claude/decision-log.md ์์ฑ (์์ผ๋ฉด)
Step 3: ํ๋ค์ค ์ฅ์น ๋ฐฐํฌ
โ DC-DEV-OPS๋ฅผ ํตํด โ ~โฆ ์ ๋ถ ๊ตฌ์ถ
โ pre-commit hook, lint ๊ท์น, ์ํคํ
์ฒ ํ
์คํธ,
commit-msg hook, CI/CD ๊ฒ์ดํธ, CODEOWNERS, gc.sh
Step 4: ์ฌ์
๋ถ๋ฅ
โ DC-BIZ ํธ์ถํ์ฌ ์ด๊ธฐ ํ๋ก์ ํธ ๋ถ๋ฅ
Step 5: ํ๋ก์ ํธ ๋ฑ๋ก
โ project-registry.md์ ์ด๊ธฐ PROJECT ํญ๋ชฉ ์์ฑ
Step 6: ์์ด์ ํธ ํ์ผ ํ์ธ
โ .claude/agents/ ๋๋ ํ ๋ฆฌ์ ๋ชจ๋ Worker ์์ด์ ํธ ํ์ผ ์กด์ฌ ํ์ธ
โ ๋ฏธ์กด์ฌ ์ ์์ฑ
Step 7: ์ด๊ธฐํ ๋ณด๊ณ
โ ์ฌ์ฉ์์๊ฒ ์ด๊ธฐํ ์ํ ๋ณด๊ณ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
AI ์ถ์ฒ/์์ฑ ๊ธฐ๋ฅ ํ์ง ๊ฒ์ฆ ๊ท์น
LLM ํ๋กฌํํธ๋ก ๋์ํ๋ ๊ธฐ๋ฅ์ ํ์
์ฒดํฌ๋ง์ผ๋ก๋ ํ์ง ๋ณด์ฅ ๋ถ๊ฐ.
์๋ ์ถ๊ฐ ๊ฒ์ฆ์ ๋ฐ๋์ ํฌํจํ๋ค.
[AI ๊ธฐ๋ฅ ์๋ฃ ๊ธฐ์ค โ tsc ํต๊ณผ ์ธ ์ถ๊ฐ ํ์ ํญ๋ชฉ]
โก ํ๋กฌํํธ์ "๊ฐ์ ๊ฐ ์ค๋ณต ๋ฐํ ํ์ฉ" ๊ตฌ๋ฌธ์ด ์๋๊ฐ?
โก ๋ค์ค ์ฌ๋กฏ ๋ฐฐ์ ๊ธฐ๋ฅ์ "์๋ก ๋ค๋ฅธ ๊ฐ ๊ฐ์ " ๊ท์น์ด ๋ช
์๋์ด ์๋๊ฐ?
โก ์๋ฒ ์ฌ์ด๋ ํ์ฒ๋ฆฌ๋ก AI ์๋ต์ ์ด์๊ฐ(์ ์ฒด ์ค๋ณต, ๋น๊ฐ) ๋ฐฉ์ด ๋ก์ง์ด ์๋๊ฐ?
โก Provider๋ณ ๋ชจ๋ธ ๋ถ๋ฅ ํํธ๊ฐ ํฌํจ๋์๋๊ฐ?
๊ธ๋ก๋ฒ ๊ธ์ง ๊ท์น
โ DC Agent๊ฐ ์ฌ์ฉ์์ ์ง์ ์ํต โ CEO๋ง ์ฌ์ฉ์์ ๋ํ
โ Builder์ Reviewer๊ฐ ๋์ผ DC Agent โ ์ญํ ๋ถ๋ฆฌ ์์น ์๋ฐ
โ GATE ๋ฏธํต๊ณผ ์ฐ์ถ๋ฌผ ์ ๋ฌ โ ํ์ง ๋ณด์ฆ ๋ถ๊ฐ
โ Token Optimizer ์์ด LARGE/HEAVY ์คํ โ ์ปจํ
์คํธ ์์ง ์ํ
โ Business Judge ์์ด ์์
์ฐฉ์ โ ์ฌ์
ํ๋น์ฑ ๋ฏธ๊ฒ์ฆ
โ error-registry ๋ฏธ์กฐํ ์ํ๋ก ์์
์์ โ ๊ณผ๊ฑฐ ์ค์ ๋ฐ๋ณต ์ํ
โ ๋ฒ์ ํ๊ทธ ์๋ ์ฐ์ถ๋ฌผ โ ์ถ์ ๋ถ๊ฐ
โ ์๋ฌ ๋ฐ์ ํ GC ๋ฏธ์คํ โ ๋ฐฉ์ด ์ฒด๊ณ ๋ฏธ๊ฐฑ์
โ GATE-5 ๋์ ๋ณ๊ฒฝ ๋ฌด๋จ ์คํ โ ํ๊ดด์ ๋ณ๊ฒฝ ์ฌ์ ์น์ธ ํ์
โ ์์
์๋ฃ ํ ๋ณด๊ณ ์ ๋ฏธ์์ฑ โ ์ฐ์ถ๋ฌผ ์ถ์ ๋ถ๊ฐ
โ ์์ด์ ํธ/์คํฌ ๋ฏธ์
๋ฐ์ดํธ ์ํ๋ก ๋์ผ ์ค์ ๋ฐ๋ณต โ GC ์๋ฌด
โ ์์ ํ์ผ ๋ฏธ์ ๋ฆฌ โ docs/ ๋์ ๋ฐฉ์ง
โ Opus๋ฅผ ๋จ์ ์์
์ ํฌ์
โ ๋น์ฉ ๋ญ๋น
โ Haiku๋ฅผ ์ํคํ
์ฒ/๋ณด์ ํ๋จ์ ํฌ์
โ ํ์ง ์ํ
โ DC-OSS ์์ด ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ/๋ชจ๋ธ ์์ ์ ํ โ ๋ณด์/๋ผ์ด์ ์ค ๋ฏธ๊ฒ์ฆ
โ SMALL ์
๋ฌด์ PLANNER Phase(DC-BIZ/PLAN.md/CONTRACT) ๊ฐ์ โ ๊ท๋ชจ๋ณ ์ถ์ฝ ๊ฒฝ๋ก(9-8) ์ ์ฉ ํ์
โ Worker ๋ฐฐ์ ์ ์คํฌ ๋ช
์ ์ง์ ์์ด "์์์ ์จ๋ผ" ๋ฌต์์ ์์ โ PRIMARY ์คํฌ ๋ช
์ ์ง์ ํ์(9-9)
โ EVALUATOR ๋ฆฌํฌํธ ์ ๋ฌธ์ CEO ์ปจํ
์คํธ์ ์ง์ ์์ โ 3์ค ์์ฝ๋ง ๋ฐ๊ณ ํ์ผ ๋ณ๋ ์ ์ฅ(9-10)
โ SMALL ์
๋ฌด์ DC-BIZ Opus ํฌ์
โ ๊ท๋ชจ๋ณ ๋ชจ๋ธ ๊ฐ๋ฑ ๊ธฐ์ค(9-12) ์ ์ฉ
โ ์คํ๋ฆฐํธ ํ์ผ docs/ ๋ฃจํธ์ ๋ฌดํ ๋์ โ 30์ผ ํ archive/ ์ด๋, 90์ผ ํ ์ญ์ (9-13)
โ LLM ํ๋กฌํํธ ๊ธฐ๋ฐ ๊ธฐ๋ฅ tsc ํต๊ณผ๋ง์ผ๋ก ์๋ฃ ์ฒ๋ฆฌ โ ์ค์ API ์๋ต ํ์ง ๊ฒ์ฆ ํ์
โ AI ์ถ์ฒ ๊ธฐ๋ฅ์์ "๊ฐ์ ๋ชจ๋ธ ์ค๋ณต ํ์ฉ" ๊ท์น ์ฝ์
โ ์ฌ๋กฏ๋ง๋ค ๋ค๋ฅธ ๋ชจ๋ธ ๋ฐฐ์ ์์น ๊ฐ์
โ DC Agent๊ฐ "TypeScript ํต๊ณผ" ๋ง์ผ๋ก ์ฐ์ถ๋ฌผ ์ ์ถ โ ์ธ๋ถ API ํธ์ถ ๊ธฐ๋ฅ์ ์ค ์๋ต ์๋๋ฆฌ์ค ๊ฒ์ฆ ํฌํจ
โ `.claude/agents/` ์๋ธ์์ด์ ํธ ํ์ผ ์์ด Worker ์ญํ ์ CEO๊ฐ ์ง์ ์ํ โ ๋ฐ๋์ ํด๋น ์์ด์ ํธ ํธ์ถ
โ ecc ์คํฌ์ ๋ฏธ๋ฆฌ ์ ๋ถ ๊ณ ์ ๋ฐฐ์ โ CEO๊ฐ ๋งค ์
๋ฌด๋ง๋ค ์ํฉ์ ๋ง๊ฒ ์คํฌ ์ ํ (๊ณผ์ ๊ณ ์ ๊ธ์ง)
โ 3ํ ์์ ๋ฃจํ ์ด๊ณผ ํ ๋ฏธ๋ณด๊ณ โ ์์ค์ปฌ๋ ์ด์
์๋ฌด
โ CEO ์๊ฐ์ ๊ฒ ์์ด ์ต์ข
๋ณด๊ณ โ ํ์ง ๊ฒ์ฆ ๋๋ฝ
โ decision-log ๋ฏธ๊ธฐ๋ก ์ํ๋ก ์ฃผ์ ๊ฒฐ์ โ ์์ฌ๊ฒฐ์ ์ถ์ ๋ถ๊ฐ
โ ์ฝ๋ ์ฐ์ถ๋ฌผ์ ํ๋ค์ค ์ฅ์น(hook/lint/test) ์์ด ๋ฉํ โ ํ๋ก๊ทธ๋๋ฐ์ ๊ฐ์ ์๋ฌด
โ ํ๋ก์ ํธ ์ต์ด ์
์
์ ํ๋ค์ค โ ~โฆ ๋ฏธ๊ตฌ์ถ โ ์ ์ฒด ๊ตฌ์ถ ํ์
โ ์๋ฌ ๋ฑ๋ก ํ gc.sh (๋๋ ๋๋ฑ ์๋จ) ๋ฏธ์คํ์ผ๋ก ๋ฐฉ์ด ์ฒด๊ณ ๋ฏธ๊ฐฑ์ โ GC ํ์ดํ๋ผ์ธ ์๋ฌด
์์คํ
์ด๊ธฐํ
mkdir -p ~/.claude/reports
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
echo "[CEO SYSTEM INITIALIZED] v2.0.28"
echo "ERROR-REGISTRY : $(grep -c 'ERROR-ID' ~/.claude/error-registry.md 2>/dev/null || echo 0)๊ฑด"
echo "SKILL-REGISTRY : $(grep -c 'SKILL-ID' ~/.claude/skill-registry.md 2>/dev/null || echo 0)๊ฑด"
echo "DECISION-LOG : $(grep -c 'DEC-' ~/.claude/decision-log.md 2>/dev/null || echo 0)๊ฑด"
echo "ACTIVE PROJECTS: $(grep -c 'ACTIVE' ~/.claude/project-registry.md 2>/dev/null || echo 0)๊ฐ"
echo "MODEL TIERS : Opus(์ค๊ณยท๋ณด์ยทOSSยท๊ฒํ ) / Sonnet(๊ฐ๋ฐยท๋ถ์) / Haiku(๋ฆฌ์์นยท๋ฌธ์ยทQA)"
echo "DEV WORKERS : FE / BE / DB / MOB / OPS / INT (๋ณ๋ ฌ)"
echo "SPECIAL WORKERS: BIZ(์ฌ์
ํ๋จ) / OSS(์์ํ์) / TOK(ํ ํฐ๊ด๋ฆฌ)"
echo "GATE : 1-5 ๊ฐ๋"
echo "SELF-INSPECT : ํ์ฑํ"
echo "GC : ์์ด์ ํธยท์คํฌ ์๋ ์
๋ฐ์ดํธ"
echo "HARNESS IMPL : ์ฝ๋ ์ฐ์ถ๋ฌผ ์ hook/lint/test/CI ์๋ ๊ตฌ์ถ"
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
echo "์ค๋น ์๋ฃ. ์ง์๋ฅผ ๋ด๋ ค์ฃผ์ธ์."