Your one stop insurance platform — quote, buy, manage and claim, all in the browser.
Advantage is a generic insurance platform that covers the full customer journey in one application: browse the product catalogue, get an instant quote, buy the policy, manage it and claim against it. It runs entirely in the browser — no backend, no database and no API keys.
Live site: https://charles2ke.github.io/Advantage/
- Features
- Quick start
- Scripts
- Testing
- Project structure
- Architecture
- Accessibility and UX
- Integrations
- How the premium is calculated
- Deployment
- Screenshots
- Contributing
- Security
- License
- Product catalogue — motor, home, life and travel cover, each with its own rating factors,
optional extras and excess options (
src/domain/catalog.ts). - Quoting — a three step wizard collects the applicant details, the cover options and the
answers to the risk questions, and prices the risk live as you type
(
src/components/QuoteWizard.tsx). - Rating engine — a deterministic pricing engine that builds the premium from the base rate,
age and risk loadings, optional coverages, excess, loyalty discount and insurance premium tax,
and returns a full breakdown (
src/domain/rating.ts). - Policy administration — quotes are saved for 30 days, accepted quotes are issued as 12 month
policies, and policies can be renewed in the 30 days before expiry or cancelled
(
src/domain/policies.ts). - Claims — claims are validated against the policy (cover period, sum insured), given a
reference and tracked through submitted → in review → approved/declined → settled, with the
settlement calculated net of the policy excess (
src/domain/claims.ts). - Admin portal — a setup area at
#/adminwhere the platform is named, products are put on or taken off sale, the pricing rules (tax, instalment loading, loyalty discount, quote validity) are tuned and the stored data can be cleared (src/pages/AdminPage.tsx,src/domain/settings.ts). - Real world integrations — the platform calls live public services from the browser: postcodes
are verified against postcodes.io and quote prices can be shown in another currency using the
European Central Bank reference rates published by Frankfurter (
src/integrations/). - Accessible by default — a skip link, focus management on validation errors, per page
document titles and a quote wizard you can step back through (
src/App.tsx,src/components/ErrorSummary.tsx). - Persistence — quotes, policies and claims are stored in the browser's local storage, so the
platform runs as a static site with no backend (
src/state/storage.ts).
Prerequisites: Node.js 24 (the version used in CI) and npm.
git clone https://github.com/charles2ke/Advantage.git
cd Advantage
npm install
npm run devThe app is served on http://localhost:5173.
First run through the app:
- Open the home page and pick a product.
- Complete the three step quote wizard and review the premium breakdown.
- Accept the quote to issue a policy, then manage or renew it on the Policies page.
- Submit a claim against the policy on the Claims page.
- Visit
#/adminto rename the platform, change the pricing rules or clear the stored data.
All data lives in your browser's local storage; clearing site data resets the platform.
| Script | Description |
|---|---|
npm run dev |
Start the development server |
npm run build |
Type check and build the production bundle into dist/ |
npm run preview |
Serve the production build |
npm run lint |
Lint the source with oxlint |
npm test |
Run the unit and component tests with Vitest |
npm run test:watch |
Run Vitest in watch mode |
npm run test:e2e |
Run the Playwright end to end tests (builds and previews the app) |
- Unit and component tests (
tests/) run on Vitest with Testing Library and jsdom. They cover the rating engine, policy and claim lifecycles, settings, the state reducer, the integration clients, the accessibility behaviour (skip link, focus on errors, page titles) and the pages that use them. - End to end tests (
e2e/advantage.spec.ts) run on Playwright against the production build and walk the full journey: quote → policy → claim → admin. The screenshots indocs/screenshotsare produced by this suite, so they stay in step with the UI.
Playwright needs its browser once per machine:
npx playwright install --with-deps chromiumCI runs npm run lint, npm test and npm run build on every push to main before deploying.
src/domain pure business logic: catalogue, rating, policies, claims, settings, formatting
src/integrations clients for the external services the platform calls
src/state reducer, React context provider and local storage persistence
src/components reusable UI: quote wizard, premium summary, product card, status badge
src/pages home, quote, policies, claims and admin pages
src/router.ts minimal hash router so the app deploys as static files
tests Vitest unit and component tests
e2e Playwright end to end tests (screenshots are written to docs/screenshots)
- Pure domain layer. Everything in
src/domainis side effect free: ids are passed in by the caller, and timestamps are injectable but default to the current date when omitted, so quoting, issuing, renewing and claiming remain easy to test. - Single reducer. Every state change goes through the pure reducer in
src/state/appReducer.ts;src/state/AppProvider.tsxwires it to React context and mirrors the state into local storage. - Static by design. A minimal hash router (
src/router.ts) keeps the app deployable as plain files on any static host, including GitHub Pages. - Isolated integrations. External calls are confined to
src/integrationsbehind a single result contract, so the rest of the app never deals with network failures directly.
The platform is keyboard and screen reader friendly:
- Skip to main content. The first control on every page moves focus straight to
<main>, past the navigation. - Announced errors. Validation problems are collected into a single summary
(
src/components/ErrorSummary.tsx) that is announced withrole="alert"and takes focus, so the reason a quote or claim was rejected is never missed. - A wizard you can revisit. The quote wizard shows which step you are on and which are complete, and completed steps are buttons that take you back with your answers intact.
- Honest page titles. The document title follows the route (
Get a quote — Advantage), so tabs, history and bookmarks stay meaningful. - Live feedback. The price panel updates as you answer, empty states explain what to do next, and every status is shown as a labelled badge rather than colour alone.
Advantage talks to real, keyless public APIs so the platform works end to end as a static site with no backend and no secrets to manage.
| Integration | Service | Used for |
|---|---|---|
| Address lookup | postcodes.io (Ordnance Survey and ONS open data) | Verifying the postcode in the quote wizard and showing its district and region |
| Exchange rates | Frankfurter (European Central Bank reference rates) | Showing the price of a quote in another currency |
Each integration lives in src/integrations behind a small contract: the client takes the request
and an optional endpoint, timeout, abort signal and fetch implementation, and always resolves to
{ ok: true, data } or { ok: false, error }. Network errors, timeouts, error statuses and
unexpected payloads are turned into a readable message, so an outage never blocks a quote, and the
tests stub fetch instead of touching the network.
Administrators manage them under Integrations in the admin portal: each one can be turned off, pointed at another https endpoint (for example a proxy of your own) and tested with a live connection check. The configuration is validated and persisted with the rest of the settings.
Adding another integration means adding its client under src/integrations and registering it in
src/integrations/catalog.ts; the settings, persistence and admin portal pick it up from there.
- Base premium — the product's flat premium plus a rate per 1,000 of the sum insured.
- Risk adjustment — the age band multiplier and every risk answer multiplier applied to the base premium.
- Optional cover — each selected extra adds a percentage of the risk adjusted premium.
- Excess — a lower excess loads the premium, a higher excess discounts it.
- Loyalty discount — 5% per policy already held, capped at 15%.
- Minimum premium, tax and instalments — the net premium never falls below the product minimum, insurance premium tax of 12% is added, and paying monthly carries a 5% loading.
The tax rate, instalment loading, loyalty discount and quote validity are defaults that an administrator can change in the admin portal; new quotes are rated with the saved settings.
The app is a static site (hash routing, browser local storage) and is published to GitHub Pages by
the .github/workflows/deploy.yml workflow on every push to main. To enable it, set
Settings → Pages → Build and deployment → Source to GitHub Actions.
The workflow builds with BASE_PATH=/<repository name>/ so the assets resolve under the project
page URL. Locally npm run build defaults to a base of /; set BASE_PATH yourself to reproduce
the deployed build:
BASE_PATH=/Advantage/ npm run build && npm run previewAny other static host works too: build the app and serve the contents of dist/.
| Quote details | Quote result |
|---|---|
![]() |
![]() |
| Policies | Claim submitted |
|---|---|
![]() |
![]() |
| Claim settled | Admin portal |
|---|---|
![]() |
![]() |
| Quote with a converted price | Integrations in the admin portal |
|---|---|
![]() |
![]() |
Issues and pull requests are welcome. Before opening a pull request:
npm run lint
npm test
npm run buildKeep business logic in src/domain pure, route state changes through src/state/appReducer.ts,
and add tests alongside the existing suites in tests/.
Advantage stores everything in your browser and calls only public, keyless APIs, so there are no credentials to manage. To report a vulnerability, see SECURITY.md.
Released under the GNU Affero General Public License v3.0.
Advantage is a demonstration platform: no real insurance cover is provided and all data stays in your browser.








