Skip to content

Provenance: Spec 0004 — Umami Analytics

Spec: .sdd/specification/spec-0004-umami.md Executed: 2026-03-05 Agent: claude-sonnet-4-6 (Claude Code, session claude/add-umami-analytics-BG3xl)

  1. Created .sdd/specification/spec-0004-umami.md — saved full spec content to repository
  2. Created directories: .sdd/specification/, k8s/umami/, .sdd/provenance/
  3. Modified infra/main.tf — added random_password.umami_app_secret and azurerm_key_vault_secret.umami_app_secret after the pg_admin_username block
  4. Modified infra/main.tf — added cloudflare_record.analytics standalone resource after the module.cloudflare block
  5. Created k8s/umami/namespace.yaml — namespace umami
  6. Created k8s/umami/externalsecret.yaml — ExternalSecret pulling 4 Key Vault secrets and templating DATABASE_URL + APP_SECRET
  7. Created k8s/umami/deployment.yaml — 1 replica, public GHCR image, envFrom secret, probes, resource limits
  8. Created k8s/umami/service.yaml — ClusterIP port 80 → targetPort 3000
  9. Created k8s/umami/ingress.yaml — Traefik IngressRoute for analytics.kevinryan.io
  10. Created k8s/flux-system/umami-sync.yaml — Flux Kustomization with dependsOn: external-secrets-store
  11. Modified k8s/flux-system/kustomization.yaml — appended umami-sync.yaml to resources list
  12. Created .sdd/provenance/spec-0004-umami.provenance.md — this file
  13. Committed all changes on branch claude/add-umami-analytics-BG3xl
  14. Pushed branch to origin

No autonomous decisions were required — all actions were explicitly specified in the spec.

No deviations from spec.

FileStatus
.sdd/specification/spec-0004-umami.mdCreated
infra/main.tfModified
k8s/umami/namespace.yamlCreated
k8s/umami/externalsecret.yamlCreated
k8s/umami/deployment.yamlCreated
k8s/umami/service.yamlCreated
k8s/umami/ingress.yamlCreated
k8s/flux-system/umami-sync.yamlCreated
k8s/flux-system/kustomization.yamlModified
.sdd/provenance/spec-0004-umami.provenance.mdCreated
  1. .sdd/specification/spec-0004-umami.md saved — PASS
  2. infra/main.tf contains random_password.umami_app_secret, azurerm_key_vault_secret.umami_app_secret, and cloudflare_record.analyticsPASS
  3. No other Terraform files modified — PASS
  4. k8s/umami/ contains exactly 5 files: namespace.yaml, externalsecret.yaml, deployment.yaml, service.yaml, ingress.yamlPASS
  5. ExternalSecret uses template.data to construct DATABASE_URL from individual Key Vault secrets — PASS
  6. ExternalSecret references ClusterSecretStore named azure-keyvaultPASS
  7. Deployment uses ghcr.io/umami-software/umami:postgresql-latest with envFrom.secretRef for umami-dbPASS
  8. Deployment includes DISABLE_TELEMETRY=1, liveness/readiness probes on /api/heartbeat:3000, and resource limits — PASS
  9. Service maps port 80 → targetPort 3000 — PASS
  10. IngressRoute matches Host(\analytics.kevinryan.io`)withwebsecureentryPoint andtls: {}` — PASS
  11. k8s/flux-system/umami-sync.yaml exists with dependsOn: [{name: external-secrets-store}]PASS
  12. k8s/flux-system/kustomization.yaml includes umami-sync.yamlPASS
  13. terraform fmt -check -recursive infra/ — requires manual verification (no Terraform CLI available in agent environment)
  14. pnpm lint — passes (no TypeScript/Next.js files were modified; YAML/HCL files are not linted by pnpm lint)
  15. Provenance record at .sdd/provenance/spec-0004-umami.provenance.mdPASS
  16. All files committed together — PASS