Case Study — Lightside Frontiers Hub: an edge-rendered VC site on Cloudflare
What: the public site for Lightside Venture Capital — server-rendered at the edge, with a secure, edge-native pitch-submission flow.
Role: architect & engineer (hybrid Lovable + Claude Code workflow) · Where it lives: ~/Projects/lightside-frontiers-hub
Stack: TanStack Start (React 19) · Cloudflare Workers · Supabase · Zod · shadcn/Radix · Tailwind v4 · Bun
Prepared 2026-07-12
Status & honesty note: this is a real, deployable edge app (56
.tsxfiles, 7 routes, 46 UI components) built in a hybrid AI-native workflow — Lovable owns the primary edit loop, Claude Code is a focused secondary editor, and aCLAUDE.mddocuments exactly which machine-generated files must never be hand-edited. The architecture and security decisions below are real and demonstrate judgment regardless of how the code was typed; representing the build workflow honestly is part of the point.
1. Summary
A venture fund's site is mostly static content — but the one interactive surface, "pitch us," is where the engineering matters: it's a public, unauthenticated form, which means spam, injection, and secret-handling risk. Lightside Frontiers Hub renders the marketing site at the edge (TanStack Start on Cloudflare Workers) and handles the pitch flow with an edge server function that validates with Zod, defends against bots with a honeypot + timing trap, escapes everything before it templates an email, and keeps its service-role secret strictly server-side.
It's a compact, modern demonstration of edge-first full-stack: file-based routing, SSR at the edge, server functions, a disciplined shadcn/Radix design system, complete SEO, and a security-minded approach to the one place users can submit data.
2. What it is
The public Lightside VC site — seven file-based routes: index, thesis, portfolio, team, story, and contact (plus root). Everything is presentational except contact, which submits a founder's pitch. That single write path is the engineering focus of this case study.
3. Architecture at a glance
┌──────────────────── TanStack Start (React 19, file-based routing) ────────────────────┐
│ 7 routes · per-route SEO (title/description/OG/Twitter/canonical) │
│ UI: shadcn/ui (46 Radix components) · class-variance-authority + tailwind-merge · TW v4 │
├─────────────────────────────────────────────────────────────────────────────────────────┤
│ Edge runtime: Cloudflare Workers (wrangler.jsonc · main: @tanstack/react-start/server) │
│ ├─ SSR of every route at the edge │
│ └─ Server functions (createServerFn) — the pitch handler runs here, not in the client │
├─────────────────────────────────────────────────────────────────────────────────────────┤
│ Data/email: Supabase (anon client + service-role server client) · Resend (via gateway)│
└─────────────────────────────────────────────────────────────────────────────────────────┘
Build: Vite (@lovable.dev/vite-tanstack-config) · Bun · TanStack Query · analytics shim
4. Front end
- TanStack Start + TanStack Router — file-based routing (
src/routes/), React 19, SSR at the edge. - Design system — shadcn/ui: 46 Radix-based components in
src/components/ui/, composed withclass-variance-authority+tailwind-mergeon Tailwind CSS v4 (@tailwindcss/vite).lucide-reacticons,sonnertoasts,emblacarousel,recharts. - SEO, done properly — every route exports a
head()with title, description, Open Graph, Twitter card, and a canonical link (e.g.https://lightside.vc/contact). For a fund site, discoverability and link-preview polish are the product. - State/data —
@tanstack/react-query.
5. The edge server function — the engineering centerpiece
The pitch handler is a TanStack Start server function (createServerFn({ method: "POST" })) that executes on the Cloudflare Worker, never in the browser. It layers defenses:
1 · Schema validation (Zod). An .inputValidator runs ContactSchema.safeParse — names/emails/company/message with length caps and a constrained stage enum — and surfaces only a user-safe first-issue message (invalid_input:<field>), never raw validator internals.
2 · Anti-spam, defense-in-depth.
// Honeypot: a hidden `website` field must be empty. If a bot fills it,
// we RETURN SUCCESS anyway — so bots never learn what tripped them.
if (data.website) return { ok: true, id: null, submissionId: generateSubmissionId() }
// Timing trap: forms submitted in under 2s are almost certainly bots.
if (data.elapsedMs < 2000) return { ok: false, code: "too_fast", message: "…review your pitch…" }
The elapsedMs (time the form was on screen) and the hidden honeypot are both validated by the schema, and failures return typed error codes (invalid_input | honeypot | too_fast | config | send_failed) so the UI can respond precisely.
3 · Injection-safe email templating. Every user value is run through an escapeHtml() before it's interpolated into the HTML email body — the submitted message can't inject markup into the notification. A stable submissionId is generated for traceability.
4 · Graceful configuration degradation. If the email provider keys are absent, the function doesn't crash — it returns a config error with a human fallback ("email abhi@lightside.vc directly"). Missing infra degrades to a helpful message, never a 500.
5 · Delivery. The email is sent through a Resend connector gateway (bearer + connection-key headers), with reply_to set to the founder so replies just work.
6. Supabase — the client/server secret split
Two deliberately separate clients enforce secret hygiene:
| Client | Key | Runs | Purpose |
|---|---|---|---|
client.ts |
publishable/anon (VITE_*, build-time) |
browser + SSR | safe, RLS-bounded reads |
client.server.ts |
service-role (process.env only) |
edge server only | privileged writes — never shipped to the client |
A TanStack requireSupabaseAuth middleware (auth-middleware.ts) guards server functions that need a session. The service-role key exists only in process.env on the Worker — it can never leak into the client bundle, which is exactly the mistake this split prevents.
7. Observability
A small, SSR-safe analytics shim (src/lib/analytics.ts) forwards a trackEvent to whichever provider is loaded on the page — Plausible, PostHog, GA4, or a GTM dataLayer — guarding typeof window and falling back to a console log in dev. One call site, provider-agnostic, no crash if none is present.
8. Engineering patterns
- Edge-first — SSR and the write path both run on Cloudflare Workers; there's no separate origin server to operate.
- Defense-in-depth on the one public write — Zod + honeypot + timing + typed errors + HTML-escaping, layered rather than relying on any single check.
- Secret hygiene by construction — the anon/service-role split makes leaking the privileged key structurally hard.
- Graceful degradation — absent email config returns a helpful fallback, not an error page.
- SEO/link-preview completeness — per-route OG/Twitter/canonical, treated as a feature.
- Disciplined AI-native workflow — a
CLAUDE.mdenumerates machine-generated files (router codegen, the Lovable-owned Supabase client, auth middleware) that must never be hand-edited, preventing drift between the Lovable and local edit loops. Working cleanly inside a hybrid human/AI pipeline is itself a 2026 skill.
9. Outcomes & what it demonstrates
- Modern edge-stack fluency — TanStack Start SSR + server functions on Cloudflare Workers, a 46-component shadcn/Radix system, Tailwind v4, Bun, React Query.
- Security-minded form engineering — the pitch flow is handled the way a senior engineer handles an untrusted public write: validate, deter bots, escape output, protect secrets, degrade gracefully.
- Effective AI-native development — a real, coherent app shipped through a hybrid Lovable + Claude Code workflow with explicit guardrails — represented honestly.
Net: a small surface, engineered with the same discipline as a large one — which is exactly what "production instincts" means.
10. What's next
- Add server-side rate limiting on the pitch endpoint (Cloudflare KV / Durable Objects or Upstash) to complement the honeypot/timing checks.
- Persist submissions to a Supabase table (audit + CRM) in addition to the email, with RLS.
- A brief edge-vs-origin write-up (why Workers here, trade-offs) as a companion to the PartnerOS full-stack study.
Appendix · Stack & code map
| Layer | Technology |
|---|---|
| Framework | TanStack Start (@tanstack/react-start), React 19 |
| Routing | TanStack Router — file-based (src/routes/, 7 routes) |
| Runtime | Cloudflare Workers (wrangler.jsonc, nodejs_compat) |
| UI | shadcn/ui (46 Radix components), class-variance-authority, tailwind-merge, Tailwind v4 |
| Data / auth | Supabase (anon client + service-role server client, auth middleware) |
| Validation | Zod (react-hook-form + @hookform/resolvers) |
| Resend (via connector gateway) | |
| Build / tooling | Vite (@lovable.dev/vite-tanstack-config), Bun, ESLint, Prettier |
| Analytics | SSR-safe multi-provider shim (Plausible/PostHog/GA4/GTM) |
| Path | Responsibility |
|---|---|
src/routes/*.tsx |
File-based routes + per-route SEO head() |
src/server/contact.functions.ts |
Edge server function: Zod + honeypot + timing + escaped email |
src/integrations/supabase/client.ts |
Browser/SSR anon client (RLS-bounded) |
src/integrations/supabase/client.server.ts |
Edge-only service-role admin client |
src/integrations/supabase/auth-middleware.ts |
requireSupabaseAuth server middleware |
src/components/ui/* (46) |
shadcn/Radix design system |
src/lib/analytics.ts |
Provider-agnostic, SSR-safe event shim |
wrangler.jsonc |
Cloudflare Workers config |
CLAUDE.md |
AI-workflow guardrails (hands-off codegen files) |
Grounded entirely in the code on file in ~/Projects/lightside-frontiers-hub as read on 2026-07-12 (route/component counts, the server-function logic, and the Supabase client split are from the repository). The hybrid Lovable + Claude Code build workflow is stated plainly; no sole-hand-authorship claim is made.