feat(observability): PO Overview Grafana dashboard (#651) #659
Open
marcel
wants to merge 9 commits from
feat/issue-651-grafana-po-overview into main
pull from: feat/issue-651-grafana-po-overview
merge into: marcel:main
marcel:main
marcel:feat/issue-560-vimock-migration
marcel:feat/issue-286-notification-bell-form-actions
marcel:feat/issue-580-sentry-backend
marcel:fix/issue-593-management-port-zero
marcel:worktree-feat+issue-557-upload-artifact-v3-pin
marcel:worktree-chore+issue-556-drop-client-branches-coverage-gate
marcel:fix/issue-514-prerender-crawl-bakes-redirects
marcel:fix/issue-472-prerender-entries
marcel:feat/issue-395-readme
marcel:feat/issue-345-bulk-mark-reviewed
marcel:feat/issue-344-bell-tooltip
marcel:feat/issue-341-annotieren-contrast
marcel:feat/issue-225-bulk-metadata-edit
marcel:feat/issue-317-bulk-upload
marcel:feat/issue-271-dashboard-redesign
marcel:docs/issue-240-mission-control-spec
marcel:refactor/issues-193-200
marcel:feat/issue-162-korrespondenz-redesign
marcel:feature/68-new-document-file-first
marcel:feat/81-discussion-discoverability
marcel:feat/62-document-bottom-panel
marcel:feature/56-backfill-file-hashes
marcel:feat/38-document-edit-history
marcel:fix/svelte5-test-delegation-and-login-auth
No Reviewers
Labels
Clear labels
P0-critical
P1-high
P2-medium
P3-later
audit
bug
cleanup
collaboration
conversation
descoped
devops
documentation
epic
feature
file-upload
legibility
notification
person
phase-1: security
phase-2: container-images
phase-3: prod-compose
phase-4: spring-prod-profile
phase-5: backups
phase-6: deployment-docs
phase-7: monitoring
refactor
security
test
ui
user
Blocks a core user journey, causes data loss, or is a security/accessibility barrier. Work on this before P1+.
Significant friction on a main user journey; workaround exists but is non-obvious. Next up after P0.
Noticeable improvement; doesn't block anything; schedule opportunistically.
Cosmetic or parking-lot work; fine to stay open indefinitely.
Read-only audit / assessment work; produces a report rather than changing code
Something isn't working
Removal of dead code, vague comments, naming violations, and scratch artifacts
We want to extend the family archive to have more collaboration tools
We will do that later
README, ARCHITECTURE, GLOSSARY, CONTRIBUTING, per-domain docs
Marker for epic-level issues that group multiple child issues
Codebase Legibility Refactor — preparing the codebase for human evaluation and bus-factor reduction
Security hygiene — must be done first
Production-ready multi-stage Docker images
Production compose overlay + Caddy reverse proxy
Spring Boot production configuration profile
Database and object storage backup strategy
.env.example, DEPLOYMENT.md, runbook
Prometheus, Loki, Grafana, Alertmanager
Code restructuring without behaviour change
UI/UX and accessibility issues
No Label
Milestone
No items
No Milestone
Projects
Clear projects
No project
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: marcel/familienarchiv#659
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "feat/issue-651-grafana-po-overview"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Provisioned a single Grafana dashboard the product owner can open once a week to answer four questions at a glance — is everything working, are people using it, is the archive making progress, is OCR working well — without needing a developer to drag SQL out of
audit_log. Closes #651.Architecture
Decisions taken (from the issue's decision queue)
FlywayConfig.placeholders(Map.of(...)). Atomic, idempotent (CREATEon first run,ALTERon re-run), no separate bootstrap script.%and a separate stat forBlocks Transcribed This Week. TheTEXT_SAVEDweekly count was already a dedicated panel in Row 3, so the "+N this week" badge collapses naturally into it.What's in the PR
backend/.../db/migration/V68__add_grafana_reader_role.sqlgrafana_readerwith SELECT onaudit_log,documents,transcription_blocks.backend/.../config/FlywayConfig.java.placeholders(Map.of("grafanaDbPassword", System.getenv(...))). Logs a warning + uses a non-secret fallback if the env var is missing, so tests/CI don't fail loudly when the secret is irrelevant.backend/.../config/GrafanaReaderRoleIntegrationTest.javaapp_users(NFR-SEC-01).infra/observability/grafana/provisioning/datasources/datasources.ymlpostgresdatasource,editable: false,sslmode: disable(intra-network).infra/observability/grafana/provisioning/dashboards/po-overview.jsonuid: po-overview, 7-day default range, manual refresh, panel titles per Leonie's recommendations.docker-compose.observability.ymlobs-grafanajoinsarchiv-netand receivesGRAFANA_DB_PASSWORD.docker-compose.ymlarchive-backendreceivesGRAFANA_DB_PASSWORD(Flyway needs it)..env.example,infra/observability/obs.envopenssl rand -hex 32hint.docs/DEPLOYMENT.mddocs/architecture/c4/l2-containers.pumlTest plan
./mvnw test -Dtest=GrafanaReaderRoleIntegrationTest— 4/4 green (positive + negative privilege assertions)./mvnw test -Dtest=AuditLogQueryRepositoryIntegrationTest— still 4/4 green (Flyway placeholder didn't break the existing migration suite)./mvnw compile— cleanhttp://localhost:3003→ PO Overview → confirm every panel populates (not "No data") and the default range is "Last 7 days".Out of scope
Alerting, per-user breakdown, per-sender OCR accuracy, mobile layout — all explicit in the issue.
🤖 Generated with Claude Code
Add Flyway V68 migration that provisions a read-only PostgreSQL role scoped to audit_log, documents, and transcription_blocks. The role's password is injected via the new ${grafanaDbPassword} Flyway placeholder, which FlywayConfig reads from the GRAFANA_DB_PASSWORD env var. The migration is idempotent: CREATE on first run, ALTER on re-run. Adds a Testcontainers integration test asserting positive grants on the three intended tables and a negative grant on app_users (NFR-SEC-01). Refs #651. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>Flyway runs inside the backend container at startup; V68's ${grafanaDbPassword} placeholder is resolved from this env var. Refs #651. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>Wires the new GRAFANA_DB_PASSWORD secret through the deploy pipeline: - docker-compose.prod.yml: backend env now passes GRAFANA_DB_PASSWORD through so Flyway V68 can resolve the ${grafanaDbPassword} placeholder in production and staging (it already worked in local dev via docker-compose.yml). - release.yml + nightly.yml: declare GRAFANA_DB_PASSWORD as a required Gitea secret, write it into .env.production / .env.staging (consumed by archive-backend), and into /opt/familienarchiv/obs-secrets.env (consumed by obs-grafana's PostgreSQL datasource). Operator action before the next deploy: add a GRAFANA_DB_PASSWORD value to the Gitea repo secrets (openssl rand -hex 32). Refs #651. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>3a0290ab35tobcba4dab80View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.