# Xertica UI — Architecture

## Audit Date

2026-05-20 (Post-Modularization + State Layer)

---

## Summary of Changes

The library underwent a **complete architectural modularization**. The flat `components/` directory was reorganized into a domain-driven structure, and a dedicated **state layer** was introduced via `features/`, `AuthContext`, TanStack React Query, and Zustand.

### Component Domains

| Domain      | Path                    | Contains                                                                                                     |
| ----------- | ----------------------- | ------------------------------------------------------------------------------------------------------------ |
| `ui`        | `components/ui/[name]/` | Design system primitives (Button, Card, Calendar, Chart, etc.)                                               |
| `layout`    | `components/layout/`    | Sidebar, Header, SidebarPrimitive                                                                            |
| `blocks`    | `components/blocks/`    | High-level composed components built from `ui/` primitives                                                   |
| `assistant` | `components/assistant/` | XerticaAssistant, MarkdownMessage, CodeBlock, etc.                                                           |
| `brand`     | `components/brand/`     | XerticaLogo, ThemeToggle, LanguageSelector, XerticaProvider                                                  |
| `pages`     | `components/pages/`     | LoginPage, HomePage, TemplatePage, etc.                                                                      |
| `shared`    | `components/shared/`    | utils.ts, use-mobile.ts, layout-constants.ts, navigation.ts, **error-boundary.tsx**, **error-fallbacks.tsx** |

### State Layer — `features/`

Feature slices separate server state, client UI state, and mock data from the component tree.

**Library source** (in this repo, used by Storybook and the showcase pages):

```
features/
├── home/
│   ├── data/mock.ts               ← typed mock data + async fetch functions (swap point for real API)
│   ├── hooks/
│   │   ├── useDashboardStats.ts   ← React Query (staleTime 5 min) — library-only
│   │   ├── useTeamMembers.ts      ← React Query (staleTime 2 min) — library-only
│   │   └── useFeatureCards.ts     ← React Query (staleTime 10 min)
│   ├── store/dashboardStore.ts    ← Zustand (progress, slider, activeTab — UI-only)
│   └── index.ts                   ← barrel
└── assistant/
    ├── data/mock.ts               ← AssistantConfig + fetchAssistantConfig (swap point)
    ├── hooks/useAssistantConfig.ts ← React Query (staleTime 30 min)
    └── index.ts                   ← barrel
```

**Scaffold template** (what `npx xertica-ui init` generates in a consumer project):

```
src/features/
├── home/
│   ├── data/mock.ts
│   ├── hooks/useFeatureCards.ts   ← only useFeatureCards is scaffolded
│   ├── store/dashboardStore.ts
│   ├── ui/HomeContent.tsx
│   └── index.ts
└── assistant/
    ├── data/mock.ts               ← exports getMockRichSuggestions() / getMockFeedbackOptions() factories
    ├── hooks/useAssistantConfig.ts
    └── index.ts
```

> `useDashboardStats` and `useTeamMembers` exist only in the library source where they power `TemplateContent.tsx`'s design-system showcase. They are NOT generated in the scaffold template. Consumer projects that need them must scaffold their own following the same pattern.

