Inspiration

I have kept seeing the same story: HR only finds out something's wrong on a team after someone's already quit, or worse, after legal gets involved. Slack analytics tell you who's active not who's getting piled on or burning out. Surveys come too late and people don't always answer honestly anyway.

We wanted something that watches how people actually communicate day to day and flags tension early, without turning the dashboard into a wall of private messages.

What it does

Ember is a app for HR and People Ops. You install it in your slack workspace, invite the bot to channels, and it listens to message events in the background.

A worker scores each message for sentiment, then rolls that up into four behavioral signals per person things like sentiment getting worse over time, after-hours messages, dropping out of channels, or going quiet compared to their usual pattern. That becomes a 0–10 risk score on the dashboard.

The main view shows metrics, an org risk map, and alerts. You can drill into a person to see which signals fired and, when needed, flagged message evidence. We deliberately kept raw chat text off the main dashboard. HR gets signals first, not a surveillance feed.

How we built it

Stack is Next.js 16 on Vercel, DynamoDB for raw Slack events, and Aurora PostgreSQL for people, scores, alerts, and relationships. Drizzle for the Postgres orm side.

Slack hits POST /api/slack/events, we write unprocessed messages to DynamoDB. A scoring worker (/api/worker/score) picks them up, sends text to LLM for sentiment (-1 to +1), falls back to a simple keyword scorer if the API fails, then combines rule-based signals in lib/scoring/. Results go to Postgres and messages get marked processed.

The dashboard is React + SWR . We sync Slack users via users.list so the org chart and risk graph have real names and departments.

For the demo we used our own Slack workspace in dev mode no App Directory approval needed. Just install the app, invite the bot, send some test messages, hit the scoring worker.

Challenges we ran into

Slack webhooks locally were annoying. ngrok URLs change, you forget to update Event Subscriptions, verification fails, repeat. Took me a while to get a reliable loop going.

Vercel Hobby only gives you one cron job per day. We wanted scores to update every few minutes for the demo, so we ended up with a daily Vercel cron as backup and cron-job.org hitting the worker every 5 minutes. Not elegant but it works on the free tier.

Tuning the scoring was harder than wiring the pipeline. Distinguishing a bad week from normal team banter is tricky. We leaned on drift over time and multiple signals instead of flagging one angry message.

Accomplishments that we're proud of

Honestly, the full loop works: real Slack message → DynamoDB → LLM sentiment → Postgres → dashboard updates. That's the thing i am happiest about.

We also like that the architecture isn't just "one database for everything." DynamoDB handles the firehose of raw events; Postgres handles the relational stuff : people, relationships, scores, alerts. Felt like a real reason to use both.

The risk graph and per-person breakdown make the demo click for non-technical judges. You can point at a red node and walk through why someone scored high without reading their entire inbox on screen.

What we learned

Slack apps are just HTTP webhooks. Once that clicked, building the receiver as a Next.js API route in the same repo was way simpler than a separate service.

Serverless limits matter early. Cron frequency, cold starts, env vars on Vercel — plan for that before demo day.

And sentiment alone isn't enough. The behavioral signals (after-hours, channel drop-off, volume changes) do a lot of the heavy lifting. The LLM scores individual messages; the rules catch patterns over time.

What's next for Ember

Multi-workspace support right now we're hardcoded to a demo org for the hackathon.

Microsoft Teams integration is the obvious next step for B2B, but we scoped it out for the MVP.

Getting the application approved on Slack as we deal with sensitive data we need to figure that part out

Longer term: better tuning on the scoring model, persisting settings (they're UI-only right now), and alerts that route to the right manager before things hit critical.

Built With

Share this project:

Updates