Private, temporary, room-based chat app (2 participants max per room) with realtime updates via Upstash.
- Create a new room and share the link.
- Join room via
/room/:roomId. - Realtime “new message” updates (no manual refresh).
- Destroy room (broadcasts a
destroyevent and clears stored data). - Room TTL (defaults to 10 minutes) and auto-expiration after inactivity.
- Framework: Next.js (
next@16.2.6) + React (react@19) - Styling: Tailwind CSS v4
- API layer: Elysia (
elysia) mounted inside Next.js Route Handlers - Client data fetching/cache: TanStack Query (
@tanstack/react-query) - Realtime transport: Upstash Realtime (
@upstash/realtime) - Storage: Upstash Redis REST (
@upstash/redis) - Validation: Zod v4 (
zod/v4) - Utilities:
nanoid,date-fns,lucide-react
src/app/page.tsx: Lobby (create/join UI + error states via query params).src/app/room/[roomId]/page.tsx: Room UI (messages list, input, TTL, copy link, destroy).
All endpoints live under src/app/api/[[...slugs]]/route.ts and are served at /api/*:
POST /api/room/create→{ roomId }GET /api/room/ttl?roomId=...→{ ttl }(seconds)DELETE /api/room?roomId=...→ destroys room + broadcastsdestroyGET /api/messages?roomId=...&token?=...→{ messages }POST /api/messages?roomId=...→ send message + broadcastmessage
Realtime handshake endpoint:
GET /api/realtime(Upstash Realtime handler) insrc/app/api/realtime/route.ts
meta:{roomId}(hash): room metadata, includingconnectedtokens andcreatedAtmessages:{roomId}(list): message history
- Uses a
x-auth-tokenHttpOnly cookie to identify a participant. - Server validates token membership via
meta:{roomId}.connectedinsrc/app/api/[[...slugs]]/auth.ts.
Note: src/proxy.ts contains a ready-to-use middleware-style gatekeeper for /room/*
(sets cookie, enforces max 2 participants, handles redirects), but it must be wired into
Next.js middleware.ts to be active.
bun installCreate .env.local:
UPSTASH_REDIS_REST_URL=...
UPSTASH_REDIS_REST_TOKEN=...These are required by src/lib/redis.ts.
bun devOpen http://localhost:3000.
- Open the lobby page.
- Click “Create room” (generates a
roomId). - Share the room link with a friend.
- Both participants open the room link and start chatting.
- Use “Destroy room” to permanently end the session for both sides.
- Room creation stores metadata in Redis with a 10-minute TTL.
- Messages are appended into a Redis list (
messages:{roomId}). - On send, the server emits a realtime
messageevent on the room channel. - Clients subscribe to the room channel and refetch messages on new events.
- Destroy emits a
destroyevent then deletes room data (meta + messages).