Skip to content

jenish-jain/dbDigest

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

10 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

DBDigest

Automated database changelog digest β€” scrapes release notes, engineering blogs, and GitHub releases, summarises them with Claude AI, and delivers a structured digest + podcast-style audio to Slack.

Currently supported: MongoDB
Planned: PostgreSQL, MySQL, Redis, Cassandra, Elasticsearch

How it works

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Scraper  │──▢│ Storage (dedup)     │──▢│ Summarizer│──▢│ Renderer     │──▢│ Notifier      β”‚
β”‚ RSS      β”‚   β”‚ SQLite  (local dev) β”‚   β”‚ Claude AI β”‚   β”‚ Markdown     β”‚   β”‚ Slack (text)  β”‚
β”‚ GitHub   β”‚   β”‚ GCS     (Cloud Run) β”‚   β”‚ Two-pass  β”‚   β”‚ Podcast .md  β”‚   β”‚ Slack (audio) β”‚
β”‚ Releases β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚ JSON +    β”‚   β”‚ MP3 via GCP  β”‚   β”‚ Email         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                             β”‚ plain textβ”‚   β”‚ TTS          β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Each run:

  1. Scrapes new articles from RSS feeds and GitHub Releases
  2. Deduplicates against seen URLs (SQLite locally, GCS JSON on Cloud Run)
  3. Summarises with Claude β€” two API calls per database to avoid JSON/prose conflicts
  4. Renders a structured .md digest + a podcast-style transcript
  5. Synthesises the transcript to MP3 via Google Cloud TTS (Neural2, free tier)
  6. Delivers text to Slack via webhook + MP3 as an inline Slack audio player via bot token

Quick start (local)

Prerequisites

Run

git clone https://github.com/your-org/dbdigest && cd dbdigest

# Required
export ANTHROPIC_API_KEY="sk-ant-..."

# Optional β€” needed for Slack notifications
export SLACK_WEBHOOK="https://hooks.slack.com/services/..."
export SLACK_TOKEN="xoxb-..."          # bot token for audio upload
export SLACK_CHANNEL_ID="C0123ABC"     # right-click channel β†’ Copy Channel ID

# Dry run first β€” scrapes sources, prints what was found, no Claude API calls
make dry-run

# Full run
make run

# Resend the last generated digest without re-scraping
make resend

Generated files land in ./digests/:

digests/
β”œβ”€β”€ dbdigest_2026-04-11_090000.md          # structured digest
β”œβ”€β”€ dbdigest_2026-04-11_090000_podcast.md  # podcast transcript
└── dbdigest_2026-04-11_090000_podcast.mp3 # audio (if TTS enabled)

Cloud Run setup (production)

One-time infrastructure provisioning via Terraform, then CI/CD handles every deploy automatically.

Prerequisites

  • GCP project with billing enabled
  • terraform >= 1.6
  • gcloud CLI, authenticated (gcloud auth login && gcloud auth application-default login)
  • A GitHub repository for this code

1. Provision infrastructure

cd terraform
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars β€” set project_id, gcs_bucket, github_repo at minimum
make tf-init
make tf-plan   # review what will be created
make tf-apply

This creates:

Resource Purpose
Artifact Registry repo Stores Docker images
GCS bucket Digest state, markdown files, MP3 audio
Cloud Run Job Runs the digest pipeline
Cloud Scheduler Triggers the job on a cron schedule (default: Mon 9 AM UTC)
4 Secret Manager secrets API keys / webhook URLs
3 Service accounts Runner, Scheduler, CI β€” minimal permissions each
Workload Identity pool GitHub Actions auth without long-lived keys

After apply, the output will show the exact commands for next steps.

2. Set secret values

echo -n "sk-ant-..." | gcloud secrets versions add dbdigest-anthropic-api-key --data-file=-
echo -n "https://hooks.slack.com/..." | gcloud secrets versions add dbdigest-slack-webhook --data-file=-
echo -n "xoxb-..." | gcloud secrets versions add dbdigest-slack-token --data-file=-
echo -n "ghp_..." | gcloud secrets versions add dbdigest-github-token --data-file=-  # optional

3. Push the first image

gcloud auth configure-docker ${REGION}-docker.pkg.dev
make docker-push

4. Set GitHub Actions variables

In your repo: Settings β†’ Secrets and variables β†’ Variables β†’ New repository variable

Variable Value (from terraform output)
GCP_PROJECT_ID your GCP project ID
GCP_REGION e.g. us-central1
GCP_WIF_PROVIDER output of terraform output wif_provider
GCP_CI_SA output of terraform output ci_service_account

After this, every push to master automatically builds a new image and updates the Cloud Run Job.

5. Run manually to verify

gcloud run jobs execute dbdigest --region us-central1 --wait

Configuration reference

All configuration lives in config.yaml. Sensitive values are read from environment variables (${VAR_NAME} syntax).

Storage

storage:
  type: "sqlite"       # local dev
  # type: "gcs"        # Cloud Run β€” uses GCS for state + digest files
  # bucket: "${GCS_BUCKET}"
  # digests_prefix: "digests/"

Summarizer

summarizer:
  provider: "anthropic"
  api_key: "${ANTHROPIC_API_KEY}"
  model: "claude-sonnet-4-20250514"
  max_tokens: 8096

