Live rooms for Q&A, polls, and open prompts. Ask, upvote, and engage in real time.
Production site: https://pulse.rsamdio.org · Owned by Rotaract South Asia MDIO (RSAMDIO)
Built on a narrow Firebase hybrid: Firestore is the write/ACL source of truth; RTDB serves cheap live-room reads.
Firebase web config is committed in src/lib/firebase/config.ts (client keys are public; Auth + security rules protect data). CLI project: .firebaserc.
- Google sign-in
- Roles: admin / organizer / attendee (Firestore
admins/{uid},organizers/{uid}; first signed-in user bootstraps if empty) - Room access modes: public, allowlist, join_code, hybrid
- Optional anonymous rooms (Ask authors shown as Anonymous)
- Ask — live question board with upvotes (toggle on/off; one vote per person)
- Engage — organizer MCQ, word cloud, and short-answer prompts (
draft→live→closed; one live at a time)- Attendees: select then submit (MCQ); answers lock after submit; results after answer or after close
- Organizers: draft edit before go-live, ordered "up next" queue (reorder / go live), optional per-prompt timer with auto-advance, Peek + Reveal for hidden-until-closed results, screen-share friendly tallies, CSV export
- Present view (
/rooms/[id]/present, noindex): a large projector screen showing the live prompt, response count, results (once revealed/closed), a live countdown, and a "Next prompt in N…" freeze during auto-advance
- Organizer moderation: delete questions, mark answered, close engagements
- Organizer controls: lock new questions, view-only, allowlist, join-code rotate, delete room, CSV export (Ask + Engage)
- Private rooms: member list, search, remove, CSV export (Manage)
- Admin console (
/admin, noindex): promote/demote organizers, all rooms, delete
Client mutations → Cloud Functions → Firestore (truth)
→ RTDB mirror (meta, questions, engagements, access, userVotes, userEngagementResponses)
Client live reads → RTDB only
Organizer secrets (allowlist / join hashes) → Firestore + Callables only
Organizers → Firestore `organizers/{uid}` (document id = Auth uid)
Admins → Firestore `admins/{uid}`
- Firebase project rotaractpulse — Auth (Google), Firestore, RTDB + Functions (
asia-southeast1). - Authorized domains:
pulse.rsamdio.org(and Netlify domain if used). - Web config already in
src/lib/firebase/config.ts; CLI default in.firebaserc. - Deploy backend:
npm run functions:build
firebase deploy --only firestore,database,functions- Deploy the Next.js app to Netlify (no Firebase env vars needed) and point the domain to pulse.rsamdio.org.
npm install
cd functions && npm install && cd ..
npm run devAgainst emulators: set useFirebaseEmulators = true in src/lib/firebase/config.ts, then run npm run emulators and npm run dev.
| Script | Purpose |
|---|---|
npm run dev |
Next.js app |
npm run build |
Production Next build |
npm run emulators |
Auth, Firestore, RTDB, Functions emulators |
npm run functions:build |
Compile Cloud Functions |
npm run test |
Unit tests |
/— landing / sign in/join— join with a 6-digit code/rooms— accessible rooms (noindex)/rooms/new— create (organizer)/rooms/[id]— live room (Ask + Engage tabs)/rooms/[id]/join— room-specific code gate/rooms/[id]/manage— organizer controls (Ask settings, Engage prep, members)/rooms/[id]/present— projector view for the live Engage prompt (noindex)/admin— super-admin console (noindex)/terms·/privacy— legal/sitemap.xml·/robots.txt— SEO
Room id === slug (rooms/{slug}, questions/{slug}/…, engagements/{slug}/…, RTDB rooms/{slug}/…).
| Path | Purpose |
|---|---|
users/{uid} |
Profile |
organizers/{uid} |
Organizer role |
admins/{uid} |
Super-admin role |
rooms/{slug} |
Room truth |
roomAllowlists/{slug}/emails/{email} |
Allowlist |
roomMembers/{slug}/members/{uid} |
Membership |
questions/{slug}/items/{qid} |
Questions |
votes/{slug}/questions/{qid}/users/{uid} |
Votes |
engagements/{slug}/items/{eid} |
Engage prompts (draft / live / closed) |
engagementResponses/{slug}/items/{eid}/users/{uid} |
Engage answers |
joinCodes/{code} |
Code → room slug |
| Path | Purpose |
|---|---|
rooms/{slug}/meta |
Live flags |
rooms/{slug}/questions/{qid} |
Live Ask board |
rooms/{slug}/engagements/{eid} |
Live Engage board (tallies / phrases) |
rooms/{slug}/engageControl |
Public engage control (phase / advanceAt / generation) for Present + grace |
access/{uid}/{slug} |
Membership bit |
userVotes/{uid}/{slug}/{qid} |
Vote flags |
userEngagementResponses/{uid}/{slug}/{eid} |
Own Engage answers |
publicRoomIndex/{slug} |
Public discovery |