A dating app built like a nightclub. Everyone gets in free with a verified ID β everyone's a VIP with an ID here.
Live at smartscott.online β every push to
main auto-deploys to Vercel.
Club Cheeky is a nightclub, not a menu. Members walk a real building:
| Room | Route | What happens there |
|---|---|---|
| πͺ The street / landing | / |
The marquee. Enter the club. |
| πͺͺ The door (verification) | /verify |
Stripe Identity ID + selfie β Silver card, VIP badge, 20 tokens. The velvet rope is up until you check in. |
| π The lobby | /club |
The entrance room β VIP area, Gift Shop, Chats, Spark List, Elevators, Coat Check, Brutus at the door. |
| π The floors | /floors Β· /floor/[slug] |
Silver β Gold β Platinum β Diamond. Each floor is its own room with its own art, its own event, and its own member of the crew. Locked floors show the rope, not a price. |
| π The Event Center | /events Β· /events/[kind] |
The hourly playlist β Dance Floor (:00), Themed Night (:15), Speed Dating (:30), Rooftop (:45). Join any room any time; your spot is held for the next set. Rooms are lit up to your floor. |
| π The crew | /crew Β· /chat/[slug] |
Six AI characters who run the club. Meet them on their floors and chat. |
| π The Gift Shop | /gifts |
Buy gifts with tokens and send them to members. |
| π§₯ Coat Check | /coat-check |
Gems, badges, your daily streak, and crew bonds. |
| ποΈ Swag Shop | /swag |
Redeem giveaway codes (SWAG-XXXXXXXX) β always in the nav. |
| β‘ The Spark List | /browse |
The spark hub β Swipes (the 1-for-1), LΒ³ (Leave Β· Like Β· Love), and Matchmaker (the memory board that unlocks first impressions). Filtered by mutual dating preference. |
| π¬ Cheeky Chats | /messages |
Conversations, waves, Date Night with matches. |
| π€ Account | /account |
Your card (grant-aware), avatar name, one-liner, photos, billing. |
| π Owner's back door | /owner |
The founder's booth β swag codes, grants, flags (owner account only). |
| πΈ The Cheeky Lounge | everywhere | The always-available chat overlay β five rooms (Global + the floors), realtime, the Horn, chat badges. The town square. |
- The Ladder β Guest (street) β Silver (verified, free) β Gold ($9.99) β Platinum ($19.99) β Diamond ($29.99) β Gems (collectibles).
- The Event Engine β live scheduled events; the hourly Dance Floor is the reference implementation.
- The Token Economy β earn (verify, referrals, giveaways) or buy (100/$4.99, 1000/$9.99); events cost tokens per floor. Server-side ledger only β never trust the client.
The games run on two engines β clock-driven rooms (the Events Engine)
and instant solo games (the Spark Game Spine: Swipes, LΒ³, Matchmaker). New
games are checked against both before they're built β see
docs/GAME-ENGINES.md.
They're workers, not actors. Each lives on their own floor; their chats are gated by the floor you can reach (a reward for membership, not a paywall). The crew can always greet any member (milestone messages fire regardless of tier). Chaz, the manager, rides the floating concierge on every page.
| Member | Job | Floor |
|---|---|---|
| Brutus | Bouncer | The lobby |
| The DJ (D34D_B34T) | Spins the floor | Silver |
| Roxy | Mixologist | Gold |
| Trixie | Waitress | Platinum |
| Valentina | Hostess | Diamond |
| Chaz Sterling | Club manager | Everywhere |
The free tier stays genuinely free and fun (30 messages/day, 5 new conversations/day β generous on purpose). No dark patterns, no fake likes, no artificial scarcity. Anti-gouging is the brand ($9.99β$29.99 ceiling). Silent loss, public win. Safety is a feature: verification-as-entry, report/block from any chat, honeypots for bots.
- Next.js 15 (App Router) + TypeScript + Tailwind β server
components by default;
'use client'only where interactivity requires. - Supabase β auth, Postgres with Row Level Security on every table, migrations, generated types.
- Stripe β subscriptions, checkout, and Identity (verification).
- DeepSeek (
/api/agent) β the crew's brains; persona prompts live in thecharacterstable. - Sentry β error tracking (wizard setup).
- Vercel β the only build gate: every push to
mainbuilds, deploys, and fails loud.
There is no local database. Everything targets the hosted Supabase project β migrations are applied to hosted directly, then types regenerated. Running the app locally only needs the keys in
.env.local.
pnpm install
cp .env.local.example .env.local # fill in your keys (see below)
pnpm dev # http://localhost:3000For local Stripe webhooks (needed for product/subscription sync):
pnpm stripe:login
pnpm stripe:listen # forward webhooks to localhost:3000/api/webhooks
pnpm stripe:fixtures # bootstrap products/prices from fixtures/The crew's chat needs DEEPSEEK_API_KEY. Verification needs real Stripe
keys. Sentry is optional locally.
The full set (see .env.local.example for the core local-dev values).
env.new is the master vault β scripts and live tests read it directly;
.env.local (for pnpm dev) is generated from it with
node scripts/sync-env.mjs.
| Variable | Used for |
|---|---|
NEXT_PUBLIC_SITE_URL |
Canonical site URL |
NEXT_PUBLIC_SUPABASE_URL Β· NEXT_PUBLIC_SUPABASE_ANON_KEY |
Client (anon key only) |
SUPABASE_SERVICE_ROLE_KEY |
Server-only writes (never in client code) |
SUPABASE_ANON_KEY Β· SUPABASE_JWT_SECRET |
Local dev / server auth helpers |
POSTGRES_URL (+ _NON_POOLING, _PRISMA_URL, _DATABASE, _PASSWORD, _HOST) |
Hosted Postgres |
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY Β· STRIPE_SECRET_KEY Β· STRIPE_WEBHOOK_SECRET |
Stripe |
DEEPSEEK_API_KEY |
/api/agent β the crew's chat engine |
OPENROUTER_API_KEY |
DateSafe β the image-review watchdog (vision model) |
RESEND_API_KEY Β· REGISTERED_DOMAIN |
Transactional mail β welcome, apology, ban notices |
SENTRY_AUTH_TOKEN |
Sentry source-map uploads |
VERCEL_OIDC_TOKEN |
Created by vercel link for CI builds |
| Command | What it does |
|---|---|
pnpm dev / pnpm build / pnpm lint |
Dev server (turbo) / production build / lint |
pnpm test |
Safe test suite (node:test, zero deps). Live suites with RUN_LIVE_TESTS=1 β see tests/README.md |
pnpm prettier-fix |
Format everything (Prettier is enforced) |
pnpm stripe:listen / pnpm stripe:fixtures |
Local webhooks / bootstrap products |
pnpm supabase:start / stop / reset |
Local Postgres + auth lifecycle (optional β the default workflow is hosted) |
pnpm supabase:generate-types |
Regenerate types_db.ts after schema changes β commit the diff |
pnpm supabase:generate-migration |
Diff local schema into supabase/migrations/ |
pnpm supabase:push / pull |
Schema sync against the linked project |
node scripts/migrate-hosted.mjs <name> |
Apply one migration to the hosted database |
node scripts/sync-env.mjs |
Refresh .env.local from env.new (the master vault) |
node scripts/backfill-*.mjs / check-*.mjs / test-*.mjs |
Ops utilities (see scripts/) |
- Schema changes go through
supabase/migrations/(87 and counting). - Apply to hosted, then regenerate types β that's the whole workflow:
node scripts/migrate-hosted.mjs <name>thenpnpm supabase:generate-types, and commit the diff. (Local Supabase is optional; it is not the default path.) - RLS is mandatory on every table. Service role for server writes; the client only ever uses the anon key.
- Money is stored as integers (cents); token amounts are server-side ledger deltas only.
mainauto-deploys to Vercel (smartscott.online). No CI ceremony β the safety valve is git history + milestone tags.- Data changes (grants, swag codes, tokens, event slots) are hot β no deploy. Only code changes need pushes.
- Never push a broken build:
pnpm lint+pnpm buildpass first.
app/ Next.js routes (landing, signin, account, club, floors, events,
chat, crew, gifts, coat-check, swag, browse, messages, verify,
owner, api/)
components/ ui primitives (ui/) + feature components (Agent, Club, Events,
Gifts, Messages, Audio, Swag, Navbar, Footer, Browse, ClubChat) β see
docs/COMPONENT-LIBRARY.md
utils/ supabase clients + queries, stripe, auth helpers, floors map,
characters, events config, swag, rate limits, token-amount
supabase/ migrations (87) β apply to hosted with scripts/migrate-hosted.mjs
scripts/ dev utilities (migrate-hosted, backfill-*, check-*, test-*)
styles/ global css (main.css) + floor palettes (styles/palettes/*.scss)
docs/ PRD-foundation.md + PRDs + GAME-ENGINES.md (the two game
engines + Playability Check) + Governance/ + COMPONENT-LIBRARY.md +
ENVIRONMENT.md + floor-map.md + event-diagrams/ +
first-floor-flow.mmd (historical audits/setup reports live in
docs/archives/)
tests/ node:test suite β safe (pnpm test) + live (RUN_LIVE_TESTS=1)
fixtures/ Stripe fixture JSON for bootstrapping products/prices
public/ served assets: brand/ (floor art, entrance), personas/ (crew
images), audio/ (DJ tracks)
- PRD first. Product decisions land in
docs/before code β and when a decision changes, the doc and the code change together. - Governance is code. The policies in
docs/Governance/(terms, privacy, safety, retention, refunds) are binding β schema and flows satisfy them. - Surgical changes. In existing code, do exactly what the task asks. No opportunistic refactors.
- Ask when it's ambiguous. When a product decision is unclear, ask rather than inventing an answer that contradicts the PRD.
Read AGENTS.md β the working guidelines β and
docs/PRD-foundation.md β the product spec.
docs/floor-map.md is the source of truth for what
belongs on every floor. docs/GAME-ENGINES.md is
where new games get checked against the two engines. CONTRIBUTING.md is the process
discipline β the standing rule, migrations, testing, secrets.
-
pnpm lintpasses -
pnpm testpasses (safe suite; run live suites if the change touches events/tokens/webhooks) -
pnpm buildpasses - Affected user flow manually verified (signup, verification, checkout, event)
- No template-branding leftovers (grep for "ACME", "Subscription Starter", "vercel.com")
- PRD/doc updated if behavior changed