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 (
pocketbasenpm 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:
- Serves static files from
dist/ - Falls back to
index.htmlfor client-side routes - Proxies
/pb/*→http://127.0.0.1:8091/api/* - Adds CORS headers
Test login: create a user via PocketBase API at 127.0.0.1:8091 (see references/pocketbase-test-users.md).