# 29. 표준 라이브러리 스택 가이드

## 0. 먼저 알고 가기 (30초 요약)

- 같은 일을 하는 라이브러리는 저장소마다 다르지 않게 하나로 모읍니다.
- HTTP는 ky, 서버 상태는 react-query, 클라이언트 상태는 zustand, URL 상태는 nuqs를 기본으로 둡니다.
- 버전은 pnpm catalog로 묶고, 의존 방향은 린트로 검사합니다.

## 초심자용 한눈에 보기

표준을 정해두면 저장소를 옮겨 다닐 때 매번 새로 익힐 필요가 줄고, 같은 문제를 같은 방법으로 풉니다. 도구를 줄이면 학습할 표면이 줄고, 보안 패치나 버전 업그레이드를 한 번에 적용하기 쉬워집니다.

### 핵심 용어 빠르게 정리

| 용어            | 쉬운 뜻                                                    |
| --------------- | ---------------------------------------------------------- |
| `catalog`       | 워크스페이스 의존성 버전을 한 곳에 모아 고정하는 pnpm 기능 |
| `공유 인스턴스` | 인증·에러 처리를 미리 설정해 재사용하는 HTTP 객체          |
| `트리셰이킹`    | 실제로 쓰는 코드만 번들에 남기는 최적화                    |
| `의존 방향`     | app→domains→shared 순서로만 import를 허용하는 규칙         |
| `철회 조건`     | 표준을 더 이상 유지하지 않고 바꾸기로 하는 명시적 기준     |

| 분류            | 핵심 기술                                                                                   | 상태          | Stable    |
| :-------------- | :------------------------------------------------------------------------------------------ | :------------ | :-------- |
| **연관 가이드** | [04. 아키텍처](./04_아키텍처_설계_패턴.md), [05. API 통신](./05_API_통신_및_모킹_가이드.md) | **도구 원칙** | 벤더 중립 |
| **핵심 테마**   | HTTP·상태·URL·검증·로깅·스타일 표준, 선택 이유, 정렬 순서                                   | **Update**    | 최신 기준 |

---

> **"도구를 통일하는 목적은 멋이 아니라, 저장소를 옮겨도 같은 방식으로 읽고 고치고 지울 수 있게 하는 것이다."**
> 이 문서는 카테고리마다 하나의 표준 라이브러리를 정하고, 왜 그것을 골랐는지와 어떻게 옮겨갈지를 함께 적습니다. 새 라이브러리가 더 분명한 이점을 보이면 철회 조건에 따라 교체합니다.

---

## 문서 책임 범위

| 이 문서가 결정하는 것                  | 단일 출처로 따르는 문서                                                                  |
| :------------------------------------- | :--------------------------------------------------------------------------------------- |
| 카테고리별 표준 라이브러리와 선택 이유 | [04. 아키텍처](./04_아키텍처_설계_패턴.md), [22. 모노레포](./22_모노레포_운영_가이드.md) |
| HTTP·검증·모킹 적용 방식               | [05. API 통신](./05_API_통신_및_모킹_가이드.md)                                          |
| 상태·URL 상태 도구 선택                | [03. 상태관리](./03_상태관리_패턴_가이드.md)                                             |
| 버전 정렬·릴리스 경계                  | [11. CI/CD](./11_CICD_파이프라인_표준.md)                                                |

---

## 0. 모든 프론트엔드 그룹 공통 Baseline

| 기준                    | 최소 적용                                                           |
| :---------------------- | :------------------------------------------------------------------ |
| **한 카테고리 한 표준** | 같은 일을 하는 라이브러리는 저장소마다 다르지 않게 하나로 모읍니다. |
| **공유 스키마**         | 검증은 zod로 작성해 프론트와 백엔드가 함께 씁니다.                  |
| **버전 정렬**           | 공통 의존성은 catalog로 버전을 맞춥니다.                            |
| **구조 경계**           | import 방향은 린트로 검사합니다.                                    |
| **점진 적용**           | 큰 변경은 저장소별 작은 PR로 나눠 검증한 뒤 머지합니다.             |

