vestige/docs/launch/waitlist-setup.md
Sam Valladares cfe8d03d36 feat(landing): full-viewport GPU node-engine hero + waitlist + dashboard auth removal
The /launch landing page (bleeding-edge waitlist hero):
- Full-viewport WebGL node engine (src/lib/hero/nodeEngine.ts): 40k GPU particles
  on a two-FBO GPUComputationRenderer running an 18s looping cinematic — particles
  stream in from the screen edges, slam together and EXPLODE at center, reform into
  a brain / graph constellation / neural lattice, dissolve back out, loop. Glowing
  additive particles + UnrealBloom, fills the whole screen edge to edge.
- Key GPGPU fix: custom DataTexture shape targets read black in GPUComputationRenderer
  (three.js #15882), so shape targets are computed PROCEDURALLY in-shader from the
  per-particle seed. Position integrates raw per-frame velocity (Codrops pattern),
  texel-center reference attribute.
- AmbientField (god-ray glow + parallax starfield), phantomBrain (deterministic
  seed-from-identity memory graph), LandingHero/neuralFlow (WebGPU Cinema-storm
  reuse + WebGL fallback, kept as alternates). Manifesto copy, seed input, email
  capture. No em-dashes. SSR off + prerender for the WebGL route.

Waitlist backend (Supabase, owned data):
- supabase/migrations/0001_waitlist.sql (RLS-locked table, dedup), Edge Function
  waitlist-join (CORS, validation, honeypot, dedup, Resend confirmation), setup doc.

Dashboard auth removed (reverts the launch-polish auth wall that 401'd the dashboard
against itself): mod.rs/state.rs/websocket.rs back to no-token, api.ts/websocket.ts/
+layout.svelte stripped of the token client. Pending-review UX + Memory PR gating kept.

Research/spec docs under docs/launch/. Frontend typechecks 0/0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 22:54:51 -05:00

83 lines
2.8 KiB
Markdown

# Waitlist capture — setup (10 minutes)
The public waitlist form (`/dashboard/waitlist`) is already built. It POSTs JSON
to `VITE_WAITLIST_ENDPOINT`. This guide stands up the storage backend: a
Supabase table + Edge Function that stores every signup and (optionally) emails a
confirmation.
Owned data, queryable Postgres, free tier handles launch-day volume.
## 1. Create the project
1. Create a project at <https://supabase.com> (free tier is fine for launch).
2. Grab the **Project Ref** (Settings → General) and the
**service-role key** (Settings → API). The service-role key is a secret —
never commit it or expose it client-side.
## 2. Deploy the schema + function
```sh
supabase link --project-ref <your-project-ref>
supabase db push # applies supabase/migrations/0001_waitlist.sql
supabase functions deploy waitlist-join # deploys supabase/functions/waitlist-join
```
## 3. Configure function secrets
`SUPABASE_URL` and `SUPABASE_SERVICE_ROLE_KEY` are injected automatically.
Email confirmation is optional — set these to enable it (reuses Resend):
```sh
supabase secrets set RESEND_API_KEY=<your-resend-key>
supabase secrets set WAITLIST_FROM_EMAIL="Vestige <waitlist@yourdomain>"
# Optional: lock CORS to your sites (comma-separated). Omit for "*".
supabase secrets set WAITLIST_ALLOWED_ORIGIN="https://samvallad33.github.io,https://vestige.dev"
```
## 4. Point the form at the function
The function URL looks like:
`https://<project-ref>.functions.supabase.co/waitlist-join`
Set it at build time for the dashboard:
```sh
# apps/dashboard/.env (or your Pages build env)
VITE_WAITLIST_ENDPOINT=https://<project-ref>.functions.supabase.co/waitlist-join
```
Rebuild the dashboard (`pnpm --filter @vestige/dashboard build`) and redeploy.
## 5. Verify
```sh
curl -X POST https://<project-ref>.functions.supabase.co/waitlist-join \
-H 'content-type: application/json' \
-d '{"email":"you@example.com","name":"You","plan":"solo","priority":"sync"}'
# -> {"ok":true,"deduped":false}
# Re-run the same command:
# -> {"ok":true,"deduped":true} (idempotent; no duplicate row)
```
## 6. Export the list on launch day
In the Supabase SQL editor:
```sql
select email, name, plan, priority, notes, created_at
from public.waitlist
order by created_at desc;
```
Or download a CSV from the Table Editor. That list is the asset that converts
to paid over the weeks after the spike.
## Notes
- **RLS is on, anon can do nothing.** Only the service-role key inside the
function can insert. The public anon key (if ever used) has zero table access.
- **Honeypot + email validation** run both client-side (in the form) and
server-side (in the function).
- **Dedup** is enforced by a unique index on the lowercased email; a re-submit
returns `{ok:true,deduped:true}` instead of erroring or duplicating.