A mobile-first room-handoff app for one live, in-person Day of Prayer
gathering. Participants join from one shared link, wait in a synchronized
lobby, and receive an immediate hidden room assignment. The organizer monitors
provisional rosters at /admin, then reveals assignments with each room’s
first participant as leader.
The guided prayer experience after people reach their rooms is intentionally deferred.
- Next.js 15 App Router and TypeScript
- PostgreSQL and Prisma
- Tailwind CSS
- Railway
- Vitest
Requires Node 22+, pnpm 10, and PostgreSQL 16.
pnpm install
cp .env.example .env
pnpm exec prisma migrate deploy
pnpm db:seed
pnpm devSet DATABASE_URL to the local database. Generate the prayer-request encryption
key with:
openssl rand -base64 32Put the result in PRAYER_REQUEST_ENCRYPTION_KEY. Keep this key stable while
stored prayer requests need to remain readable.
Open:
- Participant experience:
http://localhost:3000/ - Organizer experience:
http://localhost:3000/admin - Database-backed health:
http://localhost:3000/api/health
pnpm verify
pnpm db:check
pnpm test:integrationThe integration test needs the same DATABASE_URL and
PRAYER_REQUEST_ENCRYPTION_KEY environment variables as the application.
The load script uses the target database's existing seeded rooms and resets the active gathering before and after the run. It never modifies room configuration, refuses to start without an explicit confirmation, and refuses remote targets unless separately allowed.
LOAD_TEST_BASE_URL=http://localhost:3000 \
LOAD_TEST_CONFIRM=room-handoff \
pnpm load:room-handoffFor a remote non-production test environment, also set
LOAD_TEST_ALLOW_REMOTE=yes.
- Run
pnpm db:seedonce in each new environment to seed the physical rooms outside the event-day application. Every finite capacity must be at least two and at least one room must be unlimited. - Open
/admin, share the participant root link, and watch live provisional rosters fill in deterministic room order. - Reveal once everyone expected has arrived. Existing assignments become visible and are final until reset.
- Participants can still join afterward. Each late arrival is assigned to the first configured smallest eligible room without moving existing members or replacing an existing leader.
- Expand room cards before or after reveal to inspect rosters and leaders.
- Reset only when the run is finished or before a test run. Reset deletes live participant and prayer-request rows but does not control the separate retention period of provider-managed database backups.
railway.toml applies Prisma migrations as a pre-deploy command, starts the
standalone Next.js server, and checks /api/health.
Configure the app service with:
DATABASE_URLreferencing the Railway PostgreSQL servicePRAYER_REQUEST_ENCRYPTION_KEYcontaining a stable base64-encoded 32-byte key
Do not set PGSSLMODE when using Railway’s private Postgres network.
- Current domain context
- Room-handoff product and implementation plan
- Architecture decisions
- Historical superseded matcher specification
Contributors should read AGENTS.md before making changes.