Skip to content

Evidence

Evidence is a static-site BI tool that compiles SQL queries and Markdown into a fully static dashboard site. On this platform the queries run against ClickHouse at build time, the results are baked as Parquet into the image, and the runtime pod is just nginx serving the build output — it never opens a ClickHouse connection.

FieldValue
URLhttps://evidence.internal.stefanzhelev.com (NetBird VPN only)
Flux pathflux-clusters/stefanzhelev/apps/evidence
Base pathflux-apps/evidence
Namespaceevidence
Sync wave7
Depends onclickhouse, data-workflows-database, forgejo, harbor, external-secrets-config, authentik-app-evidence

How a content change reaches the live site:

Pages are SQL + Markdown under evidence/pages/. Sources (the queries that produce the Parquet files) live under evidence/sources/<source-name>/ — currently only clickhouse/.

Terminal window
cd evidence
yarn install
yarn sources # run queries → write parquet
yarn dev # local preview at http://localhost:3000

yarn sources requires EVIDENCE_SOURCE__clickhouse__url, EVIDENCE_SOURCE__clickhouse__username, and EVIDENCE_SOURCE__clickhouse__password in the environment. The connector exposes only those three options — qualify queries with dev__mart.<table> instead of a separate database/schema arg, since dev__mart is the only DB the read-only evidence user has SELECT on.

Open a PR against stefanzhelev. There is no per-PR preview build — review locally with yarn dev.

On any change under evidence/**, .forgejo/workflows/evidence-build.yml fires:

StepWhat happens
yarn install --frozen-lockfileInstalls deps (yarn classic via corepack)
yarn sourcesRuns every SQL source against ClickHouse, writes Parquet into sources/<source>/.evidence/
yarn buildPackages the static site (HTML + JS + Parquet) into evidence/build/
docker buildevidence/Dockerfile copies build/ into nginx-unprivileged
Push to HarborTags :latest and :<git-sha> for SHA rollback

evidence build does not run sources — it only packages whatever Parquet is already on disk. yarn sources must run first or the runtime DuckDB-WASM times out trying to load a missing manifest.json.

Flux’s image-update controllers (or a manual restart) cycle the Deployment to pick up the new :latest tag. Because the data is baked into the image, there is no runtime refresh — every dashboard update is a fresh image build.

Two consequences of the build-time model worth keeping in mind:

  • Data freshness = build time. The numbers shown on evidence.internal are as fresh as the last evidence-build run, not “live”. Trigger a rebuild (push or workflow_dispatch) to refresh them.
  • No runtime credentials. The pod has no ClickHouse credentials and no network path to ClickHouse — only build-time CI does. This is also why the evidence-config Kustomization has no clickhouse-credentials ExternalSecret.
  • Single replica nginxinc/nginx-unprivileged on the stateful-single (cx43) node
  • Read-only rootfs with a writable tmp volume (nginx-unprivileged needs writable temp dirs even with read-only root)
  • No PVC, no DB connection — it’s just static files

Evidence has no native auth. The ingress is on the internalsecure Traefik entrypoint — reachable only over the NetBird VPN — and the authentik-app-evidence Kustomization is launch-only: it provisions an Authentik tile pointing at the ingress so the app shows up on the user dashboard, but it does not gate access at the request layer. VPN membership is the access control.

CI secrets are surfaced from Vault into Forgejo Actions by Tofu modules under flux-apps/evidence/:

SecretSourceUsed by
EVIDENCE_CLICKHOUSE_USERNAME, EVIDENCE_CLICKHOUSE_PASSWORDevidence-database/tofu (read-only evidence user, SELECT on dev__mart only)yarn sources step
EVIDENCE_HARBOR_USERNAME, EVIDENCE_HARBOR_TOKENevidence-docker-registry/tofu (push robot for the Harbor evidence project)docker login + docker push
  • ClickHouse: queried at build time only — qualify with dev__mart.<table>
  • dbt: Evidence reads the mart layer dbt produces; schema changes in dbt drive Evidence content
  • Harbor: stores evidence/evidence:latest and :<sha>
  • Forgejo: runs evidence-build.yml
  • Authentik: dashboard tile only, not an auth gate
  • NetBird: the actual access boundary