### 0.1 교차 검증 매트릭스

| 권고                                    | 1차 출처                      | 실행 증거                  | 운영 증거              | 철회 조건                                   |
| :-------------------------------------- | :---------------------------- | :------------------------- | :--------------------- | :------------------------------------------ |
| 브라우저 HTTP는 ky 공유 인스턴스로 둔다 | 라이브러리 공식 문서          | 요청·에러·인증 헤더 테스트 | API 에러율, 재시도율   | 플랫폼 fetch만으로 동일 요구가 더 단순할 때 |
| URL 상태는 nuqs로 둔다                  | 라이브러리 공식 문서          | 딥링크·뒤로가기 E2E        | 잘못된 파라미터 유입률 | 라우터 내장 기능으로 충분할 때              |
| NestJS 검증은 shared zod로 둔다         | zod 문서, nestjs-zod 문서     | DTO 검증 단위 테스트       | 잘못된 요청 4xx 비율   | 런타임 검증이 불필요한 내부 전용 경로일 때  |
| 의존 방향은 boundaries 린트로 강제한다  | eslint-plugin-boundaries 문서 | lint 위반 0건              | 구조 회귀 PR 수        | 단일 모듈 규모라 계층이 불필요할 때         |

### 0.2 운영 게이트

| Gate            | Evidence                 | Owner       | Rollback                |
| :-------------- | :----------------------- | :---------- | :---------------------- |
| 라이브러리 채택 | 번들 diff, 라이선스 확인 | 플랫폼 오너 | 표준 외 라이브러리 제거 |
| 검증 계층       | shared 스키마 테스트     | 백엔드 오너 | 이전 검증 방식 복원     |
| 구조 경계       | boundaries lint 리포트   | FE 오너     | 위반 import 되돌리기    |
| 버전 정렬       | catalog diff             | 플랫폼 오너 | 이전 버전 핀 복원       |

---

## 1. 표준 스택 카탈로그

### 1.1 프론트엔드 표준

| 영역              | 표준                                  | 한 줄 이유                                          |
| :---------------- | :------------------------------------ | :-------------------------------------------------- |
| HTTP 클라이언트   | ky                                    | ESM·경량·fetch 기반, 캐싱·재시도는 react-query 담당 |
| 서버 상태         | @tanstack/react-query                 | 캐싱·재요청·동기화를 한 계층에 모음                 |
| 클라이언트 상태   | zustand                               | 작은 API, 보일러플레이트 최소                       |
| URL/쿼리 파라미터 | nuqs                                  | URL을 단일 상태원으로, 타입과 함께 다룸             |
| 폼                | react-hook-form + @hookform/resolvers | 비제어 입력, 리렌더 최소                            |
| 검증              | zod                                   | 프론트·백 공유 스키마                               |
| 스타일            | Tailwind CSS + clsx + tailwind-merge  | CSS-first·토큰화, 변형은 CVA                        |
| UI 프리미티브     | Radix + lucide-react                  | 접근성 내장, 아이콘 일관                            |
| 토스트 알림       | sonner                                | 알림 스택·키보드·접근성 기본 제공                   |
| 애니메이션        | motion                                | 기존 라이브러리의 후속 패키지명                     |
| 날짜              | date-fns (+ date-fns-tz)              | 트리셰이킹·함수형                                   |
| 유틸              | es-toolkit                            | 작고 빠른 TS 우선 유틸                              |
| 에러 경계         | react-error-boundary                  | Suspense·Error 경계 표준화                          |
| 깊은 비교         | dequal                                | 경량 deep compare                                   |
| ID 생성           | crypto.randomUUID()                   | 런타임 내장, 외부 의존 0                            |

### 1.2 백엔드(NestJS) 표준

