SkipOps

Plain English, start here

What SkipOps does — and exactly where we are

SkipOps runs the day for a UK rubbish-clearance firm, entirely through Telegram. The boss texts jobs in plain words. The system works out the smartest route for every van. The crew get tap-by-tap job cards on their phones. The boss watches it happen live and ends up with a photo-proof record of every job. No money or pricing anywhere in version 1 — the win is told in saved fuel, time and wages.

5set-up wizard: two versions now live side by side (5 Jul) — the original (now 4 steps: Ops folded into Sites) at the front door, and a new 4-step v2 ("Your firm → Your base → Where does it go? → Checklist") that Alex has walked and approved on his phone. v2 asks only what the boss can answer in a minute — the crew is never typed in (they join through Telegram later). Which one greets a new firm is the next decision
1route planner: a working core that needs a rework
7stages designed and waiting to be built
built & tested part-built to build

The whole thing on one page

The loop, top to bottom

Five moving parts. Set the firm up once, then the same loop repeats every working day.

flowchart LR
  A["① Set the firm up
(once)"] --> B["② & ③ Boss texts
jobs"] B --> C["④ System plans the
smartest day"] C --> D["⑤–⑦ Crew get job cards
+ post photos"] D --> E["⑥ ⑧ ⑨ Boss watches live +
gets the record"] E -. "new job or change
→ re-plan" .-> C classDef here fill:#eef2ff,stroke:#4f46e5,stroke-width:2px,color:#3730a3; class A here;
We are here — stage ① calibration wizard is now 5 steps with a full design-system rebuild, and as of 28 Jun the whole stack is merged to main (commit 92320e2): Van & crew (who-drives-what) → Waste typesSites (Google-satellite map per waste, multiple tips, dark all-sites overview) → Ops (3 animated "how it moves" diagrams; skipped if no yard) → Checklist (typed job + yard builder + per-job review-QR — built, Alex-approved, on main). Built + smoke-passed (worker 148 + web 163 tests, check, build all green; contrast AA-checked; walks verified @390px). Owed before go-live: a full live phone walk of all 5 steps + the save-to-Supabase path (apply the new migration, walk to Save, confirm a tenant lands). Nothing is on the public internet yet — deploying is its own later step. Update 5 Jul: a rethought v2 onboarding — 4 steps, sites-first, no crew typing, checklist + required review link — is now on main alongside the original (details in the ①·v2 card below); Alex walked it at phone width and approved it. Choosing which wizard greets a new firm is the next decision.

Every stage — what it's for, and where we are

The 9 stages in detail

Each one: the plain-English objective (what we're trying to achieve), a quick picture, and an honest done / still-to-do.

Set the firm up

now 5 steps (refined 28 Jun) · design-system rebuild + Sites/Ops redesign + typed Checklist · merged to main (92320e2) · live phone gate + save-to-DB owed

The objective: before SkipOps can run anyone's day, it has to learn how that firm works. The boss fills in a quick 5-step setup wizard + a review — (1) Van & crew, (2) Waste types, (3) Sites, (4) Ops, (5) Checklist — tap and type, then Next. Each step shows only the one thing it's asking, so it never feels busy. We started at 5/6 steps, collapsed to 3, then split back out to 5 because the honest shape is one clear question per screen: who works herewhat waste you handlewhere each one ends uphow each one gets therethe job checklist. No AI, no guessing in setup: each step is a plain form our own code checks before you can advance, and the firm is saved at the end. Hours aren't asked — they flex day to day, so the day's window comes from the crew sharing live location to sign in (gaffer's "kick off the day", stage ②).

What we gather → what it powers: the firm name; the vans + who usually drives each (a starting point the planner flexes daily); the crew with Driver / Labourer roles (so the planner knows who can move a van); the waste types you handle; the yard/base address (the route anchor + map centre); per waste type, where it's finally taken (one or more tips, picked on a Google-satellite map, or the yard itself) and how it moves — stays at the yard, straight to the tip, or stored then run in bulk (powers the consolidation trips); and the standard job checklist. Every answer feeds a feature — nothing "just in case".
flowchart LR
  S1["① Van & crew"] --> S2["② Waste types"]
  S2 --> S3["③ Sites
(map per waste)"] S3 --> S4["④ Ops
(how it moves)"] S4 --> S5["⑤ Checklist"] S3 --> R["Smart routes +
full-van trips"] S4 --> R

Done

  • Design-system rebuild — the wizard's skin was rebuilt on a small set of reusable UI primitives (restrained-premium dark, amber = action only, ≥48px controls, hazard tape retired). Logic/schema/validation/save shape untouched; guarded by a structural render test + a "design discipline" rule in CLAUDE.md. 145 web tests + astro check + build + 5-step gauntlet all green.
  • Step 1 — Van & crew: firm name → crew (each with Driver/Labourer roles) → vans (name + reg + a reactive usual-driver dropdown, greyed until a crew member exists). Schema rules: ≥1 driver; a van's usual driver must be a known driver.
  • Step 2 — Waste types: the materials you handle, as a clean list (add/remove).
  • Step 3 — Sites: an accordion — yard/base first, then one waste at a time on a Google-satellite map with search + nearby-tip suggestions. Selecting previews on the map; an in-map Add pins it; you can add several sites and the map reframes to fit them all; one-tap "it's disposed at the yard". Decided wastes collapse to a thin row (colour dot · ✓). When all are placed, a dark Google overview map shows the yard + every site in its colour (pins track the map exactly at any zoom).
  • Step 4 — Ops: per waste, 3 selectable animated flow diagrams — stays at the yard / store then bulk-run / straight to the tip. Only the cases that match Sites are selectable (a tip-waste picks store vs every-job; a yard-only waste is locked to "stays"). When a waste has the yard AND a tip as candidates, "every job" becomes "nearest site, every job" — the optimiser drops at whichever is closest. No yard → the step is skipped (everything's removed per job).
  • Step 5 — Checklist (typed, built 28 Jun, Alex-approved, on main): each item now carries a type the crew act on — Tick / Photo / Amount (log what's in the van + how full) / review QR — chosen on a segmented picker. A job checklist (8 defaults in Alex's order; before/after photo + the review ask are locked) plus, when the firm has a yard, a yard checklist (7 defaults). Add / delete / change-type / drag to reorder; locked items can't be retyped or removed. A review-QR item reveals the firm's Google review link (required when present). Per-job review-QR proof: each job gets a unique QR → GET /r/<token> logs the scan and 302-redirects to the review link (endpoint + scan table built and unit-proven; the crew job-card that draws the QR is a later bot slice).
  • Maps two-tier policy — customer-facing maps use Google (satellite picker + dark overview); backend geolocation stays keyless/free. Browser key PUBLIC_GOOGLE_MAPS_KEY on the VPS + local env.

Still to do — calibration isn't concrete until this is all done

  • Walk all 5 steps live on a real phone — Step 5 (Checklist) has been played-with + signed off in-pane and is on main; the full end-to-end phone walk of steps 1–4 + Review is still owed before go-live.
  • Persist + save path — apply the new migrations (roles/usual_driver + the checklist/review-QR one: review_url, yard_checklist, jobs.review_token, the scan table) and re-run create_tenant on Supabase, then walk the wizard to Save and verify a tenant lands with the typed checklist, yard checklist, review link, per-waste sites + movement, roles, usual drivers, and working_hours: null.
  • Go live — nothing is deployed yet (no wrangler.toml committed; SkipOps isn't on the internet). First deploy = its own job: Cloudflare project + secrets, apply the migrations to the real DB, then the live Pages domain on the Maps key's referrers + swap the deprecated google.maps.Marker pins to AdvancedMarkerElement.
①·v2

Onboarding v2 — the 4-step rethink (merged 5 Jul · checklist restored that afternoon)

built · walked + approved by Alex at phone width · lives at /v2 next to the original · the swap decision is queued

The objective: the original wizard makes the boss type in everything — crew, waste types, checklists — before the firm exists. v2 flips that: it asks only what a boss can answer in a minute, and everything else arrives later, in Telegram, where his crew already are. (1) Your firm — the name and how many vans. (2) Your base — one pin on the map. (3) Where does it go? — a card for each place he gets rid of waste: he searches a tip by name (the way he actually knows them), ticks which waste goes there, and the yard is simply the first card — anything ticked on it says whether it's stored then taken on or disposed of right there. (4) Checklist — the same job + yard checklists the original wizard builds (what the crew must tick, photograph or measure on every job), pre-filled so most bosses just glance and carry on — and the firm's Google review link is required here (Alex's call: the "ask for a review" step must always point somewhere real). Nobody types a crew list, ever: when the firm's saved, a share-able link makes whoever opens it the boss's account — so Alex can fill the whole thing in on a sales call and just send the link. If something's blocking the Next button, the screen now says exactly why, right next to the thing to fix (added after Alex's walk caught it staying silent).

What we gather → what it powers: the name + van count → the planner's fleet; the base pin → the anchor every route starts and ends at; the destination cards → right-waste-to-the-right-place routing and the stored-at-the-yard answer that powers the consolidation runs (SkipOps' signature); the share-able link → assisted setup, so signing a firm up can happen on one phone call.
flowchart LR
  A["① Your firm
(name + vans)"] --> B["② Your base
(one pin)"] B --> C["③ Where does it go?
(tip cards + waste ticks)"] C --> CL["④ Checklist +
review link"] CL --> D["Save — the
firm exists"] D --> E["Send the link →
the boss takes over"]

Done

  • The 3-step core + review + save, live on main (merged 5 Jul morning). Alex walked the whole thing at phone width: his first walk failed it on two counts (two buttons touching on the finish screen; a blocked Next with no explanation) — both fixed the same morning, locked in with tests, and the re-walk passed.
  • The checklist is back as step ④ (5 Jul afternoon) — the same typed builder the original wizard uses, pre-seeded job + yard lists, and the review link is required. Its gate caught a real bug: since 28 Jun the dev database had been silently losing the review link and yard checklist on every save — fixed the same day, and the save is now proven by reading the stored row back, not by trusting the success screen.
  • Saves through its own door — v2 is allowed an empty crew (the Telegram group becomes the roster). The original wizard's save path is untouched; the two coexist safely.
  • The share-able takeover link works — proven live in the walk: copy, open, and whoever opened it is the boss of the new firm (dev bot).

Still to do

  • Decide the front door — keep both wizards, or make v2 the setup and retire the original. Queued as its own decision, not assumed at the merge.
  • Find the review link for them — v2 now asks for the firm's Google review link (and insists on it); a later step should look it up automatically so the boss never has to hunt for it.
  • The Telegram lazy layer — the pieces v2 deliberately doesn't ask (crew roster, checklist tweaks) need their in-chat arrival built so "later, in Telegram" is real, not a promise.
①·5

Disposal Sites — how it works (PIVOTED 26 Jun)

the firm declares its OWN sites per material (routing truth) · the regulatory research now powers low-friction suggestions, NOT auto-discovery

The objective: for each waste type, capture the disposal site(s) the firm itself uses — the places it actually has access to and an account with. That list is what routing trusts. Why not just auto-find sites for them? Because no data can tell us whether a site will take a crew that turns up unannounced — many require a trade account; some (like Robins) don't. Sending a van somewhere it gets turned away is unacceptable. So the firm names its own (it only ever uses 4–5) — and our whole job is to make that entry effortless: we suggest the real sites near their yard and let them tap to add, instead of making them type everything from scratch.

What we gather → what it powers: the firm's own disposal sites, per material (tapped from suggestions or typed once) → the routing truth (each load goes to a site the firm knows it can use) → and the regulatory data (Environment Agency Waste Data Interrogator — every licensed site near the yard and what it actually received last year) → becomes the suggestion engine that makes that entry a few taps, not a chore.
flowchart LR
  A["Yard postcode"] --> B["Suggest real sites
near you, by material
(from EA data)"] B --> C["Firm taps to add
· or types its own"] C --> D["The firm's sites,
per material"] D --> E["Routing only ever
uses these"]

Done

  • The pivot is decided + de-risked. Proved (26 Jun) that auto-qualifying "where waste can go" is too risky — a site can pass every check and still refuse a no-account crew. So routing uses only what the firm declares.
  • Suggestion index ingested nationally → D1. The EA Waste Data Interrogator (free, keyless) is materialised into a disposal_suggestions table — 7,107 real commercial sites (household-only HWRCs excluded), each with what it received by the tonne. Built + loaded local + remote (26 Jun). Live Brighton query surfaces the web-quiet sites the old gate missed (Newtimber/Robins → 24,000t hardcore; OLUS → 36,000t wood).
  • Runtime suggestion query built. GET /suggestions turns the yard's location into nearest sites per material (keyless OS-grid maths, £0/zero-token) — proven live end-to-end.
  • Step 5 re-pointed — tap-to-add suggestion chips (real EA data) + a keyless "add a site you use" (address autocomplete + a draggable map pin) + the honest dynamic disclaimer (phone ahead before adding) + idiot-proof gating. Built + smoke-passed; headed test dry-run twice.
  • Auto-qualify path retired — the website-scrape + LLM "does it take commercial X?" gate and its whole module are deleted (the risky part is gone).

Still to do

  • ◐ The live gate — walk it on a real phone. Everything above is built + smoke-passed (worker 116 + web 64 tests green) and the headed test passes headless, but Alex hasn't yet walked Step 5 live and tapped real suggestions on screen. This is the one thing left before it's signed off ✓.
  • WDI licence — confirm the commercial-use terms (currently "conditional/internal-use") before it underpins the product nationally.

Give the firm its two chats

to build

The objective: every firm gets two Telegram chats — a private one for the boss (the "Gaffer" chat) and a group for the crew (the "Dispatch" group). And a hard wall so one firm can never see another firm's jobs.

flowchart LR
  A["Firm set up"] --> B["Gaffer chat
(boss only)"] A --> C["Dispatch group
(the crew)"] B --> D["Each firm's data
walled off"] C --> D

Done

  • Nothing yet — the design is set

Still to do

  • Wire up the two bots + lock each to its firm
  • Switch on the data walls (security rules) before any real firm's data lands

Boss drops a job

to build

The objective: the boss texts a job the way he'd say it out loud — "clear a garage on Dyke Road tomorrow morning, half a load, before-and-after pics." The system turns that into a proper job (where, how big, when, what photos) and reads it back so any misread is caught on the spot.

flowchart LR
  A["Boss texts it
in plain words"] --> B["System understands:
where, size, when"] B --> C["Job created"] C --> D["Reads it back
to confirm"]

Done

  • Skeleton only

Still to do

  • The "understand the text" step, save the job, and the read-back

Plan the smartest day

core built · rework owed

The objective: given the day's jobs, work out the most efficient round for every van — fewest miles, fullest loads — including nipping back to the yard to empty when a van fills up, then carrying on. This saving (fuel, time, wages) is the whole pitch.

flowchart LR
  A["The day's jobs"] --> C["The planner"]
  B["The vans + capacity"] --> C
  C --> D["Most-efficient
route per van"] D -. "van full →" .-> E["empty at the yard,
then carry on"] E -.-> D

Done

  • The core planner works and is tested (routes, time windows, empty-and-continue)

Still to do

  • It currently plans around cost (money) — rework it to plan around distance + load (no money in v1)
  • Wire in the yard-hub + the per-waste-type consolidation trips

Tell each crew their route

to build

The objective: once the day's planned, each van gets one clear, friendly message — their stops in order, what to expect, and a tap-to-navigate link for each stop that opens their own phone's maps. Nothing new to learn.

flowchart LR
  A["The day's plan"] --> B["Friendly message
per van"] B --> C["Stops in order"] B --> D["Tap-to-navigate
per stop"]

Done

  • Skeleton only

Still to do

  • Turn the cold route into a readable message + the per-stop map links

See where the vans are

to build

The objective: each driver taps "share live location" in Telegram once at the start of the day. That's it — the system now knows where every van is, with no app and no tracking box to fit.

flowchart LR
  A["Driver taps
'share location'"] --> B["System knows
where each van is"] B --> C["Feeds the
boss's live map"]

Done

  • Nothing to build on Telegram's side — by design

Still to do

  • Store the shared location + a morning "share it again" nudge

Photo-proof every job

to build

The objective: the crew snap a before and an after photo and tick the job checklist. The system files them against the job, so there's a permanent, proof-backed record of every clearance — plus a note of exactly who was on that team that day.

flowchart LR
  A["Crew: before +
after photos"] --> C["Filed against
the job"] B["Checklist ticked"] --> C C --> D["Permanent
proof record"]

Done

  • The checklist the crew tick is defined — the typed job + yard checklists (Tick / Photo / Amount / review-QR) come from the setup wizard (stage ①, Step 5).
  • Review-QR proof endpoint builtGET /r/<token> logs a scan to the scan table and 302-redirects to the firm's Google review link (unit-proven; gives the boss a "review asked · HH:MM" signal later).

Still to do

  • Photo capture + storage, the checklist tick on the crew card, the crew snapshot on finish, and the crew job-card that actually draws the per-job review QR.

Re-plan when things change

planner ready · trigger left

The objective: jobs change all day — a new one comes in, one's cancelled, a van finishes early. When that happens the system quietly re-plans the rest of the day and re-sends the routes, without anyone asking.

flowchart LR
  A["New / cancelled job,
or van free early"] --> B["Re-plan the
rest of the day"] B --> C["Re-send the
updated routes"]

Done

  • The planner can already re-plan on demand

Still to do

  • The automatic trigger that fires it the moment something changes

The boss's live dashboard

to build

The objective: one screen for the boss — a live map of his vans and jobs, a list he can filter, and a tap into any job to see its photos, crew, checklist and timings. His whole operation at a glance.

flowchart LR
  A["Live van pins"] --> C["Boss dashboard"]
  B["All the jobs"] --> C
  C --> D["Tap a job → photos,
crew, checklist, times"]

Done

  • Folder is a placeholder

Still to do

  • All of it — the map, the list, the job detail

Staying on track

What's next, in order

Calibration wizard is done. Rewrite the docs for the new sign-in strategy, then build the daily loop in the order the day actually runs.

1
Decide the front door: v2 or the original wizard next
Both are on main (5 Jul): the original 4-step at /, the approved v2 4-step at /v2. Pick which one greets a new firm — and if it's v2, plan the original's retirement plus v2's two follow-ons (auto-find the firm's review link; build the "later, in Telegram" arrival for crew + checklists).
1b
Docs rewrite for "kick off the day · share location to sign in"
CLAUDE.md + docs/HANDOFF.md updated to spell out the v1 sign-in strategy that replaces calibration-time working hours, ahead of stage ② bot work. STATE.html already reflects it.
2
Sign off the 5-step wizard live + wire the save path next
The wizard is 5 steps with a full design-system rebuild and is now merged to main (92320e2): Van & crew · Waste types · Sites (Google-satellite map per waste, multiple tips, dark overview) · Ops (3 animated "how it moves" diagrams; skipped with no yard) · Checklist (typed job + yard builder + per-job review-QR — built, played-with + signed off in-pane). Left: Alex walks steps 1–4 + Review end-to-end on his phone, then apply the migrations (roles/usual_driver + review_url/yard_checklist/scan/jobs.review_token) and walk to Save to confirm a tenant lands. Going live (first Cloudflare deploy) is a separate later job.
3
Rework the route planner's goal
Stage ④ — switch it from "cheapest" to "fewest miles + fullest loads", and wire in the yard-hub + per-material consolidation trips. The hard maths already works.
4
Build the daily loop (stage ② onwards)
Stages ②③⑤⑥⑦ — the two chats, the gaffer's "kick off the day" + crew share-location sign-in, dropping a job, sending routes, live location, and photo-proof. This is the bulk of the remaining build.
5
Auto re-plan + the boss dashboard
Stages ⑧⑨ — fire the re-plan on any change, and give the boss his live oversight screen.

Mission: 20 paying firms at £75/mo by 5 Nov 2026. Roughly the first stretch is finishing the build; the rest is selling it.