# Admin UI Work Framework Status: reference -- how admin work is scoped and reviewed How to produce the class of result the `c22bbae` Controls relayout did — work so specific it stands alone as a learning input, written as **rules the next page can apply**, backed by evidence a fresh model can trust. This framework is about the *craft* of touching the admin portal, not the visual styles (those live in `admin-design-standards.md`). Read the Standards doc first; this doc is the method. ## Why this exists Before `c22bbae`, the admin UI got "fixed" in ways that didn't transfer: a review category said "card is a single line of buttons," and a future page could easily re-produce the same dead column. The Controls relayout broke that pattern by **turning each observed defect into a rule the next page can mechanically apply** ("don't restate the control's own value," "single-line button strip goes full width"). The commit message is the artifact worth feeding a model: it spells out the three problems, why each fix is what it is, and the two consistency fixes — with enough context to stand alone. ## The method (5 moves) ### Move 1 — Diagnose at the surface, in the running browser Look at the page as a user does: full viewport and at 800px, before and after a `REFRESH_MS` poll. Name the defect in one concrete sentence before you touch anything. Good defect statements (from the real commit): - "Operational Triggers is a single line of buttons but sat in a col-xl-6 next to a much taller card, so half that row is permanently empty." - "Both settings panels used a 5/3/4 Bootstrap grid, which put the control mid-row at three different widths and spent a whole trailing column restating the value the control already displays." - "Rows alternated switches and text inputs, which differ ~10px in natural height and read as ragged." These are *specific and falsifiable*. "Fix the controls page layout" is not a diagnosis — it's a wish. ### Move 2 — Extract the grammar, not the look Don't record "Controls page uses `grid-template-columns:minmax(0,1fr) auto 176px`." Record the *transferable principle* behind it, plus the code as evidence: > A settings list is one CSS-grid row — key | meta | control — not Bootstrap > `.row/.col-*`. A fixed control track is the point: every switch, input and > select lands on the same right edge, so the eye scans one column. Then back it with the exact CSS so a future page can copy it. Grammar lives at the level of "what column exists and why," not "which pixel value." Rule templates that transfer: - **Do not add a column that restates the control's own value.** The meta track is for facts the control cannot show. - **A card whose content is a single line of buttons goes full width** with the buttons in `.card-actions`, not into a `col-xl-6` beside a tall card. - **Rows with a switch next to a text input need a fixed min-height** or they read as ragged. - **Boolean persisted-config controls use switches**, matching runtime knobs — not bare checkboxes. ### Move 3 — Keep old constraints load-bearing Every change must be verified against the survival checklist (S1–S5) in `admin-facelift.md` and the `learnings.md` notepad: - `escapeHtml()` on every interpolated string - chart instance reuse (never `.data.labels` mutation on the verdict bar) - `renderWarnings` inline placeholder rebuild - `saveAllConfig` stays sequential (`for...of await`, no `Promise.all`) - SSE status pill reflects real EventSource state If your change touches any of these, call it out explicitly in the commit. ### Move 4 — Prove it, not just observe it A single fresh-load screenshot has missed canvas-reuse and selector bugs twice in this project. Minimum evidence bar for an admin page change: 1. `python -m pytest` — full suite (733 tests) green. 2. Playwright load at 1400px **and** 800px, plus one 30s+ idle past `REFRESH_MS`, with **zero console errors** (beyond the benign `/favicon.ico 404`). 3. The exact interaction under change exercised by hand (toggle, save, range). Save the screenshots under `plans/` (e.g. `admin-controls-relayout.jpg`). ### Move 5 — Write the commit as the learning input The commit message is documentation for the next model. Structure it as: - **The problem(s)**, each in one concrete sentence (Move 1). - **Why each fix is what it is** — the reasoning, not just the change. - **Consistency fixes** called out separately from the main change. - **Test changes** explained (why the old assertion no longer held). Follow with a `git show ` that a fresh session can read and immediately apply. ## Also update the Standards doc in the same commit When the change teaches a new transferable rule, add it to `plans/admin-design-standards.md` *in the same commit* so doc and code can never drift. Write the new section in rule form ("Do not add a column that restates the control's own value"), not as a description of the one page. That is what makes it applicable to the *next* page. ## Repository of what this produces - `plans/admin-design-standards.md` — the accumulated grammar (settings rows, card-level layout, hard-won rules 1–10, data patterns). - `.omo/notepads/admin-facelift/learnings.md` — the chronological record of every diagnosis/fix/QA, including the false-starts that were corrected. - `plans/*.md` — the post-hoc audits that catch what the QA pass missed. - Commit messages themselves — the highest-signal, standalone learning input. ## When to use this framework - Any visible change to `admin/frontend/*.html` or the `/admin` API surface. - Any downstream admin page you might build (e.g. an Audit/Logs page, wiring in `admin_schema.sql` RBAC) — apply the grammar first, then the visuals.