DESIGN_RULES.md

actibooky 프론트엔드 공통 작업 규칙입니다. 브랜드가 바뀌어도 변하지 않는 원칙만 담습니다. 새 프로젝트 루트에 그대로 두면 사람과 AI 에이전트가 같은 규칙을 따릅니다.

DESIGN_RULES.md 란 & 적용 방법

  • 무엇 · 원칙·컬러·타이포·깊이·컴포넌트·폼·접근성 등 브랜드 무관 공통 규칙. "감각"이 아니라 규칙으로 일관성을 맞춥니다.
  • 서비스 비주얼 토큰 · 정확한 팔레트·스페이싱 스케일·라디우스 값 등은 각 서비스의 DESIGN.md(getdesign 형식) + globals.css 가 정의합니다. 이 문서와 짝을 이룹니다.
  • 어디에 · 프로젝트 루트DESIGN_RULES.md 로 저장합니다. (아래 버튼으로 복사 또는 다운로드)
  • 어떻게 연결(import) · 에이전트 지침 파일에서 참조합니다:
Claude Code

CLAUDE.md 에 한 줄:

@DESIGN_RULES.md
Codex / Gemini

AGENTS.md / GEMINI.md 에서 참조 또는 본문 인용.

See ./DESIGN_RULES.md
Cursor / 기타

규칙 파일에서 DESIGN_RULES.md 를 읽도록 지정.

.cursor/rules → DESIGN_RULES.md
DESIGN_RULES.md

DESIGN_RULES.md

actibooky 프론트엔드 공통 작업 규칙. 스택: Next.js (App Router) + React 19 + Tailwind v4 + shadcn/ui(Base UI). 미감은 Vercel Geist식 절제를 따른다.

이 문서는 브랜드가 바뀌어도 변하지 않는 규칙(원칙) 만 담는다. 서비스별 비주얼 토큰(정확한 팔레트·스페이싱 스케일·라디우스 값 등)은 각 서비스의 DESIGN.md(getdesign 형식)와 globals.css 가 정의한다. 프로젝트 루트에 이 파일을 두고 사람과 AI 에이전트가 함께 따른다.


1. 원칙 (절제 / subtraction)

  1. 디자이너 없이도 일관성 - "감각"이 아니라 토큰·제약(규칙) 으로 강제한다.
  2. 절제 - 거의 흰 캔버스 위 거의 검정 잉크가 제목·본문·CTA·보더를 전부 끌고 간다. 그 외에는 거의 아무것도 경쟁하지 않는다.
  3. 색은 한 곳에만 - 유일한 라이브 액센트는 브랜드 액센트(--brand). 큰 면을 액센트로 채우지 않는다(링크·포커스·핵심 CTA에만).
  4. 깊이는 그림자가 아니라 1px hairline 우선 - 면 분리는 border 로, 그림자는 최후의 수단.
  5. 단일 코어 + 서비스 스킨 · 라이트/다크 · 접근성 기본값 AA.

