WIP: Dashboard redesign — design system overhaul and component updates

Frontend redesign in progress: updated styles, layout, and components
across all pages to align with new design system. Includes Jira API
compliance specs, property tests, and load test script.
This commit is contained in:
root
2026-04-29 14:20:23 +00:00
parent 37119b9c8a
commit 27192dd69f
78 changed files with 9902 additions and 1368 deletions

View File

@@ -0,0 +1,235 @@
# STEAM Security Design System
A design system for the **STEAM Security Dashboard** — a self-hosted vulnerability management workbench used by the NTS-AEO-STEAM and NTS-AEO-ACCESS-ENG business units. This repo captures the visual language, content patterns, tokens, and UI kit needed to extend or rebuild the product without drifting from its established look.
## What the product is
The STEAM Security Dashboard centralises:
- **CVE tracking** — searchable, filterable, vendor-aware CVE list with NVD auto-fill, document attachment, and group-based ownership
- **Ivanti / RiskSense host findings** — live remediation queue with FP / Archer / CARD workflows, inline editing, per-finding notes, and a personal "Ivanti Queue" staging list
- **AEO compliance posture** — weekly xlsx upload with drift detection, diff preview, per-team metric health cards, device-level violation tracking, and timestamped notes
- **Archer EXC tickets** — risk-acceptance ticket tracking linked to CVE / vendor pairs
- **Knowledge base** — internal document library (PDF, Markdown, Office, etc.) for runbooks, advisories, and policies
- **Admin panel** — user / group management, audit log, system info — all gated behind an Admin group
Four user groups (`Admin`, `Standard_User`, `Leadership`, `Read_Only`) define every permission boundary, and every state-changing action is audit-logged.
## The 6 pages
1. **Home / Dashboard** — CVE list, filters, calendar widget for due dates
2. **Reporting** — Ivanti host findings, charts, queue, export
3. **Compliance** — AEO posture, metric health cards, device drill-in
4. **Knowledge Base** — document library
5. **Exports** — bulk export tools (group-gated)
6. **Admin Panel** — user management, audit log, system info (Admin only)
## Sources
- **Codebase:** `https://vulcan.apophisnetworking.net/jramos/cve-dashboard` (Gitea, master branch). Auth required; raw file fetch is gated. The repo's own `README.md` (fetched via the source viewer) is the most accurate functional spec we had access to and is the basis for this system.
- **Existing design ref:** `DESIGN_SYSTEM.md` (290 lines, in-repo) — referenced in the audit but not directly accessible from the host.
- **Component audit** provided in the project brief: 29 components, 5 primitives, 14 composites, 5 pages, 1 context provider.
- **Stack:** React 19, lucide-react, recharts, react-markdown + rehype-sanitize, mermaid, xlsx. Backend Express 5 / SQLite3.
## Index — what's in this folder
| Path | What it is |
|---|---|
| `README.md` | This file — context, content + visual foundations, iconography |
| `SKILL.md` | Agent Skill manifest for Claude Code compatibility |
| `colors_and_type.css` | Source-of-truth tokens — color, type, spacing, radii, elevation |
| `fonts/` | Font references (Outfit + JetBrains Mono via Google Fonts CDN) |
| `assets/` | Logo mark, brand SVGs, severity icons |
| `preview/` | Design System tab cards — registered as assets |
| `ui_kits/cve-dashboard/` | High-fidelity recreation of the dashboard, focused on Knowledge Base |
---
## CONTENT FUNDAMENTALS
The product is a tactical operations console for security engineers. Copy is dense, terse, and assumes a reader who already knows what a CVE, EXC ticket, FP workflow, and BU filter are. There is no marketing voice, no onboarding nudges, and no exclamation marks.
### Voice & tone
- **Operational, not editorial.** Buttons say "Sync", "Confirm Upload", "Reconcile Config", "Add to Queue". Never "Let's get started" or "You're all set".
- **Imperative for actions, declarative for state.** "Save", "Delete", "Hide Selected" — never "Saving your changes…" with three dots and a heart.
- **No emoji.** Status is communicated through colour-coded badges and short text labels.
- **Title Case for navigation and headers**, Sentence case for body and inline labels. Tabs and buttons: `User Management`, `Audit Log`, `System Info`. Helper text: `Filter tickets by CVE ID, vendor, or status.`
### Person & address
- **Second-person sparingly** — only when the system is talking *about* the user's data: "your login", "your filtered view", "your queue". Never "Welcome back, {name}".
- **First-person plural never.** No "We've updated" or "Let us know".
- **Errors are direct, no apology.** "SESSION_SECRET environment variable must be set." "Login rate limited — wait 15 minutes." Never "Oops! Something went wrong."
### Casing
- **CVE IDs:** uppercase with hyphen — `CVE-2024-12345`. Validated against `/^CVE-\d{4}-\d{4,}$/`.
- **EXC numbers:** uppercase — `EXC-12345`. Validated `/^EXC-\d+$/`.
- **Severity labels:** Title Case — `Critical`, `High`, `Medium`, `Low`. Status labels: `Open`, `Addressed`, `In Progress`, `Resolved`.
- **Workflow state badges:** SHOUT CASE for SLA states only — `OVERDUE`, `AT_RISK`, `WITHIN_SLA`. Everything else is Title Case.
- **Group names:** snake_case in code (`Standard_User`), Title Case in UI (`Standard User`).
### Density and units
- Numerical metrics are bare integers ("12 findings", "47 devices"). Percentages always carry the % sign with no space.
- Dates are explicit, no relative time except "Last sync: 4h ago" patterns.
- Column headers are short — `Host`, `IP Address`, `DNS`, `BU`, `SLA` — never `Host Name (Editable)`.
### Specific copy conventions seen in product
- "— empty —" as a filter option for empty cells
- "Hidden (N)" pattern for counted UI states
- "+N" badge for overflow (e.g., 2 CVEs shown, "+5" badge)
- "↻" revert glyph next to overridden cells, with a small amber dot ● for the overridden state
- Tooltips appear after a 300ms delay and are session-cached
- "View in Reporting →" inline link pattern with a literal arrow
### What NOT to write
- No motivational copy ("Great work!", "You're crushing it")
- No question-mark headlines ("Need help?")
- No marketing CTAs ("Upgrade now", "Try premium")
- No mascot or persona — the system is the system
---
## VISUAL FOUNDATIONS
The dashboard reads as a **dark tactical intelligence console** — slate / graphite backgrounds, sky-blue as the primary accent and ambient glow, severity colours used like signal flags, animated pulse-glow status dots, and information density prioritised over breathing room. The aesthetic is closer to a SOC / NOC mission display than to a flat enterprise SaaS.
### Colour vibe
- **Dark slate base.** `#0F172A` (deep slate) for the page, `#1E293B` for surfaces, `#334155` for elevated surfaces and borders. Almost black, never pure black. The cool tone is consistent — no warm shadows.
- **Sky blue is the brand accent** — `#38BDF8` is the primary action / link / focused state colour. It appears in buttons, active nav items, link text, and the "create" badge in the audit log.
- **Severity is a fixed semantic system** — the colours below MUST mean what they mean and nothing else.
- Critical → Red `#EF4444`
- High → Amber `#F59E0B`
- Medium → Sky `#38BDF8`
- Low → Emerald `#10B981`
- **Neutral text scale** — `#F1F5F9` (primary fg), `#CBD5E1` (secondary), `#94A3B8` (muted), `#64748B` (placeholder / disabled). Never pure white.
- **Group badges** — Admin red, Standard_User accent blue, Leadership amber, Read_Only muted grey. The same severity language reappears here for status urgency.
### Typography
- **Outfit** for all UI (headers, body, buttons, navigation). Geometric sans, friendly but precise; weights 400 / 500 / 600 / 700.
- **JetBrains Mono** for *data* — CVE IDs, IP addresses, hostnames, EXC numbers, finding IDs, code blocks. Anything you'd grep for.
- **Scale** is compact. Page titles 2428px / 600 weight; section headers 1618px / 600; body 14px / 400; data table cells 13px / 400 mono. Line-height stays tight (1.4) to preserve density.
### Spacing
- **4 / 8 / 12 / 16 / 24 / 32 / 48** — a roughly 4px grid. Cards have 1620px internal padding; rows in dense tables have 810px vertical padding; modals have 24px internal padding.
- **Section gaps** are 2432px. Between siblings, 1216px is the dominant rhythm.
### Backgrounds
- **No imagery.** No hero photographs, illustrations, or marketing visuals. The page is solid `#0F172A`.
- **Subtle sky-blue grid is allowed.** A 20×20px grid at `rgba(14,165,233,0.025)` (`.grid-bg` utility) sits behind hero / empty regions. It is barely visible and never dominates.
- **Surfaces use diagonal gradients**, not flat fills — `linear-gradient(135deg, rgba(30,41,59,0.95), rgba(51,65,85,0.9))` is the canonical card surface.
### Cards and surfaces (`intel-card`)
- **Background:** diagonal gradient `135deg, rgba(30,41,59,0.95) 0%, rgba(51,65,85,0.9) 50%, rgba(30,41,59,0.95) 100%`
- **Border:** 1.5px solid `rgba(14,165,233,0.30)` — sky-blue at low alpha, not slate grey
- **Radius:** 8px (default) / 12px (modals) / 4px (chips)
- **Internal padding:** 1620px
- **Resting shadow:** `0 4px 12px rgba(0,0,0,0.4)` + `0 2px 6px rgba(0,0,0,0.3)` + inset `0 1px 0 rgba(14,165,233,0.10)` (sky highlight on top edge)
- **Hover:** border opacity climbs to `0.50`, the card lifts `translateY(-2px)`, and gains a `0 0 30px rgba(14,165,233,0.10)` ambient glow. A `::after` shimmer sweeps left→right on entry.
- **Stat cards** add a 2px `linear-gradient(90deg, transparent, #0EA5E9, transparent)` rail on the top edge.
### Borders
- **Sky-blue at low alpha** is the dominant border treatment — `rgba(14,165,233,0.15)` for subtle dividers, `0.25` for default, `0.40` for strong / hover. Pure slate `#334155` borders appear only on tables and inputs at rest.
- Focus state: 2px sky-blue ring `0 0 0 2px rgba(14,165,233,0.15)` plus the border swaps to solid `#0EA5E9`.
- Severity-tinted left borders are NOT a pattern — colour is carried by badges, dots, and glow.
### Animation
- **Pulse-glow on status dots is canonical.** Every severity / SLA badge has an 8px circle that pulses `box-shadow: 0 0 5px → 15px currentColor` on a 2s ease-in-out loop (`@keyframes pulse-glow`).
- **Card hover lift** is 300ms cubic-bezier(0.4,0,0.2,1) with a `::after` shimmer sweep — `linear-gradient(90deg, transparent, rgba(14,165,233,0.08), transparent)` translating from `left:-100%` to `100%` over 500ms.
- **Buttons** have a circular ripple `::before` that scales from 0×0 to 300×300 on hover (500ms).
- Modal entry: 200ms fade + slight translate. Slide-out panels: 240ms ease-out from the right.
- Tooltips have a deliberate **300ms hover delay** before appearing.
- A `.scan-line` utility (3s loop) is available for hero / loading affordances — used sparingly.
### Hover states
- **Cards** lift `-2px`, border opacity climbs from `0.30``0.50`, and a sky-blue ambient glow `0 0 30px rgba(14,165,233,0.10)` appears.
- **Buttons** brighten their gradient fill from `0.15/0.10` to `0.25/0.20` alpha, gain a `0 0 20px` brand-color glow, and lift `-1px`.
- **Text links** lighten from `#38BDF8` to `#7DD3FC` and the bottom border brightens to match.
- **Table rows** get a `rgba(0,217,255,0.06)` wash plus `0 2px 8px rgba(0,217,255,0.10)` sub-shadow.
- The audit notes a current anti-pattern: hover states implemented via `onMouseEnter` / `onMouseLeave` JS handlers. The design system standard is **CSS `:hover` pseudo-classes** — JS hover is a defect to migrate away from.
### Press / active states
- Button: shifts to `#0EA5E9` (slightly darker than hover), no shrink, no shadow change. Press is a colour signal, not a physics signal.
- Rows / interactive cards: `#475569` background on `:active`.
### Transparency & blur
- Modal backdrops: `rgba(10, 14, 39, 0.97)` with `backdrop-filter: blur(12px)`. The blur is heavy and the backdrop is near-opaque — modals fully obscure the background.
- Tooltips: gradient `linear-gradient(135deg, #334155, #475569)` with a sky-blue border and `0 4px 12px` + `0 0 16px rgba(14,165,233,0.15)` glow.
- Inputs: translucent `rgba(30,41,59,0.6)` background with `inset 0 2px 4px rgba(0,0,0,0.2)` for a subtle recessed feel.
### Inner / outer shadows
- **Both are used.** Cards combine outer drop + inner sky-blue highlight: `0 4px 12px rgba(0,0,0,0.4), inset 0 1px 0 rgba(14,165,233,0.10)`.
- **Inputs are recessed** — `inset 0 2px 4px rgba(0,0,0,0.2)` plus a `0 1px 0 rgba(255,255,255,0.03)` top sheen.
- **Document items** (within KB / vendor lists) use a stronger inset `inset 0 2px 4px rgba(0,0,0,0.3)` to read as nested / pressed-in.
- Modals lift on `0 20px 60px rgba(0,0,0,0.6) + 0 10px 30px rgba(14,165,233,0.10)` — heavier than most enterprise products, but the brand glow is the signature.
### Layout rules
- **Full-width fluid** above 1024px — the dashboard fills the viewport, with content max-width capping at ~1600px on very wide displays.
- **Top app bar is fixed** — height 56px, contains brand mark, page nav, and `UserMenu`. Sits above all content with `z-index: 50`.
- **Side nav drawer (NavDrawer)** slides from the left on icon click; it does *not* push content (overlay model).
- **Slide-out panels** (Atlas, Compliance Detail) come from the right, ~480px wide on desktop, full-width on narrow viewports.
- **Modals** are centered, max-width 640px (small) or 960px (wizard / upload), with the standard backdrop.
### Severity language
This is the most important visual rule in the product. Severity badges use the **`status-badge` pattern**:
- 2px solid border at `0.6` alpha
- Diagonal gradient fill at `0.20 / 0.15` alpha
- **Lighter text** for legibility — `#FCA5A5` (critical), `#FCD34D` (high), `#7DD3FC` (medium), `#6EE7B7` (low) — not the raw severity colour
- Text-shadow `0 0 8px` brand-color at `0.4` alpha
- 8px filled circle dot with a pulsing `box-shadow: 0 0 12px / 0 0 6px` glow on a 2s loop
- `0 4px 8px rgba(0,0,0,0.4)` outer shadow
- **Always JetBrains Mono, uppercase, 0.5px letter-spacing**
Secondary references can use simpler tinted pills (`rgba(brand,0.12)` background + brand text, no border, no glow). Single coloured dots `●` next to numeric scores are also valid. The colour-to-severity mapping is fixed across every component.
### Headings — the brand glow
Page titles and section headers are **JetBrains Mono, uppercase, sky-blue `#38BDF8`**, with `text-shadow: 0 0 16px rgba(14,165,233,0.30), 0 0 32px rgba(14,165,233,0.15)`. This is the most identifiable single signal in the product — every page header reads as a glowing terminal title. Outfit is reserved for body, helper, and table cell text. The Knowledge Base markdown viewer continues this language: `h1` sky-blue, `h2` emerald, `h3` amber — a deliberate severity-coloured hierarchy.
---
## ICONOGRAPHY
The product uses **lucide-react** as its sole icon system. Lucide is a 1.5px-stroke, geometric, open-source icon set — clean, restrained, and perfectly aligned with the dark tactical aesthetic.
### Rules
- **All icons are line / stroke style** — never filled glyphs (with one exception: the calendar's red due-date dot is a filled circle, but it's a status indicator, not an icon).
- **Stroke width:** 1.52px (lucide default). 1.5px on small icons (≤16px), 2px on larger icons.
- **Sizes:** 14px (inline with text), 16px (default UI), 20px (nav items, prominent buttons), 24px (page-header icons).
- **Colour:** inherits `currentColor` — text-foreground for default, `#38BDF8` for active / accent, severity colours when used as a status indicator.
- **No emoji anywhere.** Status, severity, and category use icons + colour; never `🔴` or `⚠️`.
- **No unicode-as-icon shortcuts** beyond `●` (status dot), `↻` (revert / cycle), `↱` (redirect), `⊙` (filter handle), `→` (inline link), `+N` (count badge). These are part of the typography, not stand-ins for missing icons.
### Brand mark
The product has no published logo file in the repo (the audit references `AtlasIcon` as a custom SVG brand icon — Atlas appears to be the action-plan integration, not the dashboard's own brand). For this design system the brand mark is a **typographic stack**: `STEAM` in Outfit 700 with a sky-blue underline accent and a small shield glyph (lucide `Shield`) to the left. See `assets/logo.svg` and `assets/atlas-shield.svg`.
### Substitutions flagged
- **Atlas action-plan brand icon** is recreated as a generic shield (lucide `Shield`) tinted sky-blue. **If you have the real `AtlasIcon` SVG, please attach it** — the in-product version is custom and not available from the repo URL.
- Fonts (Outfit, JetBrains Mono) load from Google Fonts CDN. **If you need offline font files, attach the woff2s** and we'll bundle them into `fonts/`.
### Icons used per page (from README)
- **Home:** Calendar (CalendarWidget), Search, Filter, Plus, Upload, Edit, Trash, X (close)
- **Reporting:** RefreshCw (Sync), Eye / EyeOff (row visibility), Check, Filter (⊙ in column header), Columns, Download (Export), MoreHorizontal
- **Compliance:** Upload, AlertTriangle (drift breaking), AlertCircle (drift silent-miss), Info, ChevronRight, FileText
- **Knowledge Base:** FileText, FilePlus, Folder, Download, Eye
- **Admin:** Users, ScrollText (audit log), Activity (system info), Shield (admin badge)
- **Universal:** ChevronDown, ChevronUp, Check, X, Loader, ExternalLink
When picking an icon, prefer the lucide-react name from this list before introducing a new one.
---
## UI Kits
| Kit | Path | What it covers |
|---|---|---|
| `cve-dashboard` | `ui_kits/cve-dashboard/` | App shell (top bar, nav drawer, user menu), Knowledge Base page + viewer, primitives (Button, Badge, Pill, Input, Select, Modal shell, SlideOutPanel, DataTable, GroupBadge, SeverityBadge, EmptyState, LoadingState) |
The Knowledge Base page is the focused recreation. Other surfaces (Reporting, Compliance, Admin) are intentionally not built out — the primitives + shell are sufficient to compose them.
---
## How to use this system
1. **Tokens first.** Import `colors_and_type.css` into the root of any HTML file. All colour, type, radius, shadow, and spacing decisions should pull from these CSS custom properties.
2. **Pick a primitive before inventing.** Severity badges, group badges, status pills, table row, modal shell, slide-out panel — they all live in `ui_kits/cve-dashboard/`.
3. **Match the density.** When in doubt, tighter is more on-brand than airier.
4. **Lucide for icons.** Use the lucide-react CDN or copy individual SVGs from the lucide site. Do not draw your own.
5. **No emoji, no gradients, no illustration, no marketing copy.** The product is a console.