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
| Area | Status | Notes |
|---|---|---|
| A. Landing page / marketing site (Zola SSG) | Done | 14 pages, i18n (en/zh/zh-Hant), security headers, dark/gold brand |
| B. Booking system (form, validation, pricing) | Done | 3-step wizard, live pricing from /api/prices, 59 unit tests |
| C. Payment (Stripe) | Partial | Checkout, webhooks, refunds, cancellation done; prod webhook + constant-time sig pending |
| D. Notifications (SMS/MMS/email, bilingual) | Partial | ClickSend + Resend wired; delivery tracking, fallback, ACMA Sender ID pending |
| E. Staff PWA | Partial | Dashboard/surcharge/photos/offline wired; CF Access JWT + ntfy push pending |
| F. Photo delivery | Done | Dedicated photos worker (R2 presign + upload), MMS + email gallery |
| G. Data layer (D1) | Done | Schema 001–005, parameterized queries, nanoid IDs, dev + prod DBs |
| H. Security | Partial | Headers + webhook HMAC done; rate-limit, CSP tighten, JWT verify, CI audit pending |
| I. Developer experience | Done | Nix flake, devenv, SecretSpec, testing runbook, secrets doc |
| J. Tier-2 Rust service | Partial | Code mostly done (d1/r2 mirror, metrics, config); deploy + cf_metrics stub pending |
| K. Monitoring | Partial | 4 Grafana dashboards done; alert rules + ntfy routing pending |
| L. Testing | Partial | 59 unit tests, k6 + smoke scripts; no E2E Playwright, no integration suite |
| M. CI/CD | Partial | Workflows exist; no Forgejo remote so CI never run; build-image.yaml missing |
| N. Deployment | Not started | Nothing 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 commit | 2026-07-11 (cea6a5c, implementation plan) |
| Latest commit | 2026-07-13 (6534a05) |
| Total commits | 35, over 3 days |
| Branches | main, review-backend-foundation (active) |
| Git remote | None configured (commits are local-only; cannot push/CI yet) |
| Original plan | 12 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
- Customer: book → pay (Stripe) → get bilingual SMS/email confirmation → receive before/after photos via MMS + email gallery → cancel with refund.
- Staff: PWA to view/filter bookings, surcharge, upload photos, complete + deliver, cancel — works offline (IndexedDB queue + Background Sync).
- Operations: cron refunds expired surcharges; monitoring dashboards + alerts; daily business summary.
- Tier-2: async D1/R2 mirror to Garage, Prometheus metrics, Loki logs.
- 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.nixis source of truth;zola serveworks without generatedprices.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_idreconciliation; realcheckout_url - ✅ Webhook parses real
checkout.session.completed(data.object + metadata); reconciles the same row (fixes double-booking); idempotent onstripe_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/photosowns R2 (PHOTOSbucket);presign+upload+ OPTIONS preflight - ✅ Booking worker builds public URLs from
PHOTOS_PUBLIC_BASE, persistsphoto_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_DOMAINfor prod - ⬜ CSP
connect-src/img-srcupdate if photos on separate origin
G. Data layer (D1) — ✅
- ✅ Schema
001–005: 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
migratescript
H. Security — 🟡
- ✅ Security headers on Workers + Pages
_headers; CORS - ✅ Webhook HMAC + timestamp tolerance
- ✅ SecretSpec: no secrets in git;
.dev.vars/.secrets.envgitignored - ⬜ 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-sitecanonical - ✅ 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 upnot yet run live in this sandbox (env-specific.envrcstore-link quirk); config validated viadevenv eval
J. Tier-2 Rust service — 🟡 (code mostly done, not deployed)
- ✅ Modules:
main,config,d1_mirror,r2_mirror,metrics,cf_logs,cf_metrics - ✅
/metricsPrometheus, 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:105TODO)
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 onlyload/) - ⬜ 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.yamlexist;flake-modules/ci.nix - ⬜ No Forgejo remote → CI has never run
- ⬜ No
build-image.yamlfor 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-secretsready but not run) - ⬜ Domain DNS (
forbrisbane.org), DKIM/SPF, Stripe webhook registration - ⬜ QR code printing/placement
5. 12-phase plan vs actual (concise)
| Phase | Plan | Status |
|---|---|---|
| 0 Foundation + accounts | Week 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 + i18n | Week 2 | ✅ (minus Lighthouse verify, deploy) |
| 2 D1 + Workers core | Week 3 | ✅ |
| 3 Stripe integration | Week 4 | ✅ (minus prod webhook registration) |
| 4 Notifications | Week 5 | 🟡 (core✅; delivery-status/fallback/inbound⬜) |
| 5 Staff PWA | Week 5-6 | 🟡 (wiring✅; CF Access + ntfy push⬜) |
| 6 Surcharge/refund cron | Week 6 | 🟡 (core✅; ntfy alert + dead-letter⬜) |
| 7 Rust async service | Week 7 | 🟡 (code✅; cf_metrics stub; deploy⬜) |
| 8 Monitoring & alerts | Week 7-8 | 🟡 (dashboards✅; alert rules⬜) |
| 9 Security hardening | Week 8 | 🟡 (headers✅; rate-limit/CSP-tighten/JWT/CI-audit⬜) |
| 10 Testing & QA | Week 9 | 🟡 (unit✅; E2E/integration/load-run/security⬜) |
| 11 Launch prep | Week 10 | ⬜ |
| 12 Post-launch | Ongoing | ⬜ |
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/612— stale "TODO (Phase 3/6/5)" doc-comments onhandle_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
- No Forgejo remote — blocks CI, review, and any deploy pipeline.
- CF Access team domain + audience needed before staff JWT verification (Phase 1).
- R2 public bucket +
PHOTOS_PUBLIC_BASEneeded before photo delivery works in prod. - Stripe webhook endpoint must be registered in the Stripe dashboard for prod.
- Background Sync needs a real-device test.
- Account readiness: ClickSend Sender ID (ACMA), Resend domain verification, domain registration/DNS — status unconfirmed.
devenv uplive run hit a sandbox-specific.envrcstore-linking error here (config is valid); confirm it runs on the dev machine.
8. Suggested next steps (prioritized)
- Set up Forgejo remote + push
review-backend-foundation→ unblock CI. - Phase 1 security: CF Access JWT verify (needs team domain/audience), rate limiting, tighten CSP — then the staff PWA is production-safe.
- Infra + first deploy: create/public R2 bucket, set
PHOTOS_PUBLIC_BASEBOOKING_DOMAIN,deploy-secrets,wrangler deployworkers, CF Pages publish, register Stripe webhook, DNS.
- Testing: write Playwright E2E (booking en+zh, staff, surcharge, cancel); run k6 to p95 target; OWASP ZAP +
cargo audit/clippyin CI. - Monitoring: write
monitoring/alerts/rules + ntfy routing; add ntfy refund-failure alert in cron. - Notifications: delivery-status tracking + cross-provider fallback.
- Tier-2: finish
cf_metrics, addbuild-image.yaml, deploy Rust service to k3s + Garage (coordinate withnixos-redbeanco). - Cleanup: remove stale TODO comments; verify Lighthouse.
- 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.