- Bundle Pretendard Variable woff2 locally (air-gapped safe, no CDN) and switch UI/stamp font stacks to it; preload in index.html - Replace the forensic-dossier paper theme with a flat neutral cool palette: single teal accent, white cards, no noise texture, and zero linear/radial gradients (per design contract) - Restore the product-purpose top-bar block and its CSS, drop the unused global search form, and strip the stray UTF-8 BOM - Re-skin queue hover/selection, eyebrows, nav rail, chips, and empty states to the neutral palette; tabular numerals for numbers - Regenerate ui-overhaul final audit artifacts: zero horizontal overflow across 8 views at 1440x900 and 390x844, Pretendard active Design spec: docs/superpowers/specs/2026-06-11-operator-console-clean-review-ui-design.md Plan: docs/plans/2026-06-11-001-feat-operator-console-clean-review-ui-plan.md Tests: 358 passed (full suite incl. browser smoke)
114 lines
6.2 KiB
Markdown
114 lines
6.2 KiB
Markdown
# Operator Console Clean Review UI — Design Spec
|
||
|
||
- Date: 2026-06-11
|
||
- Status: approved (autonomous goal session)
|
||
- Goal: 전체적 UI 점검 및 폰트 변경, 깔끔하게 잘 떨어지는 심사 프로그램의 목적에 맞게 개선
|
||
|
||
## 1. Problem
|
||
|
||
The current working-tree restyle ("Forensic Dossier") gives the operator console a
|
||
vintage paper-document look: beige paper background with an SVG noise texture,
|
||
ochre/teal dual accents, a "stamp" display font (Bahnschrift), and warm hairlines.
|
||
That direction conflicts with the product's purpose — a fast, trustworthy,
|
||
**clean review instrument** an operator stares at for hours.
|
||
|
||
Additional defects found during the baseline audit (2026-06-11):
|
||
|
||
- `tests/operator_gui/test_static_workbench.py::test_workbench_shell_exposes_all_internal_operator_views`
|
||
fails: the uncommitted change deleted the `product-purpose` top-bar block and its CSS.
|
||
- `index.html` gained a UTF-8 BOM (``).
|
||
- Typography relies on Malgun Gothic, which renders Korean UI text loosely and
|
||
inconsistently across weights.
|
||
- Minor horizontal overflow offenders: `strong` inside desktop queue rows,
|
||
`span.provider-chip` on mobile queue (inside the intentionally scrollable table shell).
|
||
|
||
Baseline artifacts: `data/logs/ui-font-baseline-*.png`, `data/logs/ui-font-baseline-results.json`.
|
||
|
||
## 2. Approaches Considered
|
||
|
||
1. **Token re-skin (chosen).** Keep the stylesheet's structure, selectors, and all
|
||
test-contract strings; replace the design tokens (`:root`), the body texture,
|
||
the font stack, and sweep hardcoded decorative colors. Lowest risk: every
|
||
class hook and fixed contract string (queue grid template, audit widths,
|
||
floating panel geometry, media queries) survives untouched.
|
||
2. Full stylesheet rewrite. Cleanest end state but high risk of dropping one of
|
||
the ~30 fixed contract strings the static tests pin; harder to review.
|
||
3. Revert to the committed styles and start over. Discards legitimate layout
|
||
work already in the working tree (queue grid, floating decision panel).
|
||
|
||
## 3. Design Decisions
|
||
|
||
### 3.1 Typography (폰트 변경)
|
||
|
||
- Bundle **Pretendard Variable** (`web/operator-gui/assets/fonts/PretendardVariable.woff2`,
|
||
v1.3.9, 2.06 MB) — downloaded at build time, served locally. **No CDN reference**
|
||
at runtime (air-gapped rule).
|
||
- `@font-face` with `font-display: swap`, weight range 45–920.
|
||
- Token changes:
|
||
- `--font-ui: "Pretendard Variable", Pretendard, "Malgun Gothic", "Apple SD Gothic Neo", "Segoe UI", system-ui, sans-serif`
|
||
- `--font-stamp` (labels, IDs, numeric stamps): same Pretendard stack —
|
||
differentiation now comes from weight (650–750), size, and `letter-spacing`,
|
||
not from a second display face. Bahnschrift is dropped.
|
||
- `--font-mono` unchanged (Cascadia Mono / Consolas) for hashes, IDs, code.
|
||
- `index.html` gets `<link rel="preload" as="font" type="font/woff2" crossorigin>`
|
||
for the woff2.
|
||
- Numeric UI (scores, quotas, timestamps) uses `font-variant-numeric: tabular-nums`.
|
||
|
||
### 3.2 Surface and color (깔끔하게 잘 떨어지는 톤)
|
||
|
||
- Remove the SVG noise texture and both radial gradient washes from `body` —
|
||
flat, calm surface.
|
||
- Palette shifts from warm paper to neutral cool:
|
||
- `--paper` `#f3f5f7` (workspace background), `--paper-2` `#e9edf0`
|
||
- `--card` `#ffffff`, `--card-raised` `#ffffff`, `--card-sunk` `#f6f8fa`
|
||
- Ink scale: `--ink #1a2128`, `--ink-soft #51606b`, `--ink-faint #8794a1`
|
||
- Hairlines: cool grays (`#dde3e8` / `#e7ecf0` / `#b9c4cd`)
|
||
- Single primary accent: deep teal-blue (`--teal #1f6f8b` family). The ochre
|
||
family stays defined (components reference it) but is re-tuned toward a
|
||
restrained amber used only for "hold/attention" semantics, not branding.
|
||
- Risk semantics keep their class names and stay high-contrast:
|
||
red=high, amber=medium, green=low/approve, plus failed/pending neutrals.
|
||
- Shadows get smaller and cooler; radii stay (6/9/14px). No `linear-gradient`
|
||
(test contract), and the remaining radial gradients are removed for flatness.
|
||
- The dark nav rail stays dark (orientation anchor) but moves to a neutral
|
||
slate so the single accent color reads clearly.
|
||
|
||
### 3.3 Contract restorations
|
||
|
||
- Re-add the `product-purpose` block to the top bar (`class="product-purpose"`,
|
||
`aria-label="제품 목적"`, copy: "이미지 저작권 위험 심사" /
|
||
"제출 이미지, 외부 검색 근거, 내부 기준 DB를 한 화면에서 검토합니다.") and its
|
||
`.product-purpose` CSS, styled to fit the clean top bar.
|
||
- Remove the BOM from `index.html`.
|
||
- The deleted global-search form and operator chip stay deleted (no test
|
||
references them; the queue has its own search field).
|
||
|
||
### 3.4 Explicitly preserved test-contract strings in `styles.css`
|
||
|
||
`grid-template-columns: 28px 64px minmax(104px, 0.68fr) 72px minmax(126px, 0.58fr) minmax(360px, 1.5fr) 82px 76px 90px`,
|
||
`--audit-object-width: 24%`, `.audit-table th:nth-child(4)/(5)` with
|
||
`width: var(--audit-object-width)`, `.floating-decision-panel` with
|
||
`position: fixed` / `bottom: 24px` / `padding-right: 334px` /
|
||
`padding-bottom: 260px`, `data-workbench-panel="evidence"` selector,
|
||
`@media (max-width: 980px)`, `@media (max-width: 680px)`, `:focus-visible`,
|
||
`.risk-high/.risk-medium/.risk-low/.risk-failed`,
|
||
`.source-naver/.source-google/.source-llm/.source-internal`,
|
||
`.queue-row td:nth-child(5)/(6)`, `white-space: nowrap`, `flex-wrap: nowrap`,
|
||
`.queue-provider-strip`, `.coverage-tabs`/`.coverage-tab`, no `linear-gradient`,
|
||
no `orb`, obsolete selectors (`.coverage-main`, `.coverage-badges`,
|
||
`.coverage-provider-grid`, `.coverage-mini-line`, `.queue-table th:nth-child`)
|
||
stay absent.
|
||
|
||
## 4. Verification Plan (사용자 반응성 검토)
|
||
|
||
1. `node --check` on touched JS (none expected) and full
|
||
`pytest tests/operator_gui` static contracts.
|
||
2. Live-server Playwright audit at 1440×900 and 390×844 across all 8 views:
|
||
zero horizontal document overflow (`docW <= vw`), regenerate
|
||
`data/logs/ui-overhaul-final-results.json` and the 8 contract screenshots.
|
||
3. Interaction smoke: existing `test_browser_smoke.py` (suggested-query fill,
|
||
real upload flow) must pass against the restyled DOM.
|
||
4. Visual review of screenshots: font rendering (Pretendard active), flat
|
||
surfaces, risk colors legible, floating decision panel unobstructed.
|
||
5. Offline check: grep the GUI for `http://`/`https://` font or CSS fetches —
|
||
none allowed.
|