Ch1. 모노레포 아키텍처 설계
Turborepo 기반 apps/packages 분리 전략, 의존성 방향, 네이밍 규칙
왜 모노레포인가
| 기준 | 폴리레포 | 모노레포 |
|---|---|---|
| 코드 공유 | npm publish 후 버전 맞추기 | workspace:*로 즉시 참조 |
| 원자적 변경 | 여러 PR 조율 필요 | 단일 커밋으로 전체 반영 |
| CI 속도 | 레포별 독립 빌드 | Turborepo 캐싱으로 변경분만 빌드 |
| 온보딩 | 레포마다 환경 설정 | yarn install 한 번으로 전체 |
| 코드 거버넌스 | 레포별 규칙 파편화 | CODEOWNERS + 공유 ESLint 일원화 |
서비스가 3개를 넘으면 폴리레포의 조율 비용이 모노레포의 복잡성 비용을 초과합니다.
apps vs packages 분리 원칙
판단 기준:
apps/— 독립 배포 가능, 자체next.config.ts보유packages/— 단독 배포 불가, 다른 패키지나 앱에서 import되어 사용
별도 API 서버가 필요한가?
Next.js의 API Routes + Server Actions가 대부분의 엔터프라이즈 요구를 충족합니다.
별도 Express/Hono API 서버는 WebSocket 실시간 처리, 높은 동시성 처리 등 Next.js 서버리스 모델에 맞지 않는 특수 요구가 있을 때만 도입하세요.
Prisma를 @org/db 패키지로 공유하면 여러 Next.js 앱이 동일한 DB 스키마를 안전하게 참조할 수 있습니다.
의존성 방향과 계층
핵심 규칙: 의존성은 항상 위에서 아래로만 흐른다.
Layer 0 (최하위): @org/types, @org/tsconfig, @org/eslint-config
Layer 1: @org/utils, @org/db (Prisma)
Layer 2: @org/ui
Layer 3 (최상위): apps/web, apps/admin, apps/docs같은 계층 간 참조는 순환 의존성을 만들므로 금지합니다. @org/ui가 @org/db를 import하고 싶다면, 공통 타입을 Layer 0으로 추출하세요.
네이밍 규칙
// packages/ui/package.json
{
"name": "@acme/ui", // 조직 스코프 필수
"private": true, // 내부 패키지는 private
"exports": {
".": "./src/index.ts",
"./button": "./src/button.tsx"
}
}| 대상 | 규칙 | 예시 |
|---|---|---|
| 패키지 이름 | @org/ 스코프 + 케밥 케이스 | @acme/ui, @acme/db |
| 앱 이름 | 스코프 없는 단일 단어 | web, admin, docs |
| 디렉토리 | 케밥 케이스 | db/, eslint-config/ |
| 설정 패키지 | @org/+도구명 | @acme/tsconfig, @acme/eslint-config |
디렉토리 레이아웃
monorepo/
├── apps/
│ ├── web/ # 메인 서비스 (Next.js + API Routes)
│ ├── admin/ # 어드민 대시보드 (Next.js + Server Actions)
│ └── docs/ # 문서 사이트 (Fumadocs)
├── packages/
│ ├── db/ # Prisma 클라이언트 + 스키마
│ ├── ui/ # 공유 UI 컴포넌트
│ ├── utils/ # 공통 유틸리티
│ ├── types/ # 공유 타입 정의
│ ├── tsconfig/ # TypeScript 설정
│ └── eslint-config/ # ESLint 설정
├── tooling/ # 빌드/배포 스크립트 (선택)
├── turbo.json
├── package.json # 루트 워크스페이스
└── CLAUDE.md # 에이전틱 개발 컨텍스트tooling/ 디렉토리는 Turbo generator, DB 마이그레이션 스크립트 등 빌드 도구를 분리할 때 사용합니다. 초기에는 없어도 되지만, 스크립트가 3개를 넘으면 분리를 검토하세요.
Turborepo Boundaries로 의존성 규칙 검증
Turborepo 2.3+의 Boundaries 기능(실험적)을 사용하면 의존성 방향 규칙을 선언적으로 정의하고 자동 검증할 수 있습니다. turbo run lint에서 위반을 감지하므로, 위에서 설명한 계층 규칙을 CI에서 강제할 수 있습니다.