Pre-1.0 · one maintainer · Stripe and cards only · no SDKs (client libraries) yet · no production users yet. Docs describe v0.9.1 (29 Oct 2026) · What’s new →
web-v2 — the Hardcount dashboard
React + TypeScript + Vite single-page app: the operator dashboard (customers, invoices, subscriptions, pricing, dunning, webhooks) plus the customer-facing public pages (hosted invoice, payment update, shared cost dashboard).
npm install # .npmrc pins legacy-peer-deps — a plain install worksnpm run dev # Vite on :5173, proxying /v1 to the Go server on :8080The dev server needs the backend running — from the repo root:
make dev (or the two commands in the root README’s Quick start).
Node 22+ (CI runs 22; anything below 20.19 breaks Vite).
The checks CI runs on this directory
Section titled “The checks CI runs on this directory”npx tsc -b # strict typecheck. NOT `tsc --noEmit` — that silently # checks nothing here (composite project references).npm run lint # eslint, then knip: unused files, exports and # dependencies fail (knip.jsonc says what is ignored)npm test # vitestnpm run build # tsc -b + vite build — the strictest of the fournpm run test:e2e # Playwright browser tests; needs a running API (e2e/README.md)Generated code — do not hand-edit
Section titled “Generated code — do not hand-edit”src/lib/gen/** is generated from api/openapi.yaml at the repo root.
Change the spec, then run make gen from the root — the npm-level
generators are not the same thing. CI’s codegen-drift job fails any PR
where the spec and the generated artifacts disagree.
Conventions worth knowing before a first PR
Section titled “Conventions worth knowing before a first PR”- Relative-time / “now”-dependent UI must resolve “now” via
src/hooks/useClockFrozenMap.ts— test clocks (simulated billing timelines) freeze time per entity; an eslint rule bans bareDate.now()in the affected surfaces. - Money is formatted through
src/lib/priceDisplay.ts— exact string math, neverparseFloaton money strings. - Every user-visible change updates
CHANGELOG.md, and UI changes are covered by a Playwright spec ine2e/(same PR — see How we test).