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.
The "console completeness" pain has a measurable shape. Three findings:
url_for(...) references in templates resolve to actual routes. No broken nav links. No phantom endpoints.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=OFF per memory), the operator's actual top nav is likely Dashboard / Issues / Sign out — plus Secrets if their role is superadmin. The other 8 nav entries exist in code but are hidden until each flag is individually promoted to on in prod.The "completeness" gap is 80% flag-state (correctly-built feature gated off in prod) and 20% nav-debt (truly orphaned URLs).
| 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 |
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 |
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.
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.
url_for() calls resolve to live routes. Zero phantom endpoints.flag_console_flag_promotions = OFF → Feature Flags UI returns 404.heroku config:set FLAG_CONSOLE_FLAG_PROMOTIONS=on -a raxx-console-prod directly, per memory feedback_bootstrap_via_heroku.md. Same applies to console_nav_v2 if also OFF.ops, superadmin, or specific RBAC roles.console-billing-read), the corresponding nav entries stay hidden even with the flag ON.flags.flags_index (/console/flags) and flags.promotions_queue (/console/flags/promotions) appear as separate top-nav entries gated by the same flag + same role.UI verification is deferred until #680 lands. I could not check:
console_flag_promotions and propagate to HerokuWhen #680 lands and a CF Access service token is allowlisted on console.raxx.app, those checks become a single Playwright sweep.
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 to base.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/online placement. 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_promotions and console_nav_v2 are bootstrap-only flips via heroku config:set. Update the runbook for whoever onboards next.
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
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)