Tech stack summary
One paragraph per choice. Detailed reasoning lives in the corresponding ADR.
Cloudflare (Workers + D1 + R2 + Cron + Pages + Access)
The whole runtime. Workers for the app server (one Worker per shop, deployed independently), D1 for the database (SQLite-on-the-edge, single-tenant per shop), R2 for asset storage (receipts, photos, audit exports), Cron Triggers for scheduled jobs (daily reconciliation, weekly backups, monthly summaries), Pages for the docs site (this bible) and the shop's public marketing site, Access for SSO-gated admin areas.
Rejected: AWS (too many moving parts, per-shop blast radius too wide), Vercel (Vercel-on-Postgres complicates single-tenant, Functions cold-start hurts POS UX), self-hosted (operationally untenable for a one-person company with shop-bound SLAs). See ADR-0001.
D1 (Cloudflare's SQLite-on-edge)
One D1 instance per shop. Schema is plain SQLite-compatible SQL (no D1-specific features) so the schema is portable. Single-tenant per shop means each shop's data is physically isolated — there is no "tenant_id" column anywhere in the schema. See single-tenant per shop and ADR-0002 / ADR-0003.
Rejected: Postgres (overkill for ~3,000 customers/shop, per-shop Postgres operationally heavy), Supabase (multi-tenant by design, defeats the isolation property), DynamoDB (no SQL = no AI corpus introspection).
Stripe (Terminal + Checkout)
In-shop card via Stripe Terminal (BBPOS WisePOS E hardware). Subscription billing via Stripe Checkout. Each shop's Stripe account is theirs — Helm has read access for transaction syncing but money flows shop ↔ Stripe ↔ shop's bank, never through Kvick. See ADR-0011.
Rejected: Square Terminal (US-focused, Canadian rate disadvantage), Helcim (good Canadian rates but smaller terminal ecosystem and weaker developer experience), Moneris (legacy enterprise tooling, no modern API).
Twilio (SMS only)
One-way SMS from shops to customers (ticket-ready notifications, appointment reminders, marketing opt-ins). Two-way conversational SMS is on the roadmap (slice 4 extensions). Account-level: Kvick holds the Twilio account, each shop has a sub-account, costs pass through with small markup. See ADR-0012.
Rejected: Bandwidth.com (no Canadian numbers), MessageBird (more expensive, fewer Canadian-specific compliance features), shop-owned Twilio accounts (operationally too much support burden).
GitHub (source + GitHub Actions for CI)
Git source-of-truth. Each Helm shop deployment is a separate Worker, deployed via wrangler deploy from a per-shop branch. The bible repo and the Helm app repo are separate, each with their own Cloudflare Pages or Worker deployment. See Deployment topology.
Rejected: GitLab (smaller ecosystem, fewer Cloudflare integrations), Bitbucket (Atlassian friction).
Claude Code + Claude API
Code-development workflow is Claude Code (CLI + IDE). The Helm AI Support bubble (slice 11) calls the Claude API directly. Conversation memory lives in D1, summarized via Claude itself, with a clear opt-out per customer per data ownership. See AI integration.
Rejected: OpenAI (Anthropic's safety alignment and prompt-caching better-suited to long-corpus RAG against the bible), self-hosted LLMs (no per-shop budget for the infra).
Languages: TypeScript + Python
- TypeScript for the Worker (app), the Docusaurus site (this bible), and any client-side enhancements.
- Python for the AIM migration ETL (
migrate_aim.py), schema-document tooling (extract_migrations.py,verify_schema.py), and one-off data-engineering scripts.
The Worker has no React framework on top of vanilla Workers + HTML/JS for the operator UI — see ADR. Lighter, fewer moving parts, easier for one person to maintain.
Rejected: Go (smaller Workers ecosystem), Rust (too much ceremony for the iteration speed needed), Hono / Remix / Next on top of Workers (more complexity than the app needs).
Tooling: vitest, wrangler, prettier, eslint
Standard JavaScript toolchain. Vitest for unit + integration tests (fast, ESM-native, decent Workers compatibility via the @cloudflare/vitest-pool-workers package). Wrangler for local dev + deploy. Prettier + eslint for style; defaults mostly. See Code style and Testing.
See also
- Current state — what's actually running today
- ADR-0001: Cloudflare stack — the foundational choice
- C4 context diagram — how it all fits together