A Slack bot and interactive dashboard that powers the daily 10:30 IST Google Meet standup:
- Pre-standup brief at 10:30 IST — pulls 24-72h of Slack chatter, runs through Gemini, posts grouped digest to
#team-schedule. - Attendance DMs at 10:00 IST — every roster member gets a Block Kit DM asking office / WFH / leave, with an ETA picker.
- Interactive dashboard at
/— live attendance grid, drag-and-drop Kanban board, OpenAI Realtime voice assistant. - Voice assistant during standup — browser WebRTC straight to OpenAI Realtime API, captures action items / blockers / attendance updates while the team talks, writes them into the Kanban board in real time.
Vercel
├── api/cron/dm-attendance.ts ← 10:00 IST: DM every roster member
├── api/cron/standup-brief.ts ← 10:30 IST: post the Slack digest
├── api/slack/command.ts ← /standup-brief slash command
├── api/slack/interactions.ts ← attendance DM button clicks + ETA select
├── api/attendance/index.ts ← GET/POST attendance
├── api/kanban/board.ts ← GET board
├── api/kanban/cards.ts ← POST/PATCH/DELETE cards
├── api/roster/index.ts ← GET roster, POST ?sync=1
├── api/realtime/token.ts ← mint ephemeral Realtime session
├── api/realtime/tool.ts ← bridge function-call → DB
├── api/admin/migrate.ts ← run DB migrations
└── public/ ← dashboard HTML + JS + CSS (static)
Postgres (Neon)
roster, attendance, kanban_card
- Sign up at https://neon.tech, create a project.
- Copy the pooled connection string →
DATABASE_URL.
- https://api.slack.com/apps → From manifest → paste
slack-manifest.yaml. - Replace
YOUR-VERCEL-DOMAINonce you deploy. - Install to workspace, grab:
- Bot OAuth Token →
SLACK_BOT_TOKEN - User OAuth Token →
SLACK_USER_TOKEN - Signing Secret →
SLACK_SIGNING_SECRET
- Bot OAuth Token →
- Bot must be a member of
#team-schedule(C05BRT9CZ7G) —/invite @standup-bot.
- Azure AI Foundry → deploy
gpt-realtimemodel (Global Standard, eastus2 / swedencentral). - Copy: resource endpoint, key, deployment name, region.
- Env vars:
AZURE_OPENAI_ENDPOINT,AZURE_OPENAI_API_KEY,AZURE_OPENAI_REALTIME_DEPLOYMENT,AZURE_OPENAI_REGION.
vercel link
vercel env add SLACK_BOT_TOKEN
vercel env add SLACK_USER_TOKEN
vercel env add SLACK_SIGNING_SECRET
vercel env add GEMINI_API_KEY
vercel env add AZURE_OPENAI_ENDPOINT
vercel env add AZURE_OPENAI_API_KEY
vercel env add AZURE_OPENAI_REALTIME_DEPLOYMENT
vercel env add AZURE_OPENAI_REGION
vercel env add DATABASE_URL
vercel env add CRON_SECRET # any long random string
vercel env add DASHBOARD_SECRET # any long random string
vercel env add STANDUP_CHANNEL_ID # C05BRT9CZ7G
vercel deploy --prod# After first deploy:
curl -X POST "https://YOUR-DOMAIN/api/admin/migrate?secret=$CRON_SECRET"
# Then sync roster (also runs as part of dm-attendance cron):
curl -X POST "https://YOUR-DOMAIN/api/roster?sync=1" \
-H "x-dashboard-secret: $DASHBOARD_SECRET"Or locally with .env.local:
npm install
npm run db:migrate -- --seed-rosterhttps://YOUR-DOMAIN/ → paste DASHBOARD_SECRET to unlock.
| Time | What happens |
|---|---|
| 10:00 IST | Cron syncs roster, DMs every member with attendance buttons. |
| 10:00–30 | Replies trickle in → attendance table updates → dashboard reflects live. |
| 10:30 IST | Cron posts the Slack brief (attendance summary + Kanban summary on top). |
| 10:30 IST | Team joins Google Meet. One person opens the dashboard → clicks Start voice. |
| 10:30–45 | Assistant listens via mic (pipe Meet via BlackHole on Mac to feed all voices). Captures action items / blockers as Kanban cards, marks attendance changes ("I'm leaving early"), nudges the next speaker. |
OpenAI Realtime only sees the mic of the browser tab. To feed every speaker's audio:
- Install BlackHole (free).
- Audio MIDI Setup → create a Multi-Output Device combining your headphones + BlackHole.
- Google Meet → set output to the Multi-Output Device. Now Meet plays to your ears and BlackHole.
- Dashboard tab → in browser site settings, set the microphone to BlackHole 2ch. Mic now hears the entire Meet conversation.
Alternative: just speak into a normal mic — the assistant won't hear remote speakers but it can still capture the local moderator's notes.
CRON_SECRET— required for/api/cron/*+/api/admin/migrate. Vercel auto-injects it for scheduled crons.DASHBOARD_SECRET— required for any state-mutating endpoint hit from the browser (attendance POST, kanban POST/PATCH/DELETE, realtime token mint, realtime tool bridge). Pasted into the dashboard on first load and cached inlocalStorage.- Slack signing secret — verifies
/api/slack/commandand/api/slack/interactionspayloads.
| Knob | Where | What it does |
|---|---|---|
| Standup channel | STANDUP_CHANNEL_ID env |
Slack channel used for roster source. |
| Realtime deployment | AZURE_OPENAI_REALTIME_DEPLOYMENT env |
Azure deployment name (e.g. gpt-realtime-slackbot). |
| Realtime voice | AZURE_OPENAI_REALTIME_VOICE env |
verse (default), alloy, coral, sage, ... |
| Realtime region | AZURE_OPENAI_REGION env |
Deployment region — used for WebRTC URL. |
| DM time | vercel.json crons[0] |
30 4 * * 1-5 = 10:00 IST. |
| Brief time | vercel.json crons[1] |
0 5 * * 1-5 = 10:30 IST. |
| System prompt | api/realtime/token.ts SYSTEM_PROMPT |
What the voice assistant is told to do. |
| Tool list | api/realtime/token.ts TOOLS |
Functions the assistant can call. |
- Slack API: free
- Gemini 2.0 Flash: ~$0.01-0.05 per brief
- Azure OpenAI Realtime (
gpt-realtime): ~$32/M audio input + $64/M audio output tokens. A 15-min standup ≈ $3-6. - Neon free tier: enough until you have multiple workspaces.
- Vercel free tier: cron + functions fit.
- Slack OAuth instead of pasted dashboard secret
- Per-user DMs of action items they own after the standup
- Slack reactions (
:white_check_mark:) close Kanban cards - Cross-day continuity for blockers ("still blocked yesterday")
- Recording transcripts to Postgres for searchable history