Skip to content

Repository files navigation

DataPulse

A Slack bot that brings OpenMetadata into the channels where your data team already lives.

What is DataPulse

DataPulse is a production-grade Slack bot that integrates with OpenMetadata to surface data quality, lineage, and ownership information directly inside Slack. Instead of context-switching to a separate UI to ask "is this table healthy?", "where does this data come from?", or "who owns this asset?", your team can just type /datapulse and get a Block Kit answer in seconds.

It also runs in the background: every 15 minutes it polls OpenMetadata for newly-failing data quality tests and posts an alert to your #data-health channel, and every morning at 9am it posts a daily digest with the tables that need attention, the assets without owners, and an overall health score for the platform.

Features

  • 🔍 /datapulse search <query> — find tables by free-text search
  • 📊 /datapulse quality <fqn> — pass / fail / aborted counts with the latest failures
  • 🔗 /datapulse lineage <fqn> — upstream and downstream tree (2 levels)
  • 👤 /datapulse owner <fqn> — owner, team, last-updated, description completeness score
  • 🚨 Real-time alerts — new test failures posted to #data-health every 15 minutes
  • 🌅 Daily digest — 9am summary with health score, failing tables, and unowned assets
  • 🛡️ Resilient — retries, circuit breaker, per-user rate limiting, friendly error messages
  • 🐳 Container-ready — runs anywhere Node.js or Docker runs

Architecture

            ┌────────────────────┐
            │     Slack          │
            │  (slash commands,  │
            │   buttons)         │
            └─────────┬──────────┘
                      │ Bolt.js
                      ▼
            ┌────────────────────┐
            │     DataPulse      │
            │  ┌──────────────┐  │     polls every 15m
            │  │ command      │  │     ┌──────────────┐
            │  │ router       │──┼────▶│ alert engine │
            │  └──────────────┘  │     └──────┬───────┘
            │  ┌──────────────┐  │            │
            │  │ rate limiter │  │     ┌──────▼───────┐
            │  └──────────────┘  │     │  scheduler   │ 9am cron
            │  ┌──────────────┐  │     └──────┬───────┘
            │  │ Block Kit    │  │            │
            │  │ renderer     │  │            │
            │  └──────┬───────┘  │            │
            │         │          │            │
            │  ┌──────▼───────┐  │            │
            │  │ OM client    │◀─┼────────────┘
            │  │ (retry +     │  │
            │  │  breaker)    │  │
            │  └──────┬───────┘  │
            └─────────┼──────────┘
                      ▼
            ┌────────────────────┐
            │   OpenMetadata     │
            │   REST API         │
            └────────────────────┘

Setup guide

1. Create a Slack app

  1. Go to https://api.slack.com/appsCreate New AppFrom scratch.
  2. Under Socket Mode, enable Socket Mode and generate an app-level token (xapp-…) with the connections:write scope.
  3. Under OAuth & Permissions, add the bot scopes: chat:write, commands, chat:write.public.
  4. Under Slash Commands, create /datapulse with description Query OpenMetadata.
  5. Under Interactivity & Shortcuts, enable Interactivity (no Request URL needed in Socket Mode).
  6. Install the app to your workspace and grab:
    • Bot User OAuth Token (xoxb-…)
    • Signing Secret (Basic Information → App Credentials)
    • App-Level Token (xapp-…)

2. Configure environment

cp .env.example .env
# fill in SLACK_BOT_TOKEN, SLACK_SIGNING_SECRET, SLACK_APP_TOKEN

The OpenMetadata sandbox at https://sandbox.open-metadata.org is open — leave OPENMETADATA_TOKEN empty. For self-hosted instances, use a service-account JWT.

3. Run

npm install
npm start

You should see:

[INFO] DataPulse Slack app started {"mode":"socket"}
[INFO] Alert engine started {"intervalMs":900000,"channel":"#data-health"}
[INFO] Daily digest scheduler started {"cron":"0 9 * * *"}

Then in Slack: /datapulse search customers.

Command reference

Command Description Example
/datapulse search <query> Search tables by name / description /datapulse search orders
/datapulse quality <fqn> Show pass/fail/aborted test counts + latest failures /datapulse quality svc.db.shop.orders
/datapulse lineage <fqn> Show upstream/downstream lineage tree /datapulse lineage svc.db.shop.orders
/datapulse owner <fqn> Show owner, team, last-updated, description score /datapulse owner svc.db.shop.orders
/datapulse help Show all commands /datapulse help

Append --help to any subcommand (e.g. /datapulse quality --help) for detailed usage.

Alert configuration

All thresholds live in src/alerts/thresholds.js:

Setting Default Purpose
failingTestsPerTable 2 Digest threshold for "needs attention"
maxAlertsPerCycle 10 Cap per polling cycle to avoid Slack flooding
consecutivePollFailures 3 Trip the engine breaker after this many failed polls
pollCooldownMs 5 * 60_000 How long to pause when the breaker trips

Operational knobs are set via environment variables:

Var Default Purpose
ALERT_POLL_MINUTES 15 How often to poll for new failures
DIGEST_CRON 0 9 * * * Cron expression for the daily digest
DATA_HEALTH_CHANNEL #data-health Where alerts and the digest are posted

Production note: alert dedupe state and the rate limiter both use an in-memory Map. For multi-replica deployments, swap them for Redis — both modules call out the swap in their JSDoc.

Deployment

Railway

  1. railway init and link your repo.
  2. In the Railway dashboard, set the env vars from .env.example.
  3. Set the start command to npm start. Railway auto-detects the Dockerfile if present.
  4. Deploy — the bot will connect via Socket Mode, no public URL needed.

Render

  1. New → Web Service → connect your repo.
  2. Environment: Docker.
  3. Add the env vars from .env.example under "Environment".
  4. Set health check path to / (or disable, since Socket Mode means no inbound HTTP).

Docker / docker-compose

docker compose up -d --build

The included docker-compose.yml reads .env and runs the bot with tini as PID 1 so SIGTERM shuts the cron + alert loop down cleanly.

Contributing

  1. Fork and clone.
  2. npm install.
  3. Write your change with a test in tests/.
  4. npm test — all tests must pass.
  5. Open a PR. CI runs npm test plus a Docker build smoke test.

Style notes:

  • All public functions get a JSDoc block.
  • Async/await everywhere — no callbacks.
  • Keep Block Kit renderers pure (no I/O) so they stay easy to test.
  • Add new alert thresholds to src/alerts/thresholds.js, not inline.

DataPulse • sandbox.open-metadata.org

About

ASlack bot that brings OpenMetadata into the channels where your data team already lives.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages