zsty.us

Before / After · Case Study

DJ Jackie J — bland WordPress to a three-offer entertainment brand

  • Local Pro Services
  • Events & Entertainment

Took over a 12-year wedding & event DJ's online presence — a half-built WordPress site, three Instagram handles she manually managed, inquiries that took 24+ hours to answer. Shipped a real marketing site, wired consent-first SMS opt-ins for repeat-booking, and stood up an agent backbone that drafts ads, scrapes local OC event listings, and pushes inquiries to her phone the moment they land. Then the brand outgrew the booth: 2026-07 shipped Jackie J & The Diamonds — a configurable 5–11-piece live show band — plus an Acoustic Duo, turning a DJ site into a three-offer entertainment brand (DJ · live band · acoustic) with a cinematic /band page and a live promo reel, merged and live on both domains.

Jackie's brand should earn while she sleeps — without ever taking her voice out of the booth.
🔒https://jackiej.events
jackiej.events — modern site

Receipts — measured

Numbers that moved.

32/100
Lighthouse · mobile
was 32/100
1600ms
Time-to-first-byte (p75)
was 1600ms
24.0min
Inquiry → notification
was 24.0min
0 events/yr
5★ proof preserved
was 0 events/yr
  • 5★ across The Knot / WeddingWire / Thumbtack preserved through cutover
  • Inquiry → notification latency: 24h → <30s (push)
  • Bid submission flow: manual → draft-for-review agent
  • Live event-vendor scraping across OC public listings
  • Admin sign-in: password form → Google OAuth one-click + magic-link SSO
  • /admin/edit visual editor (Puck) — 15 blocks, draft/published versioning per page
  • Dashboard chatbot: one-shot reply → 8-tool Anthropic orchestrator, confirm-required sends
  • Slack #jackie-j-events polled every 5 min → triage queue → typed action executors
  • One brand → three offers: DJ · Jackie J & The Diamonds (5–11 piece) · Acoustic Duo
  • Slack → OpenClaw codegen daemon: a Slack message becomes a gated worktree code change

The pixel diff

Overview, then the walkthrough.

Left: everything the legacy site shipped — frozen in place. Right: an auto-scrolling tour of the rebuild, from hero to booking. No slider to fight with.

Before — the overview
🔒https://djjackiej.com
Before — the overview

This is everything the legacy site had to offer above the fold. No pricing, no calendar, no booking — the funnel ended at a mailto.

After — scroll through what shipped
🔒https://jackiej.events
After — scroll through what shipped

Auto-scrolls through the modern site so you can see the booking surface, the package grid, the pricing table, and the calendar inline — without leaving this page.

Tap a pin. The story is in the pixels.

Before — what was broken
🔒https://djjackiej.com
Before
After — what shipped
🔒https://jackiej.events
After

The four beats

Problem · Insight · Build · Outcome.

Scroll past the legacy frame. The four beats land in order. At the end, the modern site fades into the same window.

🔒https://djjackiej.com
Legacy
01 · Problem

An under-construction WordPress site greeting every visitor for 14+ months.

Jackie's old site had been promising a relaunch since early 2024. Visitors landed on a half-rendered hero, three placeholder boxes, and an 'under construction' banner. No pricing, no calendar, no way to book.

02 · Insight

Her brand is the booth, but her funnel was her phone.

Every inquiry routed through email → maybe-checked → maybe-answered next day. The brand was strong (5★ across The Knot / WeddingWire / Thumbtack) but the funnel leaked any lead that needed an answer in under 24 hours.

03 · Build

Real marketing site + an agent backbone that works while she sleeps.

Shipped jackiej.events on Next.js + Tailwind. Wired TCPA-clean SMS opt-in capture feeding the central og_life comms store. Stood up the OpenClaw Haiku agent to scrape OC vendor pages every 5 min and draft tailored applications for one-tap approval. Push notifications fire to Jackie's phone the moment a bid lands.

04 · Outcome

Inquiry latency cut by 99%. Brand keeps earning between gigs.

Lighthouse mobile 32 → 99. TTFB 1.6s → 180ms. Inquiry → notification 24h → 30s. Every vendor call in OC within 30 miles is now surfaced + drafted within an hour — she wakes up to qualified gigs ready to one-tap submit.

05 · Iteration

The same project keeps growing operator-grade tooling, every push.

