Logo
← Back to Work

Lonell's Soul Food Brand site + SMS loyalty, owned by the restaurant.

A production site and SMS loyalty system for an independent LA soul food restaurant — owned brand, explicit consent, keyword join, and staff admin. No template. No third-party loyalty marketplace.

Lonell's Soul Food preview

The Problem

The first thing I did was pull up Google. Lonell's wasn't a blank slate — years of reviews were already sitting there, people talking about the fried chicken, the jazz nights, the whole feel of the place. This wasn't a restaurant that needed to be discovered. It needed to be reclaimed.

Except nobody could log into anything. Whoever had originally set up the Google Business Profile and the review accounts was long gone — no email on file anyone recognized, no password anyone had, no way back in. The restaurant's own reputation was sitting on the internet, and the people running the restaurant couldn't touch it.

So the ask wasn't "build us an online presence." It was narrower and more specific: show the menu, give the place a home online that actually looked like Lonell's, help people find them, and give the staff a simple way to keep guests coming back — without signing away the guest relationship to a platform, and without pretending the years of goodwill already out there didn't exist.

"A restaurant with real reviews and a following was locked out of the accounts that proved it — stuck between rebuilding from a template and handing the relationship to a loyalty platform it didn't need."

Templates don't know how to inherit a reputation. Loyalty SaaS doesn't care whose name is on the door. Nobody had a good answer for a restaurant that was already loved and just needed its own front door back. So I built one.

What it does

  • 01

    Brand-owned marketing site

    Dark theme, full-bleed hero, MENU/X overlay nav. Public pages for home, menu, story, events, entertainment, FAQ, private events, and reviews. The reviews page pulls Google and Yelp ratings by place ID, not by account login — years of reviews earned before this site existed still show up front and center, no reclaimed credentials required.

  • 02

    Explicit-consent loyalty join

    Web form at /join with marketing consent unchecked by default. Join records consent_at, consent_source, and consent types. Skipping texts still lets guests use the site — opt-in is never a condition of dining.

  • 03

    Keyword SMS + welcome promo

    Text SOUL to (424) 295-8020, or join on the web. Welcome message, promo SOUL10 — 10% off dinner, expires in 30 days. Guest shows the phone; staff redeem in admin.

  • 04

    Compliance-first messaging

    STOP / HELP / START handling per TCPA/CTIA expectations. Consent audit trail in Postgres. Dedicated privacy and SMS terms pages. Message frequency and program name stay explicit in copy carriers can review.

  • 05

    Role-gated admin ops

    Clerk auth with roles: owner, manager, staff. Subscribers, broadcast, messages, reviews, settings. Visit-log and promo-redeem actions so day-7 and win-back drips skip guests who already came back.

  • 06

    Simulated SMS / production Twilio switch

    SMS_ENABLED=false writes simulated outbound rows and runs the full join → welcome → admin loop without Twilio credentials. Flip the flag when the number and A2P campaign are ready — same code path, real sends.

The operational heart is the retention loop, not the homepage. A guest opts in on /join or by texting SOUL — welcome SMS lands with the dinner promo, they show the phone at the table, staff mark redeem or visit in admin, and later broadcasts and drip fields (review prompt, day-7 nudge, win-back) use that state instead of guessing from a spreadsheet of numbers.

New join

Welcome text · SOUL10 live 30 days

Promo redeemed

Visit logged · drip skips returners

Opted out

STOP honored · no further sends

Staff don't need a second system of record, and they don't need to have ever seen the accounts that came before this. Subscriber state in Neon is the single source of truth for who can be texted, who already redeemed, and who said stop.

How it grew

  1. Marketing shell

    Static brand site first: Astro pages, overlay nav, story, menu, events, entertainment. The reviews page pulled Google and Yelp ratings by place ID — a way to show off reputation the restaurant had already earned without ever touching the locked-out accounts. It needed to look like itself online before it needed a CRM.

  2. Loyalty MVP

    The /join form, consent fields, subscriber table in Neon via Drizzle. Web opt-in wrote consent_at and consent_source before any carrier traffic existed. The guest list started building the day the form went live — simulated or not.

  3. SMS + compliance

    Twilio behind SMS_ENABLED. Keyword flow (SOUL / STOP / HELP / MENU / EVENTS), welcome + promo expiry, message log with a simulated status. Privacy and SMS terms pages carried the program language carriers expect. End-to-end testing ran on simulated sends so staff could learn the flow before a single real text went out.

  4. Ops layer

    Clerk-gated admin: subscribers, broadcast, messages, reviews, settings. Visit / redeem actions, QR and in-store print assets, review-prompt / day-7 / win-back fields on the subscriber row. The owner runs the retention strategy from the same product as the brand site — no login handoffs, no third-party platform standing between the restaurant and its own guests.

Stack

  • Astro 5
  • TypeScript
  • Tailwind CSS 4
  • Neon Postgres
  • Drizzle ORM
  • Clerk
  • Twilio
  • Vercel