Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
c28fa0f
docs: add mission control redesign implementation plan
comnam90 May 21, 2026
ba4f103
feat(ui): add typography and theme design tokens
comnam90 May 21, 2026
4e3bc6b
feat(ui): rebuild header with brand mark, status strip, and controls
comnam90 May 21, 2026
b46fcf4
fix(ui): expose live region count to assistive tech in new header
comnam90 May 21, 2026
02b0a45
feat(ui): unify control styles into single .ctl primitive
comnam90 May 21, 2026
ade8a3f
feat(ui): restyle map chrome and legend
comnam90 May 21, 2026
792df6f
feat(ui): restructure popup template; collapse vault tiers to single row
comnam90 May 21, 2026
7e605d2
feat(ui): replace circle markers with provider-shaped glyph icons
comnam90 May 21, 2026
5bafc11
feat(ui): adopt official Veeam help-center service names; fix initial…
comnam90 May 21, 2026
b7315a2
feat(ui): retoken info panel content
comnam90 May 21, 2026
8667846
chore(ui): remove unused old-design CSS and update tests for new header
comnam90 May 21, 2026
ca6f405
fix(ui): use clusterGroup.zoomToShowLayer for search-driven popup
comnam90 May 21, 2026
573376c
fix(ui): respect .hidden utility on .ctl; update Azure→Azure Protecti…
comnam90 May 21, 2026
c040fef
fix(test): zoom in before clicking marker so cluster doesn't absorb it
comnam90 May 21, 2026
d814761
fix(test): make marker-click test viewport-aware; skip on fragile bro…
comnam90 May 21, 2026
819693c
fix(ui): address PR #103 review feedback
comnam90 May 21, 2026
d81d883
fix(test): use DOM-level click on marker; works on every project
comnam90 May 21, 2026
0aa05cd
docs(adr): record service-naming convention and Mission Control aesth…
comnam90 May 21, 2026
d83701a
feat(ui): refine popup with service icons, tier tooltips, AA contrast
comnam90 May 21, 2026
6bd1c38
docs(adr): record tooltip pattern; extend ADR-004 with icons + WCAG f…
comnam90 May 21, 2026
e250d05
refactor(ui): replace .marker-glyph CSS with .map-marker-dot
comnam90 May 21, 2026
85bfa52
feat(ui): add markerLogos brand-SVG dictionary
comnam90 May 21, 2026
87b7f13
feat(ui): render map markers as hybrid POI dots with brand logos
comnam90 May 21, 2026
f89fa4a
test(ui): update marker selectors from .marker-glyph to .map-marker-dot
comnam90 May 21, 2026
5450ddf
refactor(ui): align cluster badges with POI-dot design (white surface…
comnam90 May 21, 2026
7ed291c
feat(ui): remove provider-mix strips from cluster markers
comnam90 May 21, 2026
4fd6dcc
refactor(ui): switch cluster badges to inverted brand accent for ligh…
comnam90 May 21, 2026
7ee2105
docs(adr): add ADR-006 cluster marker treatment; mark ADR-004 follow-…
comnam90 May 22, 2026
63415cd
fix(ui): fit initial map view to populated regions
comnam90 May 22, 2026
0234bde
fix(ui): keep map minZoom at 2 so mobile filter tests still see indiv…
comnam90 May 22, 2026
c6a3180
fix(ui): allow tile wrap so wide viewports fill empty edges
comnam90 May 22, 2026
0026f8c
docs(adr): add ADR-007 initial map view via fitBounds with tile wrap
comnam90 May 22, 2026
3e89b01
fix(ui): stack header filters below search on mobile
comnam90 May 22, 2026
7069a1e
fix(ui): stop multi-select chevron overlapping reset button on mobile
comnam90 May 22, 2026
03dd4ae
fix(ui): remove status-page wording from header and legend
comnam90 May 22, 2026
c4f92f1
fix(ui): match providers legend icons to map marker logos
comnam90 May 22, 2026
104d38e
docs: align ADRs and plan with shipped marker class and prior view
comnam90 May 22, 2026
6dc1e17
fix(ui): scope marker SVG defs IDs per marker and make Mono the body …
comnam90 May 22, 2026
aa75db1
fix(ui): stack vault edition pills vertically in popup
comnam90 May 24, 2026
611d5c1
fix(ui): zero-pad available services count in popup header
comnam90 May 24, 2026
cf6e3b9
fix(ui): extend east map bound so NZ popup fits on mobile
comnam90 May 24, 2026
881c5ab
fix(ui): escalate zoom on search-click so popup fits for edge regions
comnam90 May 24, 2026
3e63f41
fix(ui): address code review findings on mission control redesign
comnam90 May 25, 2026
6807133
docs(llms): adopt official Veeam service names
comnam90 May 25, 2026
8d74801
fix(ui): use defined --border token on marker dot
comnam90 May 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions docs/architecture/ADR-003-official-veeam-service-naming.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# ADR-003: Adopt Official Veeam Help-Center Service Names

**Status**: Accepted

## Context

The UI previously used a mix of ad-hoc service names produced from the YAML keys (`vdc_vault`, `vdc_m365`, `vdc_entra_id`, `vdc_salesforce`, `vdc_azure_backup`). The `serviceDisplayNames` map rendered them as a hybrid of ALL-CAPS brand acronyms and title-case product nouns — e.g. `M365 Protection`, `ENTRA ID Protection`, `SALESFORCE Protection`, `AZURE Protection`. The Vault row used short `Vault` / full `VAULT`.

Two problems emerged from this:

- The names didn’t match the section headings used in the official Veeam Data Cloud help-center user guide. Anyone reading both side-by-side had to mentally translate.
- The service-filter checkbox label `Azure` collided with the Azure cloud provider label in the provider filter directly above it. Users could mistake the service filter for a provider filter.

The names appear in three runtime contexts: the multi-select filter dropdown (short label), the filter-button label when one service is selected (short label), and the popup row per service (full label).

## Decision Drivers

- Vocabulary parity with the official Veeam documentation users are most likely to read alongside the map.
- Unambiguous filter labels — no two top-level controls should share a label.
- A single source of truth (`serviceDisplayNames`) drives every UI surface.

## Decision

Adopt the official help-center section names verbatim as the `full` display names:

| YAML key | `short` (filter UI) | `full` (popup row) |
| --- | --- | --- |
| `vdc_vault` | `Vault` | `Veeam Data Cloud Vault` |
| `vdc_m365` | `M365` | `Microsoft 365 Protection` |
| `vdc_entra_id` | `Entra ID` | `Microsoft Entra ID Protection` |
| `vdc_salesforce` | `Salesforce` | `Salesforce Protection` |
| `vdc_azure_backup` | `Azure Protection` | `Microsoft Azure Protection` |

The `short` for `vdc_azure_backup` is deliberately `Azure Protection` (not `Azure`) to disambiguate from the `Azure` cloud-provider filter that sits next to it in the header.

All UI surfaces — multi-select checkbox labels, multi-select button label, and popup rows — read these strings through `getServiceDisplayName(key, type)`. The Playwright test that filters by the Azure service uses the `Azure Protection` label accordingly.

## Options Considered

### Option A: Keep the ad-hoc names

- Pros: No code change; existing tests pass.
- Cons: Vocabulary divergence from official docs; ongoing collision between the `Azure` service short and the `Azure` provider option.

### Option B: Use only the short brand abbreviations everywhere (`Vault`, `M365`, `Entra`, `SF`, `Azure`)

- Pros: Most compact UI; no wrapping.
- Cons: `SF` is opaque without context; doesn't match any official Veeam naming; the `Azure` collision is unresolved.

### Option C: Adopt the official help-center names (chosen)

- Pros: Direct parity with documentation users already read; the `…Protection` suffix on the Azure service eliminates the provider collision naturally.
- Cons: Long labels — `Microsoft Entra ID Protection` wraps in the popup row on narrow widths. Accepted because the wrapping is benign and the disambiguation gain is worth it.

## Consequences

- Any future service added to the YAML schema MUST register a `{ short, full }` entry in `serviceDisplayNames` using the canonical Veeam help-center heading as `full`. If the official docs ever rename a section, this map is the single place to update.
- The `short` label for a new service MUST NOT collide with any existing provider value in `#providerFilter` (today: `Azure`, `AWS`). Where collision is unavoidable, follow the precedent set here and append `Protection` (or the equivalent product noun) to the `short`.
- Documentation surfaces that mention services (info panel “What is this?” copy, `static/llms*.txt`, future help text) should use the canonical `full` names.
- Tests asserting against service labels (e.g. `getByRole('checkbox', { name: 'Azure Protection' })`, `<input value=vdc_azure_backup> Azure Protection</label>` regex matches) must be updated in lockstep with any future rename.

## Links

- [PR #103](https://github.com/comnam90/veeam-data-cloud-services-map/pull/103) — the redesign that introduced this convention.
- Mission Control Redesign implementation plan: `plans/mission-control-redesign/plan.md`
- Veeam Data Cloud help-center: <https://www.veeam.com/products/veeam-data-cloud.html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# ADR-004: Paired Mission Control / Workstation Aesthetic with CSS Design Tokens

**Status**: Accepted

## Context

The SPA shipped initially with a generic Tailwind-driven SaaS dashboard look: system fonts, slate-grey palette with a green accent sprinkled evenly across the chrome, circle markers, and a popup that duplicated the Vault row when a region offered multiple editions. A UX review flagged the design as "competent but indistinguishable from every other cloud-service map" and identified specific issues: an Australia-centric default map view, hidden-on-mobile region count, no provider identity in markers, and amber styling collisions between AWS branding and warning callouts.

A redesign was proposed, brainstormed across two directions ("Mission Control HUD" vs "Cartographic Atlas"), and the Mission Control direction was chosen. To make light mode a first-class peer of dark mode — not a flashlight-inversion of the cockpit aesthetic — a second variant (`Workstation`) was added: same DNA, calmer language. The two themes share the same component anatomy and only swap underlying tokens.

The redesign is a single-file SPA change (`layouts/index.html`) because the project's architecture deliberately keeps the entire frontend in one Hugo template. Every visible component therefore has to pick its colours, fonts, and spacing values from somewhere — a Tailwind utility class, an inline style, or a custom CSS rule. Without a shared vocabulary the redesign would have continued the original pattern of scattering hex values across hundreds of lines and would have made future theme work hard.

## Decision Drivers

- One toggle, one product. Users flipping dark↔light should see the same product wearing different surfaces, not two different apps.
- A small palette that has *meaning*. The accent green was previously decorative everywhere; in the new system it signals "live / available / current selection" specifically.
- Mono-first typography (with a display serif/sans companion) to differentiate from the SaaS-dashboard pack and lean into the data-density of the map.
- Provider identity at the marker level — users shouldn't need to read the legend to know whether a marker is AWS or Azure.
- Theming must work without `.dark` / `.light` selectors on every component. The CSS variable system replaces dozens of paired overrides.

## Decision

### Tokenized theme system

A single `:root` block defines the dark-mode (default) tokens. An `html.light` block re-declares the same token names with light-mode values. Every redesigned component reads colours through `var(--bg)`, `var(--text)`, `var(--accent)`, `var(--azure)`, `var(--aws)`, etc. No component declares hex values directly except where the value is provider-identity (e.g. AWS Squid Ink) and required to render in a context that doesn't inherit CSS variables (e.g. SVG attribute fills are wrapped in `var(--azure)` / `var(--aws)` for the same reason).

Token domains:
- Surface: `--bg`, `--bg-elev`, `--bg-elev-2`
- Hairlines: `--border`, `--border-strong`
- Ink: `--text`, `--text-mute`, `--text-dim`
- Accent: `--accent`, `--accent-soft`, `--accent-glow`
- Brand: `--azure`, `--aws`

Dark accent is the fluorescent `#00ff88`; light accent is the muted `#00805a`. The two are intentionally non-identical — bright green on white reads as highlighter, muted green on black has no presence. Both still read as "Veeam green" emotionally.

### Typography

- `Space Grotesk` (weights 500, 700) for headlines and product nouns.
- `JetBrains Mono` (weights 400, 500, 700) for body text, UI labels, status strip, popup metadata, and coordinate readouts.

Loaded once via Google Fonts CDN with `display=swap` and a system-monospace fallback chain. The mono-first body type is the single biggest visual differentiator from the previous Tailwind-default look.

### Component anatomy

- Header: brand mark (pulsing dot) + live "status strip" telemetry (`Online · Regions X/Y · Providers 02 · Services 05`) + unified `.ctl` control primitive (search, selects, multi-select, icon buttons share one base class with `.ctl-*` modifiers).
- Map: edge-to-edge with a tokenized `.panel-legend` and tokenized Leaflet zoom/attribution chrome. No rounded corners, no green glow.
- Popup: one row per service (no edition-row duplication); each row carries a distinct monochrome service icon in `--accent` — the icon's presence signals "available", its shape signals which service; edition pills aligned right; vault edition pills hover-disclose commercial limits per [ADR-005](ADR-005-custom-css-tooltip-pattern.md); official Veeam service names per [ADR-003](ADR-003-official-veeam-service-naming.md).
- Markers: `L.divIcon` glyphs in provider brand colour (Azure triangle / AWS cube) replacing the prior `L.circleMarker` SVG paths. Keyboard-navigable; the parent marker carries an accessible `alt`.
- Info panel: same tokens, semantic class names (`.info-section`, `.info-link`, `.info-stat`) — no `bg-slate-*` / `bg-amber-500/10` mix.

## Options Considered

### Option A: Polish the existing design

- Pros: Lowest risk; existing tests stay green; small diffs.
- Cons: Doesn't address the "indistinguishable from every SaaS dashboard" feedback; the AWS amber/warning collision remains; mobile header still consumes ~15% of vertical space.

### Option B: Cartographic Atlas direction

- Pros: Genuinely distinctive (serif headlines, parchment palette, atlas vibe); zero competitors in this product space.
- Cons: Stronger departure from Veeam brand voice; the light-mode-first treatment doesn't translate as cleanly to a dark dashboard mode; risk of feeling like a marketing site rather than an operational tool.

### Option C: Mission Control HUD + Workstation light (chosen)

- Pros: Reads as a polished operational tool; live status strip + mono numerals lean into the data-density users care about; the dark/light pair shares one design system rather than being two separate aesthetics; CSS tokens scale to future theme work (e.g. a hypothetical high-contrast mode) without requiring `.theme-x` selectors on every component.
- Cons: Bigger up-front diff; Google Fonts adds a render-blocking stylesheet (mitigated by `display=swap` and a system fallback chain); some popup rows can wrap due to the longer official service names.

## Consequences

- New UI components MUST read colours/spacing through the existing tokens. Adding a new hardcoded hex value is a smell — either a new token is needed (justify in the PR), or the component should pick the closest existing token.
- Theme variants are added by extending `:root` / `html.light` (and potentially a future `html.high-contrast`, `html.print`, etc.). Components should NOT branch on `html.light` directly except where light mode genuinely needs a different *structure* (e.g. drop-shadow vs glow), and even then prefer adjusting tokens.
- Typography is a brand-level choice. If a future redesign wants different fonts, this ADR is the document to supersede; doing it piecemeal will fragment the system.
- The accent green is reserved for "live / active / available / focus". Don't use it as decoration. The provider blue/orange tokens are reserved for provider identity. Don't repurpose them.
- Each service registered in `serviceDisplayNames` MUST also register a corresponding inline SVG in `serviceIcons` (in `layouts/index.html`). Icons are simple monochrome geometric shapes that render crisply at 14px, using `stroke="currentColor"` so they inherit `--accent`. The shape carries service identity; the colour carries the "available" semantic. A service without an icon falls back to a generic checkmark — acceptable as a defensive default, not as a long-lived state.
- Metadata text tokens (`--text-dim`, `--text-mute`) carry a hard floor: both MUST clear WCAG AA against the popup background (`--bg-elev`) at the 9–10px sizes used in the popup header and coordinate readouts. This UI is regularly shown on projectors and screen-shared over compressed video; a token value that looks crisp on the design machine but fades on lossy displays violates the brief. Tune the values, not the font sizes, if a future contrast regression appears.
- Marker primitive: `L.divIcon` is the contract. Reverting to `L.circleMarker` would re-introduce the accessibility regression (no `keyboard: true`, no `alt`) and break the test selectors that target `.leaflet-marker-icon .map-marker-dot`.
- Cluster icons (`.cluster-small`, `.cluster-medium`, `.cluster-large`) were deliberately left on the old colour system in this redesign — a known follow-up, resolved by [ADR-006](ADR-006-cluster-marker-visual-treatment.md). The resolution re-tokenises clusters to `var(--accent)` only; per-provider colouring at cluster level (`--azure` / `--aws`) was considered and rejected because aggregated provider colouring destroyed the cluster/marker visual hierarchy — see ADR-006 §Options Considered.
- Hugo's HTML minifier strips quotes around single-token attribute values. Smoke tests using `curl | grep` should account for this (`class=hud`, not `class="hud"`).

## Links

- [PR #103](https://github.com/comnam90/veeam-data-cloud-services-map/pull/103) — the redesign that introduced this aesthetic.
- Implementation plan: `plans/mission-control-redesign/plan.md`
- [ADR-003](ADR-003-official-veeam-service-naming.md) — service-naming convention used inside the popup component defined by this ADR.
- UX review and mockups (session output): the brainstorming explored Mission Control and Cartographic Atlas directions at desktop + mobile, both themes, before this aesthetic was chosen.
Loading
Loading