# SPQ v2 — React/Vite SPA Build

The v2 frontend is a React + TypeScript + Vite SPA at `spq-v2/` under the ShopProQuote directory.

## Location

Primary: `/mnt/seagate8tb/Websites/ShopProQuote.backup-20260626-2058/spq-v2/`
(This is the live deployed source. The backup path IS the primary for v2.)

## Stack

- React 19 + TypeScript
- Vite (build tool, NOT `tsc` — see build section below)
- PocketBase JS SDK (`pocketbase` npm package)
- jsPDF 4.2.1 for PDF generation
- Tailwind CSS (PostCSS, compiled at build time — classes are NOT generated dynamically)
- React Router v7 for client-side routing
- Zustand for state management (quote form, persist middleware `spq-quote`)
- Lucide React for icons

## Build

```bash
cd /mnt/seagate8tb/Websites/ShopProQuote.backup-20260626-2058/spq-v2
npx vite build
```

**DO NOT use `npm run build`** — it runs `tsc -b && vite build`. The `tsc -b` step fails with 30+ pre-existing type errors across Appointments, Customers, FinancialDashboard, Invoices, RepairOrders, Settings (unused imports, type mismatches from rapid prototyping). These are NOT bugs introduced by new work — they've been present since initial scaffolding. `vite build` alone handles TypeScript via esbuild and produces valid JS.

**Hermes terminal note:** `vite build` is detected as a server process by Hermes. Use `background=true` with `notify_on_complete=true`, then `process wait` to retrieve the result.

Build outputs to `dist/`, served live by nginx. The QuoteGenerator page lazy-loads as an async chunk (`QuoteGenerator-<hash>.js`). jsPDF is bundled inline (~300KB).

## Key differences from v1 (vanilla JS)

| | v1 | v2 |
|---|---|---|
| Framework | Vanilla JS (ES modules) | React + TypeScript |
| Tailwind | CDN (dynamic classes) | PostCSS build (compiled) |
| Routing | Multi-page HTML files | React Router SPA |
| Auth | `pb.authStore.isValid` check | Same, via React context |
| PB URL | `/pb` (relative, same as below) | `/pb` (`VITE_PB_URL` env, defaults to `/pb`) |

## PB URL Configuration

The PocketBase URL is set at build time via the `VITE_PB_URL` environment variable:

```ts
// src/lib/pocketbase.ts
const PB_URL = import.meta.env.VITE_PB_URL || '/pb';
export const pb = new PocketBase(PB_URL);
```

When serving the built `dist/`, the frontend requests `/pb/*` from the same origin. The Python proxy server in `references/local-testing.md` handles forwarding these to PocketBase on 8091.

## Routes

| Path | Component | Auth |
|---|---|---|
| `/login` | Login | Public |
| `/` | Dashboard | Protected |
| `/quote` | QuoteGenerator | Protected |
| `/settings` | Settings | Protected |
| `*` | Redirect → `/` | — |

## Serving locally

See `references/local-testing.md` for the Python reverse-proxy script that:
1. Serves static files from `dist/`
2. Falls back to `index.html` for client-side routes
3. Proxies `/pb/*` → `http://127.0.0.1:8091/api/*`
4. Adds CORS headers

Test login: create a user via PocketBase API at `127.0.0.1:8091` (see `references/pocketbase-test-users.md`).
