10" tablet mounted in each delivery truck. Driver enters PIN at 8am, today's route loads in 2 seconds, app works for the entire shift even in rural dead zones, syncs deliveries back when signal returns. ~1 week to build, ~$720 in hardware, $0/mo to run.
Big tap targets (56px+ minimum), high contrast, no animations, single column on the left half / actions on the right. Designed to be useable in winter gloves at -20°C with the heater blasting and snow on the windshield.
Per your call — driver can just tap CONFIRM DELIVERED with no photo, no signature, no notes. Default flow takes ~3 seconds per stop. Capture only when something's worth recording (damaged box, weird location, customer drama).
5 reasons preset (no one home / wrong address / refused / damaged / other) plus optional notes. Stop becomes red on the route screen. Counter staff calls customer to reschedule.
Service worker caches the app shell aggressively. Today's route is loaded once at 8am, cached in IndexedDB. Every delivery write hits IndexedDB first, then attempts a server POST. If POST fails, the record stays in the queue with a retry timestamp. When connectivity returns, Background Sync API drains the queue automatically.
All added to the existing 613parts-bot-worker. JWT-based auth (HS256, 24h tokens) using the Web Crypto API — no external dependencies. Driver list is a static file in the repo with salted PIN hashes.
Driver ID + PIN → JWT (24h). Returns driver info for client-side display. PINs are salted SHA-256, never stored raw.
Returns the active driver list (id, name, branch). Used by the PIN screen dropdown. No auth required so the login screen can show drivers before they're authenticated.
Today's stops for the authenticated driver's branch. Reads deliveries/{date}/{branch}.json from R2. Service worker caches the response for offline use.
Marks an order delivered. Accepts optional photo (base64 JPEG → R2) + signature SVG + notes. Writes a delivery event JSON to R2.
Marks an order undelivered with a reason. Counter staff calls customer to reschedule.
Cloudflare Workers ship with the full Web Crypto API, so JWT signing + verification + PIN hashing all use built-ins. Zero npm packages added for auth.
export async function signJWT(payload: Omit<JWTPayload, 'iat' | 'exp'>, secret: string): Promise<string> {
const now = Math.floor(Date.now() / 1000);
const fullPayload: JWTPayload = { ...payload, iat: now, exp: now + TOKEN_TTL_SECONDS };
const headerB64 = base64urlEncode(JSON.stringify({ alg: 'HS256', typ: 'JWT' }));
const payloadB64 = base64urlEncode(JSON.stringify(fullPayload));
const signingInput = `${headerB64}.${payloadB64}`;
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode(secret),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
);
const signature = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(signingInput));
return `${signingInput}.${base64urlEncode(new Uint8Array(signature))}`;
}
export async function verifyPIN(pin: string, salt: string, hash: string): Promise<boolean> {
const computed = await hashPIN(pin, salt);
// Constant-time comparison
if (computed.length !== hash.length) return false;
let mismatch = 0;
for (let i = 0; i < computed.length; i++) {
mismatch |= computed.charCodeAt(i) ^ hash.charCodeAt(i);
}
return mismatch === 0;
}
Worker gets new auth + driver handler files. New separate repo driver-app houses the PWA — Vite + React + Tailwind. Both deploy to Cloudflare (Workers + Pages).
2 trucks × (1 tablet + 1 mount) + cabling. Tablets are kiosk-locked to the app, hardwired to truck power, theft-tethered with a steel cable lock through the dashboard mount.
11" screen, 1920×1200, Android 14 with Chrome (full PWA support). 2-day battery if needed for backup. Built-in WiFi + LTE option (~$100 more for cellular variant — recommend cellular so the truck doesn't depend on the customer's WiFi).
Twist-lock dashboard mount with X-Grip cradle for 7-13" tablets. Holds tablet upright in landscape mode. Suction or screw-in base depending on truck dashboard type.
USB-C cable run from fuse box to mount. Tablet always charging when truck is on. No "forgot to plug in" risk.
Steel cable lock through mount and dashboard frame. Makes tablet a 30-second-with-bolt-cutters problem instead of a 3-second grab.
Backend extensions deploy to the existing Worker. Frontend deploys to Cloudflare Pages. Hardware setup takes ~30 min per tablet.
Set the JWT secret. Existing Worker accepts new routes.
cd worker
npx wrangler secret put JWT_SECRET
npm run deploy
Replace the dev PINs in src/lib/drivers.ts with real ones.
node -e 'const c=require("crypto");
const salt=c.randomBytes(8).toString("hex");
const pin="REAL_PIN_HERE";
console.log({salt, hash: c.createHash("sha256")
.update(salt+pin).digest("hex")})'
Cloudflare Pages with custom domain.
cd driver-app
npm install
npm run build
npx wrangler pages deploy dist \
--project-name=613parts-driver-app
In Cloudflare DNS: CNAME drive → pages.dev. SSL automatic.
# In Cloudflare dashboard:
# DNS → Add record →
# Type: CNAME
# Name: drive
# Target: 613parts-driver-app.pages.dev
Setup Wizard → connect WiFi → open Chrome → drive.613parts.ca → Add to Home Screen → Kiosk Mode.
# 30-min checklist per tablet:
# 1. Install on truck mount
# 2. Wire to fuse box (always-on USB-C)
# 3. Connect to truck WiFi or cellular SIM
# 4. Install PWA
# 5. Enable Knox Kiosk Mode (Samsung)
# 6. Test PIN login + offline mode
Drivers run BOTH the printed sheet AND the tablet in parallel. Confirm parity. Drop the printed sheet at end of week 1.
# Week 1: parallel run
# Week 2: tablet only, paper backup
# Week 3: tablet exclusive
# Add new features as drivers ask