Description
Persistent-WS bot that reconciles Stripe-issued single-use invites with joining users and assigns `@attendee`. PLAYBOOK.md §5.2–§5.4.
Why Fly.io (not Vercel)
- Discord gateway needs a long-running WebSocket; Vercel Functions are request-scoped.
- Fallback (interactions HTTP on Vercel) loses `GUILD_MEMBER_ADD` events. Reject.
Responsibilities
- Watch `GUILD_MEMBER_ADD`; diff invite `uses` counts to identify which invite code a joiner used; match to `registrants` row; assign `@attendee`.
- `/whois ` slash command for organizer lookup.
- Cron-post schedule reminders to `#announcements`.
- Auto-kick unregistered joiners after 10 min grace.
Invite issuance (called from Stripe webhook)
- On `checkout.session.completed`: server calls Discord REST `POST /channels/{lobby}/invites` with `max_uses:1, max_age:0, unique:true`.
- Store code on `registrants.discord_invite_code`.
- Email registrant their personal link.
Failure modes to handle
- Registrant never joins → invite stays valid; T-7 reminder email.
- User joins on different account than email on file → surface in `/admin` for manual reconciliation.
Env vars
- `DISCORD_BOT_TOKEN`, `DISCORD_GUILD_ID`, `DISCORD_LOBBY_CHANNEL_ID`, `DISCORD_ATTENDEE_ROLE_ID`.
Monitoring
- Sentry project for the bot (separate from Vercel Observability on the web app).
Dependencies
Description
Persistent-WS bot that reconciles Stripe-issued single-use invites with joining users and assigns `@attendee`. PLAYBOOK.md §5.2–§5.4.
Why Fly.io (not Vercel)
Responsibilities
Invite issuance (called from Stripe webhook)
Failure modes to handle
Env vars
Monitoring
Dependencies