Output

output:
  format: "podcast"   # generates both structured markdown and podcast transcript
  dir: "./digests"

Text-to-speech (Google Cloud Neural2)

tts:
  enabled: false                   # set to true to generate MP3
  voice: "en-US-Neural2-D"        # Neural2 voices = free tier (1M chars/month)
  language_code: "en-US"

Available Neural2 voices:

Voice Character
en-US-Neural2-D Male, clear and neutral
en-US-Neural2-F Female, natural pace
en-US-Neural2-J Male, slightly warmer

Notifier

notifier:
  type: "slack"
  slack_webhook: "${SLACK_WEBHOOK}"    # for text digest
  slack_token: "${SLACK_TOKEN}"        # xoxb-... bot token for audio upload
  slack_channel_id: "${SLACK_CHANNEL_ID}"  # C0123ABC

Required Slack app scopes for audio upload: files:write, chat:write

Sources

databases:
  mongodb:
    enabled: true
    sources:
      - name: "MongoDB Official Blog"
        type: "rss"
        url: "https://www.mongodb.com/blog/rss"
        tags: ["official"]

      - name: "MongoDB Server GitHub Releases"
        type: "github-releases"
        url: "https://api.github.com/repos/mongodb/mongo/releases"
        github_token: "${GITHUB_TOKEN}"   # optional; raises rate limit 60β†’5000/hr
        lookback_days: 90

  # Add a new database:
  # postgresql:
  #   enabled: true
  #   sources:
  #     - name: "PostgreSQL News"
  #       type: "rss"
  #       url: "https://www.postgresql.org/news.rss"

CLI flags

./dbdigest [flags]

  --config string    Path to config file (default "config.yaml")
  --dry-run          Scrape only β€” no Claude, no writes, no notifications
  --resend           Resend the last digest without re-scraping
  --channel string   Override notification channel for --resend (slack, email)
  --verbose          Enable debug logging
  --version          Show version

Makefile commands

make run            Scrape β†’ summarize β†’ notify (full pipeline)
make dry-run        Scrape only β€” no Claude calls, no writes, no notifications
make resend         Resend the last digest + audio via configured channel
make resend-slack   Resend the last digest to Slack specifically
make verbose        Full pipeline with debug logging
make build          Compile the binary
make clean          Remove binary, local DB, and generated digests
make docker-build   Build the Docker image
make docker-push    Build and push to Artifact Registry
make docker-run     Run locally in Docker using SQLite
make tf-init        Initialise Terraform (run once)
make tf-plan        Preview infrastructure changes
make tf-apply       Provision / update GCP infrastructure
make tf-destroy     Tear down all infrastructure

Project structure

dbdigest/
β”œβ”€β”€ main.go                    # Entry point, CLI flags, storage factory
β”œβ”€β”€ config.yaml                # Configuration (edit this)
β”œβ”€β”€ Dockerfile                 # Multi-stage build for Cloud Run Jobs
β”œβ”€β”€ Makefile
β”‚
β”œβ”€β”€ internal/
β”‚   β”œβ”€β”€ config/config.go       # YAML config loader + validation
β”‚   β”œβ”€β”€ scraper/scraper.go     # RSS, web, GitHub Releases scrapers
β”‚   β”œβ”€β”€ digest/
β”‚   β”‚   β”œβ”€β”€ models.go          # Shared data types (Article, Digest, etc.)
β”‚   β”‚   β”œβ”€β”€ summarizer.go      # Claude API: two-pass JSON + plain-text
β”‚   β”‚   └── render.go          # Markdown + podcast transcript renderer
β”‚   β”œβ”€β”€ tts/tts.go             # Google Cloud TTS β€” chunked MP3 synthesis
β”‚   β”œβ”€β”€ storage/
β”‚   β”‚   β”œβ”€β”€ store.go           # Store interface + SQLite implementation
β”‚   β”‚   └── gcs.go             # GCS implementation (Cloud Run)
β”‚   β”œβ”€β”€ notify/
β”‚   β”‚   β”œβ”€β”€ notify.go          # Channel interface + AudioSender interface
β”‚   β”‚   β”œβ”€β”€ slack.go           # Slack: webhook (text) + Files v2 API (audio)
β”‚   β”‚   β”œβ”€β”€ email.go           # SMTP email
β”‚   β”‚   └── noop.go            # Discard (type: none)
β”‚   └── pipeline/pipeline.go   # Orchestration: scrapeβ†’summarizeβ†’renderβ†’notify
β”‚
└── terraform/
    β”œβ”€β”€ main.tf                # GCP resources
    β”œβ”€β”€ variables.tf
    β”œβ”€β”€ outputs.tf
    β”œβ”€β”€ versions.tf
    └── terraform.tfvars.example

Extending

Add a database β€” add an entry to databases: in config.yaml. No code changes needed for RSS or GitHub Releases sources.

Add a notifier (Discord, Teams, WhatsApp) β€” implement notify.Channel in a new file under internal/notify/, add a case in New().

Add a scraper type β€” add a case in internal/scraper/scraper.go β†’ scrapeSource().


License

MIT

About

πŸƒAutomated database changelog digest β€” scrapes release notes & blogs, summarises with Claude AI, delivers text + podcast audio to Slack.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages