Redbeanco Detailing

Project Status Dashboard

Status Report

Date: 2026-07-13 Branch: review-backend-foundation (35 commits, local-only — no git remote) Audience: project owner / stakeholders Purpose: snapshot of timelines, goals, work done, and what remains across coding, testing, validation, and deployment.


At a glance

AreaStatusNotes
A. Landing page / marketing site (Zola SSG)Done14 pages, i18n (en/zh/zh-Hant), security headers, dark/gold brand
B. Booking system (form, validation, pricing)Done3-step wizard, live pricing from /api/prices, 59 unit tests
C. Payment (Stripe)PartialCheckout, webhooks, refunds, cancellation done; prod webhook + constant-time sig pending
D. Notifications (SMS/MMS/email, bilingual)PartialClickSend + Resend wired; delivery tracking, fallback, ACMA Sender ID pending
E. Staff PWAPartialDashboard/surcharge/photos/offline wired; CF Access JWT + ntfy push pending
F. Photo deliveryDoneDedicated photos worker (R2 presign + upload), MMS + email gallery
G. Data layer (D1)DoneSchema 001–005, parameterized queries, nanoid IDs, dev + prod DBs
H. SecurityPartialHeaders + webhook HMAC done; rate-limit, CSP tighten, JWT verify, CI audit pending
I. Developer experienceDoneNix flake, devenv, SecretSpec, testing runbook, secrets doc
J. Tier-2 Rust servicePartialCode mostly done (d1/r2 mirror, metrics, config); deploy + cf_metrics stub pending
K. MonitoringPartial4 Grafana dashboards done; alert rules + ntfy routing pending
L. TestingPartial59 unit tests, k6 + smoke scripts; no E2E Playwright, no integration suite
M. CI/CDPartialWorkflows exist; no Forgejo remote so CI never run; build-image.yaml missing
N. DeploymentNot startedNothing deployed; D1/R2 created, secrets not pushed, DNS/webhook pending

1. Project overview

A premium airport car-detailing booking system with a two-tier architecture:

  • Tier 1 (Edge / critical path): Cloudflare Pages (Zola SSG) + Workers (Rust→WASM) + D1 + R2 + Queues + Cron. Handles 100% of customer booking, payment, notification, and photo-delivery logic. Always on.
  • Tier 2 (Self-hosted / async): A Rust (axum) service on NixOS/k3s that mirrors D1/R2 to Garage (S3), exposes Prometheus metrics, and ships logs to Loki. Degrades gracefully if offline.

Guiding principle: No split-brain — D1 is the single source of truth; Tier 2 is outbound-polling only.

Tech stack: Zola · Cloudflare Workers (worker-rs) · D1 · R2 · Queues · Cron · Stripe Checkout · ClickSend (SMS/MMS) · Resend (email) · Rust/axum + Garage + Grafana/Prometheus · Nix (canonical build) · SecretSpec (secrets) · devenv.

2. Timeline & pace

First commit2026-07-11 (cea6a5c, implementation plan)
Latest commit2026-07-13 (6534a05)
Total commits35, over 3 days
Branchesmain, review-backend-foundation (active)
Git remoteNone configured (commits are local-only; cannot push/CI yet)
Original plan12 phases / 8+ weeks (docs/implementation-phases.md)

The Tier-1 edge path was built intensively in ~3 days — well ahead of the original week-by-week schedule for the customer-facing surface. The focus to date has been correctness + UX, not deployment.

3. Goals

  1. Customer: book → pay (Stripe) → get bilingual SMS/email confirmation → receive before/after photos via MMS + email gallery → cancel with refund.
  2. Staff: PWA to view/filter bookings, surcharge, upload photos, complete + deliver, cancel — works offline (IndexedDB queue + Background Sync).
  3. Operations: cron refunds expired surcharges; monitoring dashboards + alerts; daily business summary.
  4. Tier-2: async D1/R2 mirror to Garage, Prometheus metrics, Loki logs.
  5. Quality: WCAG 2.1 AA, i18n (en/zh/zh-Hant), <500KB pages, Nix-reproducible builds.

4. Work done — by large requirement

Legend: ✅ Done · 🟡 Partial · ⬜ Not started

A. Landing page / marketing site (Zola SSG) — ✅

  • ✅ Zola site, 14 pages, mobile-first SCSS <500KB
  • ✅ Premium dark/luxury brand: dark gold hero, gold accents, SVG monogram, focus rings, aria-live, emoji→SVG
  • ✅ FAQ / Privacy / Terms in en + zh + zh-Hant
  • ✅ Edge security headers via _headers
  • ⬜ Upfront services/pricing explainer page; customer status-tracking /track?id= page (planned, Phase 3 of UX plan, not built)
  • ⬜ Lighthouse >90 not verified

B. Booking system (form, validation, pricing) — ✅

  • ✅ 3-step wizard, inline validation, live pricing
  • ✅ Pricing decoupled: GET /api/prices (runtime fetch); prices.nix is source of truth; zola serve works without generated prices.json
  • ✅ Input validation + 11→59 unit tests
  • ✅ i18n en/zh/zh-Hant; zh-Hant switcher fixed
  • 🟡 Form persistence on flaky WiFi (sessionStorage) — planned, not built

C. Payment system (Stripe) — ✅ (core) / 🟡 (hardening)

  • ✅ Real Stripe Checkout Sessions for bookings + surcharges; metadata.booking_id reconciliation; real checkout_url
  • ✅ Webhook parses real checkout.session.completed (data.object + metadata); reconciles the same row (fixes double-booking); idempotent on stripe_event_id
  • ✅ Surcharge webhook handling (surcharge_pending → confirmed)
  • ✅ Real Stripe Refunds in cron, retaining $60 call-out fee
  • ✅ Cancellation with best-effort refund (customer + staff endpoints)
  • 🟡 Webhook sig verify: HMAC + timestamp tolerance done; constant-time compare + require secret in prod pending (Phase 1 security)
  • ⬜ Stripe webhook endpoint registration in Stripe dashboard (prod)
  • ⬜ Restricted-key permission verification (documented, not enforced in CI)

D. Notifications (SMS/MMS/email, bilingual) — 🟡

  • ✅ Real ClickSend SMS/MMS (Basic auth, base64) + Resend email; non-fatal on failure
  • ✅ Bilingual templates from prices.nix; MMS photo delivery + email gallery on completion
  • ✅ Mock mode (NOTIFICATIONS_MOCK) for dev; SecretSpec-managed secrets
  • ⬜ Delivery-status tracking (inbound webhooks ClickSend/Resend → audit)
  • ⬜ Cross-provider fallback (ClickSend↔Resend)
  • ⬜ Inbound SMS (customer replies)
  • ⬜ ACMA Sender ID registration verification

E. Staff PWA — ✅ (wiring) / 🟡 (auth + push)

  • ✅ Dashboard + detail wired to real /api/staff/bookings[/:id]; CORS + preflight
  • ✅ Surcharge (live new total, 12h countdown) + customer/staff cancel wired
  • ✅ Photo upload + complete → delivery
  • ✅ Offline: manifest, real icons, SW precache, network-first nav + offline fallback page, IndexedDB mutation queue + Background Sync
  • ✅ Photo compression (canvas, max 1920×1080, JPEG 85%)
  • CF Access JWT verification on /api/staff/* — needs team domain + audience (Phase 1, blocked on config)
  • ⬜ Push notifications for new bookings (ntfy) from the worker
  • 🟡 Background Sync replay — needs real-device verification

F. Photo delivery — ✅

  • ✅ Dedicated workers/photos owns R2 (PHOTOS bucket); presign + upload + OPTIONS preflight
  • ✅ Booking worker builds public URLs from PHOTOS_PUBLIC_BASE, persists photo_urls, delivers email gallery + MMS
  • ✅ Frontend uploads to photos worker via PHOTOS_API_BASE (dev :8788)
  • ⬜ Infra: create/public R2 bucket, set PHOTOS_PUBLIC_BASE + BOOKING_DOMAIN for prod
  • ⬜ CSP connect-src/img-src update if photos on separate origin

G. Data layer (D1) — ✅

  • ✅ Schema 001005: bookings, audit_log, surcharge/workflow columns, Stripe id persistence, idempotency constraints
  • ✅ All queries parameterized; nanoid booking IDs
  • ✅ D1 dev + prod databases created (real IDs in wrangler.toml)
  • ✅ Migrations path fixed + devenv migrate script

H. Security — 🟡

  • ✅ Security headers on Workers + Pages _headers; CORS
  • ✅ Webhook HMAC + timestamp tolerance
  • ✅ SecretSpec: no secrets in git; .dev.vars/.secrets.env gitignored
  • ⬜ CF Access JWT verify on staff routes (blocked on team domain)
  • ⬜ Rate limiting on /api/booking + /api/photos/presign
  • ⬜ Tighten CSP off 'unsafe-inline'
  • cargo audit / cargo clippy -D warnings / OWASP ZAP / gitleaks in CI
  • ⬜ R2 bucket policy (public read photos only, presign expiry)

I. Developer experience — ✅

  • ✅ Nix flake + devShell; nix build .#zola-site canonical
  • ✅ devenv: devenv up (local) + REMOTE=1 devenv up (live infra); port-aligned workers; migrate/secrets-check/deploy-secrets
  • ✅ SecretSpec integration (secretspec.toml, scripts/dev-worker.sh, scripts/deploy-secrets.sh) — verified end-to-end
  • ✅ Local testing runbook (docs/local-testing.md) + secrets doc (docs/secrets-management.md)
  • 🟡 devenv up not yet run live in this sandbox (env-specific .envrc store-link quirk); config validated via devenv eval

J. Tier-2 Rust service — 🟡 (code mostly done, not deployed)

  • ✅ Modules: main, config, d1_mirror, r2_mirror, metrics, cf_logs, cf_metrics
  • /metrics Prometheus, JSON tracing, graceful shutdown, env config (12-factor)
  • 🟡 cf_metrics.rs:95 — CF Analytics API call still a TODO stub
  • ⬜ Container image build/push (no .forgejo/workflows/build-image.yaml)
  • ⬜ k3s deployment (detailing-service.nix), ExternalSecret/OpenBao, ArgoCD
  • ⬜ Garage bucket + lifecycle (Phase 0.5, in nixos-redbeanco)
  • ⬜ Daily 8am ntfy business summary

K. Monitoring — 🟡

  • ✅ 4 Grafana dashboards (business-overview, service-health, cf-worker-metrics, blackbox-probes)
  • ✅ CF logs→Loki bridge code; Prometheus metrics code
  • Alert rules not written (monitoring/alerts/ is empty) — RefundCronFailure, MirrorLagHigh, DetailingServiceDown, etc.
  • ⬜ ntfy routing; UptimeRobot; CF Dashboard alerts
  • ⬜ ntfy urgent alert on refund failure (cron lib.rs:105 TODO)

L. Testing — 🟡

  • ✅ Unit: 59 pass (booking 30 / cron 9 / shared 7 / webhook 13)
  • ✅ k6 load scripts: booking-flow.js, health-check.js
  • ✅ Smoke scripts: test-booking.sh, test-health.sh
  • E2E Playwright — none written (README lists it; tests/ has only load/)
  • ⬜ Automated integration suite (Stripe test mode) — only manual local testing documented
  • ⬜ Load test execution + p95 targets; OWASP ZAP; manual pen test

M. CI/CD — 🟡

  • .forgejo/workflows/ci.yaml + deploy-cf.yaml exist; flake-modules/ci.nix
  • ⬜ No Forgejo remote → CI has never run
  • ⬜ No build-image.yaml for the Rust service container
  • ⬜ Deploy workflows untested

N. Deployment — ⬜

  • ⬜ Nothing deployed: no CF Pages publish, no Worker wrangler deploy, no Rust service on k3s
  • ✅ CF D1 (dev+prod) + R2 buckets created (IDs in toml); Queues/Cron provision-on-deploy
  • ⬜ Prod secrets not pushed (deploy-secrets ready but not run)
  • ⬜ Domain DNS (forbrisbane.org), DKIM/SPF, Stripe webhook registration
  • ⬜ QR code printing/placement

5. 12-phase plan vs actual (concise)

PhasePlanStatus
0 Foundation + accountsWeek 1✅ repo/dev/schema/prices; 🟡 accounts (CF✅, Stripe/ClickSend/Resend keys exist, Forgejo remote⬜, domain? )
0.5 Garage (k3s)Week 1⬜ (cross-repo nixos-redbeanco)
1 Zola frontend + i18nWeek 2✅ (minus Lighthouse verify, deploy)
2 D1 + Workers coreWeek 3
3 Stripe integrationWeek 4✅ (minus prod webhook registration)
4 NotificationsWeek 5🟡 (core✅; delivery-status/fallback/inbound⬜)
5 Staff PWAWeek 5-6🟡 (wiring✅; CF Access + ntfy push⬜)
6 Surcharge/refund cronWeek 6🟡 (core✅; ntfy alert + dead-letter⬜)
7 Rust async serviceWeek 7🟡 (code✅; cf_metrics stub; deploy⬜)
8 Monitoring & alertsWeek 7-8🟡 (dashboards✅; alert rules⬜)
9 Security hardeningWeek 8🟡 (headers✅; rate-limit/CSP-tighten/JWT/CI-audit⬜)
10 Testing & QAWeek 9🟡 (unit✅; E2E/integration/load-run/security⬜)
11 Launch prepWeek 10
12 Post-launchOngoing

6. Known code-level gaps to close

  • workers/cron/src/lib.rs:105 — ntfy urgent alert on refund failure (real TODO).
  • rust-service/src/cf_metrics.rs:95 — CF Analytics API call stub.
  • workers/booking/src/lib.rs:354/470/612stale "TODO (Phase 3/6/5)" doc-comments on handle_booking/handle_surcharge/handle_complete; those features are implemented — clean up the comments.
  • monitoring/alerts/ — empty; needs the alert rule files listed in Phase 8.
  • No Playwright E2E; no build-image.yaml; no Forgejo remote.

7. Risks / blockers

  1. No Forgejo remote — blocks CI, review, and any deploy pipeline.
  2. CF Access team domain + audience needed before staff JWT verification (Phase 1).
  3. R2 public bucket + PHOTOS_PUBLIC_BASE needed before photo delivery works in prod.
  4. Stripe webhook endpoint must be registered in the Stripe dashboard for prod.
  5. Background Sync needs a real-device test.
  6. Account readiness: ClickSend Sender ID (ACMA), Resend domain verification, domain registration/DNS — status unconfirmed.
  7. devenv up live run hit a sandbox-specific .envrc store-linking error here (config is valid); confirm it runs on the dev machine.

8. Suggested next steps (prioritized)

  1. Set up Forgejo remote + push review-backend-foundation → unblock CI.
  2. Phase 1 security: CF Access JWT verify (needs team domain/audience), rate limiting, tighten CSP — then the staff PWA is production-safe.
  3. Infra + first deploy: create/public R2 bucket, set PHOTOS_PUBLIC_BASE
    • BOOKING_DOMAIN, deploy-secrets, wrangler deploy workers, CF Pages publish, register Stripe webhook, DNS.
  4. Testing: write Playwright E2E (booking en+zh, staff, surcharge, cancel); run k6 to p95 target; OWASP ZAP + cargo audit/clippy in CI.
  5. Monitoring: write monitoring/alerts/ rules + ntfy routing; add ntfy refund-failure alert in cron.
  6. Notifications: delivery-status tracking + cross-provider fallback.
  7. Tier-2: finish cf_metrics, add build-image.yaml, deploy Rust service to k3s + Garage (coordinate with nixos-redbeanco).
  8. Cleanup: remove stale TODO comments; verify Lighthouse.
  9. Launch prep (Phase 11): QR print, staff training, rollback drill, prod end-to-end test booking.

Bottom line: The Tier-1 customer + staff + payment + notification + photo-delivery surface is functionally complete and locally verified (59 unit tests, site builds, secretspec + devenv validated). What remains is security hardening, automated E2E/load/security tests, alert rules, the Tier-2 deploy, and actual production deployment — plus wiring up a Forgejo remote so CI/deploy can run.