wenmeet·PRD

Backend Infrastructure PRD · v1.0

Backend Infrastructure PRD

Netlify hosts the static app and serverless functions; Supabase provides Postgres, realtime channels, and storage. One stack, no servers to run, everything the orb shows is derivable from Postgres.

1 · Architecture

Client (static)
grid, orb, graph — Netlify CDN
→
Netlify Functions
/api/* — auth, compute, lock, webhooks
→
Supabase Postgres
source of truth + RLS
Supabase Realtime
meeting:{id} channel → orb params, response counts
←
Google Calendar
OAuth, event write, decline webhooks
Resend
invites, reveals, magic links

2 · Data model

TableKey columnsNotes
meetingsid, title, duration_min, window_start/end, state, quorum_mode='soft', organizer_participant_idstate mirrors the nebula machine exactly.
participantsid, meeting_id, name, email, role, is_dm, guest_token (hashed), claimed_user_id, home_city, tzGuests are rows, not users. claimed_user_id set on magic-link claim.
paintsparticipant_id, slot_ts (UTC), level ∈ {free, if_need_be}Slots stored UTC, rendered local (assumed pick).
proposalsid, meeting_id, slot_ts, score, breakdown_json, status, below_quorum boolbreakdown_json is what the ⓘ renders — verbatim.
locksmeeting_id, proposal_id, locked_at, gcal_event_id, superseded_bysuperseded_by chains the visible reschedule history.
eventsid, meeting_id, type, payload, atAppend-only audit: every state change, flex ask, decline.
graph_nodesid, meeting_id, kind ∈ {person, artifact, blob*}, parent_meeting_id, positionblob kind + parent_meeting_id exist now — v2 blob groundwork.

3 · Scoring engine — deterministic, versioned, LLM-free

4 · API surface (Netlify Functions)

EndpointAuthDoes
POST /api/meetingsnone → mints organizer tokenCreate meeting + participants; sends Resend invites.
GET /api/meetings/:idparticipant tokenRole-scoped view: organizer full, invitee aggregate.
POST /api/paintsparticipant tokenUpsert paints; bumps realtime channel.
POST /api/computeorganizer tokenRuns scorer → proposals; state → PROPOSED.
POST /api/lockorganizer tokenLocks proposal; writes Google event; Resend confirmations.
POST /api/flexorganizer tokenSends 2f flex ask; POST /api/flex/:id/answer for Sure/Can't.
POST /api/participantsorganizer tokenAdd-after-lock (2g) incl. calendar check.
POST /api/webhooks/gcalGoogle channel tokenDecline detection → DESTABILIZED.
POST /api/claimmagic-link tokenGuest → account claim; re-parents participant rows.

5 · Realtime — the orb is a subscription

6 · Auth, security, retention