diff --git a/docs/superpowers/plans/2026-07-02-ux-audit.md b/docs/superpowers/plans/2026-07-02-ux-audit.md new file mode 100644 index 0000000..5bafec6 --- /dev/null +++ b/docs/superpowers/plans/2026-07-02-ux-audit.md @@ -0,0 +1,381 @@ +# SchoolCompare UX/UI Audit Execution Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Execute the journey-led UX/UI audit of live schoolcompare.co.uk defined in `docs/superpowers/specs/2026-07-02-ux-audit-design.md`, producing a prioritized (P0–P3) audit report at `docs/superpowers/specs/2026-07-02-ux-audit-report.md`. + +**Architecture:** Five journey walk-throughs (traffic-ordered) at two viewports using Playwright browser tools against the live site, each producing a committed notes file with friction points, "works well" observations, and axe-core scan results. A cross-cutting cohesion pass compares components across pages. A final synthesis task converts notes into the prioritized report. + +**Tech Stack:** Playwright MCP browser tools (`mcp__plugin_playwright_playwright__*`), axe-core 4.x injected from CDN, markdown notes committed to git. + +## Global Constraints + +- Audit the **live site** `https://schoolcompare.co.uk` — do not start any local server (CLAUDE.md). +- Viewports: **mobile 390×844 (primary)** and **desktop 1440×900**. Mobile findings weigh more (56% of traffic). +- A finding is valid only if it cites: a Nielsen/NN-g heuristic violation, a WCAG 2.2 AA failure, a mobile-usability standard, or an observed task-flow obstruction. No taste-only findings. +- Every finding: **evidence → argument (why it hurts parents) → recommendation → uplift indication** (which analytics number moves, direction, small/moderate/large band with reasoning — never invented percentages). +- Read-only with respect to the site: browse and inspect only; never submit forms that create/modify data (search and filter interactions are fine). +- Notes live in `docs/superpowers/specs/2026-07-02-ux-audit-notes/`; screenshots go to the session scratchpad (referenced by filename in notes, not committed). +- Analytics baseline for weighting (30 days): entries `/` 63%, `/compare` 20%, `/rankings` 6%; exits `/` 46%, `/compare` 32%, `/rankings` 13%; views `/` 52%, `/compare` 27%, `/rankings` 12%, `/admissions` 5%; school pages ~1% each (SEO long tail); 56% mobile. + +**Note on tool schemas:** Playwright tools are deferred. Before first use in any task, load them: +`ToolSearch` with query `select:mcp__plugin_playwright_playwright__browser_navigate,mcp__plugin_playwright_playwright__browser_resize,mcp__plugin_playwright_playwright__browser_snapshot,mcp__plugin_playwright_playwright__browser_take_screenshot,mcp__plugin_playwright_playwright__browser_evaluate,mcp__plugin_playwright_playwright__browser_click,mcp__plugin_playwright_playwright__browser_type,mcp__plugin_playwright_playwright__browser_press_key,mcp__plugin_playwright_playwright__browser_console_messages` + +--- + +### Task 1: Audit scaffolding + axe-core harness verified on the homepage + +**Files:** +- Create: `docs/superpowers/specs/2026-07-02-ux-audit-notes/axe-snippet.js` +- Create: `docs/superpowers/specs/2026-07-02-ux-audit-notes/TEMPLATE.md` + +**Interfaces:** +- Produces: `axe-snippet.js` — a self-contained async JS function body for `browser_evaluate` that loads axe-core from CDN (idempotent) and returns `{violationCount, violations: [{id, impact, description, nodes: count, sampleTargets}]}` filtered to WCAG 2.2 A/AA rules. All journey tasks run this verbatim on each page state. +- Produces: `TEMPLATE.md` — the notes-file structure every journey task copies. + +- [ ] **Step 1: Write the axe harness snippet** + +Create `docs/superpowers/specs/2026-07-02-ux-audit-notes/axe-snippet.js`: + +```js +// Body for playwright browser_evaluate: () => { ...this content... } +// Loads axe-core 4.x from CDN (skips if already present), runs WCAG A/AA scan. +return (async () => { + if (!window.axe) { + await new Promise((resolve, reject) => { + const s = document.createElement('script'); + s.src = 'https://cdn.jsdelivr.net/npm/axe-core@4.10.2/axe.min.js'; + s.onload = resolve; + s.onerror = () => reject(new Error('axe failed to load')); + document.head.appendChild(s); + }); + } + const results = await window.axe.run(document, { + runOnly: { type: 'tag', values: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22aa'] } + }); + return { + url: location.pathname, + violationCount: results.violations.length, + violations: results.violations.map(v => ({ + id: v.id, + impact: v.impact, + description: v.help, + nodes: v.nodes.length, + sampleTargets: v.nodes.slice(0, 3).map(n => n.target.join(' ')) + })) + }; +})(); +``` + +- [ ] **Step 2: Write the notes template** + +Create `docs/superpowers/specs/2026-07-02-ux-audit-notes/TEMPLATE.md`: + +```markdown +# Journey N: — audit notes + +**Pages visited:** +**Viewports:** 390×844, 1440×900 + +## Task attempt log + + +## Friction points +For each: +- **F. ** + - Evidence: + - Criterion violated: + - Argument: + - Severity guess: + +## Works well — keep +- + +## Axe results +- @ : violations — + +## Manual WCAG spot checks +- Touch targets ≥24px on interactive elements: +- Keyboard: tab order, focus visibility (desktop only): +- Zoom 200% text reflow (desktop only): + +## Screenshots +- : +``` + +- [ ] **Step 3: Verify the harness against the live homepage** + +Load Playwright tool schemas (see Global Constraints note). Then: +1. `browser_resize` to 390×844. +2. `browser_navigate` to `https://schoolcompare.co.uk/`. +3. `browser_evaluate` with the contents of `axe-snippet.js` as the function body. + +Expected: a JSON result with `violationCount` (any number ≥ 0) and no thrown error. If the CDN is blocked, switch the `src` to `https://unpkg.com/axe-core@4.10.2/axe.min.js` in the file and re-verify. + +- [ ] **Step 4: Take a baseline screenshot to confirm capture works** + +`browser_take_screenshot` with filename `home-mobile-baseline.png`. Expected: file saved, path returned. + +- [ ] **Step 5: Commit** + +```bash +git add docs/superpowers/specs/2026-07-02-ux-audit-notes/ +git commit -m "chore(audit): axe harness and notes template for UX audit" +``` + +--- + +### Task 2: Journey 1 — Home → find my school (63% of entries, 46% exits) + +**Files:** +- Create: `docs/superpowers/specs/2026-07-02-ux-audit-notes/journey-1-home-find-school.md` (copy structure from `TEMPLATE.md`) + +**Interfaces:** +- Consumes: `axe-snippet.js` via `browser_evaluate`; `TEMPLATE.md` structure. +- Produces: `journey-1-home-find-school.md` — notes consumed by Task 8 synthesis. + +- [ ] **Step 1: Mobile walk-through (390×844)** + +1. `browser_resize` 390×844, `browser_navigate` `https://schoolcompare.co.uk/`. +2. `browser_snapshot` — record what is above the fold: is the search input visible without scrolling? What competes for attention? Screenshot `j1-home-mobile-fold.png`. +3. Scroll the full page (`browser_press_key` End or evaluate `window.scrollTo`), screenshot `j1-home-mobile-full.png`. Note content order: does featured/secondary content precede the primary task? +4. **Task attempt A (school by name):** type a real school name into search, e.g. `Welland Primary` (known from analytics). Record: keystrokes-to-results, result quality (is the right school first?), loading feedback, and taps needed to reach `/school/146678-welland-primary-school`. Screenshot the results state `j1-search-results-mobile.png`. +5. **Task attempt B (postcode):** return home, search a plausible postcode (e.g. `B91 3` area for Solihull, or any valid UK postcode like `SW1A 1AA`). Record: is postcode search discoverable/labelled? Distance shown? Sensible ordering? Screenshot `j1-postcode-results-mobile.png`. +6. Record time-to-school-page for both attempts against the spec's ~15s target. +7. Run axe snippet on: home (initial) and home (results visible). Record results. + +- [ ] **Step 2: Desktop walk-through (1440×900)** + +Repeat Step 1's navigation and task attempt A at 1440×900 (screenshots `j1-home-desktop-fold.png`, `j1-search-results-desktop.png`). Additionally: tab through the page with keyboard — record focus visibility and whether search → results → school link is keyboard-operable. Test 200% zoom (`browser_evaluate` `document.body.style.zoom` is NOT valid for this — instead resize to 720×450 which approximates 200% reflow at 1440) and note any loss of content/overlap. + +- [ ] **Step 3: Write notes file** + +Fill `journey-1-home-find-school.md` per template. Every friction point needs evidence + criterion + argument. Explicitly answer: "why do 46% of visitors exit at home?" — list the plausible causes observed. + +- [ ] **Step 4: Commit** + +```bash +git add docs/superpowers/specs/2026-07-02-ux-audit-notes/journey-1-home-find-school.md +git commit -m "docs(audit): journey 1 notes — home to school search" +``` + +--- + +### Task 3: Journey 2 — Cold landing on a school detail page (SEO long tail) + +**Files:** +- Create: `docs/superpowers/specs/2026-07-02-ux-audit-notes/journey-2-school-detail-cold.md` + +**Interfaces:** +- Consumes: `axe-snippet.js`, `TEMPLATE.md`. +- Produces: `journey-2-school-detail-cold.md` for Task 8. + +- [ ] **Step 1: Mobile cold landing (390×844)** + +Navigate **directly** (no prior site context — this simulates a Google arrival) to `https://schoolcompare.co.uk/school/136916-the-castle-school`. Then assess in order: +1. First-screen orientation: within one screen, can a parent tell what site this is, what school this is, and what the site offers? Screenshot `j2-school-mobile-fold.png`. +2. Scroll the entire page. Screenshots at each major section (`j2-school-mobile-
.png`). For each data block (results, Ofsted, characteristics, admissions): is it comprehensible to a non-specialist? Is jargon (RWM, expected standard, progress scores) explained in place? +3. Next-step paths: is there an obvious "compare this school" and "schools near this one" action? How many taps to a comparison including this school? Record the exact path or its absence. +4. Repeat the cold landing for a contrasting school `https://schoolcompare.co.uk/school/146678-welland-primary-school` (different data availability) — note any layout breakage or missing-data handling. Screenshot anomalies only. +5. Run axe snippet on both school pages. Record results. + +- [ ] **Step 2: Desktop pass (1440×900)** + +Reload `.../136916-the-castle-school` at desktop. Screenshot `j2-school-desktop-fold.png`. Check: hero/map rendering, chart legibility, keyboard focus through interactive elements, link affordance (do school-page links look clickable?). + +- [ ] **Step 3: Write notes file** + +Fill `journey-2-school-detail-cold.md`. Explicitly answer: "a parent lands here from Google — what would make them stay and use the site rather than bounce back to search results?" + +- [ ] **Step 4: Commit** + +```bash +git add docs/superpowers/specs/2026-07-02-ux-audit-notes/journey-2-school-detail-cold.md +git commit -m "docs(audit): journey 2 notes — cold landing on school detail" +``` + +--- + +### Task 4: Journey 3 — Building a comparison (27% of views, 32% exits) + +**Files:** +- Create: `docs/superpowers/specs/2026-07-02-ux-audit-notes/journey-3-compare.md` + +**Interfaces:** +- Consumes: `axe-snippet.js`, `TEMPLATE.md`. +- Produces: `journey-3-compare.md` for Task 8. + +- [ ] **Step 1: Mobile walk-through (390×844)** + +1. Navigate to `https://schoolcompare.co.uk/compare` **directly** (20% of sessions enter here). Screenshot empty state `j3-compare-empty-mobile.png`. Is the empty state instructive — does it tell a parent what to do first? +2. Add two schools via whatever mechanism the page offers (search within compare, or navigate to school pages and use their compare action — record which paths exist). Count taps from empty state to a two-school comparison. Screenshot `j3-compare-two-schools-mobile.png`. +3. Assess the comparison output on mobile: are charts/tables legible at 390px? Horizontal scrolling? Can you tell which school is which (colour + label, not colour alone — WCAG 1.4.1)? Are metric names explained? +4. Remove a school; add a third. Any state loss, confusing controls, or dead ends? Does the selection persist if you navigate away and back? +5. Run axe snippet on empty state and populated state. Record results. + +- [ ] **Step 2: Desktop pass (1440×900)** + +Repeat comparison-building at desktop. Screenshot `j3-compare-two-schools-desktop.png`. Keyboard-operate the add/remove flow; record focus behaviour. Check chart tooltips/legends for mouse-only interactions. + +- [ ] **Step 3: Write notes file** + +Fill `journey-3-compare.md`. Explicitly answer: "compare is 32% of exits — is that task-complete satisfaction (fine) or abandonment (problem)? What observed evidence points either way?" + +- [ ] **Step 4: Commit** + +```bash +git add docs/superpowers/specs/2026-07-02-ux-audit-notes/journey-3-compare.md +git commit -m "docs(audit): journey 3 notes — building a comparison" +``` + +--- + +### Task 5: Journey 4 — Rankings → shortlist (12% of views) + +**Files:** +- Create: `docs/superpowers/specs/2026-07-02-ux-audit-notes/journey-4-rankings.md` + +**Interfaces:** +- Consumes: `axe-snippet.js`, `TEMPLATE.md`. +- Produces: `journey-4-rankings.md` for Task 8. + +- [ ] **Step 1: Mobile walk-through (390×844)** + +1. Navigate to `https://schoolcompare.co.uk/rankings`. Screenshot default state `j4-rankings-mobile.png`. +2. Is the default ranking explained (which metric, which year, what the numbers mean)? Would a parent understand what "top" means here? +3. Filter to a local authority (e.g. Solihull). Count taps; is the filter discoverable on mobile? Screenshot filtered state `j4-rankings-filtered-mobile.png`. +4. Change the ranking metric. Is the metric picker comprehensible (plain-language labels vs. jargon)? +5. Tap through to a school from the list; navigate back — is filter state preserved? (Back-navigation state loss is a classic mobile task-killer.) +6. Run axe snippet on default and filtered states. Record results. + +- [ ] **Step 2: Desktop pass (1440×900)** + +Repeat at desktop, screenshot `j4-rankings-desktop.png`. Check table semantics (real `` with headers vs. divs — screen-reader implications), sortability affordances, keyboard operation of filters. + +- [ ] **Step 3: Write notes file + commit** + +Fill `journey-4-rankings.md`. + +```bash +git add docs/superpowers/specs/2026-07-02-ux-audit-notes/journey-4-rankings.md +git commit -m "docs(audit): journey 4 notes — rankings" +``` + +--- + +### Task 6: Journey 5 — Admissions content (5% of views, light pass) + +**Files:** +- Create: `docs/superpowers/specs/2026-07-02-ux-audit-notes/journey-5-admissions.md` + +**Interfaces:** +- Consumes: `axe-snippet.js`, `TEMPLATE.md`. +- Produces: `journey-5-admissions.md` for Task 8. + +- [ ] **Step 1: Single mobile pass (390×844)** + +1. Navigate to `https://schoolcompare.co.uk/admissions`. Screenshot `j5-admissions-mobile.png`. +2. Light checks only: readability (line length, heading hierarchy), whether the recently added SchoolCompare tool cross-links are present and useful, whether the page's look matches the rest of the site (this feeds the cohesion pass), and one axe scan. +3. Check discoverability in reverse: from the home page, how does a parent find this content at all? (5% views may be a discoverability problem rather than a demand problem — note evidence either way.) + +- [ ] **Step 2: Write notes file + commit** + +Fill `journey-5-admissions.md` (shorter than the others is expected). + +```bash +git add docs/superpowers/specs/2026-07-02-ux-audit-notes/journey-5-admissions.md +git commit -m "docs(audit): journey 5 notes — admissions" +``` + +--- + +### Task 7: Cross-cutting cohesion pass + +**Files:** +- Create: `docs/superpowers/specs/2026-07-02-ux-audit-notes/cohesion-pass.md` + +**Interfaces:** +- Consumes: all journey screenshots (scratchpad) and notes files; live site; optionally `nextjs-app` source for token verification. +- Produces: `cohesion-pass.md` for Task 8. + +- [ ] **Step 1: Component comparison across pages** + +Using the screenshots already captured plus targeted re-visits, compare across `/`, `/compare`, `/rankings`, `/admissions`, and a school page: +1. **Typography:** collect computed styles via `browser_evaluate` on each page — e.g. `[...document.querySelectorAll('h1,h2,h3,body p, button, a')].slice(0,40).map(e => ({tag: e.tagName, size: getComputedStyle(e).fontSize, weight: getComputedStyle(e).fontWeight, family: getComputedStyle(e).fontFamily.split(',')[0]}))` — and diff the scales page-to-page. Record any page using off-scale sizes. +2. **Colour:** same technique for `color`, `backgroundColor` on buttons/links/chips; flag near-duplicate colours (e.g. two blues doing the same job) and any accent colour used inconsistently. +3. **Components:** buttons, chips, cards, empty states, loading states — screenshot side-by-side candidates and note variant drift (different radii, padding, casing, icon usage for the same semantic role). +4. **Navigation & page furniture:** header/footer consistency, page-title patterns, back-link behaviour, breadcrumbs presence/absence across page types. +5. **Recent additions check (from spec):** map-blended hero, characteristic chips, admissions cross-links — do they feel native to the rest of the site? + +- [ ] **Step 2: Verify against source where ambiguous** + +Where a visual inconsistency could be intentional, check `nextjs-app` styles (grep for the relevant component/tokens) to determine whether a design token exists and is being bypassed, or no token exists. Record which — it changes the recommendation (enforce token vs. create token). + +- [ ] **Step 3: Write notes file + commit** + +Fill `cohesion-pass.md` with the same evidence → criterion → argument structure (criterion here is typically "consistency and standards" heuristic). + +```bash +git add docs/superpowers/specs/2026-07-02-ux-audit-notes/cohesion-pass.md +git commit -m "docs(audit): cross-cutting cohesion pass notes" +``` + +--- + +### Task 8: Synthesis — prioritized audit report + +**Files:** +- Create: `docs/superpowers/specs/2026-07-02-ux-audit-report.md` +- Read: all files in `docs/superpowers/specs/2026-07-02-ux-audit-notes/`, spec `docs/superpowers/specs/2026-07-02-ux-audit-design.md` + +**Interfaces:** +- Consumes: journey notes 1–5, cohesion notes. +- Produces: the final deliverable report. + +- [ ] **Step 1: Consolidate and deduplicate findings** + +Read all six notes files. Merge duplicate findings (same root cause observed in several journeys becomes one finding listing all occurrences). Discard any finding lacking evidence or a cited criterion — the spec forbids taste-only findings. + +- [ ] **Step 2: Assign final priorities and uplift indications** + +For each finding assign P0–P3 per the spec's definitions (traffic-weighted impact × severity), and an uplift line: **metric** (one of: home 46% exit rate; share of sessions reaching a school page; compare 32% exit rate; rankings→school click-through; school-page bounce-back-to-Google; accessibility compliance), **direction**, **band** (small/moderate/large) **with one-sentence reasoning**. Sanity rules: a P0/P1 must sit on `/`, `/compare`, `/rankings`, or the school-page template; admissions-only findings cap at P2 unless a WCAG failure. + +- [ ] **Step 3: Write the report** + +Structure (from spec): + +```markdown +# SchoolCompare UX/UI Audit — 2026-07-02 + +## Method summary + + +## What works today — keep + + +## Findings + +### P0 — Urgent + + +### P1 — High +### P2 — Medium +### P3 — Nice-to-have + +## Accessibility summary + + +## Suggested implementation sequence + +``` + +- [ ] **Step 4: Self-check the report against the spec** + +Verify: every finding has all four elements (evidence/argument/recommendation/uplift); "works well" section is non-empty; uplift bands never state invented percentages; P0/P1 findings all sit on high-traffic paths; report answers the spec's three goals (a) speed-to-information, (b) end-to-end cohesion, (c) standards compliance. Fix inline. + +- [ ] **Step 5: Commit** + +```bash +git add docs/superpowers/specs/2026-07-02-ux-audit-report.md +git commit -m "docs(audit): prioritized UX/UI audit report" +```