| 영역          | 표준                              | 한 줄 이유                        |
| :------------ | :-------------------------------- | :-------------------------------- |
| DTO 검증      | nestjs-zod                        | shared zod 재사용, 이중 정의 제거 |
| 로깅          | nestjs-pino                       | 구조적 JSON·요청 컨텍스트         |
| 인증          | @nestjs/jwt + google-auth-library | 별도 추상화 계층 제거             |
| 비밀번호 해시 | argon2                            | 메모리-하드 해시                  |
| ORM 기본값    | Prisma (기존 Drizzle 저장소 유지) | 새 백엔드의 go-forward 기본값     |

### 1.3 툴체인 표준

| 영역          | 표준                                                                  | 한 줄 이유               |
| :------------ | :-------------------------------------------------------------------- | :----------------------- |
| 패키지 매니저 | pnpm + catalog                                                        | 워크스페이스 버전 단일화 |
| 빌드          | Vite + Rolldown                                                       | 빠른 dev·번들            |
| React 컴파일  | React Compiler (babel-plugin-react-compiler)                          | 자동 메모이제이션        |
| 린트          | ESLint flat + eslint-plugin-react-compiler + eslint-plugin-boundaries | RC 규칙·계층 경계 강제   |
| 포맷          | Prettier                                                              | 단일 포맷                |
| 테스트        | vitest + @testing-library + msw + playwright                          | Vite 변환 공유, e2e 분리 |
| 시크릿 스캔   | secretlint                                                            | pre-commit 유출 차단     |
| 타입          | TypeScript strict                                                     | null 안전                |

## 발행 공유 config 패키지 (@heejun/\*)

위 툴체인 표준은 npm에 발행된 `@heejun/*` config 패키지로 구현되어, 각 저장소가 의존성으로 가져다 쓴다. 한 곳에서 관리하므로 설정 드리프트가 사라진다.

| 패키지                      | 역할                                                                           |
| :-------------------------- | :----------------------------------------------------------------------------- |
| `@heejun/eslint-config`     | ESLint flat config (typescript-eslint + React 19 + React Compiler + 계층 경계) |
| `@heejun/prettier-config`   | Prettier 설정                                                                  |
| `@heejun/typescript-config` | tsconfig (base / react / node)                                                 |
| `@heejun/tailwind-config`   | Tailwind v4 CSS-first `@theme`                                                 |
| `@heejun/vite-config`       | Vite 8 + React Compiler                                                        |

```bash
pnpm add -D @heejun/eslint-config @heejun/prettier-config @heejun/typescript-config @heejun/vite-config @heejun/tailwind-config
```

### 적용 방법

각 저장소는 인라인 설정을 지우고 위 패키지를 의존성으로 참조한다.

**Prettier** — `package.json` 에 설정 파일 대신 패키지명을 적고 인라인 `.prettierrc` 는 삭제한다. 기본값이 형제 저장소 공통 컨벤션(`semi: false`, `trailingComma: 'es5'`)이라 재포맷 없이 채택된다. Tailwind 클래스 정렬이 필요하면 `prettierConfigWithTailwind` 를 쓴다.

```jsonc
// package.json
{ "prettier": "@heejun/prettier-config" }
```

**ESLint** — `base()` 와 `react()` 를 펼쳐 합친다. `base()` 는 import 위생·typescript-eslint 권장 규칙·Prettier 충돌 비활성을 제공하고, `react()` 는 React 19·React Compiler·접근성 규칙을 더한다. 저장소별 정책(전역 함수 제한, 테스트 완화 등)은 뒤에 덧붙인다.

```js
// eslint.config.mjs
import { base, react, defineConfig } from '@heejun/eslint-config'

export default defineConfig(
  base({ files: ['**/*.{ts,tsx}'] }),
  react({ files: ['apps/web/**/*.{ts,tsx}'] }),
  // 저장소별 override는 뒤에 덧붙인다
)
```

테스트/목 컨벤션을 강제하는 `heejunRules()` 는 opt-in 이므로 필요한 저장소만 `defineConfig(base(), react(), heejunRules())` 로 펼친다.