2. 컬러 규칙

  • 모든 색은 OKLCH, raw hex/rgb 하드코딩 금지 - 반드시 토큰을 경유한다.
  • 잉크-그레이 사다리를 단계적으로: foreground(잉크) → muted-foreground(본문/보조) → 더 옅은 단계. 본문을 순수 검정(#000)으로 쓰지 않는다.
  • 표면: background(캔버스) 위 card(elevated), 경계는 border(hairline 1px).
  • 액센트는 하나: --brand = 링크 · 포커스링 · 핵심 CTA · chart-1. 큰 면 fill 금지.
  • globals.css = 코어(:root + .dark + @theme inline). 서비스 스킨은 [data-brand="<service>"] 에서 색 토큰 일부만 override. (실제 색 값은 서비스 DESIGN.md/globals.css 소관.)

3. 타이포그래피 규칙

  • 디스플레이일수록 트래킹을 타이트하게(tracking-tight), 본문은 중립.
  • 무게는 절제: 제목 700/600, 버튼·라벨 500, 본문 400. (light/black·italic 남용 금지.)
  • 금액·표·카운터 등 정렬/갱신 숫자는 tabular-nums.
  • 본문은 16px 이상, 한글 가독성 우선.
  • 폰트는 토큰으로: 기본 Pretendard, 서비스별 SUIT/SUITE(font-suit/font-suite). 기술 라벨/코드는 mono. (정확한 타입 스케일 값은 서비스 DESIGN.md 소관.)

4. 깊이 (elevation) 규칙

  • L0 평면: 1px hairline(border), 그림자 없음 - 기본 카드·인풋·구분선.
  • L1 위스퍼: border + 아주 옅은 마이크로 섀도(살짝 떠 보이는 카드).
  • L2 플로팅: 메뉴·모달·툴팁 등만 레이어드 소프트 섀도.
  • 무거운 드롭섀도·글로우 금지. 장식 시스템은 하나만(둘째 장식 추가 금지).

5. 컴포넌트

  • shadcn/ui 우선 - components/ui 의 컴포넌트를 최대한 활용한다.
  • components/ui 폴더의 기존 컴포넌트는 수정하지 않는다(업스트림/레지스트리 동기화). 변형이 필요하면 래퍼를 만든다.
  • Base UI 에는 asChild 가 없다 → 합성은 render prop: render={<Button ... />}, 필요 시 nativeButton={false}.
  • 새 UI 패턴은 컴포넌트로 추출한다(한 파일 = 한 책임). 페이지에서 raw <button> 등을 직접 만들지 말고 DS 컴포넌트를 쓴다.

6. 폼

  • 거의 모든 폼 = zod 스키마 + react-hook-form + shadcn Form 컴포넌트.
  • 검증은 제출(또는 다이얼로그 오픈) 전에 수행한다.

7. 상태 · 피드백

  • 서버 액션 결과 → 카드가 아니라 sonner toast.
  • 비동기 처리 → toast.promise 로 loading/success/error 를 일관되게.
  • 제출 버튼은 pending 상태(useTransition 등)로 중복 클릭을 막는다.

8. 확인 · 경고

  • native confirm() / alert() 금지 → shadcn/Base UI AlertDialog.
  • 필수값 검증 통과 후 controlled open 으로 열고, Action onClick 에서 실제 동작.

9. 아이콘 · 이미지 · 링크

  • 아이콘은 lucide-react.
  • 내부 이동은 next/link, 이미지는 next/image. (정적 에셋 다운로드는 일반 <a download>.)

10. 접근성

  • 대비 AA 이상. 색만으로 정보를 전달하지 않는다(텍스트·아이콘 병행).
  • 키보드 포커스를 가시화한다(focus-visible). 동적 글자크기·브라우저 줌 허용.

11. Base UI 주의점

  • GroupLabel 은 반드시 해당 Group 안에 둔다.
  • CommandDialog 는 cmdk <Command> 루트 래퍼가 필요하다.

12. Do / Don't

Do

  • 캔버스는 거의 흰색으로 두고 잉크가 제목·CTA·보더를 끌고 가게 한다.
  • 색은 브랜드 액센트와 일러스트에만. --brand 는 링크·포커스에 예약.
  • 카드·인풋은 1px hairline 먼저, 그림자는 최후.
  • 그레이 텍스트 사다리를 단계적으로 밟는다.
  • 디스플레이 제목은 타이트한 네거티브 트래킹.

Don't

  • 큰 면을 액센트 색으로 채우지 않는다.
  • 본문을 순수 검정(#000)으로 쓰지 않는다.
  • 그림자를 남발하지 않는다(hairline 우선).
  • 둘째 장식 시스템을 추가하지 않는다.
  • radius·버튼 모양을 한 맥락에서 혼용하지 않는다.