After launch it kept shipping: password sign-in hardened into Google OAuth + magic-link SSO, a Puck visual editor wired to Postgres, the dashboard chatbot rebuilt into an 8-tool Anthropic orchestrator, and a Slack-as-frontend triage queue that turns a #jackie-j-events message into a classified, approvable action. One Vercel project, all live — behind a deliberate two-step deploy gate (main = previews; prod promotes from the production branch).

06 · The band era

DJ brand → three-offer entertainment brand.

2026-07: Jackie J & The Diamonds launched as a full product line — cinematic /band hero, live promo reel, 5–11-piece configurations, an Acoustic Duo — merged production → main and live on both domains. Under it, the plumbing kept compounding: push and SMS moved onto the central og_life multi-brand rails, the DB migrated live from Neon to Prisma Postgres, the inquiry funnel got rate-limits + honeypot + double-submit guards, and the Slack → OpenClaw codegen daemon (Mission 2) turned Slack messages into gated worktree code changes.

🔒https://jackiej.events
Modern

Architecture

One chain replaced by another. Receipts above.

Old stack
  • WordPress
  • Elementor
  • WPEngine cache
  • Cloudflare CDN
  • Manual IG posts
  • Email-only inquiry
New stack
  • Next.js 16 + React 19
  • Tailwind 4
  • Drizzle + Prisma Postgres
  • NextAuth (Google + magic-link)
  • SMS consent store → og_life rails
  • Resend transactional
  • Web Push → central og_life store
  • OpenClaw agent (Haiku)
  • Slack → codegen daemon (worktrees)
  • Live tracking (trips + heartbeats)
  • Puck visual editor
  • Slack ingest (Vercel Cron)
  • Triage classifier (Sonnet)

What changed

Grouped by what kind of system shipped.

Each claim ships with concrete evidence — env vars, table names, cadence chips. No marketing fluff.

Design

Real marketing site, mobile-first

Cut the under-construction WordPress and shipped a Next.js + Tailwind site with real sections: pricing, packages, calendar, booking. The Knot / WeddingWire / Thumbtack 5★ proof is on the page. Loads in under a second on a 4G phone.

Before
Single landing page with a hero, three placeholder boxes, and an under-construction banner.
After
Full booking funnel with a public calendar, transparent packages, and direct SMS opt-in.
  • Lighthouse 99/100 mobile (was 32/100 on the WP site)
  • TTFB 1.6s → 180ms p75
  • Real /pricing, /packages, /calendar surfaces (legacy had none)
Retention

Consent-first SMS opt-in + per-referrer QR codes

Every business card carries a unique /optin?ref=… link backed by a printable QR. Subscribers go through a TCPA-clean opt-in with an explicit consent checkbox; consent rows persist to the site's own opt_ins table — owned data, not a vendor list. The forward path is the central og_life SMS store (same multi-brand rails the push path already rides), with AWS 10DLC registration filed for the sending number.

Before
Repeat clients had to text Jackie's personal cell.
After
Subscribers opt in once, with recorded consent, into a store the brand owns.
  • /api/sms/subscribe writes consent rows (phone, consent state, source ref) to opt_ins
  • Per-card QR tracking — Jackie can see which gig drove which signups
  • Central-store proxy wired (brand jackiejevents, same ingest secret as push); AWS 10DLC registration Step 1 filed
Agent backbone

SEO agent backbone — posts ads while she sleeps

Python agent on the OpenClaw machine polls every 5 minutes via launchd. Queued tasks flow through Claude Haiku: scour local OC event-vendor pages, draft applications, draft outbound DM replies, refresh Google Business posts. Every outbound is a draft — Jackie approves before anything goes live (her explicit choice).

Before
Jackie scrolled IG hashtags between sets to find vendor calls.
After
Agent surfaces ranked opportunities each morning with pre-drafted applications.
  • 5-min polling cadence, launchd-managed (no Cron drift)
  • Targets: Eventbrite OC vendor calls, Meetup events, IG hashtag scans
  • Draft-for-review — never auto-posts without Jackie's tap
Agent backbone

Auto-applies to be a vendor on scraped OC event pages

Same agent watches public Orange County event-listing surfaces — fairs, weddings expos, local-business mixers — extracts vendor application links, and queues a tailored application for Jackie to one-tap approve. She wakes up to a list of qualified gigs already drafted.

