feat(stacks): Add Evidence — SQL+markdown BI for analytics engineers#616
Merged
Conversation
Evidence is an open-source "BI as code" framework: each page is a Markdown file with embedded SQL blocks that render to charts, tables, and inline values. Projects live as plain text and diff in Git, which makes Evidence a natural complement to the existing code-server / Gitea / Woodpecker-CI workflow — write a page on a branch, review the rendered diff, merge. This stack ships the `evidencedev/devenv` runtime preloaded with a sample project that queries the in-stack Postgres via env-var interpolation. Operators extend `stacks/evidence/project/sources/` to add ClickHouse, Trino, DuckDB/pg_ducklake, Iceberg/Lakekeeper, or any external warehouse. Port 3007 → 3000 (3000–3006 are already taken by Metabase / Uptime-Kuma / Wetty / Hoppscotch / Dagster / Wiki.js / Big-AGI). Category `analytics` alongside Metabase and Superset. No Tofu-managed secrets — Evidence pipes through the existing postgres_password for the bundled sample query; operator-added sources reference whatever credentials the operator wires into stacks/evidence/.env. `evidencedev/devenv:latest` is acceptable under the CLAUDE.md exception for non-critical standalone tools (Evidence is a presentation layer with no persistent state beyond cache) and Evidence does not publish stable devenv tags. Closes #615
Contributor
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new Evidence stack to Nexus-Stack, providing a Markdown + embedded-SQL “BI as code” runtime (Evidence devenv) with a bundled sample project that queries the in-stack Postgres, plus deploy-time env rendering and documentation updates.
Changes:
- Introduces
stacks/evidence/(docker-compose + sample Evidence project with Postgres source + example page/query). - Registers the stack in
services.yamland wires deploy-time env generation viasrc/nexus_deploy/service_env.py(plus unit tests). - Updates top-level and stack documentation (README, stacks index, new
docs/stacks/evidence.md).
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
stacks/evidence/docker-compose.yml |
New Evidence service definition (ports, env, volume mount, healthcheck). |
stacks/evidence/project/pages/index.md |
Sample Evidence landing page demonstrating SQL-in-Markdown + DataTable. |
stacks/evidence/project/sources/nexus_postgres/connection.yaml |
Evidence Postgres source configured via env-var interpolation. |
stacks/evidence/project/sources/nexus_postgres/database_overview.sql |
Sample query for table list + row-count estimates. |
stacks/evidence/project/package.json |
Sample project scripts and Evidence driver dependencies. |
stacks/evidence/project/evidence.config.yaml |
Evidence config defaults (appearance, basePath). |
stacks/evidence/project/.gitignore |
Ignores node/evidence build artifacts in the sample project. |
src/nexus_deploy/service_env.py |
Adds _render_evidence and registers it in the EnvSpec list. |
tests/unit/test_service_env.py |
Adds unit tests for Evidence env rendering (domain + password piping). |
services.yaml |
Registers the new evidence service (subdomain, port, category, image, descriptions). |
README.md |
Updates stack count and adds Evidence badge + table entry. |
docs/stacks/README.md |
Adds Evidence to images table and stack-doc list. |
docs/stacks/evidence.md |
New stack documentation page for Evidence. |
- Add `env_file: .env` to evidence compose so operator-added data-source
credentials in stacks/evidence/.env reach the container for
${VAR} interpolation in sources/<name>/connection.yaml.
- Convert the inline-code line-wrapped `docker exec` chain in the
sample page to a fenced code block — inline spans don't always
render reliably across a newline.
- Use the on-server absolute path (/opt/docker-server/stacks/evidence/
project/...) in the Usage and "Building a static site" sections of
docs/stacks/evidence.md so the doc matches the "on the server"
framing it uses elsewhere.
Copilot rightly flagged that PR #616 introduces `evidencedev/devenv:latest` without an explicit CLAUDE.md exemption. Verified upstream (\`docker hub v2/repositories/evidencedev/devenv/tags\`): only two tags exist, \`:latest\` (updated 2024-12-13) and \`:ubuntu\` (2023-10-01). No semver tags published. Digest pinning is technically possible but adds zero predictability — every refresh would still require a manual update with no semantic-version migration path, same as the other entries already on the allow-list. Extends the exception to include `evidence`, and adds the underlying rationale (presentation-layer / dev-tool with no persistent state, upstream publishes no semver) so future stack additions have a test for the exemption rather than just an opaque list.
Remove misleading reference to a 'credentials.yaml' file in the
Evidence source comment — Evidence's source structure is just
connection.yaml (with ${VAR} interpolation for any credentials)
plus .sql query files. Legacy versions had a separate
credentials.yaml; current upstream uses inline env-var
interpolation in connection.yaml itself.
The renderer was emitting `EVIDENCE_DOMAIN=https://...` — a value that
contains the URL scheme. The rest of the codebase consistently reserves
`*_DOMAIN` for bare hostnames (HEDGEDOC_DOMAIN, LAKEKEEPER_DOMAIN) and
uses `*_URL`/`*_BASE_URL` when the value includes the scheme (KESTRA_URL,
CB_SERVER_URL, NC_PUBLIC_URL). Evidence was the only exception, and the
compose file even had to bridge it via `EVIDENCE_BASE_URL: ${EVIDENCE_DOMAIN}`
to match the actual upstream variable name.
Rename to align with both internal convention and upstream's own naming;
drop the now-redundant `EVIDENCE_BASE_URL` line from compose since
env_file already passes the value through.
Also fixes the multi-tenant subdomain test, whose docstring claimed
`evidence-user1.example.com` while the assertion was
`evidence-example.com` (the test only changed the separator, not the
base domain). Test input now includes `domain="user1.example.com"` so
the assertion actually demonstrates the documented behaviour.
stefanko-ch
pushed a commit
that referenced
this pull request
May 28, 2026
🤖 I have created a release *beep* *boop* --- ## [0.68.0](v0.67.0...v0.68.0) (2026-05-28) ### 🚀 Features * **stacks:** Add Evidence — SQL+markdown BI for analytics engineers ([#616](#616)) ([ac9ef64](ac9ef64)) ### 🐛 Bug Fixes * **hedgedoc:** Seeded admin account + R2 snapshot/restore persistence ([#619](#619)) ([a04d529](a04d529)) * **pipeline:** Pre-create ollama-internal network when LiteLLM enabled ([#617](#617)) ([3ea36be](3ea36be)) * **stacks:** Raise Metabase JVM heap to prevent OOM ([#620](#620)) ([70bb786](70bb786)) * **stacks:** Remove hardcoded credential fallbacks (audit C1-C3) ([#623](#623)) ([3002629](3002629)) * **stacks:** Resolve host-port 8888 collision (adminer ⇔ seaweedfs) ([#624](#624)) ([6831d2c](6831d2c)) * **tofu:** Validate cloudflare_account_id, cloudflare_zone_id, domain shapes ([#622](#622)) ([47f25c6](47f25c6)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Evidence — an open-source "BI as code" framework where each page is a Markdown file with embedded SQL blocks that render to charts, tables, and inline values. Pages diff as plain text, which makes Evidence the natural complement to the existing code-server / Gitea / Woodpecker-CI workflow.
evidence(port3007→ container3000, categoryanalytics)evidencedev/devenvruntime preloaded with a sample project that queries the in-stack Postgrespostgres_password; operator-added sources reference whatever credentials the operator wires intostacks/evidence/.envCloses #615
Why this shape
No new Tofu secret. The sample project consumes the existing
postgres_passwordvia env-var interpolation insources/nexus_postgres/connection.yaml. Operator-added data sources reference Infisical-managed credentials from any other stack. No double-managing.Port 3007. 3000–3006 already taken by Metabase / Uptime-Kuma / Wetty / Hoppscotch / Dagster / Wiki.js / Big-AGI. 3007 is the closest free slot to Evidence's default 3000.
Image
evidencedev/devenv:latest. Acceptable under the CLAUDE.md exception for non-critical standalone tools (Evidence is a presentation layer with no persistent state beyond cache) and Evidence does not publish stable devenv tags. Multi-arch verified (amd64 + arm64).No fail-fast guard. Evidence renders pages even without a working data source (it just shows query errors inline). The operator may legitimately be wiring an external warehouse instead of the in-stack Postgres. Empty postgres_password surfaces as a per-query "auth failed" message, not a crashed container.
Test plan
gh workflow run spin-up.yml --ref feat/stacks/evidencedeploys cleanlyhttps://evidence.YOUR_DOMAINrenders the sample page behind CF Accessstacks/evidence/project/pages/index.mdon the server hot-reloads in the browserdocker exec evidence npm run sources && docker exec evidence npm run buildproduces aproject/build/directory (static export path)No
initial-setup.yamlneeded — Evidence does not introduce a new secret, so the Tofu state has no new resources beyond the standard subdomain + tunnel + access bindings handled by the generic service-loop.Files
stacks/evidence/docker-compose.yml+ sample project (project/package.json,evidence.config.yaml,pages/index.md,sources/nexus_postgres/{connection.yaml,database_overview.sql},.gitignore)services.yamlentrysrc/nexus_deploy/service_env.py—_render_evidence+EnvSpecregistrationtests/unit/test_service_env.py— 3 new testsREADME.md— badge + table row + countdocs/stacks/README.md— image-versions table + stack-doc listdocs/stacks/evidence.md— full per-stack docs