|
1 | 1 | # 개발 가이드라인 |
2 | 2 |
|
3 | | -이 블로그 프로젝트의 핵심 패턴과 구현 원칙을 정의합니다. |
| 3 | +## 필수 원칙 |
4 | 4 |
|
5 | | -## 아키텍처 패턴 |
| 5 | +### 도메인 API 사용 |
| 6 | +- ✅ `import { getCategoryById } from '@/domain/blog'` |
| 7 | +- ❌ 직접 파일 시스템 접근 금지 |
6 | 8 |
|
7 | | -### 도메인 중심 설계 |
8 | | -- **도메인 로직**: `src/domain/blog/` 에 통합 |
9 | | -- **UI 컴포넌트**: `src/app/` 하위에 구현 |
10 | | -- **타입 정의**: `src/domain/blog/types.ts` 중앙 집중 |
| 9 | +### 타입 안전성 |
| 10 | +- ✅ 모든 Props 인터페이스 명시 |
| 11 | +- ❌ `any` 타입 사용 금지 |
| 12 | +- ✅ 도메인 타입 재사용 (`CategoryId`, `Post`, `Tag`) |
11 | 13 |
|
12 | | -```typescript |
13 | | -// 도메인 API 사용 예시 |
14 | | -import { getCategoryById, getPostsByCategory, getRelatedPostsByTags } from '@/domain/blog' |
15 | | - |
16 | | -const category = getCategoryById('dev') |
17 | | -const posts = getPostsByCategory('dev') |
18 | | -const related = getRelatedPostsByTags(currentSlug, 3) |
19 | | -``` |
20 | | - |
21 | | -### 모듈 레벨 캐싱 |
22 | | -빌드 타임에 모든 데이터를 사전 로드하여 SSG 최적화 |
23 | | - |
24 | | -```typescript |
25 | | -// src/domain/blog/index.ts |
26 | | -export const allPosts = await getAllPosts() |
27 | | -export const allCategories = await getAllCategories() |
28 | | -export const allTags = extractTagsFromPosts(allPosts) |
29 | | -export const tagGraph = createTagGraph(allPosts, allTags) |
30 | | -export const tagClusters = createTagClusters(tagGraph) |
31 | | -``` |
32 | | - |
33 | | -### 태그 그래프 시스템 |
34 | | -graphology 라이브러리로 태그 간 관계 분석 |
35 | | - |
36 | | -```typescript |
37 | | -// 태그 관계 분석 |
38 | | -const relationships = getTagRelationships() |
39 | | -const clusters = getTagClusters() |
40 | | -const relatedPosts = getRelatedPostsByTags(currentSlug, 3) |
41 | | -``` |
| 14 | +### 아키텍처 구조 |
| 15 | +- **도메인 로직**: `src/domain/blog/` 통합 |
| 16 | +- **UI 컴포넌트**: `src/app/` 분리 |
| 17 | +- **모듈 레벨 캐싱**: 빌드 타임 데이터 사전 로드 |
42 | 18 |
|
43 | 19 | ## 콘텐츠 구조 |
44 | 20 |
|
45 | | -### MDX 파일 구조 |
| 21 | +### MDX 파일 |
46 | 22 | ``` |
47 | 23 | src/contents/ |
48 | | -├── dev/ # 개발 카테고리 |
49 | | -│ ├── category.json |
50 | | -│ └── *.mdx |
51 | | -└── life/ # 일상 카테고리 |
52 | | - ├── category.json |
53 | | - └── *.mdx |
| 24 | +├── dev/category.json + *.mdx |
| 25 | +└── life/category.json + *.mdx |
54 | 26 | ``` |
55 | 27 |
|
56 | | -### 포스트 frontmatter |
| 28 | +### frontmatter 필수 필드 |
57 | 29 | ```yaml |
58 | | ---- |
59 | 30 | title: '포스트 제목' |
60 | 31 | date: 2025-01-17 |
61 | 32 | tags: ['tag1', 'tag2'] |
62 | | -description: '포스트 설명' |
63 | | -category: 'dev' # 또는 'life' |
64 | | ---- |
65 | | -``` |
66 | | - |
67 | | -### 카테고리 메타데이터 |
68 | | -```json |
69 | | -{ |
70 | | - "name": "개발", |
71 | | - "description": "개발 관련 포스트", |
72 | | - "color": "blue", |
73 | | - "icon": "💻" |
74 | | -} |
75 | | -``` |
76 | | - |
77 | | -## 컴포넌트 패턴 |
78 | | - |
79 | | -### 타입 정의 |
80 | | -```typescript |
81 | | -interface PostHeaderProps { |
82 | | - title: string |
83 | | - date: string |
84 | | - tags: string[] |
85 | | - category?: CategoryId |
86 | | - readingTime?: number |
87 | | - author?: string |
88 | | - className?: string |
89 | | -} |
90 | | -``` |
91 | | - |
92 | | -### 컴포넌트 구현 |
93 | | -```typescript |
94 | | -// 서버 컴포넌트 기본, 상호작용 필요시만 클라이언트 |
95 | | -export function PostHeader({ title, date, tags, category }: PostHeaderProps) { |
96 | | - return ( |
97 | | - <header className={cn('mb-8 pb-8', className)}> |
98 | | - <div className="flex items-center gap-3 mb-4"> |
99 | | - {category && <CategoryBadge categoryId={category} />} |
100 | | - <h1 className="text-3xl font-bold">{title}</h1> |
101 | | - </div> |
102 | | - <TagList tags={tags} /> |
103 | | - </header> |
104 | | - ) |
105 | | -} |
| 33 | +category: 'dev' # 또는 'life' |
106 | 34 | ``` |
107 | 35 |
|
108 | | -## 품질 기준 |
| 36 | +## 품질 체크리스트 |
109 | 37 |
|
110 | | -### TypeScript 엄격 모드 |
111 | | -- `any` 타입 사용 금지 |
112 | | -- 모든 Props 인터페이스 명시적 정의 |
113 | | -- 도메인 타입 재사용 (`CategoryId`, `Post`, `Tag`) |
| 38 | +### 컴포넌트 작성시 |
| 39 | +- [ ] Props 인터페이스 정의 |
| 40 | +- [ ] 서버 컴포넌트 우선 (상호작용 필요시만 클라이언트) |
| 41 | +- [ ] `cn()` 유틸리티로 클래스 병합 |
114 | 42 |
|
115 | | -### 테스트 패턴 |
116 | | -```typescript |
117 | | -// 비즈니스 로직 테스트 |
118 | | -describe('태그 그래프 시스템', () => { |
119 | | - it('관련 포스트를 태그 유사도로 찾는다', () => { |
120 | | - const related = getRelatedPostsByTags('test-slug', 3) |
121 | | - expect(related).toHaveLength(3) |
122 | | - }) |
123 | | -}) |
124 | | -``` |
| 43 | +### 데이터 처리시 |
| 44 | +- [ ] 도메인 API 함수 사용 |
| 45 | +- [ ] 타입 안전성 보장 |
| 46 | +- [ ] 빌드 타임 사전 계산 활용 |
125 | 47 |
|
126 | 48 | ### 성능 최적화 |
127 | | -- 모든 데이터 빌드 타임 사전 계산 |
128 | | -- `generateStaticParams()` 사용한 정적 경로 생성 |
129 | | -- 컴포넌트 간 props 최소화 |
130 | | - |
131 | | -## 디렉토리 구조 |
132 | | - |
133 | | -``` |
134 | | -src/ |
135 | | -├── app/ # Next.js App Router |
136 | | -│ ├── [category]/ # 카테고리 페이지 |
137 | | -│ │ ├── [slug]/ # 포스트 상세 |
138 | | -│ │ └── _components/ # 페이지별 컴포넌트 |
139 | | -│ └── _components/ # 전역 컴포넌트 |
140 | | -├── domain/blog/ # 도메인 로직 |
141 | | -│ ├── index.ts # 공개 API + 캐싱 |
142 | | -│ ├── types.ts # 타입 정의 |
143 | | -│ └── logic/ # 비즈니스 로직 |
144 | | -│ ├── posts.ts |
145 | | -│ ├── categories.ts |
146 | | -│ └── tags.ts |
147 | | -└── contents/ # MDX 콘텐츠 |
148 | | - ├── dev/ |
149 | | - └── life/ |
150 | | -``` |
151 | | - |
152 | | -## 구현 원칙 |
153 | | - |
154 | | -1. **도메인 API 사용**: 직접 파일 시스템 접근 금지 |
155 | | -2. **타입 안전성**: 모든 데이터 흐름 타입 보장 |
156 | | -3. **모듈 레벨 캐싱**: 빌드 타임 데이터 사전 로드 |
157 | | -4. **컴포넌트 단순화**: 단일 책임 원칙 |
| 49 | +- [ ] `generateStaticParams()` 정적 경로 생성 |
| 50 | +- [ ] 컴포넌트 간 props 최소화 |
| 51 | +- [ ] 모듈 레벨 캐싱 활용 |
0 commit comments