# Ticket 0.4 — Frontend Build Pipeline (Vite)

**Phase**: 0 — Project Scaffolding
**Priority**: Critical (blocking)
**Depends on**: 0.1, 0.2

## Description

Configure Vite as the frontend build tool for the browser-side TypeScript modules. Vite provides an ESM-native dev server with Hot Module Replacement (HMR) for rapid frontend development, plus an optimised production build using Rollup. This replaces any ad-hoc `tsc` build step for frontend assets.

The relay serves frontend assets from `src/lib/public/`. Vite compiles the TypeScript modules in `src/lib/public/modules/` and the entry point `src/lib/public/app.ts` into browser-ready JavaScript.

## Acceptance Criteria

### AC1: Vite config exists and is valid

```gherkin
Given vite.config.ts exists in the project root
When I inspect its contents
Then it sets the root to "src/lib/public"
And it configures the build output to "dist/public"
And it enables TypeScript support
And it configures the dev server proxy to forward API/WS requests to the relay server
And it sets the dev server port (e.g., 5173)
```

### AC2: Dev server with HMR

```gherkin
Given the Vite dev server is running via `pnpm dev:frontend`
When I modify a TypeScript file in src/lib/public/modules/
Then the browser updates without a full page reload (HMR)
And TypeScript errors are shown as an overlay in the browser
And the dev server proxies /ws and /api requests to the relay server
```

### AC3: Production build

```gherkin
Given I run `pnpm build:frontend`
Then Vite compiles all frontend TypeScript to optimised JavaScript
And the output is written to dist/public/
And the output includes:
  - Bundled and minified JS files
  - Source maps for debugging
  - The manifest.json and service worker (copied as-is)
  - CSS files (if any)
And the total bundle size is logged
```

### AC4: HTML entry point

```gherkin
Given src/lib/public/index.html exists
When Vite processes it
Then it resolves the <script type="module" src="./app.ts"> import
And it injects the compiled JS path in production builds
And the HTML template includes the PWA manifest link
```

### AC5: Asset handling

```gherkin
Given the public/icons/ directory contains PNG/SVG files
When Vite builds the project
Then static assets are copied to dist/public/ unchanged
And asset URLs use content hashes for cache-busting in production
And the service worker file is NOT processed by Vite (copied as-is)
```

## Testable Components

| Component | Test Type | What to Assert |
|-----------|-----------|----------------|
| `vite.config.ts` | Unit | Config resolves correctly, root and outDir set |
| Dev server | Fixture | Starts without errors, serves index.html |
| Production build | Fixture | `vite build` succeeds, output files exist in dist/public/ |
| TypeScript compilation | Fixture | Frontend .ts files compile without errors |
| Asset copying | Fixture | Icons and manifest.json present in dist/public/ |

## Files to Create

- `vite.config.ts` (project root)
- `src/lib/public/index.html` (entry point HTML template)

## Scripts (added to package.json)

- `"dev:frontend"`: `vite` — start Vite dev server with HMR
- `"build:frontend"`: `vite build` — production build to dist/public/
- `"preview:frontend"`: `vite preview` — preview production build locally

## Notes

- Vite uses **esbuild** for dev transforms (fast) and **Rollup** for production builds (optimised)
- The relay HTTP server serves the built assets from `dist/public/` in production
- During development, the Vite dev server runs separately and proxies API calls to the relay
- The service worker (`sw.ts`) may need special handling — Vite plugins like `vite-plugin-pwa` can help, or it can be compiled separately
- Frontend modules use ES module imports (`import { ... } from './modules/state.ts'`)
- Reference: claude-relay serves frontend files directly via Express static middleware
