codesyncer 1.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,324 +1,582 @@
1
1
  # 주석 작성 가이드
2
2
 
3
- > **CodeSyncer 주석 시스템** - 모든 추론과 결정을 영구 기록
3
+ > **주석으로 모든 컨텍스트 관리** - 코드가 문서
4
4
 
5
5
  ---
6
6
 
7
- ## 📋 주석 태그 레퍼런스
7
+ ## 🎯 핵심 원칙
8
8
 
9
- ### 5가지 필수 태그
9
+ **모든 결정과 맥락은 코드에 직접 기록합니다.**
10
10
 
11
- | 태그 | 용도 | 사용 시점 | 중요도 |
12
- |------|------|-----------|--------|
13
- | `@codesyncer-rule` | 특별 규칙 | 일반적이지 않은 구현 방식 | ⭐⭐⭐ |
14
- | `@codesyncer-inference` | 추론 내용 | AI가 추론한 내용과 근거 | ⭐⭐⭐⭐⭐ |
15
- | `@codesyncer-decision` | 결정 사항 | 의논 후 결정된 내용 | ⭐⭐⭐⭐⭐ |
16
- | `@codesyncer-todo` | TODO | 사용자 확인 필요 | ⭐⭐⭐⭐ |
17
- | `@codesyncer-context` | 비즈니스 맥락 | 도메인 지식, 배경 설명 | ⭐⭐⭐ |
11
+ - 별도 문서에 품질 기준 작성 AI가 읽지 못함
12
+ - ✅ 코드 주석으로 품질 기준 설명 → 영구 보존
13
+
14
+ ---
15
+
16
+ ## 📋 주석 태그 시스템 (10가지)
17
+
18
+ ### 기본 태그 (5가지)
19
+
20
+ | 태그 | 용도 | 필수 정보 |
21
+ |------|------|----------|
22
+ | `@codesyncer-inference` | 추론 + 근거 | "무엇" + "왜" |
23
+ | `@codesyncer-decision` | 결정 사항 | [날짜] + 이유 |
24
+ | `@codesyncer-todo` | 확인 필요 | 구체적인 작업 |
25
+ | `@codesyncer-context` | 비즈니스 맥락 | 도메인 지식 |
26
+ | `@codesyncer-rule` | 특별 규칙 | 예외 사항 |
27
+
28
+ ### 확장 태그 (5가지) - 컨텍스트 완전 보존
29
+
30
+ | 태그 | 용도 | 언제 사용 |
31
+ |------|------|----------|
32
+ | `@codesyncer-why` | 이유 상세 설명 | 코드만으로 이해 어려울 때 |
33
+ | `@codesyncer-tradeoff` | 장단점 | 선택의 trade-off 있을 때 |
34
+ | `@codesyncer-alternative` | 대안들 | 다른 방법 고려했을 때 |
35
+ | `@codesyncer-pattern` | 패턴명 | 재사용 가능한 패턴 |
36
+ | `@codesyncer-reference` | 참조 링크 | 외부 문서/이슈 참조 |
18
37
 
19
38
  ### 레거시 호환
20
39
 
21
- 기존 `@claude-*` 태그도 완전히 호환됩니다:
22
40
  ```typescript
23
- @claude-rule = @codesyncer-rule
24
- @claude-inference = @codesyncer-inference
25
- @claude-decision = @codesyncer-decision
26
- @claude-todo = @codesyncer-todo
27
- @claude-context = @codesyncer-context
41
+ @claude-* = @codesyncer-* // 기존 태그도 완전 호환
28
42
  ```
29
43
 
30
44
  ---
31
45
 
32
- ## 📝 주석 레벨
33
-
34
- ### 1. 📄 파일 레벨 (JSDoc)
46
+ ## 💡 실전 예시: 모든 컨텍스트를 주석으로
35
47
 
36
- **언제**: 파일 최상단, 모듈 전체 설명
48
+ ### 1️⃣ 품질 기준을 주석으로 관리
37
49
 
