Apache Superset + dbt + Neon Postgres — the BI stack behind 2nth.ai demos.
- Proposition: the lowest-risk entry point to AI transformation — Superset over a read-only warehouse, seeded by dbt, deployed on Cloudflare/Google edge, with Workers AI NL→SQL as the next layer.
- Live pitch: dev.biz-demos.pages.dev/bi/
- Explainers:
- Superset 4.x running on Google Cloud Run in
africa-south1. - Neon Postgres (paid,
imbilawork@gmail.com) inaws-eu-central-1— both Superset metadata and the analytics warehouse in one project, two schemas, two branches (main,dev). - dbt-core scheduled as a Cloud Run Job (02:00 SAST daily) seeding synthetic SilverGro agri/commodities data — SAFEX prices, client book, feedlot rations, hedge coverage.
- Redis via Upstash (cache + Celery broker).
- GitHub Actions → Artifact Registry → Cloud Run via Workload Identity Federation.
ClickHouse and Workers AI NL→SQL are v2 — see docs/architecture.md.
bi-stack/
docker-compose.yml # local dev stack
.env.example # Neon + Redis + Superset env
superset/ # Dockerfile, config, bootstrap
dbt/ # dbt project + SilverGro seeds + models
gcp/ # Cloud Run deploy scripts
.github/workflows/ # CI + tag-triggered deploy
docs/ # architecture, runbook
Full clone-to-running-stack walkthrough: docs/quickstart.md.
Short version:
./scripts/setup-env.sh # derives .env from a Neon pooled URI
# paste sql/neon-init.sql into Neon SQL Editor (one-time)
docker compose up --build
# http://localhost:8088 — login with admin / ADMIN_PASSWORD from .envRun dbt against the Neon dev branch:
cd dbt
cp profiles.yml.tmpl ~/.dbt/profiles.yml # then edit target URIs
dbt deps
dbt seed
dbt buildOne-time bootstrap (Artifact Registry, Secret Manager, Workload Identity Federation, service accounts):
./gcp/secrets-bootstrap.shThen deploy the three Superset services + the dbt job + the scheduler:
./gcp/deploy-web.sh
./gcp/deploy-worker.sh
./gcp/deploy-beat.sh
./gcp/deploy-dbt-job.sh
./gcp/scheduler.shCI/CD: tag v* to trigger .github/workflows/deploy.yml.
- Cloud Run
--cpu-always-allocatedis mandatory on theworkerandbeatservices. Without it Celery silently stops between requests. Forces instance-based billing (~$15–25/mo per always-on service). - Neon pooled endpoint breaks SQLAlchemy prepared statements. Superset metadata uses the direct (unpooled) Neon endpoint; dbt uses the pooled endpoint.
superset_config.pyis baked into the image, not mounted from Secret Manager. Secrets are env vars referenced by name inside the config.- Guest-token signing key rotation invalidates every live embed. 12-month key; rotation playbook in
docs/runbook.md. - Neon Frankfurt latency (~160 ms from africa-south1) is acceptable because Redis caches query results; dbt runs feel slow but run overnight.
MIT — see LICENSE.