@choblue/claude-code-toolkit 1.2.2 → 1.2.4

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 +1 @@
1
- af82e0967a0412bdcaa636fa0ab9e4f750d49608
1
+ 27c83ec4fadcaf1ee2f771651fa76d31262a831a
@@ -253,7 +253,142 @@ function UserContent({ isLoading, error, data }: UserContentProps) {
253
253
 
254
254
  ---
255
255
 
256
- ## 8. 금지 사항
256
+ ## 8. 에러 처리
257
+
258
+ ### 원칙: 에러 처리를 각 함수/컴포넌트에 흩뿌리지 않는다
259
+ - 각 함수마다 try-catch를 덕지덕지 붙이지 않는다
260
+ - `useState`로 에러 상태를 직접 관리하지 않는다 (TanStack Query가 제공)
261
+ - 에러 처리는 **경계(Boundary)**에서 한 번에 처리한다
262
+
263
+ ### API 에러: 서버 상태 라이브러리에 위임
264
+
265
+ ```typescript
266
+ // Bad - useState + useEffect로 에러 직접 관리
267
+ function UserList() {
268
+ const [error, setError] = useState<Error | null>(null);
269
+ const [data, setData] = useState(null);
270
+ const [loading, setLoading] = useState(false);
271
+
272
+ useEffect(() => {
273
+ setLoading(true);
274
+ fetchUsers()
275
+ .then(setData)
276
+ .catch(setError)
277
+ .finally(() => setLoading(false));
278
+ }, []);
279
+ }
280
+
281
+ // Good - 서버 상태 라이브러리가 에러를 관리
282
+ function UserList() {
283
+ const { data: users, isLoading, error } = useUserList();
284
+ if (error) return <ErrorDisplay error={error} />;
285
+ }
286
+ ```
287
+
288
+ ### 렌더링 에러: Error Boundary
289
+
290
+ ```typescript
291
+ <ErrorBoundary fallback={<ErrorFallback />}>
292
+ <UserContent />
293
+ </ErrorBoundary>
294
+ ```
295
+
296
+ ### 전역 API 에러: interceptor 또는 라이브러리 설정에서 일괄 처리
297
+ - axios interceptor, QueryClient defaultOptions 등 프로젝트 설정에 따른다
298
+ - 개별 컴포넌트가 아닌 앱 수준에서 에러 알림(toast 등)을 처리한다
299
+
300
+ ### 에러 UI 분기: early return 패턴
301
+
302
+ ```typescript
303
+ function UserPage({ userId }: UserPageProps) {
304
+ const { data: user, isLoading, error } = useUser(userId);
305
+
306
+ if (isLoading) return <Skeleton />;
307
+ if (error) return <ErrorDisplay error={error} />;
308
+ if (!user) return <EmptyState />;
309
+
310
+ return <UserContent user={user} />;
311
+ }
312
+ ```
313
+
314
+ ---
315
+
316
+ ## 9. 접근성 (a11y)
317
+
318
+ ### 시맨틱 HTML 사용
319
+ - 클릭 가능한 요소는 반드시 `<button>` 또는 `<a>`를 사용한다
320
+ - `<div onClick>`, `<span onClick>`을 금지한다
321
+
322
+ ```typescript
323
+ // Bad
324
+ <div onClick={handleDelete} className="cursor-pointer">삭제</div>
325
+
326
+ // Good
327
+ <button type="button" onClick={handleDelete}>삭제</button>
328
+ ```
329
+
330
+ ### 아이콘 버튼에 aria-label 필수
331
+
332
+ ```typescript
333
+ // Bad - 스크린 리더가 내용을 알 수 없음
334
+ <button onClick={onClose}><XIcon /></button>
335
+
336
+ // Good
337
+ <button onClick={onClose} aria-label="닫기"><XIcon /></button>
338
+ ```
339
+
340
+ ### 이미지에 alt, width, height 필수
341
+
342
+ ```typescript
343
+ // Bad
344
+ <img src={user.avatar} />
345
+
346
+ // Good
347
+ <img src={user.avatar} alt={`${user.name} 프로필`} width={40} height={40} />
348
+ ```
349
+
350
+ ### focus-visible 보장
351
+ - `outline: none`을 사용할 때 반드시 `focus-visible` 대체 스타일을 제공한다
352
+
353
+ ```typescript
354
+ // Bad - 포커스 표시 완전 제거
355
+ <button className="outline-none">
356
+
357
+ // Good - 키보드 포커스 시 표시
358
+ <button className="outline-none focus-visible:ring-2 focus-visible:ring-blue-500">
359
+ ```
360
+
361
+ ### 폼 접근성
362
+ - 모든 입력 필드에 `<label>` 또는 `aria-label`을 연결한다
363
+ - 적절한 `type`, `inputMode`, `autoComplete` 속성을 사용한다
364
+ - 붙여넣기(`onPaste`)를 차단하지 않는다
365
+
366
+ ---
367
+
368
+ ## 10. UX 패턴
369
+
370
+ ### 파괴적 액션에 확인 단계
371
+ - 삭제, 초기화 등 되돌릴 수 없는 동작에는 확인 UI를 추가한다
372
+
373
+ ### URL 파라미터와 UI 상태 동기화
374
+ - 탭, 필터, 페이지 등 공유 가능한 UI 상태는 URL 파라미터에 반영한다
375
+
376
+ ```typescript
377
+ // Bad - 새로고침하면 상태 소실
378
+ const [tab, setTab] = useState('overview');
379
+
380
+ // Good - URL에 상태 반영 (deep-link 가능)
381
+ const [searchParams, setSearchParams] = useSearchParams();
382
+ const tab = searchParams.get('tab') ?? 'overview';
383
+ ```
384
+
385
+ ### 대규모 리스트 가상화
386
+ - 50개 이상의 항목을 렌더링할 때는 가상화 라이브러리를 사용한다
387
+ - `@tanstack/react-virtual`, `react-window` 등을 활용한다
388
+
389
+ ---
390
+
391
+ ## 11. 금지 사항
257
392
 
258
393
  - `any` 타입 사용 금지
259
394
  - 인라인 스타일(`style={{}}`) 사용 금지 - 프로젝트 스타일링 방식을 따른다
@@ -263,4 +398,10 @@ function UserContent({ isLoading, error, data }: UserContentProps) {
263
398
  - `React.FC` 사용 금지
264
399
  - 배열 인덱스를 `key`로 사용 금지 (정적 리스트 제외)
265
400
  - `useEffect` 내에서 상태 동기화 로직 작성 금지 (파생값으로 처리)
266
- - Props drilling이 3단계 이상일 때 Context 또는 상태 관리 라이브러리 미사용 금지
401
+ - Props drilling이 3단계 이상일 때 Context 또는 상태 관리 라이브러리 미사용 금지
402
+ - 서버 상태(API 데이터)를 `useState` + `useEffect`로 관리 금지 (서버 상태 라이브러리 사용)
403
+ - 각 함수/컴포넌트마다 try-catch 남발 금지 (에러 경계에서 일괄 처리)
404
+ - `<div onClick>`, `<span onClick>` 금지 (`<button>` 또는 `<a>` 사용)
405
+ - 아이콘 버튼에 `aria-label` 누락 금지
406
+ - `outline: none` 단독 사용 금지 (`focus-visible` 대체 필수)
407
+ - 입력 필드에 `onPaste` 차단 금지
@@ -361,7 +361,43 @@ export function Button({ variant, size, className, ...props }: ButtonProps) {
361
361
 
362
362
  ---
363
363
 
364
- ## 8. 금지 사항
364
+ ## 8. 트랜지션 & 모션
365
+
366
+ ### transition 속성 명시
367
+ - `transition-all` 사용을 금지한다 - 변경되는 속성만 명시한다
368
+ - 불필요한 속성까지 트랜지션되면 성능이 저하된다
369
+
370
+ ```typescript
371
+ // Bad - 모든 속성에 트랜지션
372
+ <button className="transition-all">
373
+
374
+ // Good - 필요한 속성만
375
+ <button className="transition-colors">
376
+ <div className="transition-[transform,opacity]">
377
+ ```
378
+
379
+ ### prefers-reduced-motion 존중
380
+ - 애니메이션/트랜지션이 있는 요소에는 `motion-reduce:` 변형을 고려한다
381
+
382
+ ```typescript
383
+ // 모션 감소 선호 시 애니메이션 비활성화
384
+ <div className="animate-bounce motion-reduce:animate-none">
385
+ <div className="transition-transform motion-reduce:transition-none">
386
+ ```
387
+
388
+ ### 다크 모드 color-scheme
389
+ - 다크 모드 지원 시 `color-scheme: dark`를 설정하여 네이티브 UI(스크롤바, 입력 필드 등)도 다크 테마에 맞춘다
390
+
391
+ ```css
392
+ /* app.css */
393
+ .dark {
394
+ color-scheme: dark;
395
+ }
396
+ ```
397
+
398
+ ---
399
+
400
+ ## 9. 금지 사항
365
401
 
366
402
  - 인라인 `style={{}}` 사용 금지 - Tailwind 유틸리티 클래스를 사용한다
367
403
  - 임의값(arbitrary values) 남용 금지 - `w-[137px]` 같은 임의값은 최소화한다
@@ -373,6 +409,7 @@ export function Button({ variant, size, className, ...props }: ButtonProps) {
373
409
  - Tailwind 기본 테마 토큰 삭제 금지 - `@theme`에서 필요한 토큰만 추가한다
374
410
  - 사용하지 않는 커스텀 색상/간격 정의 금지 - 실제 사용하는 값만 정의한다
375
411
  - `tailwind.config.ts` 사용 금지 - v4에서는 CSS `@theme`으로 설정한다
412
+ - `transition-all` 사용 금지 - 변경되는 속성만 명시한다 (`transition-colors`, `transition-opacity` 등)
376
413
  - 클래스 문자열 동적 생성 금지 - Tailwind의 JIT가 감지하지 못한다
377
414
 
378
415
  ```typescript
@@ -237,7 +237,56 @@ const queryClient = new QueryClient({
237
237
 
238
238
  ---
239
239
 
240
- ## 9. 금지 사항
240
+ ## 9. 캐시 전략 가이드
241
+
242
+ 데이터 특성에 따라 `staleTime`을 다르게 설정한다.
243
+
244
+ | 데이터 유형 | staleTime | 예시 |
245
+ |------------|-----------|------|
246
+ | 거의 안 바뀜 | `Infinity` | 코드 테이블, 카테고리 목록, 약관 |
247
+ | 가끔 바뀜 | `10~30분` | 사용자 프로필, 설정 |
248
+ | 자주 바뀜 | `1~5분` | 게시글 목록, 댓글 |
249
+ | 실시간 필요 | `0` | 채팅, 알림, 재고 수량 |
250
+
251
+ ### 도메인별 staleTime 설정
252
+
253
+ ```typescript
254
+ // queryKey 팩토리에서 기본 옵션을 함께 관리
255
+ export const categoryKeys = {
256
+ all: ['categories'] as const,
257
+ list: () => [...categoryKeys.all, 'list'] as const,
258
+ };
259
+
260
+ // 거의 안 바뀌는 데이터
261
+ useQuery({
262
+ queryKey: categoryKeys.list(),
263
+ queryFn: fetchCategories,
264
+ staleTime: Infinity,
265
+ });
266
+
267
+ // 자주 바뀌는 데이터
268
+ useQuery({
269
+ queryKey: postKeys.list(filters),
270
+ queryFn: () => fetchPosts(filters),
271
+ staleTime: 1000 * 60, // 1분
272
+ });
273
+ ```
274
+
275
+ ### 실시간 데이터: refetchInterval 사용
276
+
277
+ ```typescript
278
+ // 폴링 방식 (WebSocket이 없을 때)
279
+ useQuery({
280
+ queryKey: ['notifications'],
281
+ queryFn: fetchNotifications,
282
+ staleTime: 0,
283
+ refetchInterval: 1000 * 30, // 30초마다 재요청
284
+ });
285
+ ```
286
+
287
+ ---
288
+
289
+ ## 10. 금지 사항
241
290
 
242
291
  - `useEffect`로 데이터 페칭 금지 - TanStack Query를 사용한다
243
292
  - queryKey 하드코딩 금지 - queryKey 팩토리 패턴을 사용한다
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@choblue/claude-code-toolkit",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "Claude Code 서브에이전트 위임 툴킷 - npx로 바로 설치",
5
5
  "bin": {
6
6
  "claude-code-toolkit": "bin/cli.js"