Skip to main content

Onboarding a new shop

The end-to-end process for taking a new bike shop from "signed contract" to "first transaction in Helm production." Targets 1-3 days for a clean shop, more for a complex AIM migration.

Drafted from planning · v0.1

This runbook will be templatized into scripts/onboard-shop.sh once we onboard our second shop and the patterns stabilize.

Pre-day-1 (sales conversation outputs)

Before we start the technical onboarding:

  • Signed Master Services Agreement
  • Shop slug agreed (e.g., mike-s-bikes for Mike's Bikes — kebab-case)
  • Stripe Connect Standard onboarding initiated by shop
  • Twilio number procured (Kvick handles)
  • AIM data dump received from shop's prior system (or "no migration; greenfield")
  • Hardware list confirmed: terminals, printers, scanners, drawer, tablets

Day 1: Cloudflare resources

# All in the Cloudflare hello@kvick.ca account
wrangler d1 create helm-{slug}-db
wrangler r2 bucket create helm-{slug}-assets
wrangler kv:namespace create "helm-{slug}-kv"

# Note the IDs returned; needed for wrangler.jsonc

Day 1: Repo branch

git switch main
git pull
git switch -c shops/{slug}

# Edit wrangler.jsonc — add env.{slug} block with the IDs
# Edit shop-overrides/{slug}/branding.json — colors, logo, copy

git commit -am "Onboard {slug}: bindings + branding"
git push -u origin shops/{slug}
# CI deploys

Day 1: Schema + seeds

wrangler d1 migrations apply helm-{slug}-db --remote
wrangler d1 execute helm-{slug}-db --remote --file=seed_permissions.sql

# Sets shop_config row, default roles, screens, role_permissions
# Creates auto Sys Admin staff with default PIN-reset code

Day 1: Hostname + Access

# Add the route in wrangler.jsonc env.{slug} (already done above)
# Verify DNS: helm-{slug}.kvick.bike resolves to Workers

# Optional: add Cloudflare Access policy if shop owner wants extra gating

Day 1-2: AIM migration (if applicable)

# Dry run first — local
python migrate_aim.py --all --target=local

# Verify counts + spot checks
python verify_schema.py --shop {slug}

# Owner reviews; signs off

# Cutover — point at production D1
python migrate_aim.py --all --target=remote --shop {slug}

Day 1: Owner sign-in

The shop owner signs in:

  • Visits https://helm-{slug}.kvick.bike
  • Sign-in overlay appears
  • Enters PIN-reset admin code (currently 466687); signs in as Sys Admin
  • Sets their own PIN
  • Adds initial staff with their PINs

Day 2: Stripe Terminal hardware setup

  • Pair the BBPOS WisePOS E reader (per Stripe's provisioning flow)
  • Register the reader in the shop's Stripe account (Reader Locations, etc.)
  • Test charge $1 + refund

Day 2: Twilio sub-account

  • Provision Twilio sub-account
  • Attach the procured phone number
  • Configure Helm secret bindings: TWILIO_SUB_ACCOUNT_SID, TWILIO_AUTH_TOKEN (stored via wrangler secret put --env {slug})
  • Test SMS to shop owner's phone

Day 2-3: Training

  • Walk owner through Today / Customers / Service / Sales (whatever is built)
  • Show the in-situ editing pattern (the helm-editable dashed-underline cells + composite-till modals)
  • Show audit log
  • Show data export (Settings → Data → Export)
  • Hand over runbooks for daily ops

Day 3+: Shadow week

The shop runs Helm alongside their old system for 5-7 business days. Daily reconciliation cron compares totals. Discrepancies investigated; usually data quality on the migrated side.

After shadow week is clean, old system is read-only. Helm becomes primary.

Cutover checklist

  • All Helm endpoints respond OK from the shop's Wi-Fi
  • Owner has signed in and set PINs for all staff
  • At least one test sale rung (cash + card) and refunded
  • At least one service ticket dropped off and cashed out
  • Daily backup cron has run successfully once
  • Audit chain verifies clean
  • R2 bucket has at least one receipt PDF
  • Owner has the export bundle download URL

See also