Real-time incident war room. When something breaks, Mayday gives your team a shared space to coordinate, log the timeline, assign tasks, and export a post-mortem when it's over.
- Incident management — create incidents with severity (
low/medium/high/critical) and track status throughinvestigating → identified → resolving → resolved - Real-time collaboration — live presence (who's in the room), typing indicators, and instant timeline updates via Socket.IO
- Timeline — chronological log of updates posted by any team member
- Claims — each person declares what they're investigating so the team doesn't overlap
- Post-mortem export — once resolved, download a Markdown post-mortem with the full timeline and participants
- GitHub OAuth — sign in with your GitHub account, no passwords
| Layer | Tech |
|---|---|
| Framework | Next.js 16 (App Router) |
| Real-time | Socket.IO 4 |
| Auth | NextAuth v4 (GitHub provider) |
| Database | MySQL (mysql2) |
| Styles | Tailwind CSS v4 |
| Server | Custom Node.js (tsx server.ts) |
- Node.js 20+
- pnpm
- MySQL 8+
-
Clone and install
git clone <repo> cd mayday pnpm install
-
Create the database
CREATE DATABASE mayday CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Then run the schema:
mysql -u root -p mayday < schema.sql -
Configure environment
cp .env.example .env
Fill in
.env:Variable Description DB_HOSTMySQL host (default: localhost)DB_PORTMySQL port (default: 3306)DB_USERMySQL user DB_PASSWORDMySQL password DB_NAMEDatabase name (default: mayday)NEXTAUTH_URLFull URL of the app (e.g. http://localhost:3000)NEXTAUTH_SECRETRandom secret — generate with openssl rand -base64 32GITHUB_CLIENT_IDGitHub OAuth app client ID GITHUB_CLIENT_SECRETGitHub OAuth app secret -
Create a GitHub OAuth app
Go to github.com/settings/apps → New OAuth App. Set Authorization callback URL to
http://localhost:3000/api/auth/callback/github. -
Run in development
pnpm dev
Open http://localhost:3000.
-
Build for production
pnpm build pnpm start
The app uses a custom Node.js HTTP server (server.ts) instead of next start so that Socket.IO can share the same port as Next.js. The Socket.IO server authenticates connections by verifying the NextAuth JWT from the session cookie — no separate token exchange needed.
Presence state (who's in which incident room) lives in-memory on the server. This works for a single-instance deployment; a multi-instance setup would need a shared store (e.g. Redis pub/sub).
| Method | Path | Description |
|---|---|---|
GET |
/api/incidents |
List incidents (supports q, status, severity, page) |
POST |
/api/incidents |
Create incident |
GET |
/api/incidents/:id |
Get incident with entries and claims |
PATCH |
/api/incidents/:id |
Update status (creator only) or edit title/description/severity (creator only) |
DELETE |
/api/incidents/:id |
Delete incident (creator only) |
POST |
/api/incidents/:id/entries |
Add timeline entry (rate-limited: 10/min) |
DELETE |
/api/incidents/:id/entries/:entryId |
Delete own entry (blocked on resolved incidents) |
PUT |
/api/incidents/:id/claims |
Claim or update task |
DELETE |
/api/incidents/:id/claims |
Remove own claim |
GET |
/api/postmortem/:id |
Download Markdown post-mortem (resolved incidents only) |