Console Completeness Audit — 2026-05-06 UTC
Status: Static QA pass (Phase 1+3 of the test plan)
Scope: console.raxx.app and raxx-console-staging.herokuapp.com — code-side analysis only
Why static: Live UI/UX click-through is blocked by absence of a CF Access service token allowlisted on console.raxx.app's CF Access app (#680). UI verification deferred until that lands.
Executive summary
The "console completeness" pain has a measurable shape. Three findings:
- Code internally consistent. All 94
url_for(...)references in templates resolve to actual routes. No broken nav links. No phantom endpoints. - The visible nav today is much smaller than the shipped surface. 11 nav entries are wired in
base.html, but 9 of them are gated behind flags that default to OFF, plus role checks. With current prod flag state (console_flag_promotions=OFFper memory), the operator's actual top nav is likely Dashboard / Issues / Sign out — plus Secrets if their role issuperadmin. The other 8 nav entries exist in code but are hidden until each flag is individually promoted toonin prod. - Five pages have no nav entry even when every flag is on. These are the "shipped but invisible" surfaces — features whose only entry point is the URL itself or a click-through from another deep page.
The "completeness" gap is 80% flag-state (correctly-built feature gated off in prod) and 20% nav-debt (truly orphaned URLs).
Numbers
| Metric | Count |
|---|---|
| GET routes registered in console | 56 |
| User-facing HTML pages (excluding API + HTMX fragments) | ~22 |
url_for() references in templates that resolve to real routes |
94 / 94 ✓ |
Top-nav entries wired in base.html |
11 |
| Top-nav entries visible to a fresh operator (current prod flag state) | 3 (Dashboard / Issues / Sign out) |
Pages with zero url_for() references in any template |
31 — but most are API/HTMX, not pages |
| Pages with no nav entry even when all flags ON | 5 |
The 11 nav entries and their gates
Reading console/app/templates/base.html lines 1051–1149, the nav block has these entries (when the operator is authed):
| # | Nav entry | Endpoint | Visibility gate |
|---|---|---|---|
| 1 | Dashboard | dashboard.index |
Any authed admin |
| 2 | Security | security.index |
flag_console_nav_v2 AND role ops/superadmin |
| 3 | Status | status_page.index |
flag_console_nav_v2 |
| 4 | Issues (external → FreeScout) | console_tickets_url |
Any authed admin |
| 5 | Secrets | secrets.secrets_index |
role superadmin |
| 6 | Feature Flags | flags.flags_index |
flag_console_flag_promotions AND role ops/superadmin |
| 7 | Promotions | flags.promotions_queue |
flag_console_flag_promotions AND role ops/superadmin |
| 8 | Customers | customers.invite_get |
flag_console_customer_admin AND role superadmin |
| 9 | Billing | billing.billing_index |
flag_billing_summary_api AND RBAC admin_has_billing_read |
| 10 | Ops (dropdown) → Ops dispatch panel | ops.ops_index |
flag_console_claude_menu AND role superadmin |
| 11 | Ops (dropdown) → Versions | console_versions_ui.console_versions_index |
flag_console_claude_menu AND flag_console_version_manager AND role superadmin |
Default state of those flags (from backend_v2/api/feature_flags.yaml)
| Flag | Default | Notes |
|---|---|---|
console_nav_v2 |
(not in YAML) | Likely on by env var; verify via heroku config:get |
console_flag_promotions |
false | "default OFF; flip after migration 0010 applies" |
console_customer_admin |
false | "default OFF; customer invite + bootstrap token mint UI" |
billing_summary_api |
false | "default OFF; billing summary API gated by console-billing-read" |
console_claude_menu |
false | "default OFF; flip to enable ops dispatch panel" |
console_version_manager |
false | "default OFF; console staging-to-prod promotion endpoint" |
Per memory project_console_flag_toggle.md (operator-locked), console_flag_promotions is currently OFF in both staging and prod. If the other defaults haven't been individually promoted, the live nav is Dashboard + Issues + Sign out, possibly plus Secrets and Status.
This is not a bug in any single feature. This is the cumulative effect of every feature being built behind a flag and most of those flags never being promoted to on in prod after their soak.
The 5 truly orphaned pages
These have no nav entry and no url_for() reference from any other template. They exist in code as routes, render real HTML, but there's no path to reach them other than typing the URL.
| # | Path | Endpoint | Likely intended home | Severity |
|---|---|---|---|---|
| 1 | /console/deploy-freeze |
deploy_freeze.deploy_freeze_page |
Top nav OR ops dropdown | Operator already aware — needs nav entry |
| 2 | /console/admins/online |
admins_online.admins_online |
Security panel sub-nav OR Ops dropdown | Medium |
| 3 | /console/customers/<id>/tickets |
customers.customer_tickets |
Tab on customer detail page | Medium |
| 4 | /billing/alert-config |
billing.billing_alert_config |
Sub-link on /billing page |
Low (sub-page of /billing) |
| 5 | /totp/enroll |
auth.totp_enroll |
Account/security menu | Acceptable — likely accessed during auth flow |
Verdict: #1, #2, #3 are real UX bugs. #4 and #5 are arguably acceptable depending on the auth/billing flows.
Other observations
Code-quality positives
- All 94 template
url_for()calls resolve to live routes. Zero phantom endpoints. - Nav is properly role-gated and flag-gated — defense in depth, not just visual hiding.
- The auth + billing + customers panels all decline gracefully when flags or roles are missing.
Self-referential bootstrap trap (already-known, worth restating)
flag_console_flag_promotions = OFF→ Feature Flags UI returns 404.- To turn it ON via UI, you'd use the very Feature Flags UI that's hidden by it being OFF.
- First flip must use
heroku config:set FLAG_CONSOLE_FLAG_PROMOTIONS=on -a raxx-console-proddirectly, per memoryfeedback_bootstrap_via_heroku.md. Same applies toconsole_nav_v2if also OFF.
Possible RBAC observation (not verified — needs UI access)
- 8 of 11 nav entries require
ops,superadmin, or specific RBAC roles. - If the operator's current admin record lacks one or more roles (e.g.
console-billing-read), the corresponding nav entries stay hidden even with the flag ON. - Worth verifying once we have UI access: which roles is the operator's account assigned to?
Possible redundancy in the Promotions vs Flags nav
- Both
flags.flags_index(/console/flags) andflags.promotions_queue(/console/flags/promotions) appear as separate top-nav entries gated by the same flag + same role. - May be intentional — Flags is the live state, Promotions is the queue. Worth confirming the UX intent.
What this audit could NOT cover
UI verification is deferred until #680 lands. I could not check:
- Whether each page actually renders correctly in a browser
- Whether modals + HTMX fragments load + dismiss properly
- Whether real-time tile pulse/breathing-line/build-strip animations look right
- Whether the deploy modal opens, dispatches, and shows progress
- Whether form submissions actually persist to the DB
- Whether flag promotions actually write to
console_flag_promotionsand propagate to Heroku - Whether the navigation order matches the user's mental model
- Mobile breakpoints, accessibility, dark-mode contrast
When #680 lands and a CF Access service token is allowlisted on console.raxx.app, those checks become a single Playwright sweep.
Recommendations
In priority order, ranked by user-visible impact:
-
Audit prod flag state. Run
heroku config -a raxx-console-prod | grep FLAG_(operator action; I'm not authorized) and decide which flags should be ON for everyday operator use. Most-likely candidates to turn on now:FLAG_CONSOLE_NAV_V2,FLAG_CONSOLE_FLAG_PROMOTIONS,FLAG_CONSOLE_CLAUDE_MENU. The first one alone unlocks Security + Status nav entries. -
File card: nav entry for
/console/deploy-freeze. Single-line addition tobase.html. Operator already noted this gap in chat today. Likely belongs under the Ops dropdown. -
File card: nav-tab for
/console/customers/<id>/tickets. Should be a tab on the customer detail page (next to Audit, Danger Zone). Discoverable when looking at a specific customer. -
File card:
/console/admins/onlineplacement. Either Security sub-nav or Ops dropdown. Pick one. -
Provision CF Access service token for console.raxx.app (#680). Without this, every future agent QA pass is gated on you running Playwright manually. 5 min in CF dashboard.
-
(Optional) Audit the bootstrap trap. Document explicitly that
console_flag_promotionsandconsole_nav_v2are bootstrap-only flips viaheroku config:set. Update the runbook for whoever onboards next.
Test plan when UI access lands
When #680 closes and a CF Access service token is allowlisted on console.raxx.app:
Phase 1 — reachability (~30 min): - Playwright loads each of the 22 user-facing pages - Captures HTTP status, full-page screenshot - Pass = HTTP 200 + page renders without console errors
Phase 2 — function spot-check (~1-2 hr): - Dashboard tile hover popover (after PR #1263 landed) - Build-strip animation states (if PR #1264 implementation lands) - Deploy modal open/close (no actual dispatch) - Flag promotion mark + approve flow (no actual promote) - Secret rotate modal v2 open (no actual rotate) - Customer detail tab navigation - Mobile breakpoint at 375px
Phase 3 — staging vs prod diff: - Run Phase 1+2 on both, diff screenshots - Identifies drift between the two envs
Phase 4 — gap remediation: - Each "missing from UI" → file as a card with the exact gap - Quick wins (single-line nav adds) ship as small PRs
Appendix: full route inventory
Source-of-truth: console/app/blueprints/*.py. All 56 GET routes:
| Module | Path | Function | Linked from |
|---|---|---|---|
| admins_online | /console/admins/online |
admins_online |
— (orphan) |
| alerts | /_alerts/drawer |
alerts_drawer_fragment |
— (HTMX) |
| alerts | /api/_internal/alerts/unread-count |
unread_count |
— (JS poll) |
| api_billing | /alert-config |
get_billing_alert_config |
— (API) |
| api_billing | /summary |
billing_summary |
— (API) |
| api_status | /builds |
get_builds |
— (API) |
| api_status | /secrets |
get_secrets |
— (API) |
| api_status | /sites |
get_sites |
— (API) |
| api_status | /sites/<site_id> |
get_site |
— (API) |
| auth | /bootstrap |
bootstrap |
— (entry-only) |
| auth | /login |
login |
base.html, dashboard |
| auth | /totp/enroll |
totp_enroll |
— (probable orphan) |
| auth | /totp/verify |
totp_verify_page |
— (server-redirect target) |
| billing | /billing |
billing_index |
base.html nav |
| billing | /billing/alert-config |
billing_alert_config |
— (orphan, sub-page of /billing) |
| console_versions_ui | /admin/console-versions |
console_versions_index |
base.html nav (Ops dropdown) |
| customers | /console/customers/ |
customer_list |
7 references |
| customers | /console/customers/<id> |
customer_detail |
3 references |
| customers | /console/customers/<id>/audit |
customer_audit_log |
5 references |
| customers | /console/customers/<id>/danger-zone |
danger_zone_get |
1 reference |
| customers | /console/customers/<id>/tickets |
customer_tickets |
— (orphan) |
| customers | /console/customers/invite |
invite_get |
base.html nav |
| dashboard | /dashboard |
index |
6 references |
| dashboard | /dashboard/_activity |
activity_partial |
(HTMX from dashboard) |
| dashboard | /dashboard/_status_grid |
status_grid_partial |
(HTMX from dashboard) |
| dashboard | /dashboard/api/sites/<id>/latency-history |
latency_history_api |
— (API/JS) |
| dashboard | /dashboard/sites/<site_id> |
site_detail |
2 references |
| deploy_freeze | /api/internal/deploy-freeze/state |
deploy_freeze_state_api |
— (CI workflow gate) |
| deploy_freeze | /console/deploy-freeze |
deploy_freeze_page |
— ORPHAN |
| deploys | /api/internal/deploys |
list_deploys |
— (API) |
| deploys | /api/internal/deploys/<id> |
get_deploy |
— (API) |
| deploys | /api/internal/deploys/<id>/xenv |
get_deploy_xenv |
— (API) |
| flags | /console/flags |
flags_index |
base.html nav |
| flags | /console/flags/promotions |
promotions_queue |
base.html nav |
| flags | /console/flags/promotions/fragment |
promotions_fragment |
(HTMX) |
| health | /health |
health |
(CI smoke check) |
| internal | /active-sessions |
active_sessions |
— (API) |
| internal | /flag-drift/pending |
flag_drift_pending |
— (API for #1266) |
| internal | /poller-status |
poller_status |
— (API) |
| internal | /promotions/badge-fragment |
promotions_badge_fragment |
— (HTMX) |
| internal | /promotions/pending-count |
promotions_pending_count |
— (API) |
| internal | /surfaces/<id>/p5 |
surface_p5 |
— (HTMX) |
| ops | /ops |
ops_index |
base.html nav (Ops dropdown) |
| ops | /ops/status/<job_id> |
ops_status |
(JS redirect from /ops) |
| root | / |
index |
base.html (logo link) |
| secrets | /secrets |
secrets_index |
base.html nav (superadmin) |
| secrets | /secrets/_list |
secrets_list_partial |
(HTMX) |
| secrets | /secrets/history |
rotation_history |
base.html (superadmin) |
| secrets | /secrets/<name>/rotate-modal |
rotate_modal |
(HTMX modal trigger) |
| secrets | /secrets/<name>/rotate-modal-v2 |
rotate_modal_v2 |
(HTMX modal trigger) |
| secrets | /secrets/<name>/rotate/<job_id>/cell |
get_rotation_action_cell |
(HTMX) |
| secrets | /secrets/<name>/rotate/<job_id>/progress |
get_rotation_job_progress |
(HTMX poll) |
| secrets | /secrets/<name>/sop |
secret_sop |
(HTMX modal — likely OK) |
| secrets | /api/secrets/<name>/rotate/<job_id> |
get_rotation_job |
— (API) |
| security | /security |
index |
base.html nav |
| status_page | /status |
index |
base.html nav |
Audit run by: Claude Code session, 2026-05-06 UTC Phase 2 (UI click-through): deferred until #680 (CF Access service token for console)