Skip to content

Aurora Design

CyberMind-FR edited this page Oct 11, 2026 · 1 revision

Aurora Design

EN | FR | Aurora | design system of the administration pages

Dark, dependency-free, honest about its data. One page = one HTML file.

What this is for

"Aurora" (the reference project profile, named 2026-10-11) is the common style of the redesigned administration pages: WAF overview and its six tabs, Guardian, DPI and its five ndpid tabs, SOC, Actor Intelligence, Threats, Metrics and the Toolbox. This guide gives the principles, the colour tokens, the page anatomy and the rules to follow when you add or port a page. The living model is packages/secubox-waf-ng/composants/waf/www/waf/vue.html; when in doubt, the code wins. See the result in Admin-Panels-Gallery.

1. Principles

Rule Why
One self-contained HTML file: inline CSS and JS The vhost CSP (default-src 'self'; script-src 'self' 'unsafe-inline') forbids more, and every dependency is extra surface
No library, no remote font, no <script src> Same reason; nothing to download
Charts are hand-written SVG No canvas, no chart library
Font stack "IBM Plex Sans","Inter",system-ui,… with tabular-nums on aligned numbers System fallback; monospace only for technical identifiers (interfaces, hashes, IPs)
SPDX CMSD-1.0 header, no secret ever displayed A truncated public key is enough
Single dark theme No light theme in this profile

2. Colour tokens

Copy them as they are:

