범위
Next.js App Router, Tailwind CSS v4, shadcn/ui base-nova, Base UI와 pnpm
monorepo 기준의 기술 참조임
owner 결정표
| 질문 | owner |
|---|---|
| light·dark 실제 값이나 app font가 바뀌는가 | theme provider |
| utility로 공개할 semantic role이 바뀌는가 | token adapter |
| keyboard·focus·ARIA·범용 visual state가 바뀌는가 | shared primitive |
| 업무 문구·domain state·primitive 조합이 바뀌는가 | product composition |
| routing·grid·container·responsive placement가 바뀌는가 | page·feature |
| 제어할 수 없는 markup이나 vendor selector인가 | scoped integration CSS |
semantic role
| 범주 | 우선 role | 조건 |
|---|---|---|
| surface | background, card, popover, muted, accent | accent를 brand primary 동의어로 쓰지 않음 |
| action | primary, secondary, destructive | background에는 foreground pair를 제공함 |
| 상태 | success, warning, info | 제품 전반에 반복될 때 provider·adapter·test를 함께 추가함 |
| 제품 값 | terminal, repository, marketing | 앱 theme 또는 composition에서 소유함 |
component 선택 순서
- 설치된 primitive와 built-in variant 확인
- 기존 primitive composition으로 표현
- registry와 공식 docs에서 component 확인
- 반복되는 제품 composition 작성
- 제품 중립 동작이 실제로 빠진 경우에만 shared primitive 작성
class 작성 규칙
| 상황 | 사용할 방식 | 피할 방식 |
|---|---|---|
| runtime 상태 | 완성된 class map 또는 cva | bg-${tone}-600 |
| runtime 수치 | typed CSS variable과 정적 utility | runtime class 문자열 |
| sibling spacing | flex·grid gap-* | 반복 margin과 space-* 남용 |
| 같은 width·height | size-* | w-* h-* 반복 |
| ellipsis | truncate | 세 utility 직접 조합 |
| RTL 가능한 공용 UI | start, end, ms, me | 방향이 고정된 left, right, ml, mr |
| one-off layout formula | arbitrary value 허용 | 의미 없는 near-scale 숫자 drift |
| raw color | renderer allowlist에만 제한 | 일반 consumer의 hex·palette utility |
cva, cn, className
cva는variant,size,tone,density처럼 유한하고 반복되는 공개 API에 사용함cn은 조건부 class와 의도적인 Tailwind conflict merge에 사용함- consumer
className은 margin, width, grid·flex placement와 responsive layout에 한정함 - color, typography, border, shadow, 내부 padding과 interaction state는 variant 또는 별도 API로 승격함
shadcn 명령
pnpm exec shadcn info --json -c apps/web
pnpm exec shadcn docs <component> -c apps/web
pnpm exec shadcn search @shadcn -q "<need>" -c apps/web
pnpm exec shadcn add <component> --dry-run -c apps/web
pnpm exec shadcn add <component> --diff <file> -c apps/web--overwrite는 local 변경이 없는 generated-only 계층이거나 local 변경 폐기가 명시된 경우만 사용함- Base UI는
render, Radix는asChild를 사용하며 두 API를 혼용하지 않음 - component 추가 후 import, icon, accessible name, group 구조와 loading state를 확인함
Tailwind v4 source 계약
@import "@jongminchung/ui/globals.css";
@import "./theme.css";
@source "../**/*.{ts,tsx,mdx}";
@source not "../../.next/**/*";- class는 scanner가 읽을 수 있는 완성된 정적 문자열로 source에 둠
- linked workspace와 route 밖 component는 명시적
@source로 등록함 - generated selector 존재는 production CSS contract로 확인함
@reference는 별도 stylesheet가 Tailwind compile context를 실제로 요구할 때만 사용함
검증 행렬
| 변경 | 최소 검증 | 추가 검증 |
|---|---|---|
| utility·layout | format, typecheck, 관련 test | responsive screenshot |
| primitive style | UI typecheck·test, consumer build | light·dark screenshot |
| primitive behavior | UI test, browser interaction | 영향 앱 E2E |
| token·global CSS | theme contract, consumer build | contrast와 visual |
| source·package export | generated CSS contract, tarball | Next.js·Vite fixture |
| shadcn update | dry run, diff, UI test | 접근성·migration |
저장소 명령
pnpm run fmt:check
pnpm run lint
pnpm run typecheck
pnpm run test
pnpm --filter @jongminchung/web run build연결 문서
관련 글
방법 안내기존 Tailwind와 shadcn/ui 화면을 감사하는 방법기존 화면의 owner 누수, raw color, 동적 class와 shadcn update 위험을 찾아 안전하게 리팩터링합니다.튜토리얼유지보수 가능한 Tailwind와 shadcn/ui 기능 만들기기존 primitive와 semantic token을 사용해 상태 안내 panel을 만드는 학습 과정을 안내합니다.설명Tailwind와 shadcn/ui의 유지보수성은 소유권에서 시작함class 수보다 theme, primitive, composition과 page의 변경 권한을 분리해야 하는 이유를 설명합니다.