Files
manage/openspec/changes/mobile-responsive-parity/verify-report.md
T
Developer 32516f6e3b Docs + verify report for mobile responsive parity (Slice 10)
Add Mobile Responsive Design section to docs/REQUIREMENTS.md documenting
the breakpoint policy (single md:768px), hybrid table strategy (cards below
md), SheetForm edit flows, 44px touch targets, dashboard single-column +
anchors, unchanged polling, and HoverEditButton behavior.

Add openspec verify-report.md with per-AC evidence (AC1-AC8), residual
risks (R4.5 dirty-state confirm, default-button touch targets, polling on
battery, iOS Safari manual verification, pagination duplication), and
non-goals confirmation.

All 9 routes fully operable at 375px. 116 frontend tests pass; lint/build
green. Desktop layout unchanged. No backend changes.

Refs openspec/changes/mobile-responsive-parity/ (tasks slice 10).
2026-06-26 14:40:04 +00:00

5.1 KiB
Raw Blame History

Verify Report — Mobile responsive parity

Change: mobile-responsive-parity Phase: verify Date: 2026-06-26

Summary

All 9 routes are fully operable in phone portrait (≥360px) at a single md: (768px) breakpoint. Desktop layout (≥768px) is unchanged. No backend changes. No new product features.

Acceptance criteria

AC1 — Every route fully operable at 375px

All 9 routes (Dashboard, Observability, Media, Files, Backups, Users, Actions, Services, Settings) render and operate at phone-portrait width:

  • Dashboard: single-column widget stack + section anchor bar (Slice 2).
  • Observability: existing responsive layout + touch-target audit (Slice 9).
  • Media: card layout with mobile pagination, card-tap navigation (Slice 3).
  • Files: card layout with directory navigation, preserved ffprobe/jobs (Slice 4).
  • Backups: card layouts for alerts/jobs/runs tables (Slice 5).
  • Users: card layout with selection checkboxes + drawer navigation (Slice 5).
  • Actions: existing responsive layout + touch-target audit (Slice 9).
  • Services: list renders stacked; service edit via SheetForm (Slices 6, 9).
  • Settings: machine editor via SheetForm; existing inline panels stack (Slice 7, 9).

AC2 — Four wide tables show cards at 375px and tables at 1280px

Media, FileBrowser, UsersPage, and the three Backups tables each render MobileCardRow cards below md and <DataTable> tables at/above md. Each card shows a primary title + 35 fields chosen per-table. Tested in Vitest with mocked matchMedia at both breakpoints.

AC3 — Four edit forms open in Sheet at 375px and Dialog at 1280px

ServicePage, Settings (machine editor), message compose, and WidgetConfigDialog each branch on useIsMobile() to render SheetForm (side=bottom, full-height) below md and the existing Dialog at/above md. Tested in Vitest.

AC4 — HoverEditButton always visible at 375px, hover-revealed at 1280px

HoverEditButton defaults to mobile="always" (always visible below md, hover-revealed at md:+). Tested in HoverEditButton.test.tsx with class- composition assertions.

AC5 — 44px minimum touch-target audit

40 interactive elements across 12 files now carry the mobile-touch-target class (applies min-height: 44px; min-width: 44px only below 768px). Covers icon buttons, checkboxes, switches, and small text buttons. Default-size text buttons (32px) were deliberately skipped to stay surgical — flagged as a residual risk if strict WCAG 2.5.5 on ALL elements is required.

AC6 — Dashboard single column + anchors at 375px, grid at 1280px

Tested in Dashboard.test.tsx: mobile test asserts single column + section labels + anchor pills; desktop test asserts no anchor bar + widgets present.

AC7 — lint/build/test green

cd frontend && npm run lint    → 0 errors (2 pre-existing warnings)
cd frontend && npm run build   → ✓ built (tsc -b + vite)
cd frontend && npm run test    → 28 files / 116 tests passed

AC8 — Vitest test per touched page at <768px and ≥768px

Each touched page has at least one mobile and one desktop test:

Page/Component Mobile tests Desktop tests
Dashboard 3 3 (existing)
Media 5 existing
FileBrowser 4 existing
UsersPage 2 existing
Backups (Alerts/Runs) 3 existing
BackupJobs 2 (new file)
ServicePage 3 2 (new file)
Settings 3 existing
WidgetConfigDialog 1 1 (new file)
MobileCardRow 7 — (primitive)
SheetForm 5 — (primitive)
HoverEditButton 2 2

Non-goals confirmed

  • No tablet/landscape/sm: intermediate layout.
  • No PWA, manifest, service worker.
  • No polling-interval changes.
  • No backend changes.
  • No new data-table library.

Residual risks / known gaps

  1. R4.5 dirty-state outside-click confirm not implemented in SheetForm. The sheet closes on any outside-click/Escape without checking if the form is dirty. Low impact (user loses unsaved edits, same as closing a browser tab), but spec R4.5 called for a confirm prompt. Deferred — the SheetForm primitive would need an isDirty prop to address this centrally.

  2. Default-size text buttons (32px) remain below 44px height. Icon buttons, checkboxes, switches, and size="sm" buttons were upgraded. If strict WCAG 2.5.5 on ALL interactive elements is required, a second touch-target pass on size="default" buttons is needed.

  3. Polling on battery (D8 risk): intervals unchanged. Dashboard polls every ~30s per widget + 5s queue-status. A document.visibilityState pause-refetch effect (~10 lines) is the recommended follow-up.

  4. iOS Safari manual verification not performed in CI. h-[100dvh] on SheetForm, position: sticky behavior, and attachment upload from Files need real-device testing. The flex-column layout (not position: sticky) avoids the known sticky-inside-transform pitfall.

  5. Pagination duplication: MediaMobilePagination duplicates DataTablePagination semantics. Extracting a shared TablePagination component is a follow-up refactor.