9.1 Answer one question per surface
A page that answers two questions answers neither. The product's own IA is built on this: Home answers what happened, Apps answers where do I go. Merging them works at three apps and falls apart at fifty.
Before building a page, write the question it answers in one sentence. If you need "and", you need two pages.
9.2 Fixed chrome, growing content
The platform sidebar is four items, forever: Home, Apps, Team, Organization. Apps are reached through the ⌘K launcher and the catalogue — they never join the nav.
This is the single most important structural decision in the product. Any navigation that grows with the number of things it lists has a ceiling, and you hit it in production, in front of a customer, with no cheap fix. Chrome is fixed. Content grows.
The same rule governs the operator console: per-app back-office surfaces hang off
/admin/apps from each app's manifest, so the operator nav does not grow either.
9.3 Search beats browse past about fifteen
A dropdown of everything works up to roughly fifteen items and then quietly stops. Typing is O(1) in the number of items.
So: the app switcher is search-first, on ⌘K, from anywhere. Anything expected to exceed fifteen entries gets a search field before it gets a filter menu.
9.4 Progressive disclosure, one branch at a time
Sub-navigation reveals only while its parent branch is current. The sidebar never shows two app sections expanded at once.
Generally: show the next decision, not every possible decision. Detail lives one click in, not in an accordion stack on the index.
9.5 Destructive actions are confirmed, reversible, and logged
Three requirements, all of them:
- Confirmed in a real
<dialog>withshowModal()— never a<details>popover. A popover inside a card withoverflow-hiddengets clipped, and the confirm button becomes unreachable on the last row of a table. This has actually happened here. - Named. The confirmation says what is about to happen, to what: "Delete Maanrakennus Virtanen Oy and all of its data?" — not "Are you sure?"
- Logged. Anything destructive writes to the audit log with an actor and a reason.
The confirm button carries the destructive variant and repeats the verb:
Delete organization, not Confirm.
9.6 State is never a mystery
Every surface has a designed state for all five:
| State | Requirement |
|---|---|
| Loading | A skeleton over a spinner. Nothing at all under ~300ms |
| Empty | Says what is not here and what to do. Never a shrug |
| Partial | Says what is missing — "Environmental only", "Partial data" — not a blank cell |
| Error | Says what happened and what to do. Degrades the region, never the page |
| Success | Visible confirmation. A silent save is a bug report |
A page that reads "0" and a page that failed to load must never look the same.
9.7 Nothing is communicated by colour alone
A status chip carries a dot and a word. A chart series is labelled directly. A required field is marked in text, not by a red border.
This is WCAG 1.4.1, and it is also just correct for an audience reading a phone in daylight on a job site.
9.8 Keyboard is a first-class input
- ⌘K / Ctrl-K opens the switcher from anywhere.
↑↓move,↵opens,Esccloses — in every list, dialog and palette.- Tab order follows visual order. Focus moves into a dialog on open and returns to the trigger on close.
- The focus ring is never removed without an equivalent replacement.
- Every interactive element is reachable without a mouse. If it is a
<div>with anonClick, it is a bug.
9.9 Operator and customer are different products
The same codebase serves two audiences with different needs, and they get different vocabularies:
| Workspace (customer) | Operator console (staff) | |
|---|---|---|
| Density | Comfortable | Dense |
| Identifiers | Hidden | Visible, in mono |
| Language | Plain — "Your apps" | Precise — "Entitlements" |
| Errors | What to do next | What happened, with the ID |
| Role shown | Membership role | Internal rank |
Never leak operator vocabulary into the workspace. A customer should never see the word "entitlement", a UUID, or an internal role name.
9.10 The five-second test
Export any screen or asset. Look at it for five seconds. Close it. Write down what you remember.
If you cannot recall the main message, the hierarchy is wrong — start again. This applies to a dashboard as much as to a LinkedIn cover.