:root{--fond:#060d1b;--trait:rgba(86,150,255,.22);--trait2:rgba(86,150,255,.38);--texte:#eaf1ff;--doux:#9fb3d6;--faible:#6f84a8;
  --cyan:#29b6f6;--bleu:#3b82f6;--vert:#2ecc71;--rouge:#ff4d5e;--orange:#ff9f1c;--violet:#a78bfa;--jaune:#ffd23f}
Token Meaning
--cyan information, incoming, primary
--vert healthy, active, successfully blocked
--orange attention, demonstration, stale
--rouge threat, critical, dropped packets, offline
--jaune outgoing
--violet, --bleu secondary series
--texte / --doux / --faible value / label / note and unit

A colour keeps the same meaning on every page. Background: two radial gradients (blue top right rgba(59,130,246,.2), red or cyan bottom left at .10) over --fond. Severity badges: critical red, high orange, medium yellow, low blue or green.

3. Page anatomy

.cadre   container-type:inline-size; container-name:a; padding:10px  (NO min-height)
 └ .app  border --trait2, radius 16, 160deg dark gradient, cyan shadow, grid gap 10
    ├ .tete      brand · status pill · right side: time + Refresh button
    ├ banners    .demo (orange) · .info "session required" (cyan)
    ├ .tuiles    2 columns, 4 to 6 wider (container query)
    └ .grille    of .pan panels (h3 title, faint note on the right)
Element Spec
Tile radius 12, --trait border; label .74rem --doux, value 1.45rem/700 tabular-nums, sub-line .68rem --faible. Every tile carries its definition as a tooltip (title)
Panel .pan radius 12, --trait border, background rgba(10,22,46,.6); shadowed cards only for objects worth singling out
Pill radius 999, border and text in the semantic colour, background the same colour at 12 %
List / bar row name · value · bar (6 px bar)
Table small-caps header .66rem, sort/filter/search client side, horizontal scroll inside its own container
Curve one scale (the larger of the two series), real graduations, translucent area fill-opacity .14, vector-effect:non-scaling-stroke. Never an invented series

4. Layout: container queries

The grid is decided on the width of .cadre (@container a (min-width:700px|900px|1100px)), not on the viewport, so the same page serves as a card, an embedded tab and full screen.

  • ?embed=1 or width under 900 px: a single column; give text-bearing grid children min-width:0.
  • At 420 px (phone): no horizontal page scroll. Only tables, code and diagrams scroll, each in its own container.

5. Data truth

Situation What the page does
Measurement missing "—", never 0. Zero is a measurement
API does not provide a series no curve
Value derived on the page (family, category, confidence, trend) the page says so (note or tooltip)
Partial figure announced as partial
401 / failure banner "No measurement: session required. Log in", tiles in "—"
?demo=1 realistic demo data, orange banner, documentation addresses (RFC 5737 / 3849), fictitious names, no write call
Collector stopped / stale data visible state (orange pill "STALE DATA — COLLECTOR STOPPED?"), not silence

Corollaries: a timeline without empty days is not padded with zeros (the axis shows measured days only and averages count only those); "unique visitor = 1" can be a proxy IP, and the tooltip explains it instead of hiding the figure.

6. Fetching data

  • fetch(url, {headers:{Accept:'application/json'}, credentials:'same-origin', cache:'no-store'}); add Authorization: Bearer from localStorage.sbx_token when present (wrap the read in try/catch, localStorage can throw).
  • Same origin only: routes /api/v1/<module>/… of the page's own host.
  • Prefer aggregated reads (/pub/…) over removed legacy routes: on the admin host /api/v1/dpi/stats answered "removed" with no connected field and the view wrongly showed OFFLINE (#2368).
  • Refresh every 15-60 s only while document.hidden is false, and never during typing or an open confirmation.

7. Iframe height protocol

A framed page measures its frame, not the document:

parent.postMessage({sbxVue: Math.ceil(document.querySelector('.cadre').getBoundingClientRect().bottom + scrollY), onglet:'name'}, location.origin)

Post on load, on resize and after each render (ResizeObserver on body).

  • Forbidden: documentElement.scrollHeight and min-height:100vh on the frame. The measure could then only grow (the document is never shorter than the iframe) and you get thousands of pixels of blank (#2323, #2354, #2358).
  • Existing keys: sbxwafVue (WAF overview, lowercase w), sbxWafVue + onglet (WAF tabs), sbxdpiVue, sbxSocVue, sbxNdpidVue, sbxThreatsVue, sbxMetricsVue, sbxToolboxVue, and the generic sbxVue (SOC/Toolbox). A new page posts sbxVue + onglet.
  • The host clamps the value (WAF 300-4000 px, SOC 400-4000 px, plus 4 px) and checks e.origin === location.origin; with several frames, onglet must match the frame. A page that announces nothing keeps the iframe's default height.

8. Actions and confirmations

  • A page is read-only unless the old tab wrote. Existing actions keep exactly the same call (route, body, headers): you re-skin, you do not change the contract. Invent no action.
  • Confirmation is inside the page (Confirm / Cancel buttons in the panel). Never confirm(), alert() or prompt(): the viewer's browser ignores them (confirm() silently returns false). Show result or error in the page.
  • Actions are inert in ?demo=1. Anything irreversible asks for confirmation; never offer to wipe learned lists.

9. Embedding in a host (tabs, SOC, Hall)

  • Each tab of a tabbed page is a standalone page framed in a same-origin iframe; the old content stays in the DOM, hidden, so the rest of the script keeps working.
  • One source: the SOC frames /waf/*.html, /dpi/vue.html, /actor-intelligence/; the Toolbox frames /soc/reseau.html. Never copy a page. The host must list in Depends the packages carrying the pages it frames (otherwise the tab is empty); the lite Profils pulls them through dependency closure.
  • Pages are served by a static root, never alias + try_files (it loses the extension). A Hall relay is a list of exact routes behind auth_request.
  • The common side menu (/shared/sidebar.js) stays loaded outside ?embed=1 and outside demo.

10. Pitfalls

Pitfall Remedy
The shared hybrid-skin.css is injected after the page and sets its tints with !important A page keeping that skin must answer with higher specificity (html :is(.hybrid-skin, body) …); a full Aurora page does not load it
Frame height only grows See section 7
Browser dialogs ignored In-page confirmation
Relative fetch fails under file:// That is the "no session" empty case, useful for testing

11. Tests and verification

  1. Static test (pytest, no browser) per page: SPDX header, height key posted, demo, no external <script src=, no "lorem", no secret, no confirm( / alert( / prompt(, API routes cited, write routes identical to the old page, and for a read-only page no POST.
  2. Real capture (Playwright, file://…?demo=1) at 1400x900 then 420 px wide; read the PNGs; fix until nothing overflows horizontally and no text is cut. scripts/snapshots-aurora.py regenerates the gallery.
  3. Empty case: without ?demo=1 expect "—", the banner and no JS error (page.on('pageerror')).
  4. Integration: switch every tab, note the iframe src and height, no error.
  5. On the box: curl the pages (200) and have a human look at the real data; an empty capture does not prove real series are legible.

12. Content and accessibility

French UI vocabulary of the project; sober titles; a definition tooltip on every measure; explicit labels ("Incoming now", not "In"); aria-selected on tabs, visible focus, comfortable touch targets, contrast per the tokens above.

See also

SecuBox | FR | DE | 中文 | v3.0.0-alpha.12


Projet

Soutenir


🔴 BOOT — Démarrer

🟢 ROOT — Configuration

🟣 MIND — Modules

🔵 MESH — Référence

🟠 WALL — Matériel

🤖 Workflow Agents


Liens

Clone this wiki locally