# Xertica UI — Project Rules

This project uses **xertica-ui**, an enterprise React design system built on Tailwind CSS v4, Radix UI, and Lucide Icons.

## Command Reference

- **Dev Server**: `npm run dev`
- **Build Production**: `npm run build`
- **Linter**: `npm run lint` / `npm run lint:fix`
- **Type Checker**: `npm run type-check`
- **All Validation Checks**: `npm run check` (type-check + lint)
- **Code Formatter**: `npm run format`

---

## Architecture — Feature-Sliced Design (FSD) + Feature-Driven Architecture (FDA)

This project follows **FSD (Feature-Sliced Design)** layered architecture combined with **FDA (Feature-Driven Architecture)** vertical slicing. Layers can only import from layers below them.

- **`src/app/`**: Application shell (BrowserRouter, AppLayout, AuthGuard, AuthContext). No business logic.
- **`src/shared/`**: Shared layer with no business domain (config/navigation, lib/auth, types). Importable by any layer.
- **`src/features/`**: Self-contained vertical slices by business capability (auth, home, template, assistant). Import only from the barrel `src/features/<name>/index.ts` — never from internal feature paths.
- **`src/pages/`**: Thin route wrappers composing `AppLayout` + feature content. No logic or API calls here.

### Adding a New Route

1. **Create the feature content**: `src/features/<name>/ui/<NameContent>.tsx`
2. **Export from the barrel**: `src/features/<name>/index.ts`
3. **Create the page**: `src/pages/<NamePage>.tsx` (thin AppLayout wrapper)
4. **Register the route**: Add route path, label, and icon to the `routes` array in `src/shared/config/navigation.ts`.
5. **Register the `<Route>`**: Add the route element inside `<Routes>` in `src/app/components/AuthGuard.tsx`.

---

## Import Rules

Always use the correct `xertica-ui` subpath:

- **UI Primitives**: `xertica-ui/ui` (e.g. `Button`, `Card`, `Input`, `Badge`, `Table`, `Dialog`, `Select`)
- **Providers & Brand**: `xertica-ui/brand` (e.g. `XerticaProvider`, `XerticaLogo`, `ThemeToggle`, `LanguageSelector`)
- **Navigation Shell**: `xertica-ui/layout` (e.g. `Sidebar`, `Header`)
- **AI Assistant**: `xertica-ui/assistant` (e.g. `XerticaAssistant`, `generateDemoResponse`)
- **Media Players**: `xertica-ui/media` (e.g. `VideoPlayer`, `AudioPlayer`)
- **Hooks & Contexts**: `xertica-ui/hooks` (e.g. `useLayout`, `useOptionalLayout`, `useTheme`, `useLanguage`)
- **Styles**: Import `xertica-ui/style.css` once in `src/styles/index.css` (never directly inside components).

Icons always come from `lucide-react` — never from `xertica-ui`.

---

## Non-Negotiable Coding Rules

### HTML & Radix Elements

Never use native HTML interactive elements where design system components exist:

- `<Button>` instead of `<button>`
- `<Input>` instead of `<input>`
- `<Select>` instead of `<select>`
- `<PageHeader>` + `<PageHeaderHeading>` instead of `<h1>`/`<h2>` for page titles
- `<Card>` instead of `<div className="card">`
- `<ScrollArea>` instead of custom scrollbars

### Color & Border Radius Styling

- **Never use raw color values** (`#hex`, `rgb()`, `hsl()`) or inline styles for theming.
- **Never use standard Tailwind color classes for semantic/status contexts** (e.g., do not use `bg-red-500` or `text-green-500` for status/feedback/errors). Use semantic tokens: `bg-destructive`/`text-destructive` for errors, `bg-success` for success, `bg-warning` for warnings, `bg-info` for info.
- **Tailwind colors** (`bg-blue-500`, `text-gray-700`) are allowed **only** for layout, spacing, and general non-semantic UI where no semantic token applies.
- **Borders**: Always use `rounded-[var(--radius)]` — never use fixed radius classes like `rounded-lg` or `rounded-xl`.

### Layout State

Never hardcode sidebar or layout widths (e.g. `256px`). Read them dynamically:

