Repository navigation
Front-end & product-readiness overhaul: restore dashboard design quality and fix web-app defects #33
Description
The workbench was ported from a polished single-page review dashboard to a Django backend. The data model and review flows came across, but the user-facing experience regressed and several web-app essentials are missing. This issue catalogs the defects to remediate. Grouped by theme; severity noted where cross-cutting.
1. Design regression vs. the original dashboard
The original was a dense, branded, single-page dashboard. The current app kept counts, a technique table, a basic module grid, and a tactic list, but lost or degraded:
- The branded top bar with live KPI metrics (techniques / tactics / modules / quick-starts) and a status pill.
- The Overview experience: per-tactic horizontal bar chart, tier-colored challenge-progression cards, and the integrity/digest block — none of these were carried over.
- Consistent 3-tier color-coding (quick / intermediate / advanced) applied across progression, module cells, and labels.
- The cohesive dashboard aesthetic (sticky table headers, KPI clusters, panel/split layout, tabular numerics). The current pages read as unstyled forms and tables.
- A print/PDF full-report mode.
- Overall: the current CSS is ~170 lines and only styles a few components; the product looks unfinished next to the prototype.
2. Landing page & information architecture
- No sign-in entry point for anonymous users (high). The landing copy says "Sign in…" but there is no sign-in link/button, and the top bar shows auth links only when logged in. An anonymous visitor has no discoverable path to the login page.
- The landing page's only link points at the Django admin (high). The public entry page advertises the admin surface while hiding the normal user login.
- Landing copy is thin and jargon-y ("review surface"): no explanation of the product, no value proposition, no call to action.
- The privacy notice exists but is linked only from the authenticated account page — unreachable by the public it is meant for.
- Breadcrumb roots are inconsistent (some trails start at "Projects", the object detail pages drop that crumb).
- Terminology drift: UI says "Module" while routes/models say "step" /
path_step; labels like "Project activity" read as internal. - Destructive "delete my account" is a bare one-click POST with no confirmation step.
3. Branding
- No favicon (empty
data:URI); blank tab glyph on every page. - No logo or product mark anywhere (no images/SVG assets); branding is a plain text string.
- The declared UI webfont is never actually loaded, so intended typography never renders.
- The brand accent reuses a data-classification tier color rather than an intentional brand color.
- No
meta description, Open Graph/Twitter, ortheme-colortags; shared links have no preview.
4. Admin & security surface
- Django admin is mounted at the default, predictable
/admin/path (high). No obscured path or URL-layer restriction; it's the first thing scanners probe. - The public landing page links straight to the admin login, actively pointing unauthenticated visitors at it.
- Staff have no admin link in the normal authenticated nav — they're funneled through the public landing link, an inconsistent and leaky pattern.
5. Cookie consent & GDPR
- No cookie-consent banner or notice of any kind (high). The app sets session/CSRF cookies and writes
localStoragewith no notice. - No footer anywhere, so there is no persistent Privacy / Terms / cookie / copyright link in the chrome.
- The privacy notice is not reachable before/without login.
6. Accessibility (WCAG 2.1)
Already correct: lang, a working skip link, role="alert" on login errors, table caption/th scope, labelled nav landmarks, no inline handlers. Defects:
- Dark-theme primary button fails contrast (~2.9:1) — hardcoded white text on the theme's lighter accent, below the 4.5:1 AA threshold.
- Focus indicator is a 45%-opacity outline that can fall below the 3:1 non-text contrast expectation on some backgrounds.
- Pervasive tiny, muted text carrying real content (10px uppercase table headers; 12–13px muted metadata) leans on color for hierarchy.
- Theme-toggle
aria-pressedships stale from the server and is only corrected by JS; state is mis-announced without JS, and the label never reflects the current mode. - Prose has no max line length; paragraphs run the full ~1540px width on large screens.
- No
prefers-reduced-motionhandling. - Auth forms render via Django form defaults with no error summary, no explicit
autocomplete/aria-describedby, and no styled help/error text.
7. Visual design & CSS coverage
- Auth-form inputs, textareas, and most submit buttons are entirely unstyled (high) — only the filter toolbar and top-bar buttons have CSS, so forms/buttons look different page to page and render as native controls.
- No hover/active/disabled/pressed/loading states for buttons; links only underline on hover.
- A single 900px breakpoint; no handling for small phones or intermediate widths; wide tables rely solely on horizontal scroll.
- No custom 404/500 pages (only a 429 exists); those fall back to unbranded Django defaults. No print styles.
- Empty states are bare muted text — no guidance or call to action; feels unfinished.
- The theme toggle gives no visual cue (icon/label) of the current mode.
8. First-run / product polish
- No guided empty state or onboarding for a fresh install; the first thing a new admin sees is bare.
- During testing the app surfaced ad-hoc placeholder naming in the UI; there is no clean, brandable first-run experience.
Most severe, cross-cutting: no anonymous sign-in path; the public page linking the admin; admin at /admin/; no cookie notice / no footer; dark-theme button contrast failure; unstyled auth forms and buttons; and the overall regression from the prototype's dashboard design.
Activity
Brad-Edwards commentedon Jul 12, 2026
🛠️ Picked up by /implement - driver Codex, branch
33-frontend-polish, 2026-07-12T05:20:09Z.Brad-Edwards commentedon Jul 12, 2026
gc workflow phase recorded:
preflight(issue #33). Posted by the MCP server to enforce ordering between workflow steps (issue #794 MVP-2). Do not edit or delete — used by downstream tools to gate phase prerequisites.Brad-Edwards commentedon Jul 12, 2026
gc workflow phase recorded:
plan(issue #33). Posted by the MCP server to enforce ordering between workflow steps (issue #794 MVP-2). Do not edit or delete — used by downstream tools to gate phase prerequisites.Implementation plan
Issue #33 is requirement-free maintenance/product work. The implementation restores the static dashboard's core capabilities inside the existing internet-safe Django application rather than replacing Django or adding a second client stack.
Scope
Revisiongraph:ACES_WORKBENCH_ADMIN_PATHsetting;doctor, and tests derive from that setting;/admin/.Design constraints
Revision,Step,Tactic,Technique,Evidence, metadata, and content digest data; add no reporting tables or schema migrations.Files expected to change
changelog.d/33.changed.mdfor the source-bearing change.Verification
Run:
uv run ruff check .uv run ruff format --check .uv run pytestThen run the full completion command
uv run pytestbefore declaring readiness.Brad-Edwards commentedon Jul 12, 2026
gc_codex_review — cycle 1 of 1 (pre-push) on issue #33 (branch
33-frontend-polish)Core review
Verdict:
ship-with-fixesThe change is shaped correctly around the repository’s existing server-rendered Django seams: dashboard data remains derived presentation context, authorization stays in incumbent views/helpers, shared chrome lives in the base template, and the configurable admin mount is centralized in settings and reused by URLs, CSP, diagnostics, documentation, and tests. It leaves sensible extension points for future dashboard metrics and legal chrome without introducing speculative persistence or a parallel client architecture. Two interaction regressions in the new tabbed and clickable-container behavior need correction before shipping.
Blocking findings (2):
src/aces_scenario_workbench/workbench/templates/workbench/revision_overview.html:99Submitting this GET form produces a URL without
#techniques. On reload,setupReviewTabstreats an absent hash asoverview, so the filtered results are rendered inside the hidden Techniques view and the user sees no visible result from the filter action. Preserve the Techniques view in the form action or select it when technique-filter query parameters are present, and pin that navigation contract in a test.src/aces_scenario_workbench/workbench/static/workbench/app.js:92The click handler correctly ignores events originating from nested interactive elements, but the keydown handler does not. Pressing Enter or Space on a tactic, evidence, or primary link inside a clickable row/card bubbles here, is canceled with
preventDefault(), and navigates to the container’s URL instead of the focused link. Apply the same interactive-target guard to keyboard events; retain container keyboard activation only when the container itself is the event target.Security review
Verdict:
shipThis change is shaped correctly around the repository’s existing security seams: project-scoped views remain intact, account deletion retains authentication, POST, and CSRF protection while adding confirmation, and the configurable admin route is normalized once and reused by URL routing and CSP configuration. The new dashboard projections expose only authenticated revision data already inside the scoped object graph, and Django template escaping remains in effect. I found no concrete, exploitable security regression introduced by the diff.
No blocking findings.
Brad-Edwards commentedon Jul 12, 2026
gc_codex_review pre-push cycle 1 of 1 complete for issue #33 on branch '33-frontend-polish'. Posted by the MCP server to enforce the pre-push hard-cap-1 contract (issues #796, #804, #906). Do not edit or delete — used by the next
gc_codex_review(uncommitted) invocation to count cycles.Brad-Edwards commentedon Jul 12, 2026
Review decision record — codex cycle 1 (issue #33)
Reviewer: codex
Cycle: 1
Architectural read:
Blocking findings: 2
Finding 1 —
one-offF1src/aces_scenario_workbench/workbench/templates/workbench/revision_overview.html:99#techniques. On reload,setupReviewTabstreats an absent hash asoverview, so the filtered results are rendered inside the hidden Techniques view and the user sees no visible result fro…Finding 2 —
class(3 instances)F2src/aces_scenario_workbench/workbench/static/workbench/app.js:92src/aces_scenario_workbench/workbench/static/workbench/app.js:92src/aces_scenario_workbench/workbench/templates/workbench/revision_overview.html:158src/aces_scenario_workbench/workbench/templates/workbench/revision_overview.html:212Brad-Edwards commentedon Jul 12, 2026
gc_review_cap_disposition — issue #33 (codex, cycle 1 of 1)
Disposition: proceed
Auto-override grant #: n/a
Rationale: Only 1 known, non-security, single-class finding survived review with zero prior overrides used; the large diff and 'unclassified' surface reflect breadth (docs, templates, static assets) rather than risk, so proceeding is reasonable.
Posted by the MCP server to record the review-cap auto-disposition. Do not edit or delete — the cycle wrappers read this marker to verify an over-cap auto-grant before running a cycle.
Brad-Edwards commentedon Jul 12, 2026
gc_test_quality_review cycle 1 of 1 — issue #33
Reviewer: test-quality (claude-sonnet-5 via gc_test_quality_review)
Branch:
33-frontend-polishCycle: 1 / 1
Findings: 1
Finding 1 — [critical]
tests/test_hardening.py::test_doctor_reports_hardening_postureProblem: The test only asserts that six label strings ("HTTPS redirect", "HSTS", "Secure cookies", "Brute-force protection", "Content-Security-Policy", "Admin path") appear somewhere in the doctor command's stdout. It never asserts the "on"/"off" value or OK/!! marker that
_report_hardeningcomputes from the live settings for each line.Why it matters:
_report_hardeningin workbench/management/commands/doctor.py computes anokboolean per row from live settings (e.g.dev or settings.SECURE_SSL_REDIRECT) and prints on/off plus a status marker. Since the test never inspects those computed values, inverting the boolean logic, or hardcoding every row to report "on"/OK regardless of the real setting, would leavedoctorsilently reporting a secure posture during a misconfigured deployment (e.g. SSL redirect actually off) without this test noticing. This is the exact command docs/go-live-checklist.md points operators at before shipping.Fix: Use @override_settings to force both a compliant and a non-compliant hardening state (mirroring tests/test_onboarding.py::test_doctor_flags_missing_deployment_prereqs / test_doctor_accepts_public_deployment_config, which already do this for
_report_deployment_prereqs), and assert the differential text ("on" vs "off", or presence/absence of the "!!" marker) rather than only label presence.Brad-Edwards commentedon Jul 12, 2026
gc_test_quality_review cycle 1 of 1 complete for issue #33 on branch '33-frontend-polish'. Posted by the MCP server to enforce the gc_test_quality_review hard-cap-1 contract (issue #884 follow-up, default lowered in #906). Do not edit or delete — used by the next
gc_test_quality_reviewinvocation to count cycles.Brad-Edwards commentedon Jul 12, 2026
Review decision record — test-quality cycle 1 (issue #33)
Reviewer: test-quality
Cycle: 1
Architectural read:
Blocking findings: 1
Finding 1 —
one-offF1Brad-Edwards commentedon Jul 12, 2026
gc_review_cap_disposition — issue #33 (test-quality, cycle 1 of 1)
Disposition: proceed
Auto-override grant #: n/a
Rationale: Only 1 known, one-off, non-security finding with zero class-level issues and no prior auto-overrides used; despite the unclassified surface tag and large diff, nothing here signals systemic risk requiring another cycle or human review.
Posted by the MCP server to record the review-cap auto-disposition. Do not edit or delete — the cycle wrappers read this marker to verify an over-cap auto-grant before running a cycle.
Brad-Edwards commentedon Jul 14, 2026
Ready for review — issue #33
PR: #46
Outcome
Reviewers can now inspect the scenario as a real interactive network diagram and evaluate each challenge with participant guidance, organizer detail, and related systems in one place.
Files changed
Added:
changelog.d/+network-diagram.changed.mdfrontend/src/components/NetworkDiagram.tsxModified:
frontend/package-lock.jsonfrontend/package.jsonfrontend/src/api/client.tsfrontend/src/main.tsxfrontend/src/pages/RevisionObjectPage.tsxfrontend/src/pages/RevisionPage.tsxsrc/aces_scenario_workbench/workbench/api.pysrc/aces_scenario_workbench/workbench/ingest.pysrc/aces_scenario_workbench/workbench/management/commands/sync_scenario.pysrc/aces_scenario_workbench/workbench/static/workbench/spa/app.csssrc/aces_scenario_workbench/workbench/static/workbench/spa/app.jstests/test_ingest.pytests/test_spa_api.pyReviews
Traceability reconciliation
Status
Documentation
Verified unchanged: no documentation surface in scope.
Brad-Edwards commentedon Jul 14, 2026
gc workflow phase recorded:
traceability_reconciled(issue #33). Posted by the MCP server to enforce ordering between workflow steps (issue #794 MVP-2). Do not edit or delete — used by downstream tools to gate phase prerequisites.override=true; reason: User directed: "merged. close 33". No requirements are in scope; the configured project is not registered, so the multi-project issue-link audit cannot resolve a project.
Brad-Edwards commentedon Jul 14, 2026
Final report — issue #33 complete
PR: #46
Outcome
Reviewers can now inspect the scenario as a real interactive network diagram and evaluate each challenge with participant guidance, organizer detail, and related systems in one place.
Files changed
Added:
changelog.d/+network-diagram.changed.mdfrontend/src/components/NetworkDiagram.tsxModified:
frontend/package-lock.jsonfrontend/package.jsonfrontend/src/api/client.tsfrontend/src/main.tsxfrontend/src/pages/RevisionObjectPage.tsxfrontend/src/pages/RevisionPage.tsxsrc/aces_scenario_workbench/workbench/api.pysrc/aces_scenario_workbench/workbench/ingest.pysrc/aces_scenario_workbench/workbench/management/commands/sync_scenario.pysrc/aces_scenario_workbench/workbench/static/workbench/spa/app.csssrc/aces_scenario_workbench/workbench/static/workbench/spa/app.jstests/test_ingest.pytests/test_spa_api.pyReviews
Traceability reconciliation
Issue-only implementation run with no requirements in scope; no requirement transitions or links were needed.
Status
Documentation
Verified unchanged: no documentation surface in scope.