38
50
  ```typescript
39
51
  /**
40
- * User authentication service
52
+ * 결제 처리 서비스
41
53
  *
42
- * @codesyncer-context JWT 기반 인증 시스템
43
- * @codesyncer-rule 토큰은 httpOnly 쿠키에 저장 (XSS 방지)
44
- * @author CodeSyncer
45
- * @date 2024-10-17
54
+ * @codesyncer-context 실시간 카드 결제 처리 (PG사: Stripe)
55
+ * @codesyncer-rule 모든 금액은 정수로 처리 (소수점 오류 방지)
56
+ * @codesyncer-pattern Transaction Script (단순 결제는 도메인 모델 불필요)
57
+ *
58
+ * 품질 기준:
59
+ * - 타임아웃: 30초 (PG사 권장)
60
+ * - 재시도: 3회 (멱등성 보장 필수)
61
+ * - 로깅: 모든 결제 시도 기록
62
+ * - 에러 처리: 사용자 친화적 메시지
46
63
  */
47
- ```
64
+ export class PaymentService {
65
+ /**
66
+ * 결제 실행
67
+ *
68
+ * @codesyncer-why 동기 처리로 구현 (결제 완료 즉시 확인 필요)
69
+ * @codesyncer-tradeoff 동기: 빠른 피드백 | 비동기: 높은 처리량
70
+ * @codesyncer-decision [2024-11-12] 동기 방식 선택 (UX 우선)
71
+ */
72
+ async processPayment(
73
+ amount: number,
74
+ cardToken: string
75
+ ): Promise<PaymentResult> {
76
+ // @codesyncer-inference: 최소 금액 100원 (PG사 정책)
77
+ if (amount < 100) {
78
+ throw new ValidationError('최소 결제 금액은 100원입니다');
79
+ }
80
+
81
+ // @codesyncer-why: 멱등성 키 생성 (중복 결제 방지)
82
+ const idempotencyKey = this.generateIdempotencyKey(amount, cardToken);
83
+
84
+ // @codesyncer-pattern: Retry with Exponential Backoff
85
+ return await this.retryWithBackoff(async () => {
86
+ return await stripe.charge({
87
+ amount,
88
+ source: cardToken,
89
+ idempotencyKey
90
+ });
91
+ }, {
92
+ maxRetries: 3,
93
+ initialDelay: 1000
94
+ });
95
+ }
48
96
 
49
- ### 2. 🔧 함수/클래스/컴포넌트 레벨
97
+ /**
98
+ * @codesyncer-pattern Exponential Backoff
99
+ * @codesyncer-reference https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/
100
+ */
101
+ private async retryWithBackoff<T>(
102
+ fn: () => Promise<T>,
103
+ options: RetryOptions
104
+ ): Promise<T> {
105
+ // ... 구현
106
+ }
107
+ }
108
+ ```
50
109
 
51
- **언제**: 함수, 클래스, 컴포넌트 정의 위
110
+ ### 2️⃣ 복잡한 비즈니스 로직 설명
52
111
 
53
- ```tsx
112
+ ```typescript
54
113
  /**
55
- * 주문 생성 폼
114
+ * 할인 계산기
56
115
  *
57
- * @codesyncer-context 6단계 주문 프로세스
58
- * @codesyncer-inference 단계마다 자동 저장 (일반적인 UX 패턴)
59
- * @codesyncer-decision [2024-10-15] Zustand로 상태 관리 (복잡한 폼 상태)
116
+ * @codesyncer-context 복합 할인 정책 (중복 적용 가능)
117
+ * - 회원 등급 할인: 5-15%
118
+ * - 쿠폰 할인: 고정 금액 또는 비율
119
+ * - 프로모션 할인: 특정 조건 충족 시
120
+ *
121
+ * @codesyncer-decision [2024-11-10] 할인 순서 고정 (마케팅팀 합의)
122
+ * 1. 회원 등급 할인
123
+ * 2. 쿠폰 할인
124
+ * 3. 프로모션 할인
125
+ *
126
+ * @codesyncer-why 순서가 중요함 (최종 금액이 달라짐)
127
+ * @codesyncer-alternative 할인율 합산 후 적용 → 거부됨 (복잡한 케이스 처리 어려움)
60
128
  */
61
- export default function OrderForm() {
62
- // ...
63
- }
64
- ```
65
-
66
- ### 3. 📝 인라인 레벨
67
-
68
- **언제**: 코드 라인 또는 옆
129
+ function calculateFinalPrice(
130
+ basePrice: number,
131
+ user: User,
132
+ coupon?: Coupon,
133
+ promotion?: Promotion
134
+ ): number {
135
+ // @codesyncer-context: 모든 중간 계산 저장 (환불 시 추적용)
136
+ const breakdown: PriceBreakdown = {
137
+ basePrice,
138
+ discounts: []
139
+ };
140
+
141
+ let currentPrice = basePrice;
142
+
143
+ // Step 1: 회원 등급 할인
144
+ // @codesyncer-inference: GOLD 15%, SILVER 10%, BRONZE 5% (일반적 패턴)
145
+ const memberDiscount = this.calculateMemberDiscount(user.tier);
146
+ if (memberDiscount > 0) {
147
+ currentPrice -= memberDiscount;
148
+ breakdown.discounts.push({
149
+ type: 'MEMBER',
150
+ amount: memberDiscount
151
+ });
152
+ }
69
153
 
70
- ```typescript
71
- // @codesyncer-inference: 페이지 크기 20 (일반적인 테이블 UX)
72
- const PAGE_SIZE = 20;
154
+ // Step 2: 쿠폰 할인
155
+ // @codesyncer-rule: 쿠폰은 할인된 금액에 적용 (중요!)
156
+ if (coupon) {
157
+ const couponDiscount = this.applyCoupon(currentPrice, coupon);
158
+ currentPrice -= couponDiscount;
159
+ breakdown.discounts.push({
160
+ type: 'COUPON',
161
+ amount: couponDiscount,
162
+ couponId: coupon.id
163
+ });
164
+ }
73
165
 
74
- // @codesyncer-todo: mainApi 엔드포인트 URL 확인 필요
75
- const API_URL = '/api/temp';
166
+ // Step 3: 프로모션 할인
167
+ // @codesyncer-todo: 프로모션 중복 적용 정책 확인 필요
168
+ if (promotion) {
169
+ const promoDiscount = this.applyPromotion(currentPrice, promotion);
170
+ currentPrice -= promoDiscount;
171
+ breakdown.discounts.push({
172
+ type: 'PROMOTION',
173
+ amount: promoDiscount,
174
+ promotionId: promotion.id
175
+ });
176
+ }
76
177
 
77
- // @codesyncer-decision: [2024-10-17] Soft Delete (30일 복구 가능)
78
- async function deleteUser(id: string) {
79
- // @codesyncer-inference: deleted_at 플래그 사용 (복구 기능용)
80
- return db.update(id, { deleted_at: new Date() });
178
+ // @codesyncer-rule: 최종 금액은 0 이상이어야
179
+ return Math.max(0, currentPrice);
81
180
  }
82
-
83
- const maxRetry = 3; // @codesyncer-inference: 3회 재시도 (안정성)
84
181
  ```
85
182
 
86
- ---
87
-
88
- ## ✅ 좋은 주석 예시
183
+ ### 3️⃣ 성능 최적화 기록
89
184
 
90
- ### 예시 1: 비즈니스 로직
91
-
92
- ```tsx
185
+ ```typescript
93
186
  /**
94
- * 배송비 계산 함수
187
+ * 주문 목록 조회 API
95
188
  *
96
- * @codesyncer-context 배송비 정책
97
- * - 3만원 이상: 무료 배송
98
- * - 3만원 미만: 3,000원
99
- * - 제주/도서산간: +3,000원
189
+ * @codesyncer-context 주문이 많은 사용자는 10만 건 이상 (성능 이슈)
190
+ * @codesyncer-decision [2024-11-12] 페이지네이션 + 인덱스 + 캐싱
100
191
  *
101
- * @codesyncer-decision [2024-10-10] 정책 확정 (마케팅팀 협의)
102
- * @codesyncer-rule 정책 변경 반드시 마케팅팀 승인 필요
192
+ * 성능 목표:
193
+ * - 응답 시간: < 500ms (P95)
194
+ * - 동시 접속: 1000 TPS
195
+ * - 캐시 히트율: > 80%
103
196
  */
104
- function calculateShippingFee(orderAmount: number, region: string): number {
105
- // @codesyncer-inference: 3만원 기준 (업계 표준)
106
- const FREE_SHIPPING_THRESHOLD = 30000;
107
-
108
- // @codesyncer-decision: [2024-10-10] 기본 배송비 3,000원
109
- const BASIC_FEE = 3000;
110
-
111
- // @codesyncer-todo: 제주/도서산간 지역 목록 확인 필요
112
- const EXTRA_FEE_REGIONS = ['제주', '울릉도'];
113
-
114
- if (orderAmount >= FREE_SHIPPING_THRESHOLD) {
115
- return 0;
197
+ export class OrderController {
198
+ /**
199
+ * @codesyncer-pattern Cursor-based Pagination
200
+ * @codesyncer-why Offset 페이징은 뒤로 갈수록 느려짐 (OFFSET 10000)
201
+ * @codesyncer-tradeoff Cursor: 빠름 | Offset: 페이지 번호 표시 가능
202
+ * @codesyncer-alternative Offset 페이징 → 테스트 결과 P95 3초 (거부)
203
+ * @codesyncer-reference https://use-the-index-luke.com/no-offset
204
+ */
205
+ async getOrders(userId: string, cursor?: string, limit = 20) {
206
+ // @codesyncer-inference: Redis 캐싱 5분 (실시간성 vs 성능)
207
+ const cacheKey = `orders:${userId}:${cursor}`;
208
+ const cached = await redis.get(cacheKey);
209
+ if (cached) {
210
+ return JSON.parse(cached);
211
+ }
212
+
213
+ // @codesyncer-pattern: Index Hint
214
+ // @codesyncer-why userId + createdAt 복합 인덱스 사용 강제
215
+ const orders = await db.query(`
216
+ SELECT /*+ INDEX(orders idx_user_created) */
217
+ id, total, status, created_at
218
+ FROM orders
219
+ WHERE user_id = ?
220
+ ${cursor ? 'AND created_at < ?' : ''}
221
+ ORDER BY created_at DESC
222
+ LIMIT ?
223
+ `, cursor ? [userId, cursor, limit] : [userId, limit]);
224
+
225
+ const result = {
226
+ data: orders,
227
+ nextCursor: orders.length === limit
228
+ ? orders[orders.length - 1].created_at
229
+ : null
230
+ };
231
+
232
+ // @codesyncer-inference: 5분 TTL (주문은 자주 변경되지 않음)
233
+ await redis.setex(cacheKey, 300, JSON.stringify(result));
234
+
235
+ return result;
116
236
  }
117
-
118
- const baseFee = BASIC_FEE;
119
- const extraFee = EXTRA_FEE_REGIONS.includes(region) ? 3000 : 0;
120
-
121
- return baseFee + extraFee;
122
237
  }
123
238
  ```
124
239
 
125
- ### 예시 2: 데이터 구조
240
+ ### 4️⃣ 보안 요구사항 명시
126
241
 
127
- ```tsx
242
+ ```typescript
128
243
  /**
129
- * 사용자 인터페이스
244
+ * 사용자 인증 미들웨어
245
+ *
246
+ * @codesyncer-context 금융 서비스 (보안 최우선)
247
+ * @codesyncer-rule OWASP Top 10 준수 필수
130
248
  *
131
- * @codesyncer-context GDPR 준수 필요
132
- * @codesyncer-rule 개인정보는 암호화 저장
249
+ * 보안 체크리스트:
250
+ * SQL Injection 방지 (Prepared Statement)
251
+ * ✅ XSS 방지 (CSP 헤더)
252
+ * ✅ CSRF 방지 (토큰 검증)
253
+ * ✅ Rate Limiting (분당 100 요청)
254
+ * ✅ 민감 정보 로깅 금지
133
255
  */
134
- interface User {
135
- id: string;
136
-
137
- // @codesyncer-inference: email을 username으로 사용 (일반적 패턴)
138
- email: string;
256
+ export async function authenticate(req: Request, res: Response, next: NextFunction) {
257
+ try {
258
+ // @codesyncer-rule: 토큰은 httpOnly 쿠키에서만 (XSS 방지)
259
+ const token = req.cookies.access_token;
260
+
261
+ if (!token) {
262
+ // @codesyncer-why: 401 vs 403 구분 (보안 best practice)
263
+ // 401: 인증 안됨 | 403: 권한 없음
264
+ return res.status(401).json({ error: 'Authentication required' });
265
+ }
266
+
267
+ // @codesyncer-decision [2024-11-12] JWT 대신 세션 사용 (더 안전)
268
+ // @codesyncer-tradeoff JWT: Stateless | Session: Revoke 가능
269
+ const session = await sessionStore.get(token);
270
+
271
+ if (!session) {
272
+ // @codesyncer-why: 에러 메시지 최소화 (공격자에게 정보 제공 최소화)
273
+ return res.status(401).json({ error: 'Invalid token' });
274
+ }
275
+
276
+ // @codesyncer-pattern: Session Rotation
277
+ // @codesyncer-reference: OWASP Session Management Cheat Sheet
278
+ if (session.shouldRotate()) {
279
+ const newToken = await sessionStore.rotate(session.id);
280
+ res.cookie('access_token', newToken, {
281
+ httpOnly: true,
282
+ secure: true,
283
+ sameSite: 'strict'
284
+ });
285
+ }
286
+
287
+ req.user = session.user;
288
+ next();
289
+
290
+ } catch (error) {
291
+ // @codesyncer-rule: 민감 정보 로깅 금지
292
+ logger.error('Authentication error', {
293
+ // ❌ token, password, email 등 민감 정보 절대 금지
294
+ ip: req.ip,
295
+ userAgent: req.get('user-agent')
296
+ });
297
+
298
+ return res.status(500).json({ error: 'Internal server error' });
299
+ }
300
+ }
301
+ ```
139
302
 
140
- // @codesyncer-decision: [2024-10-12] bcrypt 해싱 (보안팀 권고)
141
- passwordHash: string;
303
+ ### 5️⃣ 에러 핸들링 전략
142
304
 
143
- // @codesyncer-context: Soft Delete용
144
- // @codesyncer-decision: [2024-10-15] 30일 후 완전 삭제 (GDPR)
145
- deletedAt?: Date;
305
+ ```typescript
306
+ /**
307
+ * 외부 API 호출 래퍼
308
+ *
309
+ * @codesyncer-context 외부 서비스 불안정 (SLA 95%)
310
+ * @codesyncer-pattern Circuit Breaker + Retry + Timeout
311
+ * @codesyncer-reference Netflix Hystrix pattern
312
+ *
313
+ * 에러 처리 전략:
314
+ * - Timeout: 30초
315
+ * - Retry: 3회 (Exponential Backoff)
316
+ * - Circuit Breaker: 5번 실패 시 open
317
+ * - Fallback: 캐시된 데이터 반환
318
+ */
319
+ export class ExternalApiClient {
320
+ private circuitBreaker = new CircuitBreaker({
321
+ failureThreshold: 5,
322
+ resetTimeout: 60000
323
+ });
324
+
325
+ /**
326
+ * @codesyncer-why 모든 에러를 한 곳에서 처리 (일관성)
327
+ * @codesyncer-alternative 각 호출마다 try-catch → 코드 중복 심함
328
+ */
329
+ async call<T>(
330
+ endpoint: string,
331
+ options?: RequestOptions
332
+ ): Promise<Result<T>> {
333
+ // @codesyncer-pattern: Circuit Breaker
334
+ if (this.circuitBreaker.isOpen()) {
335
+ logger.warn('Circuit breaker is open', { endpoint });
336
+ return this.getFallback<T>(endpoint);
337
+ }
338
+
339
+ try {
340
+ // @codesyncer-inference: 30초 타임아웃 (외부 API 권장값)
341
+ const response = await this.retryWithTimeout(
342
+ () => fetch(endpoint, options),
343
+ { timeout: 30000, maxRetries: 3 }
344
+ );
345
+
346
+ this.circuitBreaker.recordSuccess();
347
+ return Result.ok(response.data);
348
+
349
+ } catch (error) {
350
+ this.circuitBreaker.recordFailure();
351
+
352
+ // @codesyncer-pattern: Error Classification
353
+ if (error instanceof TimeoutError) {
354
+ logger.warn('API timeout', { endpoint, duration: error.duration });
355
+ return this.getFallback<T>(endpoint);
356
+ }
357
+
358
+ if (error instanceof NetworkError) {
359
+ logger.error('Network error', { endpoint, error });
360
+ return this.getFallback<T>(endpoint);
361
+ }
362
+
363
+ // @codesyncer-why: 예상치 못한 에러는 전파 (상위에서 처리)
364
+ throw error;
365
+ }
366
+ }
146
367
 
147
- createdAt: Date;
148
- updatedAt: Date;
368
+ /**
369
+ * @codesyncer-pattern: Fallback with Stale Cache
370
+ * @codesyncer-why 오래된 데이터라도 없는 것보다 낫다
371
+ */
372
+ private async getFallback<T>(endpoint: string): Promise<Result<T>> {
373
+ const staleData = await cache.getStale<T>(endpoint);
374
+ if (staleData) {
375
+ logger.info('Returning stale cache', { endpoint });
376
+ return Result.ok(staleData, { isStale: true });
377
+ }
378
+
379
+ return Result.error('Service unavailable');
380
+ }
149
381
  }
150
382
  ```
151
383
 
152
- ### 예시 3: 컴포넌트
384
+ ### 6️⃣ 테스트 전략 문서화
153
385
 
154
- ```tsx
386
+ ```typescript
155
387
  /**
156
- * 주문 목록 테이블 컴포넌트
388
+ * 결제 서비스 테스트
389
+ *
390
+ * @codesyncer-context 결제는 critical path (버그 허용 불가)
157
391
  *
158
- * @codesyncer-context 고객용 주문 내역 조회
159
- * @codesyncer-inference 페이지네이션 필요 (대량 데이터)
160
- * @codesyncer-decision [2024-10-16] TanStack Table 사용 (성능)
392
+ * 테스트 전략:
393
+ * - Unit: 모든 public 메서드
394
+ * - Integration: PG사 API 호출 (Mock)
395
+ * - E2E: 실제 결제 플로우 (Staging)
396
+ * - 커버리지 목표: 95% 이상
397
+ *
398
+ * @codesyncer-rule 결제 로직 수정 시 QA 필수 승인
161
399
  */
162
- export function OrderListTable({ orders }: OrderListTableProps) {
163
- // @codesyncer-inference: 페이지당 20개 (UX 표준)
164
- const [pageSize, setPageSize] = useState(20);
165
-
166
- // @codesyncer-todo: 정렬 옵션 추가 (날짜, 금액, 상태)
167
-
168
- return (
169
- <Table>
170
- {/* @codesyncer-rule: 모바일에서는 카드 레이아웃으로 변경 */}
171
- {/* ... */}
172
- </Table>
173
- );
174
- }
400
+ describe('PaymentService', () => {
401
+ describe('processPayment', () => {
402
+ /**
403
+ * @codesyncer-pattern: AAA (Arrange-Act-Assert)
404
+ * @codesyncer-why 테스트 가독성과 유지보수성
405
+ */
406
+ it('should process payment successfully', async () => {
407
+ // Arrange: 테스트 데이터 준비
408
+ const service = new PaymentService();
409
+ const amount = 10000;
410
+ const cardToken = 'tok_test_1234';
411
+
412
+ // @codesyncer-inference: PG사 API는 Mock (실제 과금 방지)
413
+ const mockStripe = jest.spyOn(stripe, 'charge')
414
+ .mockResolvedValue({ id: 'ch_1234', status: 'succeeded' });
415
+
416
+ // Act: 실제 실행
417
+ const result = await service.processPayment(amount, cardToken);
418
+
419
+ // Assert: 결과 검증
420
+ expect(result.isSuccess).toBe(true);
421
+ expect(result.data.status).toBe('succeeded');
422
+
423
+ // @codesyncer-why: 호출 파라미터 검증 (올바른 값 전달 확인)
424
+ expect(mockStripe).toHaveBeenCalledWith({
425
+ amount,
426
+ source: cardToken,
427
+ idempotencyKey: expect.any(String)
428
+ });
429
+ });
430
+
431
+ /**
432
+ * @codesyncer-pattern: Edge Case Testing
433
+ * @codesyncer-why 경계 조건에서 버그 많이 발생
434
+ */
435
+ it('should reject payment below minimum amount', async () => {
436
+ const service = new PaymentService();
437
+
438
+ // @codesyncer-context: 최소 금액 100원 (PG사 정책)
439
+ await expect(
440
+ service.processPayment(99, 'tok_test')
441
+ ).rejects.toThrow('최소 결제 금액은 100원입니다');
442
+ });
443
+ });
444
+ });
175
445
  ```
176
446
 
177
447
  ---
178
448
 
179
- ## 나쁜 주석 예시
449
+ ## 🎯 주석 작성 원칙
180
450
 
181
- ### 피해야주석들
451
+ ### DO (해야 것)
182
452
 
183
- ```tsx
184
- // 너무 모호함
185
- // @codesyncer-inference: 이렇게 했음
186
- const value = 10;
453
+ ```typescript
454
+ // 구체적인 이유와 근거
455
+ // @codesyncer-inference: 페이지 크기 20 (사용자 연구 결과, 스크롤 3번 이내)
456
+ const PAGE_SIZE = 20;
187
457
 
188
- // 근거 없음
189
- // @codesyncer-decision: 변경함
190
- const API_URL = '/api/new';
458
+ // 날짜와 맥락
459
+ // @codesyncer-decision: [2024-11-12] PostgreSQL 선택 (복잡한 쿼리 + ACID 필요)
191
460
 
192
- // 의미 없음
193
- // @codesyncer-todo: 나중에
194
- function doSomething() {}
461
+ // Trade-off 명시
462
+ // @codesyncer-tradeoff: 캐싱으로 성능 50% 개선, 메모리 사용 20% 증가
195
463
 
196
- // 맥락 부족
197
- // @codesyncer-context: 중요함
198
- const IMPORTANT_VALUE = 42;
199
- ```
464
+ // 대안 기록
465
+ // @codesyncer-alternative: MongoDB 검토 → JSON 스키마 변경 빈번해 거부
200
466
 
201
- ### 개선된 버전
467
+ // 패턴 명시 (재사용)
468
+ // @codesyncer-pattern: Repository Pattern (데이터 접근 추상화)
469
+ ```
202
470
 
203
- ```tsx
204
- // ✅ 구체적인 근거
205
- // @codesyncer-inference: 기본값 10 (일반적인 재시도 대기 시간)
206
- const RETRY_DELAY = 10;
471
+ ### ❌ DON'T (하지 말 것)
207
472
 
208
- // ✅ 명확한 이유와 날짜
209
- // @codesyncer-decision: [2024-10-17] /api/v2로 변경 (API 버전업)
210
- const API_URL = '/api/v2';
473
+ ```typescript
474
+ // 너무 모호
475
+ // @codesyncer-inference: 이렇게
476
+ const value = 10;
211
477
 
212
- // 구체적인 TODO
213
- // @codesyncer-todo: 에러 케이스 핸들링 추가 (네트워크 오류, 타임아웃)
214
- function fetchData() {}
478
+ // 코드 그대로 반복
479
+ // @codesyncer-context: 사용자 생성 // 코드 보면 수 있음
480
+ function createUser() {}
215
481
 
216
- // 비즈니스 맥락 설명
217
- // @codesyncer-context: VAT 세율 (2024년 기준 10%)
218
- const TAX_RATE = 0.1;
482
+ // 근거 없음
483
+ // @codesyncer-decision: 변경함
484
+ const API_URL = '/new';
219
485
  ```
220
486
 
221
487
  ---
222
488
 
223
489
  ## 🔍 주석 검색
224
490
 
225
- ### Bash 명령어
491
+ ### 프로젝트 전체 검색
226
492
 
227
493
  ```bash
228
- # 모든 추론 내용 찾기
494
+ # 모든 추론 찾기
229
495
  grep -r "@codesyncer-inference" ./src
230
496
 
231
- # TODO 목록 확인
497
+ # 확인 필요한 TODO
232
498
  grep -r "@codesyncer-todo" ./src
233
499
 
234
- # 의논 결정 사항
500
+ # 의논 결정 사항
235
501
  grep -r "@codesyncer-decision" ./src
236
502
 
237
- # 특별 규칙
238
- grep -r "@codesyncer-rule" ./src
503
+ # 패턴 찾기 (재사용)
504
+ grep -r "@codesyncer-pattern" ./src
239
505
 
240
- # 비즈니스 맥락
241
- grep -r "@codesyncer-context" ./src
506
+ # 특정 패턴 찾기
507
+ grep -r "@codesyncer-pattern.*Retry" ./src
242
508
  ```
243
509
 
244
510
  ### VS Code 검색
245
511
 
246
- 1. `Cmd/Ctrl + Shift + F` (전체 검색)
247
- 2. 검색어 입력: `@codesyncer-todo`
248
- 3. 파일 필터: `src/**/*.{ts,tsx,js,jsx}`
512
+ ```
513
+ Cmd/Ctrl + Shift + F
514
+ @codesyncer-todo
515
+ → src/**/*.{ts,tsx,js,jsx}
516
+ ```
249
517
 
250
518
  ---
251
519
 
252
520
  ## 📊 주석 통계
253
521
 
254
- ARCHITECTURE.md에서 자동으로 통계를 제공합니다:
522
+ ARCHITECTURE.md 자동 집계:
255
523
 
256
524
  ```markdown
257
525
  ## 주석 태그 통계
258
526
  - @codesyncer-inference: 45개
259
527
  - @codesyncer-decision: 12개
260
- - @codesyncer-todo: 8개
261
- - @codesyncer-rule: 5
262
- - @codesyncer-context: 15개
528
+ - @codesyncer-pattern: 8개
529
+ - @codesyncer-todo: 3
263
530
  ```
264
531
 
265
- "통계 업데이트" 명령으로 수동 갱신 가능
532
+ 명령어: `"통계 업데이트"`
266
533
 
267
534
  ---
268
535
 
269
- ## 💡 주석 작성
536
+ ## 💡 주석이 문서를 대체하는 이유
270
537
 
271
- ### 1. 추론은 항상 근거와 함께
272
-
273
- ```tsx
274
- // ❌ @codesyncer-inference: useState 사용
275
- // ✅ @codesyncer-inference: useState 사용 (간단한 로컬 상태, Zustand 불필요)
538
+ ### 기존 방식의 문제
276
539
  ```
277
-
278
- ### 2. 결정은 날짜와 이유
279
-
280
- ```tsx
281
- // ❌ @codesyncer-decision: Stripe 사용
282
- // @codesyncer-decision: [2024-10-15] Stripe 사용 (해외 결제 지원 필요)
540
+ ❌ 별도 문서 작성
541
+ AI가 읽지 못함
542
+ → 코드와 문서 불일치
543
+ → 문서 업데이트 안됨
544
+
545
+ 가이드 문서
546
+ → AI context 초과
547
+ → 실제로 적용 안됨
548
+ → 까먹음
283
549
  ```
284
550
 
285
- ### 3. TODO는 구체적으로
286
-
287
- ```tsx
288
- // ❌ @codesyncer-todo: 수정 필요
289
- // ✅ @codesyncer-todo: 에러 바운더리 추가 (API 실패 시 폴백 UI)
551
+ ### 주석 기반의 장점
290
552
  ```
291
-
292
- ### 4. 맥락은 "왜"에 집중
293
-
294
- ```tsx
295
- // ❌ @codesyncer-context: 인증
296
- // @codesyncer-context: OAuth 2.0 인증 (Google, Kakao 로그인 지원)
297
- ```
298
-
299
- ### 5. 규칙은 예외적인 경우만
300
-
301
- ```tsx
302
- // ❌ @codesyncer-rule: TypeScript 사용 (이건 당연함)
303
- // ✅ @codesyncer-rule: 이 파일만 any 타입 허용 (외부 라이브러리 타입 없음)
553
+ ✅ 코드에 직접 기록
554
+ 영구 보존
555
+ → Git으로 버전 관리
556
+ → 코드와 항상 일치
557
+
558
+ 필요한 곳에만
559
+ → Context 효율적
560
+ → 검색 가능
561
+ AI가 실제 참고
304
562
  ```
305
563
 
306
564
  ---
307
565
 
308
566
  ## 🎯 체크리스트
309
567
 
310
- 코드 작성 후 확인:
568
+ 코드 작성 후:
311
569
 
312
- - [ ] 추론한 내용에 `@codesyncer-inference` 추가했나?
313
- - [ ] 의논 결정은 `@codesyncer-decision`으로 기록했나?
314
- - [ ] 확인 필요한 부분은 `@codesyncer-todo`로 표시했나?
315
- - [ ] 비즈니스 로직에 `@codesyncer-context` 설명했나?
316
- - [ ] 특별한 규칙은 `@codesyncer-rule`로 명시했나?
317
- - [ ] 모든 주석에 구체적인 근거를 포함했나?
570
+ - [ ] 모든 추론에 `@codesyncer-inference` + 근거
571
+ - [ ] 결정 사항에 `@codesyncer-decision` + [날짜] + 이유
572
+ - [ ] Trade-off 있으면 `@codesyncer-tradeoff` 명시
573
+ - [ ] 재사용 패턴에 `@codesyncer-pattern` 표시
574
+ - [ ] 확인 필요한 부분 `@codesyncer-todo`
575
+ - [ ] 복잡한 로직에 `@codesyncer-why` 설명
318
576
 
319
577
  ---
320
578
 
321
- **버전**: 1.0.0
579
+ **버전**: 2.0.0
322
580
  **마지막 업데이트**: [TODAY]
323
581
 
324
- *이 주석 시스템으로 모든 의사결정이 코드에 영구 기록됩니다.*
582
+ *주석이 문서입니다. 모든 컨텍스트를 코드에 기록하세요.*