**적용 시 알아둘 점** — `eslint-plugin-jsx-a11y` 는 `minimatch` v3을 쓰므로, 저장소가 `minimatch` v10을 전역 고정했다면 스코프 override(`eslint-plugin-jsx-a11y>minimatch`)로 v3을 함께 둔다. 의존성 감사 게이트가 있는 저장소는 `eslint-plugin-boundaries` 가 끌어오는 전이 의존성을 override로 고정한다.

## 2. 표준 선택 이유

- **ky (HTTP)**: ESM 네이티브이며 번들이 가볍고 플랫폼 fetch 위에서 동작합니다. 캐싱과 재시도는 react-query가 담당하므로, 클라이언트에는 얇은 fetch 래퍼만 있으면 충분합니다.
- **nuqs (URL/쿼리 파라미터)**: 화면 상태를 URL에 두면 뒤로가기, 새로고침, 링크 공유가 자연스럽게 동작합니다. 쿼리 파라미터를 타입과 함께 다뤄 수동 파싱 코드를 없앱니다.
- **sonner (토스트 알림)**: 알림 스택, 키보드 처리, 접근성 기본값을 제공해 별도 구현 부담을 줄입니다.
- **motion (애니메이션)**: 기존 라이브러리의 후속 패키지명으로 API가 이어지며, 앞으로의 릴리스 라인을 따릅니다.
- **date-fns / es-toolkit**: 함수 단위로 임포트해 번들에 필요한 것만 포함됩니다. 타입 우선 설계라 별도 타입 패키지가 필요 없습니다.
- **argon2 (해시)**: 메모리 비용을 조절할 수 있는 해시로, 무차별 대입 공격에 더 강합니다.
- **nestjs-zod (검증)**: 프론트와 백엔드가 같은 zod 스키마를 공유해 검증 규칙이 한 곳에서 관리됩니다. 데코레이터 검증과의 이중 정의를 없앱니다.
- **nestjs-pino (로깅)**: 요청 컨텍스트가 붙은 구조적 JSON 로그로 관측성 도구와 바로 연동됩니다([09. 장애 대응](./09_장애_대응_및_관측성_표준.md)).
- **ESLint flat + Prettier**: React Compiler 규칙을 검사하는 플러그인이 ESLint 위에서만 제공되므로, 자동 메모이제이션의 안전망을 유지하려면 ESLint 계열을 유지합니다.
- **eslint-plugin-boundaries**: app→domains→shared→infrastructure 의존 방향을 린트로 강제해 구조가 시간이 지나도 무너지지 않게 합니다([04. 아키텍처](./04_아키텍처_설계_패턴.md)).
- **pnpm + catalog**: 워크스페이스 전반의 버전을 한 곳에서 고정해 드리프트를 막습니다.
- **Prisma 기본값, 기존 Drizzle 유지**: 새 백엔드는 Prisma를 기본으로 하되, 이미 Drizzle로 운영 중인 저장소는 옮기지 않습니다. 데이터 계층 이전은 위험 대비 효용이 낮습니다.

---

## 추천 항목 (실무 우선순위)

- **시작 추천**: 버전 정렬과 패키지명 교체처럼 위험이 낮은 항목부터 맞춥니다.
- **안정 추천**: HTTP·검증·토스트 알림 라이브러리를 표준으로 교체합니다.
- **운영 추천**: 의존 방향 린트와 catalog로 다시 어긋나지 않게 고정합니다.

## 추천 항목 고도화 체크

- `즉시 적용` — 추천 항목 1개를 이번 주 내에 실제 작업 1건에 반영한다.
- `1주 내 정리` — 적용 결과를 PR 본문이나 회고 노트에 간단히 기록한다.
- `1개월 내 점검` — 재작업률/리뷰 충돌/배포 이슈 중 적어도 한 항목이 개선되었는지 확인한다.

## 추천 항목 실행 기록 템플릿

- `담당자` : 항목 적용 주체(문서 오너/팀원)를 명시
- `적용일` : 실제 반영된 날짜 및 작업 ID를 남김
- `측정 지표` : 리뷰 충돌/재작업/버그 재발 중 1개 이상 수치로 기록
- `보류 사유` : 적용을 못한 경우 이유를 1줄 기록하고 다음 액션을 지정

