Developer DocsGetting Started

Getting Started

SignQuote is a Vite + React 18 + TypeScript + Tailwind single-page app. There is no backend, no environment variables, and no network calls at runtime — pricing runs in the browser and all state lives in localStorage. That makes it trivial to run: clone, install, npm run dev.

Prerequisites

  • Node 18 or newer. The repo was developed and tested on Node 25; any current LTS works.
  • npm (ships with Node). No other global tooling is required.

No .env file, API keys, or services to provision. If npm install succeeds, the app will run.

Run it

Install dependencies

npm install

Start the dev server

npm run dev

This runs vite and prints a local URL (typically http://localhost:5173). The page hot-reloads on save.

Run the tests

npm test

This runs vitest run. The suite is the pricing-engine acceptance fixtures in src/pricing/engine.test.ts, which pin the worked examples and acceptance criteria (AC-1…AC-8) against the seeded constants. See Acceptance & Testing.

Build for production

npm run build

The build script is tsc --noEmit && vite build — it type-checks the whole project first, then produces the optimized bundle. Preview that build locally with:

npm run preview

The four scripts come straight from package.json:

ScriptCommandWhat it does
npm run devviteDev server with hot reload
npm run buildtsc --noEmit && vite buildType-check, then production bundle
npm run previewvite previewServe the built bundle locally
npm testvitest runRun the pricing-engine fixtures once

Vitest is configured in vite.config.ts with environment: 'node' and include: ['src/**/*.test.ts'], so npm test only picks up the engine test file.

First-run behavior

The app is never empty. On first load, loadState in src/storage.ts finds no saved state under the localStorage key signquote.v1 and calls seedState, which writes the two example quotes from buildSeedState in src/data/defaults.ts:

#CustomerFamilyConfig
1001Maria Torres / Cafe LunaChannel lettersSEED_CAFE_CONFIG"CAFE", 4 letters, 18”, front-lit
1002David Chen / Chen & Associates LLPDimensional lettersSEED_LAW_OFFICE_CONFIG"LAW OFFICE", 8 letters, 12”, cast aluminum

These two seeds are the same configs the test suite pins as AC-1 and AC-2 — the prices you see in the app match the prices the tests assert.

State persists across reloads because AppProvider (src/context/AppContext.tsx) saves to localStorage on every change. Anything you create or edit survives a refresh. Clearing the browser’s site data wipes everything and the seeds are rebuilt on the next load — acceptable for a demo.

To restore the original seeds at any time, use Reset demo data on the Settings screen (src/screens/settings/DemoDataCard.tsx). It calls resetDemoData, which reseeds state and returns you to the quotes list — restoring the two seeded quotes (#1001 and #1002) and resetting all Table B settings (constants, LED products, price grid, shop info) to their defaults.

⚠️

Reset is destructive: quotes you created are deleted along with any constant edits. The Settings card asks for a window.confirm before proceeding.

Project layout

The app source lives under src/. The two files to read first are the pricing engine and the seeded defaults — they define the whole behavior; the rest is UI around them.

      • engine.ts
      • engine.test.ts
      • defaults.ts
      • constantMeta.ts
    • types.ts
    • storage.ts
PathWhat it is
src/pricing/engine.tsThe pure pricing engine: computePricing(config, settings). No I/O, no React — see Pricing Engine.
src/pricing/engine.test.tsVitest fixtures pinning the acceptance criteria against the seeded constants.
src/data/defaults.tsTable B cost constants (DEFAULT_SETTINGS), the LED products and dimensional price grid, new-quote defaults, and the two seed quotes.
src/data/constantMeta.tsDisplay metadata (CONSTANT_GROUPS) that drives how constants are grouped and labeled on the Settings screen.
src/types.tsAll shared types — SignConfig, Constants, Settings, Quote, PricingResult, and friends.
src/storage.tslocalStorage load/save/seed under the signquote.v1 key.
src/context/AppContext.tsxApp-wide state and the action API (createQuote, updateQuoteConfig, resetDemoData, …) plus the current view.
src/screens/QuotesList.tsxThe quotes list — the salesperson’s home screen.
src/screens/QuoteEditor.tsx + editor/The guided quote form: category cards, field controls, and the live price panel.
src/screens/SettingsScreen.tsx + settings/The owner’s Table B editor: constant groups, LED products, the price grid, shop info, a pricing preview, and demo-data reset.
src/pdf/The branded PDF: QuotePDF (the document), PdfPreviewModal (in-app preview), and downloadQuotePdf (the download action), built with @react-pdf/renderer.
src/ui/Small UI helpers: format.ts (currency/number formatting) and labels.ts (human-readable labels for config enums).

The docs site

These docs are a separate Nextra v3 site living in docs/ within the same repo. They are bilingual (English + Russian) — use the language switcher in the navbar. To run them:

cd docs && npm install && npm run dev

That serves the docs at http://localhost:3030 (the same URL the app’s Docs button points to). To build and serve a production version:

npm run build && npm run start

The docs use Nextra’s i18n routing, which needs a Node server — so this is a normal next build (not a static export). Host it on Vercel or any Node platform.

  • Architecture — how the pieces fit: the two-table model, state flow, and the role boundary.
  • Pricing EnginecomputePricing formulas, the line items, and the seeded numbers behind the worked examples.