Repository navigation
feat: mount LiveDashboard under /admin in production - #305
Merged
Merged
Conversation
Moves the dashboard from /dev/dashboard to /admin/dashboard, behind the admin basic auth, and stamps its scripts with the CSP nonce. Adds ecto_psql_extras so the Ecto Stats page works. Closes #302
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
Static review identified no blocking issues; production smoke checks remain a post-deployment step.
No open issues 🎉
What changed in this PR
Makes LiveDashboard available in production behind existing admin authentication, complementing remote-shell diagnostics.
Changes:
- Moves LiveDashboard to
/admin/dashboard, retaining/dev/mailbox. - Adds script nonce support, embedded-font permissions, and Ecto Stats dependencies.
- Adds authentication and CSP tests and updates operational documentation.
| File | Description |
|---|---|
| test/flick_web/live_dashboard_test.exs | Tests authentication, script nonces, and Ecto Stats availability. |
| mix.lock | Locks Ecto Stats dependencies. |
| mix.exs | Adds ecto_psql_extras. |
| lib/flick_web/telemetry.ex | Updates the documented dashboard path. |
| lib/flick_web/router.ex | Mounts the authenticated dashboard and adjusts CSP. |
| config/dev.exs | Clarifies the mailbox-only development route comment. |
| AGENTS.md | Documents dashboard access and operational safeguards. |
Review effort: Balanced
This was referenced Oct 20, 2026
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.
Closes #302
Phoenix LiveDashboard now runs in production at
/admin/dashboard, behind the same basic auth as/admin/ballots. It joins observer_cli from #301 as the second way to inspect a live node, and the one that needs no Render Shell.A request without the admin login gets a 401, so the dashboard is no more open than the admin ballot index. A revert removes the route and the new dependency, and nothing else depends on them.
/dev/dashboardis gone, and/dev/mailboxstill works. The suite passes with 193 tests, three of them new inlive_dashboard_test.exs.The dashboard needs two CSP changes to load cleanly
The dashboard's scripts get the per-request nonce through
csp_nonce_assign_key: %{script: :csp_nonce}(router.ex:73). Onlyscript-srccarries a nonce, so styles do not get one. A test asserts that every<script>on the page carries the nonce from the response header. It failed when I removed the option.The dashboard's CSS also embeds its font as a
data:URL, whichdefault-src 'self'blocked. The policy now allowsfont-src 'self' data:(router.ex:34). With both changes, Home and Processes load in headless Chromium with no console errors.Ecto Stats works, and OS Data stays off
ecto_psql_extrasbacks the Ecto Stats page. It shows table and index sizes, index usage, bloat, locks, and long-running queries. Since #304 closed the database's allow list, a remote IEx shell was the only other way to see these. LiveDashboard hides the library's destructivekill_all, so the page only reads.:os_monstays out. Inside a container,memsupreports the host's memory rather than the 512 MB limit, so the OS Data page would mislead. Render's service charts already show CPU and memory.Try it
Run
mix phx.server, openhttp://localhost:4000/admin/dashboard, and sign in asflick-admin/unsafe-password. CLAUDE.md's Observability section now describes the route.Worth a reviewer's attention
font-src 'self' data:applies to the whole app, not just/admin. A per-scope policy would be tighter, but fonts cannot run script, so the global rule is simpler and loses little.pg_stat_statements. I don't know whetherflick_prodhas it enabled. If it does not, those two tables show an error and the rest still work.Process.info/2for the dictionary, links, and stack trace, not:sys.get_state, and no page dumps ETS contents. CLAUDE.md still says to keep the dashboard in the/adminscope, because it exposes the node's internals.ifchecks:dev_routes, and the comment is what says that means development./admin/dashboardand that the console shows no CSP violations.