# Cowork UI Kit — Naming Convention

> Consistent naming = AI generate code accurate. Random names = AI confused, dev confused.

Tài liệu này chốt naming convention cho **toàn bộ Cowork UI Kit** — áp dụng cho mọi project dùng kit này (KHI Wellness, An Nhien, BetterBuy, Xanh Marketing, A-Kryphan, HaoGood Group, và brand mới). Cross-link: 📄 [INTERACTION-RULES](file:///C:/Users/DANG/AI-Cowork/00-templates/ui-kit/INTERACTION-RULES.md) · 📄 [USAGE](file:///C:/Users/DANG/AI-Cowork/00-templates/ui-kit/USAGE.html) · 📄 [INDEX](file:///C:/Users/DANG/AI-Cowork/00-templates/ui-kit/INDEX.md).

**Triết lý:** Name = contract. Một khi đã chốt, AI và dev đều tự generate đúng mà không cần đoán. Naming sai = entropy tăng = mọi session AI sau phải re-discover.

---

## 1. Component naming (React TSX)

**Pattern:** `PascalCase` per file, single noun hoặc noun-noun.

| Layer | Examples |
|---|---|
| **Atom** | `Button.tsx`, `Avatar.tsx`, `Input.tsx`, `Badge.tsx`, `Spinner.tsx`, `Icon.tsx`, `Label.tsx`, `Divider.tsx` |
| **Molecule** | `Card.tsx`, `SearchBar.tsx`, `FormGroup.tsx`, `Tooltip.tsx`, `Dropdown.tsx`, `Tabs.tsx`, `Pagination.tsx`, `Breadcrumb.tsx` |
| **Organism** | `Navbar.tsx`, `DataTable.tsx`, `Hero.tsx`, `Footer.tsx`, `Sidebar.tsx`, `Modal.tsx`, `Toast.tsx`, `CommandPalette.tsx` |
| **Template** | `LandingTemplate.tsx`, `DashboardLayout.tsx`, `EditorialLayout.tsx`, `DeckTemplate.tsx` |
| **Page** | `HomePage.tsx`, `PricingPage.tsx`, `LoginPage.tsx`, `SettingsPage.tsx` |

### Rule

- KHÔNG suffix `Component` (vd `ButtonComponent.tsx` ❌)
- KHÔNG suffix `Container` / `Wrapper` (vd `ButtonWrapper.tsx` ❌)
- KHÔNG prefix `My*` / `Base*` / `App*` (vd `MyButton.tsx` ❌)
- Compound component: dùng dot notation (`Card.Header`, `Card.Body`, `Card.Footer`) — KHÔNG tách `CardHeader.tsx` riêng
- Anti-pattern: `button2-final.tsx`, `new-button.tsx`, `ButtonV2.tsx`, `ButtonFixed.tsx` → version sống trong git, KHÔNG trong filename

### Compound component pattern

```tsx
// Card.tsx
export const Card = Object.assign(CardRoot, {
  Header: CardHeader,
  Body: CardBody,
  Footer: CardFooter,
});

// Usage
<Card>
  <Card.Header>Title</Card.Header>
  <Card.Body>Content</Card.Body>
  <Card.Footer><Button>Action</Button></Card.Footer>
</Card>
```

---

## 2. CSS class naming

**Pattern:** kebab-case BEM-lite — `.<block>__<element>--<modifier>` hoặc atomic-style utility.

### 2a. Block-Element-Modifier (BEM-lite)

```css
.card { }                          /* block */
.card__header { }                  /* element */
.card__body { }                    /* element */
.card__footer { }                  /* element */
.card--featured { }                /* modifier */
.card--elevated { }                /* modifier */
.card--featured .card__header { }  /* modifier affects element */
```

### 2b. Utility / token classes (atomic-style)

```css
.touch              /* min touch target 44px */
.touch--comfy       /* size variant 48px */
.touch--tight       /* size variant 40px */
.sa-bottom          /* safe-area bottom utility */
.sa-top             /* safe-area top utility */
.aesthetic-warm     /* aesthetic mode switch */
.aesthetic-dark     /* aesthetic mode switch */
.mesh-warm          /* background utility */
.glow-primary       /* shadow utility tinted */
```

### Rule

- Block name = component name lowercased (`Card.tsx` → `.card`, `SearchBar.tsx` → `.search-bar`)
- Element với `__` separator (2 underscore)
- Modifier với `--` separator (2 dash)
- KHÔNG dùng camelCase trong CSS (`.cardHeader` ❌ → `.card__header` ✅)
- KHÔNG dùng PascalCase trong CSS (`.Card` ❌ → `.card` ✅)
- KHÔNG dùng dấu cách trong class names
- KHÔNG quá 3 cấp BEM (`.card__header__title__icon` ❌ → flatten lại)
- Utility classes ngắn, action-oriented (`.flex-center`, `.text-balance`)

---

## 3. Token naming

**Pattern:** `<category>-<role>[-<scale>]`

### 3a. Categories

| Prefix | Category | Example |
|---|---|---|
| `--brand-*` | Raw HSL per brand | `--brand-primary-h`, `--brand-primary-s`, `--brand-primary-l` |
| `--primary`, `--accent` | Computed brand color (semantic) | `--primary`, `--primary-soft`, `--accent` |
| `--bg`, `--surface`, `--text` | Aesthetic semantic | `--bg`, `--surface`, `--surface-2`, `--text`, `--text-muted` |
| `--space-*` | Spacing scale | `--space-1`, `--space-4`, `--space-8` |
| `--fs-*`, `--lh-*`, `--tracking-*` | Typography | `--fs-md`, `--lh-tight`, `--tracking-wide` |
| `--radius-*` | Border radius | `--radius-sm`, `--radius-md`, `--radius-full` |
| `--shadow-*`, `--elevation-*`, `--glow-*` | Shadow / elevation | `--shadow-sm`, `--elevation-2`, `--glow-primary` |
| `--z-*` | Z-index | `--z-dropdown`, `--z-modal`, `--z-toast` |
| `--duration-*`, `--ease-*`, `--trans-*` | Motion | `--duration-fast`, `--ease-out`, `--trans-base` |
| `--touch-*`, `--sa-*`, `--m-*`, `--vh-*`, `--phone-*` | Mobile | `--touch-target`, `--sa-bottom`, `--vh-screen`, `--phone-max` |
| `--success-*`, `--danger-*`, `--warning-*`, `--info-*` | Status semantic | `--success`, `--danger-bg`, `--warning-ring` |
| `--warm-*`, `--dark-*` | Raw aesthetic palette | `--warm-cream`, `--dark-near-black` |

### 3b. Scale suffix conventions

- **Size scale:** `xs / sm / md / lg / xl / 2xl / 3xl` (skip `4xl`+ unless cần thật)
- **Variant suffix:**
  - `-soft` — lighter / tinted version
  - `-deep` — darker / saturated version
  - `-hover` — hover state
  - `-active` — active/pressed state
  - `-on` — text color on tinted bg (vd `--primary-on` = text trên `--primary`)
  - `-bg` — tinted background variant
  - `-ring` — focus ring color
- **Semantic states:** `success`, `danger`, `warning`, `info` (KHÔNG `green`/`red`/`yellow`/`blue` raw)

### Rule

- KHÔNG dùng raw color names trong token (`--blue-500` ❌, `--primary` ✅)
- KHÔNG dùng số tuyệt đối khi có scale (`--space-22` ❌ → dùng `--space-6` hoặc add vào scale)
- KHÔNG abbreviation không phổ biến (`--clr-pri` ❌ → `--primary` ✅)
- Scale phải có gap nhỏ-lớn dễ remember (`xs < sm < md < lg < xl`, KHÔNG `xs/sm/regular/lg`)
- Token tham chiếu token khác → dùng `var()` chain (`--card-bg: var(--surface)`)

### 3c. Brand-specific

`--brand-<entity>-<property>` — vd `--brand-primary-h`, `--brand-accent-l`, `--brand-neutral-s`.

```css
/* brands/khi.brand.css */
:root {
  --brand-primary-h: 340;
  --brand-primary-s: 65%;
  --brand-primary-l: 55%;
  --brand-accent-h: 280;
  --brand-accent-s: 50%;
  --brand-accent-l: 60%;
}
```

---

## 4. File naming

### 4a. HTML pages (archetype)

`page-<X>-<name>.html` — X = A/B/C/D/E/F (archetype letter).

- `page-A-dashboard.html`
- `page-B-tool.html`
- `page-C-landing.html`
- `page-D-editorial.html`
- `page-E-deck.html`
- `page-F-pwa-app-flow.html`

### 4b. Blocks

`<descriptor>.html` trong folder archetype-grouped.

- `blocks/A-dashboard/kpi-grid.html`
- `blocks/A-dashboard/chart-area.html`
- `blocks/C-landing/hero-split.html`
- `blocks/C-landing/pricing-3col.html`
- `blocks/D-editorial/article-prose.html`

### 4c. Brand CSS

`<brand>.brand.css` — slug brand kebab-case.

- `annhien.brand.css`
- `khi.brand.css`
- `betterbuy.brand.css`
- `xanh.brand.css`
- `akryphan.brand.css`
- `haogood.brand.css`
- `_template.brand.css` (underscore prefix = template, không brand thật)

### 4d. Token CSS

`<role>.css` — singular role noun.

- `tokens/foundation.css` — primitive tokens (raw HSL, scales)
- `tokens/semantic.css` — semantic tokens (--primary, --bg, --text)
- `tokens/tokens-mobile.css` — mobile-specific tokens

### 4e. Doc Markdown

`<TOPIC>.md` UPPERCASE cho root docs ở level ui-kit.

- `INDEX.md`
- `NAMING.md` (file này)
- `USAGE.html`
- `INTERACTION-RULES.md`
- `MAPPING-SHADCN.md`
- `A11Y-RULES.md` (planned)
- `GOVERNANCE.md` (planned)

### 4f. Per-component docs

`<ComponentName>.md` matching TSX file.

- `react/src/atoms/Button.tsx` + `react/src/atoms/Button.md`
- `react/src/molecules/Card.tsx` + `react/src/molecules/Card.md`

### Rule

- KHÔNG dấu cách (dùng kebab-case hoặc PascalCase)
- KHÔNG dấu tiếng Việt
- Extension lowercase (`.html` không `.HTML`, `.tsx` không `.TSX`)
- KHÔNG suffix versioning trong filename — version sống trong git tag (`v0.4.0`) + `package.json`
- KHÔNG suffix `-final`, `-new`, `-old`, `-backup`, `-copy` — git đã handle
- Backup tạm thời (vd patch theme WordPress): `.bak-YYYYMMDD-HHMMSS` cho phép

---

## 5. Folder naming

**Pattern:** lowercase kebab-case OR `<layer>` singular noun.

```
ui-kit/
├── tokens/              # plural — collection of token files
├── atoms/               # plural — layer (Atomic Design)
├── molecules/           # plural — layer
├── organisms/           # plural — layer
├── templates/           # plural — layer
├── pages/               # plural — collection of demo pages
├── brands/              # plural — collection of brand presets
├── blocks/              # plural with sub-folders per archetype
│   ├── A-dashboard/
│   ├── B-tool/
│   ├── C-landing/
│   ├── D-editorial/
│   ├── E-deck/
│   └── F-pwa/
├── mobile/              # collection — special layer for mobile-specific
│   ├── patterns/
│   └── starters/
├── react/               # implementation — singular
│   └── src/
│       ├── atoms/
│       ├── molecules/
│       ├── organisms/
│       └── tokens/
├── icons/               # plural — collection
└── starter/             # singular — scaffolding kit
```

### Rule

- KHÔNG mix CamelCase / kebab-case trong cùng level (`Atoms/` + `molecules/` ❌)
- KHÔNG snake_case cho folder (`my_folder/` ❌ → `my-folder/`)
- Plural cho **collection** (`atoms/`, `tokens/`, `brands/`)
- Singular cho **concept hoặc implementation root** (`react/`, `starter/`)
- Underscore prefix `_` cho folder đặc biệt (`_previews/`, `_showcase-v03-deprecated/`) — báo hiệu "skip in normal scan"

---

## 6. Variant naming

**Pattern:** semantic intent, NOT visual description.

| ✅ Good | ❌ Bad | Why |
|---|---|---|
| `variant="primary"` | `variant="blue"` | Color thay đổi per brand, intent không |
| `variant="danger"` | `variant="red"` | Same reason — KHI danger có thể là magenta |
| `variant="ghost"` | `variant="transparent"` | Ghost = pattern (transparent bg + colored text + hover bg), transparent = chỉ property |
| `variant="outline"` | `variant="bordered"` | Outline = convention chuẩn shadcn/HeroUI |
| `size="md"` | `size="medium"` | Convention short (md/lg/xl phổ biến) |
| `size="2xl"` | `size="huge"` | Scale có boundaries rõ, "huge" không quantify được |
| `tone="soft"` | `tone="light"` | Soft = subtle tinted, light = chỉ về lightness |

### Standard variants per component type

- **Button**: `primary` / `secondary` / `ghost` / `outline` / `danger` / `link`
- **Badge**: `primary` / `success` / `warning` / `danger` / `info` / `neutral`
- **Card**: `default` / `elevated` / `outlined` / `interactive`
- **Input**: `default` / `error` / `success` (size: `sm` / `md` / `lg`)
- **Banner / Alert**: `info` / `success` / `warning` / `danger`
- **Avatar**: shape `circle` / `square` / `rounded` (size: `xs` / `sm` / `md` / `lg` / `xl`)
- **Tooltip**: side `top` / `right` / `bottom` / `left`

### Rule

- Variant prop tên chuẩn: `variant` (KHÔNG `type`, `kind`, `style`, `appearance`)
- Size prop tên chuẩn: `size` (KHÔNG `scale`, `dimension`)
- Boolean flag: positive name (`disabled`, `loading`, `selected`) — KHÔNG `notActive`
- Compound state: dùng `state` prop (`state="loading"`) nếu nhiều state mutex

---

## 7. Anti-patterns tổng

```
❌ button-blue-large.tsx               → ✅ Button.tsx với variant + size props
❌ FinalButton.tsx, ButtonNew.tsx      → ✅ versioning sống trong git, không filename
❌ --color-primary-500                 → ✅ --primary (semantic, brand-agnostic)
❌ .CardHeader { } (CSS PascalCase)    → ✅ .card__header { }
❌ space-22 hardcoded                  → ✅ add vào scale hoặc dùng --space-5/6
❌ font-family: Arial trực tiếp        → ✅ font-family: var(--font-sans)
❌ #FF5733 in component CSS            → ✅ var(--primary)
❌ <div class="text-red-500">          → ✅ <Badge variant="danger"> hoặc class semantic
❌ ButtonComponent / ButtonWrapper     → ✅ Button (KHÔNG suffix wrapper)
❌ my-button.tsx (kebab cho component) → ✅ Button.tsx (PascalCase cho TSX)
❌ folder Atoms/ + molecules/          → ✅ thống nhất lowercase: atoms/ + molecules/
❌ var(--clr-pri) abbreviation         → ✅ var(--primary)
❌ size="medium-large"                 → ✅ size="lg" (scale chuẩn)
```

---

## 8. AI generation rules

Khi AI generate code dùng Cowork UI Kit, BẮT BUỘC tuân thủ:

1. **Token-first** — ưu tiên `var(--*)` hoặc Tailwind class wrap token (vd `bg-[var(--primary)]`). KHÔNG hardcode hex / rgb / px arbitrary.
2. **Variant > custom** — dùng variant prop có sẵn (`<Button variant="danger">`), KHÔNG override style bằng className hex.
3. **Semantic > visual** — `<Badge variant="danger">` thay vì `<span class="text-red-500">`.
4. **Layer-correct** — atom chỉ dùng atom + token. Molecule dùng atom + token. Organism dùng atom + molecule + token. KHÔNG cross-layer ngược (atom dùng organism).
5. **No magic numbers** — padding/margin từ `--space-*` scale, radius từ `--radius-*` scale, duration từ `--duration-*` scale.
6. **Archetype-aware** — nếu generate page mới, BẮT BUỘC pick 1 trong 6 archetype (A-F) × 1 trong 2 aesthetic (warm/dark) và comment header. Xem 📄 [INTERACTION-RULES](file:///C:/Users/DANG/AI-Cowork/00-templates/ui-kit/INTERACTION-RULES.md).
7. **Brand-context-aware** — nếu CWD trong `khi-wellness/`, dùng `khi.brand.css`. Nếu `annhien/`, dùng `annhien.brand.css`. KHÔNG mix.
8. **Compound component over prop explosion** — `<Card.Header>` thay vì `<Card hasHeader headerTitle="...">`.

---

## 9. Naming validation (CI optional)

Script `scripts/validate-naming.js` (planned) có thể check tự động:

- Component files PascalCase (regex `^[A-Z][a-zA-Z]+\.tsx$`)
- CSS classes kebab-case + BEM-lite (no camelCase, no PascalCase)
- Tokens follow prefix convention (whitelist categories)
- No banned suffixes: `Wrapper`, `Component`, `Container`, `V2`, `V3`, `Final`, `New`, `Old`
- No raw color names trong tokens (`blue`, `red`, `green`, etc.)
- No hardcoded hex/rgb trong component CSS (chỉ allowed trong `tokens/foundation.css`)
- Brand files match `<slug>.brand.css` pattern
- Page archetype files match `page-[A-F]-<name>.html`

**Output format:**

```
✓ Button.tsx                       (PascalCase OK)
✗ button-new.tsx                   (lowercase + banned suffix "new")
✓ .card__header                    (BEM OK)
✗ .cardHeader                      (camelCase in CSS)
✓ --primary                        (semantic token)
✗ --color-blue-500                 (raw color name)
```

(Implementation TBD — track trong roadmap UI Kit v0.5)

---

## 10. Migration cho file/folder không follow

Khi phát hiện file/folder vi phạm naming:

1. **Atomic rename** — đổi tên file + update tất cả import trong 1 commit (đừng để half-renamed)
2. **Search-replace toàn workspace** — tránh broken reference
3. **Update doc liên quan** — INDEX.md, USAGE.html, brand demo HTML
4. **Git mv** thay vì delete + create để giữ history
5. **Deprecation period** — nếu file public-exported, giữ re-export alias 1 version trước khi xoá

```ts
// Deprecation alias pattern
// Old: ButtonComponent.tsx → New: Button.tsx
export { Button as ButtonComponent } from './Button';  // deprecated alias
export { Button } from './Button';  // canonical
```

---

## 11. Cross-link

- 📄 [INDEX](file:///C:/Users/DANG/AI-Cowork/00-templates/ui-kit/INDEX.md) — entry point UI Kit
- 📄 [USAGE](file:///C:/Users/DANG/AI-Cowork/00-templates/ui-kit/USAGE.html) — usage guidelines tổng
- 📄 [INTERACTION-RULES](file:///C:/Users/DANG/AI-Cowork/00-templates/ui-kit/INTERACTION-RULES.md) — interaction patterns + archetype rules
- 📄 [MAPPING-SHADCN](file:///C:/Users/DANG/AI-Cowork/00-templates/ui-kit/MAPPING-SHADCN.md) — map sang shadcn naming
- 📁 [tokens/](file:///C:/Users/DANG/AI-Cowork/00-templates/ui-kit/tokens/) — token files
- 📁 [brands/](file:///C:/Users/DANG/AI-Cowork/00-templates/ui-kit/brands/) — brand preset files

---

**Version:** v0.4 · **Last updated:** 2026-05-20 · **Owner:** Dang (AI-Cowork)
