Files
2026-07-12 10:17:17 -04:00

3.0 KiB

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

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:

// 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).