## 추천 항목 실행 우선순위 매핑

- `P1(7일 내)` — 추천 항목 1개를 우선 적용하고 1회 사용자 관측 신호(에러율/실패율/지연)와 연결한다.
- `P2(30일 내)` — 추천 항목 1개를 팀 내 표준/템플릿에 반영해 재사용성을 확보한다.
- `P3(90일 내)` — 추천 항목 1개를 다른 관련 문서에 역링크로 연동해 중복 작업을 줄인다.
- `완료 기준` — 각 항목별 산출물(예: PR 링크/체크리스트/회고 노트)을 1개 이상 남긴다.

## 추천 항목 실행 체크리스트

- [ ] `1단계(7일)` : 추천 항목 1개를 실제 작업으로 전환
- [ ] `2단계(30일)` : 전환 결과를 팀 산출물(ADR/PR/체크리스트)에 반영
- [ ] `3단계(60일)` : 정적 지표 1개 이상으로 효과 검증
- [ ] `문제 대응` : 미달성 시 보류 사유와 다음 실행 액션을 문서화

## 추천 항목 실행 운영 규칙

- `실행 게이트` : 위험, 비용, 기대 효과가 1회 이상 정량화되어야 적용한다.
- `승인 체계` : 적용 전 사전 승인자(팀 리드/보안/운영)와 rollback 담당자를 확인한다.
- `리스크 점수` : 1~5 등급으로 현재 위험도를 기록하고 정량 기준을 남긴다.
- `리더 승인자` : 최종 승인 책임자(예: 팀 리드/PO/보안리더)를 명시한다.
- `승인 역할` : 승인자, 실행자, 모니터링 주체 역할을 분리해 적는다.
- `재개 조건` : 실패 신호가 기준치 이내로 돌아오면 다음 단계로 확장한다.
- `정지 조건` : 회귀 지표 악화가 1개 이상이면 즉시 중단하고 보류 사유를 갱신한다.
- `재평가 주기` : 최소 2주 단위로 상태를 리뷰하고 조정한다.

---

## 실무 적용 가이드

### 언제 이 문서를 펼칠까

- 새 저장소를 만들거나 라이브러리를 새로 추가할 때
- 같은 일을 하는 라이브러리가 저장소마다 달라 정리가 필요할 때
- 의존성 버전이 저장소 간에 어긋나 빌드나 동작이 갈릴 때

### 적용 순서

1. 대상 저장소의 현재 라이브러리를 카테고리별로 정리한다.
2. 이 문서의 표준과 다른 항목을 골라낸다.
3. 저위험 항목(버전 정렬, 패키지명 교체)부터 작은 PR로 바꾼다.
4. 라이브러리 교체(HTTP, 토스트 알림, 검증)는 동작 테스트와 함께 PR을 만든다.
5. typecheck·lint·test·build를 모두 통과시킨 뒤 머지한다.

### 함께 두는 파일

- HTTP 공유 인스턴스: `src/infrastructure/http/`
- env 스키마: `src/shared/config/`
- 린트 경계 설정: `eslint.config.mjs`

### 흔한 실수

- react-query를 쓰면서 HTTP 클라이언트에 재시도·캐싱을 또 얹어 동작이 중복된다.
- 버전을 저장소마다 손으로 올려 다시 어긋난다(catalog로 묶어야 한다).
- 검증 스키마를 프론트와 백엔드에 따로 정의해 규칙이 갈린다.
- 큰 구조 변경을 한 PR에 몰아 리뷰와 롤백이 어려워진다.

### PR 완료 기준

- [ ] 변경한 카테고리가 이 문서의 표준과 일치한다
- [ ] typecheck·lint·test·build가 모두 통과한다
- [ ] 교체한 라이브러리의 동작을 테스트나 스모크로 확인했다
- [ ] 버전은 catalog 또는 공통 기준에 맞춰 정렬했다
