WorkThe April wave
Kaiplan
A wedding planning workspace with a budget ledger, guest list, seating chart, vendor tracker, and a public wedding website guests could RSVP to without an account.
- Ran on
- Cloudflare
- Ran
- April 2026 to June 2026
- Domain
- Wedding planning
That platform choice is part of a longer migration: Azure, then Railway, then Cloudflare, across the whole estate. Read how and why.
Built with
- Cloudflare Workers
- Hono
- React 19
- Astro
- Neon Postgres
- D1
- Drizzle
Hosted services
- Cloudflare Workers
- Hyperdrive
- D1
- Durable Objects
- R2
- Cron Triggers
- Turnstile
- Neon Postgres

The decision
A seating chart was one jsonb column per wedding, and every seat inside it held a guestId
pointing at the normalized guest table: a foreign key Postgres could not see or enforce inside a
JSON blob. A guest could also decline from the public wedding website without ever logging in, so
the row that invalidated a seat could change from outside any session.
Four mechanisms enforced the invariant the schema could not express: a zod refinement blocking a chart that seated the same guest twice, a transactional re-read on save that rejected a stale reference, a self-repairing read that dropped assignments for guests who had since declined or been deleted, and seven call sites that stripped a guest out of the chart in the same transaction that removed them.
The call site that mattered was the seventh: the public RSVP handler, reachable with no session at
all, behind a rate limiter and a Turnstile check. That route lived inside
apps/api/src/routes/wedding-website.ts, 1,559 lines carrying most of the guest-facing surface, and
it sat outside the per-file coverage gate: the highest-risk call site and the thinnest test
evidence sat in the same file.
Architecture
Three Cloudflare Workers sat in front of two databases and one Durable Object: a React SPA for the couple, an Astro site for guests and marketing, and a Hono API between them. Postgres, behind Hyperdrive with a pool capped at one connection, held the transactional product data: weddings, guests, budgets, vendors, seating charts.
A separate Cloudflare D1 instance held marketing signups, pricing clicks, and email preferences, bound into both the product API Worker and the marketing Worker, so a transactional product email could honor an unsubscribe made from a marketing footer without either Worker touching the other’s primary store.
Stripe webhook verification ran through Stripe.createSubtleCryptoProvider(), since the Workers
runtime has no Node crypto module to verify signatures the usual way. Five nightly maintenance
jobs, scheduled through Cron Triggers, ran strictly in series to match Hyperdrive’s single-connection
pool, each job holding that one connection until it finished before the next began.
By the numbers
Each figure carries where it came from and when it was measured. Open one to see the command behind it, where the repository recorded a command.
- Application source
- 230,851 lines across 981 files
Provenance
Source portfolio/METRICS.md § 1. Lines of code
git ls-files | grep -E '\.(ts|tsx|astro|css|sql|mjs)$' | xargs cat | wc -lMeasured
- Source vs test
- 89,693 source, 141,158 test (test outweighs source 1.57 : 1)
Provenance
Source portfolio/METRICS.md § 2. Source against test
Measured
- Test cases
- 6,929 across 425 test files, 13,758 assertions
Provenance
Source portfolio/METRICS.md § 3. Test files, cases, assertions
git ls-files | grep -E '\.(test|spec)\.(ts|tsx)$' | xargs grep -cE '^\s*(it|test)(\.\w+)?\(' | awk -F: '{t+=$2} END{print t}'Measured
- Coverage gate
- 95% per file (lines, functions, branches, statements) across the unit-tested code in all 8 workspace packages
Provenance
Source portfolio/METRICS.md § 4. The coverage gate
Measured
- End-to-end
- 24 Playwright specs, 96 running cases, across 3 device profiles
Provenance
Source portfolio/METRICS.md § 5. End-to-end
git ls-files | grep -cE '^e2e/.*\.spec\.ts$'Measured
- API and data surface
- 79 HTTP endpoints across 14 route modules; 20 Postgres tables over 25 migrations; 9 D1 tables over 14 migrations
Provenance
Source portfolio/METRICS.md § 6. Surface and data
git ls-files 'apps/api/src/routes/*.ts' | grep -v test | xargs grep -hcE '^\s*app\.(get|post|put|patch|delete)\(' | awk '{t+=$1} END{print t}'Measured
- Marketing content
- 247 Markdown entries across 6 Astro collections (133 guides, 29 listicles, 26 comparisons, 24 pricing breakdowns, 19 alternatives, 16 lead magnets)
Provenance
Source portfolio/METRICS.md § 6. Surface and data: The 247 marketing entries
git ls-files 'apps/web/src/content/**' | sed 's|apps/web/src/content/||;s|/.*||' | sort | uniq -cMeasured
- History
- 469 commits, 2026-04-07 to 2026-07-08, 1 contributor
Provenance
Source portfolio/METRICS.md § 7
Measured
Screens




Its portfolio/ directory holds the architecture, metrics and testing documents these figures were taken from.