디자인 시스템
세 단계에서 동일한 전문성을 제공합니다. 오케스트레이터(orchestrator)가 mode를 명시적으로 전달합니다.
| 모드 | 시기 | 질문 |
|---|---|---|
| PLAN | 기능 개발 단계 2 | 이 기능은 어떤 패턴/추상화를 사용해야 하는가? |
| BUILD | 기능 개발 단계 4 | PLAN 결정 사항을 구현하면서 적용한다. |
| REVIEW | 기능 개발 단계 5 | 구현이 실제로 PLAN 결정 사항을 따르는가? |
모드가 지정되지 않고 브랜치 차이가 존재하는 경우 REVIEW가 기본값입니다. 모드가 지정되지 않고 차이가 없는 경우 PLAN이 기본값입니다.
PLAN 모드
코드가 존재하기 전. 입력: 개선 브리핑(refinement brief), Figma 노드 또는 스크린샷, 범위 내 라우트(routes).
- pattern-library (
src/index.ts,src/theme.ts,src/core/)와 app-pro-ui에서 유사한 기능을 검색합니다. - 디자인의 각 주요 UI 요소에 대해 추상화 테스트(아래)를 실행합니다.
- 각 요소에 대해: 로컬 유지(local) | 기존 PL API | 토큰/변형(token/variant) | PL PR 필요 — 인용된 경로와 함께 제시합니다.
- PL 순서(PL PR이 app-pro-ui보다 먼저 또는 병렬로)와 누락된 카피/에셋을 플래그합니다.
UI 표면이 없는 경우: 한 줄로 **해당 없음 (UI 없음)**을 반환합니다.
출력: # 디자인 시스템 (PLAN): [기능] — 재사용 목록, 예상 변경 사항, 순서. 브랜치 차이는 필요하지 않습니다.
BUILD 모드
구현 중. 입력: 디자인 시스템 PLAN 출력, 편집 중인 파일.
- PLAN 결정 사항을 적용합니다: 명명된 PL 컴포넌트/토큰 사용, 로컬 유지 호출 존중.
- 아래 **추론 계층(reasoning layer)**을 따릅니다 — 재사용 가능한 외형을 기능 코드에서 다시 생성하지 마세요.
- 코딩 중에 배운 내용으로 인해 PLAN이 잘못된 경우, 빌드 요약에 변경 사항을 문서화하고 조용히 표류하지 마세요.
출력: 변경 사항이 없는 한 필요하지 않음 — 변경 사항이 있으면 빌드 요약에 기록.
REVIEW 모드
구현 후. 이 브랜치(app-pro-ui 또는 pattern-library)에서 디자인 시스템에 포함되어야 하는 UI 결정 사항을 스캔합니다. 단순히 "스타일을 삭제하세요" 또는 "공유 컴포넌트를 사용하세요"라고 말하지 마세요. 어떤 기능이든 동일한 작업을 수행할 수 있게 하는 가장 작은 전역 패턴 라이브러리 변경을 선호하거나, 추상화가 정당화되지 않는 경우 로컬 구현을 유지하는 것을 권장합니다.
이것은 "모든 스타일이 패턴 라이브러리에 속한다"는 의미가 아닙니다. 반복되는 제품/UX 결정 사항은 점차 시스템에 인코딩되어 개별 빌더가 재창조하지 않도록 해야 합니다. 기능 코드는 여전히 로컬에서 구성될 수 있습니다.
아키텍처 규칙: 재사용 가능한 시각적 결정 사항은 pattern-library에 속합니다. 기능 코드는 진정으로 로컬인 레이아웃/구성에 sx를 사용할 수 있지만, 재사용 가능한 컴포넌트 스타일링, 토큰, 상태 또는 상호작용 패턴을 재생성해서는 안 됩니다. 확립된 PL/MUI API가 있는 경우 style, 사용자 정의 CSS, 레거시 MUI 시스템 props를 피하세요.
이 스킬은 DS 계층입니다. app-pro-ui의 훅/유틸리티/그리드 구조 및 일반 코드 위생에 대해서는 refactoring 스킬을 사용하세요.
추론 계층
모든 발견 사항을 다음 규칙으로 판단합니다. 이 규칙은 수년간의 pattern-library 및 app-pro-ui 리뷰 코멘트에서 비롯되었습니다. 기존 API를 새 API보다 선호하세요. 코드를 pattern-library로 이동하는 것이 자동으로 개선되는 것은 아닙니다.
추상화 테스트
모든 후보 레시피(recipe), 토큰 또는 새 API에 대해 이 테스트를 실행하세요. 이것이 기본 판단입니다 — 탐지는 후보만 생성합니다.
- 이것은 로컬 구성인가?
- 동일한 레시피가 다른 곳에 존재하는가?
- 컴포넌트가 이미 이것을 소유해야 하는가?
- pattern-library로 이동하면 의미 있는 미래 결정 사항이 줄어드는가?
- API를 추가하면 실제로 pattern-library가 나빠지는가?
유사성만으로는 추상화를 정당화하지 않습니다. 비슷해 보이는 두 코드 조각이 다른 제품 개념을 나타낼 수 있습니다. 동일한 제품/UX 결정 사항이 함께 발전해야 할 때 공유 추상화를 선호하세요.
sx는 문제가 아닙니다. 문제는 디자인 결정 사항이 어디에 있는지입니다. 테마 토큰 sx는 16진수(hex)보다 낫습니다. 반복되는 레시피는 pattern-library에 속할 수 있습니다. 일회성 <Stack sx={{ mt: 2 }}>는 일반적으로 그렇지 않습니다. 테스트에서 로컬 솔루션이 올바르다고 판단되면 발견 사항에서 생략하세요 — 낮음(Low)으로 나열하지 마세요.
1. 디자인 시스템 사용 — 기능에서 재사용 가능한 결정 사항을 다시 스타일링하지 마세요
- 확립된 pattern-library 컴포넌트를 재사용 가능한 제품 패턴에 선호하세요 (
CardWithAction, 작업이 없더라도;CardCTAFeatured를 복합 카드로;DetailPanelToggle). 원시Card로 재구축하지 마세요. - 로컬 레이아웃인 경우 사용자 정의 레이아웃 CSS보다 MUI 구성 기본 요소(예:
Stack/Grid)를 선호하세요. - 로컬 기하학을 발명하기 전에 확립된 레이아웃 기본 요소와 기본값을 사용하세요.
- 재사용 가능한 색상, 그림자 및 마케팅/AI 처리는 palette 모양의 토큰(
primary.main,ai.gradient.start)으로pattern-library/src/theme.ts에 배치하세요. 값이 제품 결정 사항인 경우 하드코딩된 16진수, 채움 또는 그림자보다 토큰 또는theme.shadows를 선호하세요. - 사용 중단된 MUI style-as-props가 아닌
sx를 사용하세요. 이를 해결하기 위해 공유 컴포넌트에 style-named props를 추가하지 마세요. 로컬sx는 구성(composition)일 때 괜찮지만, 재사용 가능한 외형(reusable look)일 때는 아닙니다. - 기능에 다른 표면에서 공유할 새로운 외형(특집 미디어, 확장 오버레이, 반전/마케팅 표면)이 필요한 경우 pattern-library에 패턴 또는 prop을 추가하세요.
2. 공유 컴포넌트를 일반적으로 유지하세요
- 공유
Card,PageSection또는 공개index.ts내보내기에 기능별 패딩, 사이드바 또는 차트 변경 사항을 적용하지 마세요. 프로토타입 범위를 지정하고, 관련 없는 파일은 되돌리세요. 아이템만 잘못된 경우 크롬(chrome)이 아닌 아이템을 변경하세요. - 재사용을 위해 props 이름을 지정하세요 (
footerDescription, 단일 기능 레이블이 아닌). 추가 동작은 선택 사항입니다(줄 번호, textarea의 쉼표). - 포크된 JSX보다 테마 변형과 Storybook
args를 선호하세요 (variant === "marketing"검사). - 앱이 소비하지 않는 경우 pattern-library에서 차트 또는 기타 내부 사항을 내보내지 마세요.
- 장기적으로는 모든 페이지를 통해 일회성 시각적 props를 전달하는 대신 표면을 테마로 감싸세요(예: 마케팅).
3. 가장자리의 시각적 QA
- 둥근 모서리, 동일 높이 카드, 고아 줄바꿈 텍스트, 모바일 FAB 축소, 드로어/모달 대비 z-index, 흰 배경에서 컨트롤이 여전히 작동하는지 확인하세요.
- 특별한 간격이 필요한지 또는 기본 스타일이 다른 모달/페이지와 이미 일치하는지 물어보세요. 잘못 정렬된 이웃과 맞추기 위해 공유 헤더에 패딩을 추가하지 말고 이웃을 수정하세요.
4. 디자인 요구 사항에 의문을 제기하세요
비정상적인 디자인을 지원하기 위해 DS 기능을 추가하기 전에 디자인 자체가 확립된 시스템 동작을 따라야 하는지 판단하세요. 의심스러운 일회성 요구 사항을 인코딩하기 위해 디자인 시스템을 확장하지 마세요.
5. 불필요한 API 표면에 저항하세요
모든 제안된 DS 추상화는 추가하는 API 표면을 정당화해야 합니다. 코드를 pattern-library로 이동하는 것이 자동으로 개선되는 것은 아닙니다. 경험을 개선하지 않는 구성은 유지 관리 비용입니다.
DS 아키텍처 위생만 유지하세요: 구성을 방해하는 불필요한 래퍼, 중복 스타일링, 컴포넌트 API 복잡성, 공유 기본 요소의 기능별 로직. 중첩된 Box는 Stack/sx 구성을 방해할 때 평탄화하세요. 단순 토큰의 경우 useTheme 대신 테마 축약어(background.main)를 사용하세요.
6. 관련 표면과 함께 출시하세요
- 앱이 소비해야 하는 pattern-library 변경 사항은 일치하는 app-pro-ui 또는 moz-ui PR과 이를 확인할 수 있는 방법(amplify/domain 또는 동등)이 필요합니다.
- 범프 방법을 추천하기 전에 소비하는 저장소(
package.json, lockfile 또는 설치 문서)에서 현재 패키지/버전 관례를 확인하세요. 핀 스타일을 가정하지 마세요. - 소비 앱 PR이 준비될 때까지 공유 기본 요소를 병합하지 마세요.
호출 시 (REVIEW 모드)
복사하여 추적하세요:
리뷰 진행 상황:
- [ ] 이 브랜치와 병합 기준(merge-base) 간의 차이 확인
- [ ] 후보 수집 (결론 아님)
- [ ] 의도별로 클러스터링 (동일한 코드가 아닌 동일한 결정)
- [ ] 추상화 테스트 실행
- [ ] 기존 위치를 위해 pattern-library 검색
- [ ] 가장 작은 변경 권장 — 로컬 유지 / DS 변경 없음 포함
- [ ] 결과 보고, 요청하지 않는 한 구현하지 않음
발견 작업이 필수는 아닙니다. 차이가 적절히 로컬 범위라면 그렇게 말하고 중단하세요.
1단계: 브랜치 스캔
이 브랜치와 병합 기준(merge-base)을 비교하세요. 기본 브랜치를 감지하세요 (git symbolic-ref refs/remotes/origin/HEAD 또는 origin/main, 그 다음 main). 변경 사항이 있는 저장소(app-pro-ui 또는 pattern-library)에서 실행하세요.
DEFAULT=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/@@')
DEFAULT=${DEFAULT:-origin/main}
git merge-base "$DEFAULT" HEAD
git diff $(git merge-base "$DEFAULT" HEAD)...HEAD -- '*.tsx' '*.ts' '*.jsx' '*.js' '*.css' '*.scss'
git diff --name-only $(git merge-base "$DEFAULT" HEAD)...HEAD
추가된 줄에서 후보를 검색하세요:
스타일링
style=sx=styled(css\`` /css(`makeStyles/createStyles/withStyles- 하드코딩된
#hex,rgb(,rgba(,px(조사, 자동 분류 금지) - 레거시 Box props:
display=,alignItems=,justifyContent=,flexDirection=
재창조되거나 표류한 UI
- 확립된 카드 패턴(
CardWithAction,CardCTAFeatured)이 적합한 곳에 원시Card DetailPanelToggle대신 사용자 정의 확장 컨트롤Stack/Grid가 로컬로 구성될 수 있는 곳에 사용자 정의 레이아웃 CSS- 레이아웃 기본 요소 또는 기본값이 이미 너비를 설정한 곳에 발명된 페이지 기하학
- 공유 외형일 때
theme.shadows대신 하드코딩된 그림자 - 하나의 기능만 제공하는 새로운 공개 내보내기 또는 테마 편집
그런 다음 각 적중을 열고 주변 JSX를 읽어 의도를 파악하세요. 또한 JSX 전에 할당된 sx 객체, <style> 태그, 가져온 스타일시트도 잡으세요.
.cursor/, node_modules/, .next/는 무시하세요. 기능 코드, 공유 components/, Storybook, src/theme.ts를 포함하세요.
2단계: 탐지 후 판단
탐지는 휴리스틱입니다. 분류는 추상화 테스트 후에 이루어집니다.
| 탐지기 | 처리 | 예시 |
|---|---|---|
style= / styled( / css / 새 .css | 후보 누수(candidate leak) | <Card style={{ flexBasis: "50%" }}> |
| 디자인 시스템 결정 사항을 인코딩하는 것으로 보이는 하드코딩된 시각적 값, 특히 색상, 간격, 타이포그래피, 반경, 그림자, 반복되는 차원 | 후보 토큰(candidate token) | color: "#002F50"; 누수로 처리하기 전에 px 조사 |
테마 키를 사용하는 sx={{ ... }} | 후보 레시피(candidate recipe) | sx={{ mt: 3, width: "100%" }} |
| 레거시 Box 시스템 props | 후보 레거시(candidate legacy) | <Box display="flex" alignItems="center"> |
| 사용되지 않은 기존 PL 컴포넌트 | 후보 기존 시스템 솔루션 | CardWithAction에 감싸지지 않은 테이블 |
| 공유 컴포넌트에 대한 기능별 편집 | 후보 범위 누수(candidate scope leak) | 하나의 이야기에 맞추기 위해 CardHeader에 패딩 |
| 하나의 기능을 위한 prop 또는 내보내기 | 후보 비-일반 API | 기능 이름이 지정된 footer prop, 사용되지 않은 차트 내보내기 |
하드코딩된 값을 분류하기 전에 조사하세요. 합법적인 로컬 사례에는 계산된 차원, 차트 기하학, 아이콘/캔버스 내부, 테두리, 가상화된 레이아웃, 본질적인 컴포넌트 제약 조건이 포함됩니다.
최후의 수단 예외 (이유를 문서화하고, 기본 요소를 발명하지 마세요):
- pattern-library props를 사용할 수 없는 타사 / 캔버스 / 차트 내부
- 기존 보고 기본 요소가 없고 진정으로 일회성인 인쇄/PDF 레이아웃
- pattern-library에서 내보내지지 않은 프로토타입 전용 파일
추상화 테스트를 로컬 구성으로 통과한 후보는 발견 사항이 아닙니다. 누락으로 오해될 가능성이 있는 경우에만 승격하지 않음 아래에 배치하세요. 그렇지 않으면 생략하세요.
3단계: 의도별로 클러스터링
동일한 CSS 또는 비슷해 보이는 마크업이 아닌 동일한 결정을 표현하는 적중을 그룹화하세요.
일반적인 의도: 색상/강조, 간격/정렬 레시피, 타이포그래피, 컴포넌트 크롬, 상호작용 상태, 기능 패턴(배너, 페이지 헤더, 카드 CTA, 상태), 일반 대 단일 기능 API, 프로토타입 범위, 의심스러운 디자인 요구 사항.
하나의 클러스터 → 하나의 권장 사항. 동일한 발견 사항의 여러 사소한 변형보다 하나의 강력한 권장 사항을 선호하세요.
4단계: 먼저 pattern-library 검색
새로운 것을 제안하기 전에 형제 pattern-library 저장소를 검색하세요. 경로를 인용하세요.
- 공개 내보내기 —
pattern-library/src/index.ts - 토큰 및 전역 기본값 —
pattern-library/src/theme.ts pattern-library/src/core/아래의 컴포넌트 props / 변형- 누수를 이미 피한 동일한 컴포넌트의 기존 app-pro-ui 사용 사례
UI를 DS로 흡수하는 선례 (이것들을 인용하고, 내부를 app-pro-ui로 복사하지 마세요):
- 의미 있는 prop:
TypographylineClamp—pattern-library/src/core/Typography/Typography.tsx - 의미 있는 prop:
ButtonaiGlow—pattern-library/src/core/Button/Button.tsx