Before
Vendor opportunities slipped past during peak season — too many sites, no time.
After
Every public OC vendor call within 30 miles is surfaced + pre-drafted within an hour.
  • Per-event tailored cover note (uses Jackie's voice, not boilerplate)
  • De-dupes against already-applied events automatically
  • Surfaces in /dashboard with a single Approve → Submit button
Real-time push

Real-time inquiry push (PWA), not email

Every inbound — bid request, calendar question, review reply — fires a Web Push to Jackie's phone via her installed PWA. She taps the notification, the app opens straight to the relevant inbox thread. Push now rides the central og_life push store (brand jackiejevents): the site route is a thin proxy, and the same multi-brand rails serve every property in the portfolio — one keypair, one ingest secret, zero new infra per brand.

Before
Inquiries arrived as email; replies came hours or days later, if at all.
After
Phone buzzes the moment a bid lands; Jackie can reply from the lock screen.
  • PR #7 merged: standalone VAPID keys retired; /api/push proxies the central og_life push store
  • Average inquiry → notification: <30 seconds end-to-end
  • Tap-through deep-links to the exact inbox thread
Design

Puck visual editor wired to Postgres

/admin/edit is a real drag-and-drop editor (Puck) with 15 typed blocks — hero, services, calendar, reviews, the disco-ball accent, the parallax scene, the Instagram embeds row. Edits save as drafts and publish per page; every version is kept in Neon so a change can be rolled back.

Before
Copy changes meant a code edit + redeploy, every time.
After
Jackie (or Brendon) edits the live page visually; drafts publish without touching the repo.
  • 15 Puck blocks in src/puck/config.tsx
  • puck_pages + puck_page_versions tables (draft/published per page)
  • Auth-gated — redirects to /dashboard/sign-in if not an owner
Agent backbone

Tool-using chatbot for Jackie's dashboard

/dashboard/ai runs a real Anthropic tool-use loop (Sonnet, 6-iteration cap) over 8 hard-typed tools — it can search inquiries, pull a full client record, check the calendar for open weekends, draft a reply in Jackie's voice, and send it. Every send needs an explicit confirm and is audit-tagged in the messages table.

Before
Jackie re-read threads and hand-wrote every reply on her phone.
After
She asks for an inquiry in plain English; the bot finds it, drafts the reply, and sends only on her confirm.
  • 8 tools: search_inquiries, get_inquiry, search_clients, draft_message, send_message, queue_long_task, check_calendar, generate_brochure
  • Sends require confirm:true and are tagged ai:chat:<email>
  • Errored tools return is_error so Claude can recover mid-loop
Agent backbone

Slack-as-frontend triage queue

A Vercel Cron polls #jackie-j-events every 5 minutes for /jj or @JACKIEBOT messages and pushes them into a deduped triage queue. An Anthropic classifier sorts each into one of 8 typed actions — swap a hero photo, update text, add an event, queue for research/dev — and a whitelisted few execute straight into the published Puck page; the rest wait for one-tap approval at /admin/queue.

Before
Quick-change requests lived in scattered texts and got lost.
After
A Slack message becomes a classified, approvable action — some apply themselves, the rest are one tap away.
  • triage_queue table with unique (source, source_ref) dedup index
  • 8 typed action kinds → executor framework (swap_hero_photo + update_text write puck_pages.home.published)
  • LIVE_SAFE_WHITELIST gates auto-approval; everything else queues for Brendon
Real-time push

Admin notification tree across 6 sources

The /dashboard sidebar carries an admin-only bell that aggregates six signals — Slack ingest, new inquiries, triage-queue activity, and more — on a 30-second poll, so nothing waits on someone remembering to check a tab.

Before
Status lived in N separate places; you found out when you looked.
After
One bell rolls up every operational signal the moment it lands.
  • 6 aggregated sources, 30s poll, admin-only
  • Surfaces alongside the Web Push path, not in place of it
  • Built on the same Auth.js owner/allowlist role layer
Design

The band era — Jackie J & The Diamonds ships as a product line

2026-07: the site stopped being DJ-only. A cinematic /band page (framed lineup photo over a moody backdrop), a live promo reel with non-teardown unmute, and configuration tiles for a 5–11-piece show band plus an Acoustic Duo — the brand now sells three offers from one homepage: DJ · live band · MC. Band content merged production → main and confirmed live on both domains.

Before
One offer: DJ sets.
After
Three offers — DJ, a configurable 5–11-piece band, an acoustic duo — one funnel.
  • BandHero rewrite (149 lines) + BandCinema promo reel + band configuration tiles
  • Lineup photo optimized 424 KB → 127 KB in the same merge
  • Live title: “Wedding & Event DJ · Live Band · MC | LA + OC” — verified on jackiej.events
Agent backbone

Slack → OpenClaw codegen daemon (Mission 2)

One tier above the triage queue: a Slack message can now become an actual code change. The codegen daemon picks up a request, builds it in an isolated git worktree with its own Vercel preview, and holds at a gate — nothing merges or ships without human approval. Gates 1–2 proven on this repo, with hardening follow-ups (worktree .vercel sharing, stale-job cleanup, Slack webhook guard).

Before
Slack messages could reclassify content; code changes still meant a dev session.
After
A Slack request becomes a gated, previewable code change awaiting one approval.
  • Mission 2 Gates 1 & 2 landed (PR #4/#3 + hardening commits)
  • Isolated worktree builds — the daemon never touches main directly
  • Same human-gated promotion contract as the triage queue
Retention

Inquiry + forms hardening — the funnel stopped trusting the internet

The inquiry pipeline grew a DB-backed rate limit, a honeypot, a double-submit guard, and real date validation. Every form on the site now goes through a shared useFormSubmit hook with stale-bundle auto-reload (a deploy can't strand an open tab on dead JS) and a CI guard that keeps new forms on the same rails.

Before
One unguarded form endpoint; two pollers kept the DB billing 24/7.
After
Hardened funnel, uniform form rails, and a DB that sleeps when Jackie does.
  • DB-backed rate-limit + honeypot + double-submit guard + date validation on /contact
  • Shared useFormSubmit hook + stale-bundle auto-reload + CI guard
  • Live DB migration Neon → Prisma Postgres executed with a fail-soft env fallback; the two 24/7 pollers that pinned the DB awake were killed

While she sleeps.

Autonomous surfaces

The agent backbone keeps the brand earning between gigs. Jackie approves; the system runs.

  • Polls OC vendor pages every 5 minutes

    every 5 min

    Eventbrite, Meetup, local chamber sites — pulls fresh listings, de-dupes against the applied set.

  • Drafts outbound bids in Jackie's voice

    on each new opportunity

    Claude Haiku composes a tailored cover note per event; routes to /dashboard for one-tap approval.

  • Pushes inbound inquiries to her phone

    real-time

    Web push fires in under 30 seconds when a /contact submission lands or a vendor portal replies.

  • Captures SMS consent on every opt-in

    on each opt-in

    Each /optin submission writes a TCPA consent row (phone, checkbox state, referrer QR) to the brand-owned opt_ins table — the audience is portable, forward-ready for the central og_life SMS rails.

  • Builds Slack-requested code changes in gated worktrees

    on each codegen request

    The OpenClaw codegen daemon picks up a Slack change request, builds it in an isolated worktree with a Vercel preview, and parks it at an approval gate — no human, no merge.

  • Tracks her live location during wheels-up trips

    30s heartbeat

    Broadcast/consume trip endpoints — clients on the booked event can follow Jackie's drive without sharing her actual phone number.

  • Refreshes Google Business + IG posts on a cadence

    daily draft, weekly post

    Agent rotates featured packages, posts gig recaps, and queues hashtag stacks — Jackie reviews + taps approve.

  • Polls #jackie-j-events for /jj + @mentions

    every 5 min

    Vercel Cron sweeps the Slack channel for change requests, de-dupes them, and drops each into the triage queue.

  • Classifies each triage row with an 8-tool Anthropic loop

    on each new message

    Sonnet sorts the message into one of 8 typed actions — swap hero photo, update text, add event, queue for research/dev, reject, escalate.

  • Auto-executes safe-whitelisted actions, queues the rest

    on classification

    Whitelisted actions write straight into the published Puck page; everything else waits for Brendon's one-tap approval at /admin/queue.

  • Rolls up 6 admin signals into one bell

    30s poll

    The /dashboard notification tree aggregates Slack ingest, new inquiries, triage activity, and more for admin accounts.

← All rebuilds

DJ Jackie J — bland WordPress to a three-offer entertainment brand — zsty.us