9 binding decisions locked with user 2026-06-09 (4-question + 4-question + 3-question rounds). Visual direction Bloomberg / terminal SOC. Border radius 0 except status pills and avatars. Palette kept (primary blue + slab + canvas/paper/cloud/fog/ink), ADD success/warn semantic tokens. Scope: 8 pages + 17 components + tokens + DESIGN.md rewrite, all in one sprint. JetBrains Mono for data only (Inter stays for body/headers). Light + dark both kept. Zero transitions (brutalist). Plan validated by spec-reviewer pre-pass: APPROVED with 3 findings addressed inline (D9 added, R2 reworded, semantic tokens promoted from optional to locked). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
12 KiB
12 KiB
Sprint 7 — Design Refresh: Terminal-SOC Aesthetic
Branch :
sprint/7-design· Worktree :.claude/worktrees/sprint-7-design· Base :main@e27babe
§0 — Binding decisions (locked with user, 2026-06-09)
- Visual direction: Bloomberg / Terminal-SOC — dense, brutalist, semantic colors strong, no ornament.
- Border-radius: 0 everywhere except status pills (
rounded-pill) and avatars (round). All buttons, cards, modals, inputs, dropdowns, tables, tags → angular. - Palette: KEEP current (
#024ad8primary blue,slab #111827,canvas/paper/cloud/fog/inklight+dark vars). ADD semantic tokenssuccess-green+warn-amber(confirmed scope add — needed for SOC-grade status legibility on dashboards and badges). - Scope: Refonte globale en 1 sprint (all 8 pages + 17 components + tokens + DESIGN.md).
- Monospace: data-only — JetBrains Mono for IDs, dates ISO, commands, execution output, MITRE techniques, metrics. Inter stays for body/labels/headers.
- Mono font: JetBrains Mono, bundled locally via
@fontsource-variable/jetbrains-mono(consistent with existing Inter bundle). - Modes: KEEP light + dark both. Toggle stays.
- Animations: Brutalist — zero transition. Remove all
transition-*utilities, focus rings sharp, hover instantaneous. - Display scale reduction: locked.
display-xxl 72→40,display-xl 56→32,display-lg 44→28,display-md 32→24,display-sm 24→20,display-xs 20→16. Headers stay modest in terminal aesthetic — no editorial flourish at hero scale.
§1 — Pre-work checks (team-lead, before dispatch)
- Confirm
tasks/lessons.mdhas nothing contradicting this brief - Verify uncommitted
.claude/agents/frontend-builder.mdpatch (Skill mandatory) is restored in worktree — sprint hygiene - Send plan to spec-reviewer for 2-pass approval (vs SPEC.md, vs §0 binding decisions). MUST be APPROVED before any code touches
frontend/. - After approval: dispatch frontend-builder with this todo as brief.
§2 — Sprint hygiene (commit #1)
chore(agents): frontend-builder must invoke Skill frontend-design before UI work— lands BEFORE design work so the agent itself triggers the Skill on first call this sprint.
§3 — Foundation: DESIGN.md + tokens (commits #2–#4)
§3.1 DESIGN.md rewrite (commit #2)
- Replace current HP-catalog doc (346 lines, off-brand) with terminal-SOC spec covering:
- Overview: brutalist BAS Purple Team console, angular surfaces, semantic color signals, data-monospace hybrid
- Colors: keep all existing tokens with role redefinition for terminal-SOC context. Primary = neutral action. Bloom-deep/coral = destructive/alert. ADD
success(green) +warn(amber) — locked §0 D3 — with light + dark variants and WCAG AA contrast on slab and canvas surfaces - Typography: Inter (body/headers/labels) + JetBrains Mono (data). Concrete tier table with size/weight/line-height
- Layout: tighter spacing (replace
section 80px→section 48px; halve card padding on dense surfaces) - Shapes: ALL radii = 0 except
rounded-pillreserved for status badges and avatars - Components: re-document
btn-*,text-input,card-*,badge-*,nav-*,modal-*with brutalist specs (no shadow, hairline borders, zero transition) - Do's/Don'ts: zero rounded on conteneurs; zero transitions; semantic colors only on status surfaces; mono ONLY for data, never headers
- Iteration guide
- Doc lives in English (in-repo).
§3.2 Tailwind token refresh (commit #3)
frontend/tailwind.config.ts:borderRadius: keepnone: 0, keeppill: 9999px. Drop or stop usingxs/sm/md/lg/xlfor surfaces — keep only if a badge variant needs2px- ADD
fontFamily.mono:['JetBrains Mono Variable', 'JetBrains Mono', 'ui-monospace', 'monospace'] - ADD semantic colors (locked §0):
success: { DEFAULT, soft }(green) +warn: { DEFAULT, soft }(amber). Pull dark-mode variants from CSS vars too. Suggested anchors —success #16a34a(dark#22c55e),warn #d97706(dark#f59e0b); design-reviewer audits WCAG AA at both modes. - Reduce
display-*scale (locked §0):display-xxl 72px → 40px,display-xl 56→32,display-lg 44→28,display-md 32→24,display-sm 24→20,display-xs 20→16— terminal headers are modest - Drop
tracking[0.7px]and uppercase frombutton-md(still ALLCAPS via class but no letter-spacing) - Drop shadow tokens or keep but ensure no component class applies them
frontend/src/styles/index.css:- Drop
font-size: 16.5pxroot bump (back to16pxstandard) - Set body
line-height: 1.4, tighten headings to 1.1 - Rewrite
.btn-primary/ink/outline/outline-ink:rounded-none, NOtransition-colors, keepuppercase, droptracking-[0.7px], keeph-11(touch target) - Rewrite
.text-input:rounded-none, focus border-primary sharp (no halo), no transition - Rewrite
.card-productand any.card-*:rounded-none, no shadow, 1px hairline border for separation - Rewrite
.badge-pill-*: keeprounded-pillONLY here (status badges); strip uppercase if applied - Rewrite
.modal-backdrop: same dark backdrop, no rounded for the modal frame itself - ADD
.monoutility or rely on Tailwind'sfont-mono(preferred) for data cells
- Drop
§3.3 JetBrains Mono bundle (commit #4)
cd frontend && npm i @fontsource-variable/jetbrains-monofrontend/src/styles/fonts.css: add@import '@fontsource-variable/jetbrains-mono'- No CDN. Confirms via
npm ls @fontsource-variable/jetbrains-mono.
§4 — Component sweep (commit #5)
Rule: rounded-* → rounded-none unless explicitly an avatar or status pill; remove transition-*; data text → font-mono.
Layout.tsx: nav-bar/utility-strip already angular — confirm. Removetransition-colorson theme button and hover-underline transitions. Mono font for any data label exposed (e.g. user.role pill).StatusBadge.tsx: KEEP rounded → switch torounded-pill(it's a status pill, locked exception). Audit semantic mapping (planned/active/closed → semantic tokens once added).SimulationStatusBadge.tsx: same —rounded-pill, semantic colors aligned with new tokens.FormField.tsx: angular inputs (already via.text-inputrecipe — confirm).EmptyState.tsx: angular wrapper. No rounded illustration container.ErrorState.tsx: angular. Bloom-deep border-left if signalling.LoadingState.tsx: drop any rounded spinner background. Spinner shape ok.ConfirmDialog.tsx: angular modal. Buttons via new.btn-*recipes.Toast.tsx: angular. Semantic color border-left strip.ExportEngagementButton.tsx(sprint 6): angular dropdown menu. Auditrounded-*in the menu/item classes.MitreMatrixModal.tsx: angular modal. Cells already grid — confirm no rounded.MitreTechniquePicker.tsx: angular dropdown.MitreTechniquesField.tsx: angular chips.MitreTechniqueTag.tsx: angular tag (NOT pill — terminal tag, not a status). Decide once and apply consistently across MITRE surfaces.TemplatePickerModal.tsx: angular modal.SimulationList.tsx: angular table. Data cells (commands, executed_at, MITRE techniques) →font-mono.ProtectedRoute.tsx: no visual surface, skip.
§5 — Page sweep (commit #6)
For each page: header/body/footer review, replace rounded card containers with angular hairline-bordered containers, ensure data cells use mono.
LoginPage.tsx: angular form card. Drop ornament.EngagementsListPage.tsx: angular table container (currently.card-productwith rounded-xl). Data cells (dates) → mono.EngagementDetailPage.tsx: angular header section. Engagement metadata (start/end dates, IDs, created_at) in mono. Simulations table covered via SimulationList.EngagementFormPage.tsx: angular form. Date inputs ok.SimulationFormPage.tsx: angular form. Commands textarea → mono.TemplatesListPage.tsx: angular list.TemplateFormPage.tsx: angular form. Commands field → mono.UsersAdminPage.tsx: angular table. Username column → mono (it's an ID).
§6 — Test refresh (commit #7)
cd frontend && npm run test -- --run— identify failing assertions on class names (rounded-xl,card-product, etc.). Update tests to use semantic queries (role, name, data-testid) where possible; if test asserts on visual class, update assertion to the new class.- No new vitest tests added (visual sprint, behavior unchanged).
- Playwright e2e: should be
data-testid-driven — run full suite to confirm no regression. If breakage, fix the testid not the test logic.
§7 — Reviews
- spec-reviewer (pre-dispatch, §1): plan validated vs SPEC.md and §0 binding decisions
- frontend-builder (§2-§6): implements, runs typecheck/lint/test, delivers screenshots for design-reviewer (every page + key states, light+dark)
- design-reviewer (post-frontend): reviews screenshots + diff vs new DESIGN.md. Brutalist consistency, mono-discipline (only data), zero-rounded discipline.
- code-reviewer (post-design): reviews frontend diff for duplication, lost reuse, dead code.
- test-verifier: skipped this sprint (no new US, no behavior change).
- backend-builder: idle, no work this sprint.
§8 — Git workflow
- Branch:
sprint/7-design(already created from origin/main) - Commits: conventional, one per logical group (§2 to §7)
- PR via
make open-pr(Gitea pattern, per memory) - PR body in
tasks/pr-body-sprint-7.md - CHANGELOG.md sprint 7 section
§9 — Risks & mitigations
- R1 — Tests break en masse: many vitest specs may assert on class strings (e.g.,
rounded-xlon cards). Mitigation: update assertions to semantic queries; budget half a phase to test repair. - R2 — Dark mode contrast lost: angular + new semantic colors may break WCAG AA contrast on dark slab. Mitigation: design-reviewer audits both modes; adjust the dark variant hex to meet WCAG AA. Rollback the success/warn family only if no accessible green/amber is achievable on the dark slab.
- R3 — Mono overflow: JetBrains Mono is wider than Inter at same px. Cell widths in tables may overflow. Mitigation: keep
table-layout: fixedandword-break: break-word(pattern reused from PDF export CSS sprint 6). - R4 — DESIGN.md rewrite churn: replacing 346 lines is a big diff. Mitigation: rewrite atomically in commit #2, keep token names consistent so downstream commits don't drift.
- R5 — User taste mismatch: "Bloomberg/SOC" may not match user's mental image. Mitigation: design-reviewer screenshots → user check-in BEFORE merge.
§10 — Definition of Done
- All §0 decisions reflected in DESIGN.md + tokens + components + pages
npm run typecheckcleannpm run lintcleannpm run test -- --runall green- Backend untouched —
git diff origin/main -- backend/empty - Playwright e2e green (223 baseline preserved)
- Screenshots delivered (light + dark) for every page + key states
- DESIGN.md rewritten, no HP/Forma/wordmark/chevron references
- CHANGELOG.md sprint 7 section
- PR opened on Gitea
- User merges PR → sprint closed → team idle ready for sprint 8
§11 — Lessons being applied from prior sprints
- SPEC/DESIGN commit-first: DESIGN.md rewrite is commit #2 (after sprint hygiene). No design churn mid-sprint.
- spec-reviewer 2-pass: APPROVED before dispatch, not after.
- Team idle policy: 6 agents already mounted, no shutdown until PR merged.
- frontend-builder MUST invoke
Skill frontend-designbefore UI work (the patch commits as #1, takes effect immediately for the same sprint).