Skip to content
Evangeline Café logo
Small Business Rescue · No-Code OpsLive in production

Evangeline Café

A South Austin Cajun institution, off a 2000s website

www.evangelinecafe.com

Evangeline Café has been serving Cajun and Creole food in South Austin since the early 2000s, with live music most nights. Its website was from roughly the same era. The rebuild had one hard constraint that shaped everything: whatever replaced it had to be maintainable by restaurant staff, during service, without training.

6
Pages, hand-authored
17+
AI crawlers explicitly allowed
3
Fallback tiers on the calendar
11.5K
Lines of source

The problem

Restaurant websites rot for a predictable reason: the events calendar. A developer builds an admin panel, staff use it twice, then the calendar shows last spring's lineup forever and the whole site starts looking abandoned.

Any CMS was the wrong answer. A busy kitchen is not going to log into a headless content platform to add Thursday's band, and a monthly retainer to have someone else do it is exactly the cost this business didn't want.

What we built

The CMS is a Google Sheet

Staff edit a spreadsheet — a tool they already use and cannot break in an interesting way. The sheet is published to the web as CSV and the site reads it. No login, no training, no admin panel to maintain.

Three tiers so it never shows empty

The calendar fetches server-side at request time to produce the Schema.org event markup search engines need, re-fetches client-side so an edit appears without a redeploy, caches to localStorage, and falls back to a static set if Sheets is unreachable. A spreadsheet is not a highly-available service, so it is treated as one input rather than a dependency.

Parsing a spreadsheet defensively

Published CSV from a spreadsheet is untrusted input: it contains whatever someone typed, including commas inside quoted fields and arbitrary URLs in the link column. The component uses a hand-rolled quoted-CSV parser and a URL sanitiser that allowlists http and https only, so a pasted javascript: URL can't become an XSS vector.

Reviews and enquiries wired to real services

Google reviews are pulled through the Places API and cached at the edge for a week with stale-while-revalidate. The contact form verifies a Cloudflare Turnstile token server-side before sending through Resend.

Engineering highlights

The parts that were genuinely hard — and how they were solved.

A documented security trade-off, not a silent one

Astro's default origin check had to be disabled: Vercel's edge rewrites the Origin header, which was rejecting the legitimate multipart form post. The config carries an inline explanation of why, plus the compensating control — server-side Turnstile verification, and a site with no cookies or sessions to forge against. A workaround that explains itself is a workaround the next engineer can safely evaluate.

Built to be quoted by AI, not just crawled

A structured llms.txt fact file — hours, address, menu, phone — sits alongside a robots.txt that names and admits seventeen-plus AI crawlers individually. When someone asks an assistant where to get gumbo in South Austin, the goal is that the assistant has clean facts to answer with.

A reproducible migration path

A Cheerio-based scraper captured the legacy site into structured JSON, and a Sharp pipeline converted the image library to WebP with per-file size reporting. The menu itself was transcribed by hand from photographs of the physical menu, because OCR on a laminated menu is not accurate enough to publish prices from.

Where it stands

  • Live at evangelinecafe.com, replacing the legacy static site.
  • Staff update the live-music calendar themselves in a spreadsheet, with zero developer involvement.
  • Event data emits Schema.org markup on every render, so listings are eligible for rich results.

The stack

Framework
Astro 5Server outputVercel adapter
Content
Google Sheets CSVHand-rolled CSV parserStatic fallback
Services
ResendCloudflare TurnstileGoogle Places API
Media
SharpWebP pipelineCheerio migration scraper
Growth
Schema.org eventsllms.txtAI crawler allowlist
Third-party services wired in
Google SheetsGoogle Places APIResendCloudflare Turnstile