UX Language

Table of Contents

1. Summary

ORE Studio's UI speaks one visual language across every screen: colours carry fixed meanings (gray always reads "inactive", orange always reads "missing badge definition"), icons follow the semantic rules of the Icon Guidelines, and every journey screen draws its steps from the same vocabulary. A journey is one screen organised around a goal. Its rail orders the steps, and each step draws the one view it needs. This document is the umbrella reference for that language; the per-aspect documents it links to carry the inventories. The aesthetic rules (typography, spacing, motion) live in UI design principles; this document covers semantics: what the visual vocabulary means.

2. Detail

2.1. Colour semantics

Badge and indicator colours are drawn from the Tailwind palette and carry fixed, application-wide meanings. The two load-bearing rules:

  1. Gray (#6b7280) is reserved for inactive states. Gray exclusively means inactive, off, "no", never-used, or otherwise negative/dormant: Inactive, Never (logged in), Draft, Raw (unprocessed), the "No" half of boolean badges, Pending=/=Unsent result states. No positive, completed or neutral-active state may be gray — "Unlocked" is green, "Done" is green, "Service" is teal.
  2. Orange (#f97316) means "badge definition missing". When a badge resolver finds no definition for a code-domain value (or the definition carries an unparseable colour), the badge renders in orange — the reserved __unmapped__ fallback definition in the badge seed data. Orange is never a semantic state colour: an orange badge in the UI is a gap in the badge seed data to be fixed, deliberately visible rather than camouflaged as "inactive".
  3. Green, Red and Amber ("RAG") are reserved for true status semantics — never for a plain category. Green means healthy/ positive/succeeded, red means broken/failed/dangerous, amber means caution/needs-attention. Reserve this triad for badges that genuinely carry one of those three meanings (active=/=inactive, outcome_success=/=outcome_failed, account_locked, login_old=/=frozen=/=fsm_suspended). A code domain that is purely descriptive — a category with no inherent "good/bad/caution" connotation, such as a currency pair's liquidity tier (major/minor/exotic/commodity) — must not borrow RAG colours even if a naive reading suggests one ("exotic" is not "bad"; it is a different tier). Use the Blue/Violet/Teal/Pink "classification" family instead, so a red or amber badge in the UI reliably means "something needs attention," never "this happens to be one particular category."

The full colour vocabulary:

Colour Hex Meaning
Green #22c55e Positive/healthy: active, online, success, done, unlocked, actual
Red #ef4444 Negative/destructive: locked, failed, fail policy, archived
Amber #eab308 Caution: frozen, old login, no-reply, skip policy, suspended, estimated
Blue #3b82f6 Informational/neutral: pending, recent, queue, primary origin, user account
Sky #0ea5e9 In-progress/transitional: running, cleaned, bootstrapping
Teal #14b8a6 Service account type
Violet #7c3aed / #8b5cf6 / #a855f7 Classifications: virtual type, derived origin, enriched treatment, LLM account
Pink #ec4899 Simulated nature
Gray #6b7280 Inactive only: inactive, never, draft, raw, "No"
Orange #f97316 Missing badge definition (fallback, never semantic)

2.1.1. Badge colour catalogue

Badges are database-driven: severities, code domains, definitions and mappings live in the dq schema, seeded by projects/ores.sql/populate/dq/dq_badge_system_populate.sql — the populate script is the source of truth. The full per-badge and per-code-domain listing — every definition's hex colour, and every code domain's value→badge mapping — is Badge Catalogue, kept as its own page since it is long and grows with every new code domain.

A badge definition carries its label, hex colour and meaning. The dq definitions are the shared source of every badge in the interface. A code-domain value with no matching definition falls back to orange per rule 2.

2.2. Iconography

The icon vocabulary — inventory, variants, sizes and semantic usage rules — lives in the Icon Guidelines. The semantic core: each concept has exactly one icon application-wide, so Add, Edit, Delete and History never vary between screens. Icon colour follows the same rules as badges, with gray reserved for disabled actions. The live set is 68 Fluent regular SVG files in projects/ores.web/packages/web/src/assets/icons/.

2.3. Access: editable or read only

A screen tells a person whether they may change what they see with one mark, never with a permission code. The access mark (AccessMark in web/src/ui/AccessMark.tsx) is a pill with an icon and one word:

Mark Icon Means
Editable edit The person may change this
Read only lock_closed The person may read this but not change it

Hovering the mark says why in plain words, such as "A tenant administrator can change it." Codes such as iam::accounts:update are the server's vocabulary and never appear on a screen. The mark is shared: a record page's header draws it from whether Edit is offered (RecordHeader), and a form panel draws it beside its title. A page whose parts carry their own marks draws none in its header. The server still decides every write; the mark only says what it will allow.

2.4. Journey screen anatomy

A journey is a design document, and a screen is never a journey copied step by step; that rule is the Entity screen specification's User journeys and screens (decided 2026-10-25). The screen with a rail of steps described below is a wizard, the exception that specification allows for a task that steps make quicker, and this section moves to the Journey runtime page. Where it speaks of a journey as a screen, read a wizard.

A journey is one screen, organised around a goal. The screen carries an ordered rail of steps, and each step draws the view it needs. Commit e47043269f deleted the generated entity screens. A step that lists, shows or maintains records of one kind does not draw its own table or form: it is a record screen, and it uses the shared list, record page, dialogs and timeline that the Record screen standard defines.

The journey catalogue, and the "one screen, not one per entity" rule, live in User Journeys. The step and the rail are defined in Journey runtime.

2.4.1. The rail

A step is data, not a component. It carries an id, a title for the rail, a lead sentence, a body, an optional next action, and a final flag. The rail is the ordered list of steps, so the rail and the steps cannot disagree. A position outside the journey throws rather than rendering an empty rail. Going back is refused at the first step and when the step before the current one is final.

2.4.2. A step's body

The body is opaque to the runtime, so a step draws whatever view its goal needs: a table, a form, a panel of related fields, or a confirmation. Related aspects are panels on the step, not screens of their own. The account journey is the worked example: its contact details and its sign-in state are panels. The entity models supply the fields; the journey decides which fields belong together and in what order.

2.4.3. History and Audit

History always means versioned-entity history: the versions of one record, the field-by-field difference between them, and the revert that restores a selected version as a new current version. A step that shows a log of events that happened — login sessions, dataset publications, job executions — is called Audit instead. An Audit step is a read-only event log: it has a Refresh action, but no versions, no difference and no revert. The sign-in record is the worked example, and its journey is Audit sign-ins.

3. See also

Emacs 29.3 (Org mode 9.6.15)