deckhearth/.convoys/scanner-mobile-checkout/audits/design-system-20260814.md
varutasu 73424aae59
Mobile scanner checkout: scan first, commit later (#157)
* Start scanner-mobile-checkout convoy for the cart-then-commit phone flow.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Ship a cart-then-commit mobile scanner so phone sessions stay on the camera.

Scan matches enqueue locally instead of auto-writing ownership, checkout happens in a sheet, and audit fixes cover stale commit detection, returnUrl open redirects, nested Escape, and ember detection chrome.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-14 20:20:43 -05:00

153 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Design-System Audit — scanner-mobile-checkout
**Role:** `role-design-system-auditor`
**Surface:** uncommitted `feat/scanner-mobile-checkout` UI (`git diff origin/main` + untracked scanner UI)
**Convoy:** `.convoys/scanner-mobile-checkout.md`
**Date:** 2026-08-14
**Scope:** UI / DS only — read-only; no code changes
**Inputs reviewed**
| Source | Notes |
| --- | --- |
| Diff UI | `Layout.js`, `ScannerCamera.js`, `ScannerCountPill.js`, `ScannerToast.js`, `ReviewCardItem.js`, `ScannerReview.js`, `pages/scanner.js` |
| Untracked | `ScannerCheckoutSheet.js`, `ScannerScanPeek.js` |
| Direction lock | `design_direction` v1 + `## Design direction` in convoy |
| Tokens | `docs/DESIGN_TOKENS.md`, `styles/globals.css` |
| Primitives | `components/ui/{GlassSurface,Button,Modal,Input}.js` |
| Skill | `.cursor/skills/design-systems/SKILL.md` **not installed** in this repo; audit follows role file + prior Liquid Glass audit shape + `docs/DESIGN_TOKENS.md` |
---
## Audit summary
| Check | Status | Notes |
| --- | --- | --- |
| Direction lock (Liquid Glass + immersive camera + sheet) | ⚠️ Partial | Chrome bars + VOCAB CTAs + Modal reuse land; **L-brackets / scan-line missing**; sheet tint recipe drifts |
| Hex in JSX | ❌ | 1 literal `#ffffff` in `ReviewCardItem.js` |
| Binder / stale vocab | ✅ | No `binder` / `Mark Owned` / `Save to binder` in scoped UI |
| `backdrop-filter` on cart **thumbnails** | ✅ | Thumbs are solid image/`--bg-tertiary`; no filter on `<img>` |
| GlassSurface / Button / Modal reuse | ⚠️ Mixed | Camera chrome + peek: GlassSurface; checkout sheet/toast/rows: `glass-panel*` / hand-rolled |
| Sev ≥ 3 findings | **2** | Hex literal; missing bracket + scan-line direction lock |
---
## Maturity scoring (repo DS + this surface)
Scores 04. Evidence cites paths/counts.
| Axis | Score | Evidence |
| --- | --- | --- |
| **Tokens (T)** | **3** | Documented 3-tier glass surface / blur / rim / elevation / scrim in `docs/DESIGN_TOKENS.md` + `styles/globals.css`. Diff mostly consumes `var(--*)`. Residual: `.glass-panel` still hardcodes `blur(12px) saturate(180%)` (not `--glass-blur-*` / `--glass-saturate`); toast uses literal `blur(12px)`. |
| **Components (C)** | **3** | Kit under `components/ui/`: GlassSurface, Modal, Button, Input, SearchBar, StatCard (+ chrome). Scanner adopts GlassSurface on camera bars/icons/peek (9 call sites in `ScannerCamera.js`); Modal×2 + Button in `pages/scanner.js` / checkout footer. Gaps: toast + sheet panel + cart rows skip GlassSurface. |
| **Patterns (P)** | **2** | Locked pattern “immersive camera + bottom-sheet checkout” partially shipped (immersive Layout, sheet shell mirroring Disambiguation, peek non-interactive). **Detection chrome still filled rectangles** (info/success), not ember L-brackets + scan-line. Confidence mid-band maps to gold, not directions amber/ember table. |
| **Governance (G)** | **3** | Convoy `design_direction` locked 2026-08-14; `ui-and-theming.mdc` + vocab CI; `forbidden-hex-in-jsx` / forbidden stale strings. No design-systems skill package in-repo (template path missing). |
| **Adoption (A)** | **2** | This surface: GlassSurface on live chrome/peek ✅; checkout sheet + toast + rows use utility classes / ad-hoc styles ❌; Review N pill is raw `<button>` with gradient (OK shape) but skips ember-rim + dead GlassSurface import. Vocab CTAs ✅. |
**Composite:** T3 / C3 / P2 / G3 / A2
**Top leverage:** **Patterns (P)** — implement Screen 1 bracket + scan-line recipe and align checkout sheet to `GlassSurface tint="low"` + toast to GlassSurface/`--glass-surface-high` so the locked Liquid Glass pattern reads as one system, not chrome-good / body-utility.
---
## Direction lock
Locked fields enforced: Liquid Glass; immersive overlay + bottom sheet; ember/flame accents as rim/glow/gradient only; VOCAB CTAs; no binder; no hex; no per-card Add on peek; no `backdrop-filter` on cart thumbs; reuse GlassSurface / Modal / Button.
| Locked requirement | Diff status |
| --- | --- |
| Immersive `chrome="immersive"` mobile | ✅ `Layout.js` + `pages/scanner.js` |
| Top/bottom glass bars (`--glass-surface-mid`) | ✅ `GlassSurface tint="mid"` in `ScannerCamera.js` |
| L-brackets `--accent-flame` / `--accent-ember` + scan-line | ❌ Filled `border` boxes + `--color-info` / `--color-success` overlays; **no** scan-line / `prefers-reduced-motion` gate |
| Scan peek glass, tap-to-cart only | ✅ `ScannerScanPeek.js` |
| Toast glass-high + SVG check | ⚠️ SVG ✅; surface is `rgba(--bg-secondary-rgb)` + literal blur, not GlassSurface / `--glass-surface-high` |
| Review N gradient + `--ember-rim-pronounced` | ⚠️ Gradient ✅; **no** ember rim; unused `GlassSurface` import |
| Sheet scrim `--modal-scrim` + blur-high | ✅ `ScannerCheckoutSheet.js` styled-jsx |
| Sheet panel `--glass-surface-low` via GlassSurface | ❌ `glass-panel-strong` → surface-**high** recipe |
| Footer VOCAB + Button primary/ghost | ⚠️ VOCAB ✅; secondary uses `variant="secondary"` not `ghost` |
| Confidence rings tokenized (green / amber / orange) | ⚠️ Tokens used; mid=`--accent-gold`, low=`--color-warning` vs locks ember/amber table |
| No hex / no binder | ❌ one `#ffffff`; binder clear |
| Modal for leave + list picker | ✅ |
| No backdrop on thumbnails | ✅ |
---
## Token audit (3-tier)
| Tier | Expectation | Diff notes |
| --- | --- | --- |
| Primitives | Palette / RGB triples in CSS only | No new hex in CSS from this diff. JSX `#ffffff` violates consumer rule. |
| Aliases | `--glass-surface-*`, `--glass-blur-*`, rims, scrim | Camera/scrim/peek mostly correct. Toast blur literal `12px` should be `var(--glass-blur-low)`. `.glass-panel` utility (row list) still non-token blur/saturate (pre-existing; amplified by N cart rows). |
| Components | GlassSurface / Button / Modal compose aliases | Sheet + toast + rows compose utilities/hand styles instead of primitives. |
---
## Component / adoption audit (scoped surface)
| Element | Expected | Actual | Rate |
| --- | --- | --- | --- |
| Glass chrome bars | `<GlassSurface>` | Yes (`ScannerCamera`) | High |
| Scan peek | `<GlassSurface>` | Yes | High |
| Toast | `<GlassSurface tint="high">` or equivalent | Hand-rolled | Low |
| Checkout sheet panel | `<GlassSurface tint="low">` | `glass-panel-strong` | Low |
| Cart rows | GlassSurface high **or** solid `--bg-secondary` | `.glass-panel` (blur per row) | Medium — OK container glass; GPU stack risk |
| Footer CTAs | `<Button>` | Yes | High |
| Leave / List dialogs | `<Modal>` | Yes | High |
| Review N | Button or GlassSurface + ember rim | Raw `<button>` + gradient | Medium |
**Missing primitive usage (not missing primitives):** toast + sheet should compose existing GlassSurface rather than inventing parallel glass.
---
## Findings
Severity 04. Cap prioritized; sev ≥ 3 blocks merge recommendation for DS gate.
| ID | Sev | Finding | Evidence | Fix |
| --- | --- | --- | --- | --- |
| DS-1 | **3** | Hardcoded hex in JSX | `ReviewCardItem.js` qty `+` button `color: '#ffffff'` | Use theme-safe token (e.g. dark-theme `--text-primary` on ember fill, or shared on-accent pattern used by `<Button variant="primary">`) |
| DS-2 | **3** | Direction lock: detection chrome ≠ L-brackets + scan-line | `ScannerCamera.js` filled rect overlays via `overlayBorderColor` (`--color-info` / `--color-success`); no bracket SVG/corners; no ember scan-line / reduced-motion | Ship Screen 1 bracket recipe (`--accent-ember` / `--accent-flame`) + gradient scan-line; disable loop under `prefers-reduced-motion` |
| DS-3 | **2** | Toast bypasses glass recipe | `ScannerToast.js`: `rgba(var(--bg-secondary-rgb), 0.9)` + `backdropFilter: 'blur(12px)'` | Wrap with `<GlassSurface tint="high" blur="low|mid" rim="subtle">`; drop literal blur px |
| DS-4 | **2** | Checkout sheet panel wrong surface tier + no GlassSurface | `ScannerCheckoutSheet.js` `glass-panel-strong` (high) for panel + sticky footer | Panel: GlassSurface `tint="low"` inside scrim; footer sticky on same recipe or solid inner; match Modal panel docs |
| DS-5 | **2** | Review N missing ember-pronounced rim; dead import | `ScannerCountPill.js` imports GlassSurface unused; no `--ember-rim-pronounced`; `text-white` utility | Apply rim via GlassSurface `as="button"` `rim="ember-pronounced"` or box-shadow token; remove dead import; avoid raw white |
| DS-6 | **2** | Confidence band colors drift from lock | `confidenceRingColor`: &lt;70 `--color-warning`, 7084 `--accent-gold`, else success | Align to lock: &lt;70 `--accent-ember`, 7084 amber/warning token, ≥85 `--color-success` |
| DS-7 | **1** | Secondary CTA variant | Checkout footer `Button variant="secondary"` | Prefer `variant="ghost"` per design direction |
| DS-8 | **1** | Leave-modal dismiss copy | `pages/scanner.js` label `"Stay"` | Direction: primary dismiss **"Keep scanning"** |
| DS-9 | **1** | Hardcoded vocab fallback | `ReviewCardItem.js` `'My Collection'` string | `VOCAB.MY_COLLECTION` |
| DS-10 | **1** | Stacked row `backdrop-filter` via `.glass-panel` | Each cart row blurs (`blur(12px)` in utility) | Prefer solid `--bg-secondary` (or GlassSurface without stacking N blurs) for row inners over thumbs — thumbs themselves are clean |
### Passes (not findings)
- No `"binder"` / `"Save to binder"` / `"Mark Owned"` in scoped UI.
- Checkout CTAs import `VOCAB.ADD_TO_MY_COLLECTION` / `VOCAB.ADD_TO_LIST`.
- List picker uses `collectionDisplayName`.
- Peek has no Add / condition / foil; single open-cart control.
- Toast icons are SVG (no emoji glyphs).
- Scrim uses `--modal-scrim` + `var(--glass-blur-high)`.
- Cart thumbnails: no `backdrop-filter`.
- Leave + List picker use `<Modal>`; commit CTAs use `<Button>`.
---
## Governance notes
- Contribution path for glass: `docs/DESIGN_TOKENS.md` + `ui-and-theming.mdc` (“reach for `components/ui/` first”).
- CI: hex-in-JSX + stale vocab gates apply — **DS-1 will fail / should fail `forbidden-hex-in-jsx`**.
- Design-systems skill/templates not present under `.cursor/skills/design-systems/` — maturity G capped partly by missing shared audit tooling in-repo.
---
## Recommendation
**Do not treat DS as merge-clean until DS-1 and DS-2 are fixed.** DS-3DS-6 are the follow-up pass that makes checkout/toast/pill match the same Liquid Glass composition as the camera chrome.
**Child tasks (sev ≥ 3):**
1. Replace `#ffffff` in `ReviewCardItem.js` (and any sibling `text-white` on detection badges if hex-gate/token policy treats them as on-accent debt).
2. Implement ember/flame L-brackets + reduced-motion-aware scan-line on the viewfinder per locked Screen 1.
---
## Hand-off
DS audit complete. Maturity: **T3/C3/P2/G3/A2**. Top leverage: invest in **Patterns** (brackets/scan-line + sheet/toast GlassSurface alignment). Sev ≥ 3 findings: **2**. Report: `.convoys/scanner-mobile-checkout/audits/design-system-20260814.md`.