POSA_Copyrighter/docs/superpowers/specs/2026-06-11-operator-console-clean-review-ui-design.md
유창욱 ed701bd436 feat: clean review-instrument restyle with bundled Pretendard font
- 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)
2026-06-11 10:31:16 +09:00

6.2 KiB
Raw Blame History

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 45920.
  • 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 (650750), 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.