From 479a4bfc560471bad1b07c93b842d1bb41585cb0 Mon Sep 17 00:00:00 2001 From: htlee Date: Wed, 8 Apr 2026 13:29:28 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=8B=9C?= =?UTF-8?q?=EC=8A=A4=ED=85=9C=20SSOT=20=EA=B0=9C=EB=B0=9C=20=EC=A7=80?= =?UTF-8?q?=EC=B9=A8=20+=20=EB=A6=B4=EB=A6=AC=EC=A6=88=20=EB=85=B8?= =?UTF-8?q?=ED=8A=B8=20=EA=B0=B1=EC=8B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CLAUDE.md '디자인 시스템' 섹션 신규: - 쇼케이스(/design-system.html)를 단일 진실 공급원으로 명시 - 공통 컴포넌트 목록 (Button/Input/Select/PageContainer/PageHeader/Badge 등) - 카탈로그 API 사용 패턴 (getAlertLevelIntent/Label 등) - CSS 작성 6대 규칙 (인라인 색상 금지, 하드코딩 Tailwind 색상 금지, className override 정책, 시맨틱 토큰 우선, !important 절대 금지, vendor prefix 수동 대응) - 페이지 작성 표준 템플릿 - 접근성 (WCAG 2.1 Level A) 필수 사항 - 변경 사이클 (쇼케이스 → 카탈로그 → 컴포넌트 → 자동 반영) - 금지 패턴 체크리스트 RELEASE-NOTES.md [Unreleased]에 디자인 시스템 SSOT 작업 항목 추가: - 쇼케이스 페이지 + 신규 공통 컴포넌트 + 중앙 레지스트리 - 35+ feature 페이지 마이그레이션 - Badge intent 팔레트 테마 분리 - 접근성 전수 처리 (Select TypeScript 강제 등) --- CLAUDE.md | 120 ++++++++++++++++++++++++++++++++++++++++++ docs/RELEASE-NOTES.md | 34 ++++++++++++ 2 files changed, 154 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index e17f2b0..b119896 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -101,6 +101,126 @@ make format # 프론트 prettier - 커밋: Conventional Commits (한국어), `.githooks/commit-msg` 검증 - pre-commit: `frontend/` 디렉토리 기준 TypeScript + ESLint 검증 +## 디자인 시스템 (필수 준수) + +프론트엔드 UI는 **`/design-system.html` 쇼케이스를 단일 진실 공급원(SSOT)** 으로 한다. +모든 페이지/컴포넌트는 쇼케이스에 정의된 컴포넌트와 토큰만 사용한다. + +### 쇼케이스 진입 +- **URL**: https://kcg-ai-monitoring.gc-si.dev/design-system.html (메인 SPA와 별개) +- **소스**: `frontend/design-system.html` + `frontend/src/designSystemMain.tsx` + `frontend/src/design-system/` +- **추적 ID 체계**: `TRK-<카테고리>-<슬러그>` (예: `TRK-BADGE-critical-sm`) + - 호버 시 툴팁, "ID 복사 모드"에서 클릭 시 클립보드 복사 + - URL 해시 딥링크: `#trk=TRK-BUTTON-primary-md` +- **단축키 `A`**: 다크/라이트 테마 토글 + +### 공통 컴포넌트 (반드시 사용) + +| 컴포넌트 | 위치 | 용도 | +|---|---|---| +| `Badge` | `@shared/components/ui/badge` | 8 intent × 4 size, **className으로 색상 override 금지** | +| `Button` | `@shared/components/ui/button` | 5 variant × 3 size (primary/secondary/ghost/outline/destructive) | +| `Input` / `Select` / `Textarea` / `Checkbox` / `Radio` | `@shared/components/ui/` | 폼 요소 (Select는 aria-label 타입 강제) | +| `TabBar` / `TabButton` | `@shared/components/ui/tabs` | underline / pill / segmented 3 variant | +| `Card` / `CardHeader` / `CardTitle` / `CardContent` | `@shared/components/ui/card` | 4 variant | +| `PageContainer` | `@shared/components/layout` | 페이지 루트 (size sm/md/lg + fullBleed) | +| `PageHeader` | `@shared/components/layout` | 페이지 헤더 (icon + title + description + demo + actions) | +| `Section` | `@shared/components/layout` | Card + CardHeader + CardTitle + CardContent 단축 | + +### 카탈로그 기반 라벨/색상 + +분류 데이터는 `frontend/src/shared/constants/`의 19+ 카탈로그를 참조한다. +중앙 레지스트리는 `catalogRegistry.ts`이며, 쇼케이스가 자동 열거한다. + +```tsx +import { Badge } from '@shared/components/ui/badge'; +import { getAlertLevelIntent, getAlertLevelLabel } from '@shared/constants/alertLevels'; + + + {getAlertLevelLabel(event.level, t, lang)} + +``` + +ad-hoc 한글/영문 상태 문자열은 `getStatusIntent()` (statusIntent.ts) 사용. +숫자 위험도는 `getRiskIntent(0~100)` 사용. + +### CSS 작성 규칙 + +1. **인라인 색상 금지** — `style={{ backgroundColor: '#ef4444' }}` 같은 정적 색상은 작성 금지 + - 예외: 동적 데이터 기반 (`backgroundColor: meta.hex`, progress width `${value}%`) +2. **하드코딩 Tailwind 색상 금지** — `bg-red-500/20 text-red-400` 같은 직접 작성 금지 + - 반드시 Badge intent 또는 카탈로그 API 호출 +3. **className override 정책** + - ✅ 레이아웃/위치 보정: `` + - ❌ 색상/글자 크기 override: `` +4. **시맨틱 토큰 우선** — `theme.css @layer utilities`의 토큰 사용 + - `text-heading` / `text-label` / `text-hint` / `text-on-vivid` / `text-on-bright` + - `bg-surface-raised` / `bg-surface-overlay` / `bg-card` / `bg-background` +5. **!important 절대 금지** — `cn()` + `tailwind-merge`로 충돌 해결 +6. **`-webkit-` 벤더 prefix** — 수동 작성 CSS는 `backdrop-filter` 등 prefix 직접 추가 (Tailwind는 자동) + +### 페이지 작성 표준 템플릿 + +```tsx +import { PageContainer, PageHeader, Section } from '@shared/components/layout'; +import { Button } from '@shared/components/ui/button'; +import { Badge } from '@shared/components/ui/badge'; +import { getAlertLevelIntent, getAlertLevelLabel } from '@shared/constants/alertLevels'; +import { Shield, Plus } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; + +export function MyPage() { + const { t, i18n } = useTranslation('common'); + const lang = i18n.language as 'ko' | 'en'; + + return ( + + }> + 추가 + + } + /> +
+ + {getAlertLevelLabel('HIGH', t, lang)} + +
+
+ ); +} +``` + +### 접근성 (a11y) 필수 + +- **`