- `const { sidebarExpanded, sidebarWidth } = useLayout()`
- For components that might render outside the layout provider:
  `const layout = useOptionalLayout(); const fallbackSidebarWidth = layout?.sidebarWidth ?? 80;`

### Confirm Destructive Actions

Always wrap destructive actions in `<AlertDialog>` for confirmation:

```tsx
<AlertDialog>
  <AlertDialogTrigger asChild>
    <Button variant="destructive">Delete</Button>
  </AlertDialogTrigger>
  <AlertDialogContent>
    <AlertDialogHeader>
      <AlertDialogTitle>Are you sure?</AlertDialogTitle>
      <AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
    </AlertDialogHeader>
    <AlertDialogFooter>
      <AlertDialogCancel>Cancel</AlertDialogCancel>
      <AlertDialogAction onClick={handleDelete}>Delete</AlertDialogAction>
    </AlertDialogFooter>
  </AlertDialogContent>
</AlertDialog>
```

### Toast Notifications

Always use `toast` from `sonner` and translate messages via `t()`:

```tsx
toast.success(t('common.saveSuccess'));
toast.error(t('errors.somethingWentWrong'));
```

Never render `<Toaster>` manually — it is auto-injected by `<XerticaProvider>`.

---

## Internationalization (i18n)

Every user-facing string must go through `useTranslation()`:

- Translate all labels, placeholders, titles, aria-labels, tooltips, toasts, etc.
- Add translation keys to split JSON files in `src/locales/<lang>/` for all languages.
- **Monolingual Mode**: `<LanguageSelector>` auto-hides when a single language is configured. Use `<LanguageSelector showWhenMonolingual />` to override.
- **Dynamic mock data / outside React cycle**: Always use **factory functions** returning `i18n.t(...)` rather than static arrays, so translations update dynamically:
  ```tsx
  export function getMockOptions() {
    return [i18n.t('feedback.notWhatIWanted')];
  }
  ```
- Inside components, wrap enum label maps in `useMemo([..., t])`.

---

## Server State (React Query)

- Place typed fetch functions in `data/mock.ts` and React Query wrappers in `hooks/use<Xxx>.ts`.
- **Language-aware queryKey is MANDATORY**: Every hook returning translated data must include `language` in its `queryKey` so switching languages invalidates the cache and triggers a refetch:
  ```tsx
  const { language } = useLanguage();
  return useQuery({
    queryKey: ['home', 'feature-cards', language],
    queryFn: fetchFeatureCards,
    staleTime: 10 * 60 * 1000,
  });
  ```

---

## Loading States (Skeletons)

Always render matching skeletons instead of spinners for data loading:

- Wrap cards/lists with their matching FSD skeleton companions (`ActivityCardSkeleton`, `ProfileCardSkeleton`, `ProjectCardSkeleton`, `NotificationCardSkeleton`, `QuickActionCardSkeleton`, `FeatureCardSkeleton`, `StatsCardSkeleton`).
- Pass `rows` to skeletons (e.g. `<ActivityCardSkeleton rows={5} />`) to match the loaded state height.
- For tables, build loading rows using `<TableRow>` + `<TableCell>` + `<Skeleton className="h-3.5 w-28" />`.

---

## Theme & Token Customization

- Customize colors, fonts, and dark mode classes by editing `src/styles/xertica/tokens.css`.
- Update theme or languages using the CLI: `npx xertica-ui update`.

---

## Authentication Pattern

The auth flow is managed in `src/app/context/AuthContext.tsx` via the `useAuth()` hook:

- `getStoredUser()` / `storeUser()` / `clearStoredUser()` — from `src/shared/lib/auth.ts`
- Auth pages (`/login`, `/forgot-password`, etc.) redirect to `/home` when user is already logged in
- Protected routes use `<ProtectedRoute>` wrapper that redirects to `/login` if user is null
- `useAuth().login(email, password)` stores the user
- `useAuth().logout()` clears storage and navigates to `/login`

---

## Before Writing Any Component

1. Check `node_modules/xertica-ui/llms-compact.txt` — the component may already exist.
2. Check `node_modules/xertica-ui/docs/decision-tree.md` — you may be choosing the wrong component.
3. Read the specific component doc at `node_modules/xertica-ui/docs/components/[name].md`.
4. Never create custom primitives that duplicate library components.