All four hooks include the active **language** in their `queryKey` (`['home', 'feature-cards', language]`) so switching language triggers an automatic refetch in the new locale — see [`docs/i18n.md`](./i18n.md#language-aware-react-query-keys).

**Swap pattern**: to connect a feature to a real API, replace only the `async function fetch*()` in `data/mock.ts`. The hook, the component, and the type contract remain unchanged.

```ts
// data/mock.ts — before (mock)
export async function fetchTeamMembers(): Promise<TeamMember[]> {
  await new Promise(resolve => setTimeout(resolve, 250));
  return MOCK_TEAM_MEMBERS;
}

// data/mock.ts — after (real API)
export async function fetchTeamMembers(): Promise<TeamMember[]> {
  return fetch('/api/team/members').then(r => r.json());
}
```

### i18n Layer

Internationalization uses `i18next` + `react-i18next`. The setup is bootstrapped in `i18n.ts` (imported in `main.tsx`) and wired to `LanguageContext`:

```
i18n.ts                          ← configures i18next via import.meta.glob (auto-discovers new JSON files)
locales/
├── pt-BR/
│   ├── common.json              ← shared action labels
│   ├── nav.json                 ← navigation labels
│   ├── errors.json              ← error boundary UI
│   ├── languageSelector.json    ← language picker UI
│   ├── themeToggle.json         ← theme toggle UI
│   ├── pages/
│   │   └── home.json, templates.json, login.json, resetPassword.json, verifyEmail.json,
│   │       loginTemplate.json, formTemplate.json, dashboardTemplate.json, crudTemplate.json
│   └── components/
│       └── assistant.json, sidebar.json, media.json, projectCard.json, profileCard.json,
│           notificationCard.json, activityCard.json, stats.json, team.json
├── en/    ← same structure
└── es/    ← same structure
contexts/LanguageContext.tsx      ← setLanguage() calls i18n.changeLanguage() + persists to localStorage
components/brand/language-selector/LanguageSelector.tsx  ← uses useLanguage() + useTranslation()
```

All page components use `useTranslation()` for UI strings. Mock data functions use `i18n.t()` (the instance) at query time so they respond to the active language.

### ErrorBoundary Layer

Three pre-configured wrappers for granular error isolation:

```
components/shared/
├── error-boundary.tsx    ← ErrorBoundary class + AppErrorBoundary, PageErrorBoundary, SectionErrorBoundary
└── error-fallbacks.tsx   ← AppErrorFallback, PageErrorFallback, SectionErrorFallback
```

Placement in `App.tsx`:

```
AppErrorBoundary (outermost — before QueryClientProvider)
  └─ QueryClientProvider
      └─ ...providers...
          └─ Router
              └─ AuthProvider
                  └─ PageErrorBoundary (wraps Routes/AuthGuard)
                      └─ Suspense + Routes
                          └─ Pages
                              └─ SectionErrorBoundary (wraps data sections)
```

### AuthContext

Authentication state lives in `contexts/AuthContext.tsx` and is consumed via `useAuth()`:

```
contexts/
└── AuthContext.tsx    ← AuthProvider + useAuth() hook
```

`AuthProvider` must be rendered **inside** `<BrowserRouter>` (it uses `useNavigate`). It:

- Hydrates session from `localStorage` on mount (`isLoading` flag prevents flash redirects)
- Exposes `user`, `login(email, password) → boolean`, `logout()`
- Redirects authenticated users away from auth-only pages automatically

Page components (`HomePage`, `TemplatePage`) consume `useAuth()` directly — no `user`/`onLogout` prop drilling.

### Lazy Loading

All routes in `App.tsx` use `React.lazy()` + `<Suspense>`. Each page is a separate chunk loaded only when the route is first visited:

```tsx
const HomePage = React.lazy(() =>
  import('./components/pages/home-page').then(m => ({ default: m.HomePage }))
);
```

### Provider Stack

```tsx
<QueryClientProvider client={queryClient}>
  {' '}
  // ← TanStack React Query
  <ApiKeyProvider>
    <GoogleMapsLoaderProvider>
      <LanguageProvider>
        <BrandColorsProvider>
          <ThemeProvider>
            <AssistenteProvider>
              <LayoutProvider>
                <Router>
                  <AuthProvider>
                    {' '}
                    // ← must be inside Router
                    <Suspense fallback={null}>
                      <AppRoutes />
                    </Suspense>
                  </AuthProvider>
                </Router>
              </LayoutProvider>
            </AssistenteProvider>
          </ThemeProvider>
        </BrandColorsProvider>
      </LanguageProvider>
    </GoogleMapsLoaderProvider>
  </ApiKeyProvider>
</QueryClientProvider>
```

### blocks/ domain

The `blocks/` domain contains **pre-composed patterns** built exclusively from `ui/` primitives. Unlike primitives, blocks encapsulate specific use-case logic and are ready to drop into dashboards and feature pages without additional composition.

```
components/blocks/
└── card-patterns/
    ├── ActivityCard.tsx      — activity feed with avatars and type badges
    ├── ProfileCard.tsx       — user/member card with stats and actions
    ├── ProjectCard.tsx       — project status with progress bar and member avatars
    ├── QuickActionCard.tsx   — icon + title + description + action button
    ├── NotificationCard.tsx  — notification list with unread indicators
    ├── FeatureCard.tsx       — colored icon + title + badge + description + CTA
    └── index.ts
```

All block components are exported from both `components/blocks/index.ts` and the root `components/index.ts` barrel.

**Consumers can import from the root `xertica-ui` entrypoint (all components) or from granular subpath entries (v2, recommended for FSD/FDA projects).**

---

## Subpath Exports (v2)

The build system produces 7 distinct entry bundles from a multi-entry Vite `lib.entry` configuration. Each bundle maps to a `package.json` `exports` subpath:

| Subpath                | Source entry                    | Contents                                                                   |
| ---------------------- | ------------------------------- | -------------------------------------------------------------------------- |
| `xertica-ui`           | `components/index.ts`           | Full barrel — all components                                               |
| `xertica-ui/ui`        | `components/ui/index.ts`        | All UI primitives                                                          |
| `xertica-ui/blocks`    | `components/blocks/index.ts`    | High-level composed patterns (ActivityCard, ProjectCard, etc.)             |
| `xertica-ui/layout`    | `components/layout/index.ts`    | Sidebar, Header                                                            |
| `xertica-ui/brand`     | `components/brand/index.ts`     | XerticaProvider, XerticaLogo, ThemeToggle, LanguageSelector, etc.          |
| `xertica-ui/assistant` | `components/assistant/index.ts` | XerticaAssistant, MarkdownMessage, CodeBlock, etc.                         |
| `xertica-ui/media`     | `components/media/index.ts`     | VideoPlayer, AudioPlayer, FloatingMediaWrapper                             |
| `xertica-ui/hooks`     | `components/hooks/index.ts`     | useLayout, useTheme, useLanguage, useBrandColors, useAssistente, useApiKey |

Each subpath exposes three fields in `exports`: `types` (`.d.ts`), `import` (ES module), `require` (UMD).

> TypeScript consumers need `"moduleResolution": "bundler"` (or `"node16"` / `"nodenext"`) to resolve subpath exports.

---

## Headless UI Pattern (v3)

The library follows a **three-tier composability model** for its complex components. Each tier is a superset of the previous — consumers can choose the level of control they need.

### Tier 1 — Monolithic API (drop-in)

The default export. Zero configuration, full functionality. Ideal for rapid integration.

```tsx
import { Sidebar } from 'xertica-ui/layout';
import { XerticaAssistant } from 'xertica-ui/assistant';
import { RichTextEditor } from 'xertica-ui/ui';

<Sidebar navigationGroups={groups} />
<XerticaAssistant demoMode={true} />
<RichTextEditor value={html} onChange={setHtml} />
```

### Tier 2 — Compound Components (structural control)

Sub-components exposed as static properties on the main component. Consumers control layout and composition while the shared React Context handles state propagation.

```tsx
import { Sidebar } from 'xertica-ui/layout';

<Sidebar.Root navigationGroups={groups}>
  <Sidebar.Header logo={<MyLogo />} />
  <Sidebar.Nav />
  <Sidebar.Search search={searchConfig} />
  <Sidebar.Footer showUser showSettings />
</Sidebar.Root>;
```

Available compound components:

| Component | Sub-components                                                                      |
| --------- | ----------------------------------------------------------------------------------- |
| `Sidebar` | `Sidebar.Root`, `Sidebar.Header`, `Sidebar.Nav`, `Sidebar.Search`, `Sidebar.Footer` |

### Tier 3 — Headless Hooks (full control)

Pure logic hooks with zero UI. Consumers bring their own markup, styling, and layout. The hook manages all state, refs, effects, and handlers.

```tsx
import { useSidebar } from 'xertica-ui/layout';
import { useAssistant } from 'xertica-ui/assistant';
import { useRichTextEditor } from 'xertica-ui/ui';

// Full custom sidebar
const { expanded, toggleExpanded, navigationGroups } = useSidebar({ defaultExpanded: true });

// Full custom assistant
const { mensagens, mensagem, setMensagem, handleEnviarMensagem } = useAssistant({ demoMode: true });

// Full custom editor
const { editorRef, activeFormats, execCommand, handleInput } = useRichTextEditor({
  value,
  onChange,
});
```

### Available Headless Hooks

| Hook                | Import                 | Description                                             |
| ------------------- | ---------------------- | ------------------------------------------------------- |
| `useSidebar`        | `xertica-ui/layout`    | Sidebar expansion, overflow detection, navigation state |
| `useAssistant`      | `xertica-ui/assistant` | Full assistant state: messages, conversations, handlers |
| `useRichTextEditor` | `xertica-ui/ui`        | Editor formatting state, search, link management        |

### Design Principles

1. **Hooks own all state** — No state lives in the presentational component; it is always delegated to the hook.
2. **Backward compatible** — The Tier 1 monolithic API is unchanged. Existing consumers are unaffected.
3. **Single source of truth** — The hook is the canonical implementation. The default component is a thin wrapper around it.
4. **`useCallback` everywhere** — All handlers in hooks are memoized to prevent unnecessary re-renders in custom UIs.
5. **TypeScript-first** — Every hook exports a `Props` interface and a `Return` interface for full type safety.

---
