# RFC 0001: Web UI Redesign — the Instrument Panel **Status:** - proposed: 2026-09-03 - accepted: - - rejected: - **Proposal:** The Werkator web UI adopts the **Instrument Panel** direction: a teal palette in a light and a dark mode, IBM Plex typography, a repository strip that previews the state of every served repository, a title hierarchy that names the view first and explains it second, and a tab bar at the foot that becomes the mobile navigation. The architecture does not change: server-rendered Thymeleaf, one `werkator.css`, one hand-written `werkator.js`, JSON polling, no framework, no frontend build pipeline. ## Context and Problem Statement The current UI is a functional port of the legacy generated pages: a table per view, pill badges, system font, blue links. It is correct and calm, but it looks like every other CI page and gives no hint of the other repositories an instance serves (ADR 0009). The brief for this RFC was "fancy, but serious and trustworthy", with two references from the same author for visual kinship: - [werkbaum.javagil.de](https://werkbaum.javagil.de/) — light paper with a fine grid, IBM Plex, a petrol accent, panel labels in small caps. - [javagil.de/vibe-engineering](https://javagil.de/vibe-engineering) — a dark instrument panel: ink and petrol, clay for warnings, monospaced spaced labels, a tab bar at the foot. A hard constraint of this RFC is honesty towards the data. The mockups show only what the API delivers today; nothing is invented to make a screen look richer. ### What the UI Has to Work With Per build row (`BuildRowView`, `BuildResultDto`): status, branch name, commit (12-character abbreviation, full id for copying), started at (`yyyy-MM-dd HH:mm`), duration (`m:ss`; a pending build shows its wait time in italics), artifact key with the artifact, permalink and live-log links, and the actions restart and delete (history has no restart). Statuses: `pending`, `running`, `success`, `failed`, `interrupted`, `cancelled`, plus `unknown` for a never-built branch and the client-side `finished` on a card whose build has left the current list. Views: Latest (one build per name), Branches (every origin branch and its latest build), History (all stored builds), Current (running builds with their live log), System (seven metric rows with current/min/max/avg, warn from 80 %, critical from 90 %), the artifact page, and the release notes. Live state: the indicator is `static`, `live` or `error`; the watcher banner reports `watcher stopped`, `origin unreachable` or `poll cycle failed`. Multi-repo: the repository switcher is a server-rendered `` switcher is replaced by a strip below the header that shows every served repository with its state, so a failure elsewhere is visible without leaving the page. - Up to about three repositories: **tiles** (220 px), each with `current` or `repo` label, the name, one dot per branch in the branch's latest status, a summary line (`6 builds · 1 failed · 1 running`), and the watcher warning in clay when that repository's watcher reports an error. - More repositories: **chips** (30 px), each with one dot for the worst status in the repository, the name, an optional short finding (`1 failed`, `main`, `never built`), and a warning triangle when the watcher reports an error; the current repository has an accent-2 border on panel-2, a failing one a clay-2 border on the clay tint. - Order is *failing first*: the current repository, then failing, running, then green; a summary line above (`10 served · 2 failing · 1 unreachable · 2 running`) and a sort control on the right. - The strip **scrolls**: horizontally on the phone, and on the desktop it wraps to a second row up to about ten repositories and becomes a horizontally scrollable band beyond that, with the failing chips pinned at the front so they never scroll out of view. - Beyond roughly twenty repositories the strip shows only the conspicuous chips (failing, running, unreachable) plus a search field for the rest. - With a single served repository the strip is omitted, as the switcher is today. ### Phone (below 680 px) The existing breakpoint behaviour is kept and restyled: rows become cards with the `data-label` captions, the live indicator collapses to a dot. The header stacks `Werkator` over the repository name; the repository strip scrolls horizontally under its summary line; the panel title keeps its hierarchy; each card carries the status line with the branch, then commit, started and duration, then the artifact icons and the actions as 44 px targets. The footer tab bar becomes a fixed bottom tab bar with icons — the same four entries as on the desktop. No painted status bar or keyboard; the device provides those. ### What Is Deliberately Not in the Proposal - The `DE` language button in the mockups is a leftover of the reference; the UI stays English-only. - No commit subjects, typical durations, ETAs or history strips: they need data the server does not have, and each would be its own RFC with its own storage. - No manual theme toggle; `prefers-color-scheme` decides, as today. ## Consequences ### Backend - One new endpoint, `GET /api/repos`: for every served repository its name, its UI root (`/repos/`), whether it is the current one, the latest status per build name (the Latest view's `latestPerName` reduced to counts, plus the worst status), and its `RepoWatcherState` (`lastFetchError`, `lastPollError`, `lastPollAt`). With one served repository the endpoint returns a list of one and the strip stays hidden. - `werkator.js` polls it on the table interval (10 s) and renders the strip; every fetch keeps the timeout and the explicit error badge. - `UiFormats` and `werkator.js` keep producing identical formats; the palette and the title labels are template and CSS only. ### Rollout, One Concern per Pull Request 1. Palette, typography and the title hierarchy in `werkator.css` and the fragments — no data change, both modes. 2. Header and footer tab bar, including the phone tab bar. 3. `GET /api/repos` and the repository strip, replacing the `