Files
bbq/CLAUDE.md
T
ryan cf2ef77bb0 Add yes/no RSVP answers with required login
RSVPs now carry a status ('yes'/'no'). When auth is enabled, answering
requires login for all events, not just capped ones. Answers are deduped
one per user and re-answering updates in place. A 'no' zeroes plus_one,
is excluded from Going counts and cap math, frees the person's slot
claims, and shows in a separate "Can't make it" list.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 07:59:33 -04:00

3.3 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

What This Is

Potluck signup app. No accounts — share a link, people claim slots. Open like a shared Google Sheet.

Commands

# Build and run
go build -o bbq . && ./bbq

# Docker
docker compose up -d --build

# Regenerate DB layer after editing schema.sql or db/queries.sql
$(go env GOPATH)/bin/sqlc generate

Environment Variables

  • PORT — Go server listen port (default 8080)
  • BBQ_DB — SQLite database path (default bbq.db)
  • BBQ_BASE_URL — Absolute URL for OG images (e.g. https://bbq.torrtle.co)
  • HOST_PORT — Compose host-side port mapping (default 8090)

Architecture

Stack: Go, chi router, sqlc + SQLite (mattn/go-sqlite3), html/template, HTMX + SSE

Design: Soft Brutalism — cream #f5f0e8, black borders/shadows, yellow #f5e642 accents, Bricolage Grotesque + DM Mono fonts

Data Flow

schema.sql defines tables (events, slots, claims, rsvps) → db/queries.sql has SQL queries → sqlc generate produces db/ package (models.go, queries.sql.go, db.go). Never edit generated files in db/ directly.

Server (main.go)

Server struct holds *db.Queries, *sql.DB, baseURL, and SSE client channels. SSE uses subscribe/unsubscribe/notify pattern — any mutation calls notify(slug) to push updates to all viewers.

Templates

Go template inheritance doesn't work with a single ParseFS, so each page is parsed separately into pageTmpl map:

  • pageTmpl["home"] / pageTmpl["event"] — full pages, rendered via .ExecuteTemplate(w, "layout", data)
  • pageTmpl["slots"] — partial for HTMX responses, rendered via .ExecuteTemplate(w, "slots-inner", data)

Template files: layout.html (shell + all CSS/JS), slots.html (shared partial), event.html, home.html. All CSS is inline in layout.html.

Handlers (handlers.go)

loadEventPage() is the shared data loader — assembles EventPageData with event, slots+claims, rsvps, and counts. Used by both full page renders and HTMX partial responses.

OG Image (ogimage.go)

Dynamic PNG generation at /e/{slug}/og.png using Go's image package with a custom 5x7 bitmap font. Renders event title, date/time/location in the app's visual style.

Routes

  • GET / — create event form
  • POST /events — creates event + slots, redirects to admin URL
  • GET /e/{slug} — guest view
  • POST /e/{slug}/claim / DELETE /e/{slug}/claim/{claimID} — HTMX claim/unclaim
  • POST /e/{slug}/rsvp / DELETE /e/{slug}/rsvp/{rsvpID} — HTMX RSVP
  • GET /e/{slug}/sse — SSE stream for live updates
  • GET /e/{slug}/og.png — dynamic OG image
  • GET /e/{slug}/admin/{token} — admin view (same template, IsAdmin=true)
  • POST /e/{slug}/admin/{token}/slot / DELETE /e/{slug}/admin/{token}/slot/{slotID} — manage slots

Auth Model

Email-code login behind the BBQ_FEATURES=auth flag. When auth is on, RSVP answers (yes or no) require login and are deduped one-per-user; when off, everything is open like a shared Google Sheet. RSVPs have a status column (yes/no) — no's don't count toward Going and free any claimed slots. Admin access is via secret admin_token in the URL (plus event ownership when auth is on).