> For the complete documentation index, see [llms.txt](https://gotts.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://gotts.gitbook.io/docs/monorepo-infrastructure/monorepo/07-frontend.md).

# Frontend

> **Part of**: [Monorepo Infrastructure PRD](/docs/monorepo-infrastructure/monorepo.md) | **Last Updated**: 2026-02-19

***

## Overview

The frontend stack powers `apps/web` (the debug UI) and the shared `packages/ui` component library. The stack is:

* **Next.js 15.5+** (App Router) — React framework
* **Tailwind CSS v4** — CSS-first utility framework
* **shadcn/ui** — Copy-paste component library built on Radix UI

> **Scope note**: The debug UI (`apps/web`) is developer-facing only. It is not a production product. It provides tools for inspecting vault state, agent activity, and MCP tool execution during development. See the [Vault PRD](/docs/gotts-vaults/vault.md) for UI specifications.

## Next.js 15.5+ / 16

### Key Features Used

| Feature           | Version | Purpose                                   |
| ----------------- | ------- | ----------------------------------------- |
| App Router        | 13+     | File-based routing with layouts           |
| Server Components | 13+     | Default rendering mode, reduces client JS |
| Server Actions    | 14+     | Type-safe server mutations                |
| Turbopack         | 15+     | Fast dev server (`next dev --turbopack`)  |
| `next.config.ts`  | 15+     | TypeScript configuration file             |

### `apps/web/next.config.ts` (normative)

```typescript
import type { NextConfig } from "next";

const config: NextConfig = {
  reactStrictMode: true,
  transpilePackages: ["@gotts.ai/ui"],
};

export default config;
```

> **`transpilePackages`** — Required for internal packages that export TypeScript source. Next.js transpiles `@gotts.ai/ui` as part of its own build.

### `apps/web/package.json` (normative)

```jsonc
{
  "name": "web",
  "version": "0.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start",
    "lint": "eslint .",
    "check-types": "tsc --noEmit",
  },
  "dependencies": {
    "@gotts.ai/ui": "workspace:*",
    "next": "^15.5.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
  },
  "devDependencies": {
    "@gotts.ai/eslint-config": "workspace:*",
    "@gotts.ai/typescript-config": "workspace:*",
    "@types/react": "^19.0.0",
    "@types/react-dom": "^19.0.0",
    "typescript": "^5.8.0",
  },
}
```

## Tailwind CSS v4

Tailwind v4 uses a **CSS-first configuration** model. There is no `tailwind.config.js` or `tailwind.config.ts`. All configuration is done via CSS `@theme` directives.

### `apps/web/tailwind.css` (normative)

This is the Tailwind entry point, imported in the root layout:

```css
@import "tailwindcss";
@import "@gotts.ai/ui/styles";

/*
 * Theme customization via CSS @theme directive.
 * Replaces the old tailwind.config.js theme.extend object.
 */
@theme {
  /* Brand colors */
  --color-brand-50: #fef2f8;
  --color-brand-100: #fce7f3;
  --color-brand-500: #ec4899;
  --color-brand-600: #db2777;
  --color-brand-700: #be185d;
  --color-brand-900: #831843;

  /* Semantic tokens */
  --color-background: var(--color-white);
  --color-foreground: var(--color-gray-950);
  --color-muted: var(--color-gray-100);
  --color-muted-foreground: var(--color-gray-500);
  --color-border: var(--color-gray-200);
  --color-ring: var(--color-brand-500);

  /* Typography */
  --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, monospace;

  /* Border radius */
  --radius-sm: 0.25rem;
  --radius-md: 0.375rem;
  --radius-lg: 0.5rem;
  --radius-xl: 0.75rem;
}

/*
 * Dark mode overrides using CSS cascade layers.
 * Tailwind v4 uses native @media or .dark class strategy.
 */
@media (prefers-color-scheme: dark) {
  @theme {
    --color-background: var(--color-gray-950);
    --color-foreground: var(--color-gray-50);
    --color-muted: var(--color-gray-900);
    --color-muted-foreground: var(--color-gray-400);
    --color-border: var(--color-gray-800);
  }
}
```

### PostCSS Configuration

Tailwind v4 includes its own PostCSS plugin. No separate `postcss.config.js` is needed — Next.js auto-detects Tailwind v4.

If explicit configuration is needed:

```javascript
// postcss.config.mjs
export default {
  plugins: {
    "@tailwindcss/postcss": {},
  },
};
```

### Key Changes from Tailwind v3

| Tailwind v3                           | Tailwind v4                                        | Notes                       |
| ------------------------------------- | -------------------------------------------------- | --------------------------- |
| `tailwind.config.js`                  | CSS `@theme` directives                            | No JS config file           |
| `@tailwind base/components/utilities` | `@import "tailwindcss"`                            | Single import               |
| `theme.extend` in JS                  | `@theme` in CSS                                    | CSS-native customization    |
| JIT mode (opt-in)                     | Always-on                                          | No configuration needed     |
| `darkMode: "class"`                   | `@media (prefers-color-scheme)` or `.dark` variant | CSS-native dark mode        |
| Content paths in config               | Auto-detection                                     | Scans project automatically |

## shadcn/ui

[shadcn/ui](https://ui.shadcn.com/) provides copy-paste React components built on Radix UI primitives. Components are copied into the project (not installed as a dependency), allowing full customization.

### Setup

```bash
cd apps/web
pnpm dlx shadcn@latest init
```

This creates a `components.json` configuration and a `src/components/ui/` directory.

### `components.json` (normative)

```jsonc
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "default",
  "rsc": true,
  "tsx": true,
  "tailwind": {
    "config": "",
    "css": "tailwind.css",
    "baseColor": "gray",
    "cssVariables": true,
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks",
  },
}
```

### Adding Components

```bash
# Add a specific component
pnpm dlx shadcn@latest add button

# Add multiple components
pnpm dlx shadcn@latest add card table dialog
```

Components are generated in `src/components/ui/` and can be freely modified.

## Shared UI Package

`packages/ui` contains shared React components used across apps. It follows the **internal packages pattern** — no build step.

### `packages/ui/package.json` (normative)

```jsonc
{
  "name": "@gotts.ai/ui",
  "version": "0.0.0",
  "private": true,
  "type": "module",
  "exports": {
    ".": {
      "types": "./src/index.ts",
      "default": "./src/index.ts",
    },
    "./*": {
      "types": "./src/*.tsx",
      "default": "./src/*.tsx",
    },
    "./styles": "./src/styles.css",
  },
  "dependencies": {
    "react": "^19.0.0",
  },
  "devDependencies": {
    "@gotts.ai/typescript-config": "workspace:*",
    "@types/react": "^19.0.0",
    "typescript": "^5.8.0",
  },
}
```

### Usage in Apps

```typescript
// apps/web/src/app/page.tsx
import { Button } from "@gotts.ai/ui/components/button";
import { Card } from "@gotts.ai/ui/components/card";
```

The CSS import in `tailwind.css` (`@import "@gotts.ai/ui/styles"`) ensures shared component styles are included.

### When to Put Components in `packages/ui` vs `apps/web`

| Signal                           | Location                  |
| -------------------------------- | ------------------------- |
| Used by multiple apps            | `packages/ui`             |
| App-specific layout or page      | `apps/web/src/components` |
| Generic primitive (Button, Card) | `packages/ui`             |
| Vault-specific visualization     | `apps/web/src/components` |
