Step 1-2 (audit + plan): classified 35 project markdown files into Core/Architecture/ADR/Temporary-audit/Sprint-report/Generated-review/ Duplicate/Obsolete/Historical. Agent-tooling files (.agents/skills/**, .superpowers/**, docs/context/**, CLAUDE.md/GEMINI.md/AGENTS.md/ .github/copilot-instructions.md) explicitly out of scope — intentional per-tool duplication, not documentation debt. Step 3 (merge, no information lost): - docs/PROJECT.md -> docs/PROJECT_INDEX.md, rewritten as the single entry point: system overview, living-doc index, archive pointer, current status, and a critical-finding callout up top. - docs/backend/BACKEND-INTEGRATION.md -> docs/BACKEND_API.md, docs/backend/REMAINING-BACKEND-WORK.md -> docs/BACKEND_API_REMAINING_WORK.md (also folded in a legitimate uncommitted status update that had been sitting unstaged all session: categories marked DONE, order-creation endpoint noted done). - RELEASE-NOTES.md merged into CHANGELOG.md (was a near-duplicate of the same release content in friendlier prose), then deleted. - KNOWN-ISSUES.md: added item 13 (see below) and item 14 (missing canDeactivate on admin/products edit, from the archived PROJECT-STATE audit, re-verified still true); added a correction note to Fixed item 7. - All cross-references to renamed/moved files fixed across every kept doc (grep+sed pass, then verified with a link-existence check across all 58 in-scope markdown files -> 0 broken links). Step 4 (archive, nothing deleted without merging first): created docs/archive/, moved 19 files there (3 root sprint reports, 1 platform report, SPRINT-PLAN.md, and 14 one-off audit/review/report docs). Added correction headers to the 3 archived docs whose conclusions were affected by the finding below, rather than silently leaving them misleading. Step 5: docs/PROJECT_INDEX.md rewritten per the mission brief - someone opening the repo should understand the whole system from it. IMPORTANT FINDING (surfaced during this audit, not the mission's primary goal but too significant to bury): pages/category/*, pages/search/*, pages/item-detail/*, pages/info/**, pages/legal/** (40+ files) are entirely unrouted dead code - app.routes.ts's cmsContentRoutes is a literal empty array, and category/search/product routes redirect to CatalogContainerComponent/ ProductDetailsContainerComponent, not these files. Confirmed against app.routes.ts directly and cross-checked against FRONTEND.md's own routing description. This means several fixes from earlier this cycle (RC-Premium-01, RC STORE-01) and the dead-code cleanup sprint's conclusion that these files were live were all wrong - documented as KNOWN-ISSUES.md item 13, flagged at the top of PROJECT_INDEX.md, and noted on the 3 archived docs whose conclusions it affects. No application code was changed to fix this (out of scope per this session's 'documentation only' constraint) - it needs a wire-it-up-or- delete-it decision first. Verification: tsc --noEmit clean, npm run build green, all markdown links across 58 in-scope files resolve (checked programmatically). No application/Angular/backend code modified. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
6.7 KiB
Accessibility Report — RC A11Y-01
WCAG 2.1 AA audit + fixes across the whole application: Storefront, Builder (Project Editor), Backoffice (Admin). No redesign, no layout changes, no route/business-logic changes. Three sequential commits on branch B2B (not pushed):
| Commit | Scope |
|---|---|
fb1afb7 |
Storefront |
a03260e |
Builder |
565fd9b |
Backoffice |
npm run build verified green after every commit. npx tsc --noEmit clean throughout.
This audit goes deeper than the prior composition pass (docs/UI-COMPOSITION-REVIEW.md — skeletons/empty-states/scope="col") into categories that pass didn't cover: skip links, keyboard-operable drag-and-drop, dialog focus management, color contrast ratios, form label association, live-region announcements, and combobox/tablist ARIA patterns.
Fixes by area
Storefront (fb1afb7)
- Skip link — didn't exist anywhere in the app. Added as the first focusable element (
app.html), targeting a new#main-contentlandmark. Single most commonly-missing WCAG 2.4.1 fix, present nowhere before this. - Keyboard/focus traps — header mobile menu kept its items tabbable/screen-reader-reachable while visually collapsed; fixed via
visibility+ delayed transition. Header's search input had no keyboard activation path. - Dialog accessibility — cart's custom payment/bank-payment modals had no focus-trap, Escape handling, or return-focus, despite prior docs assuming
app-dialogcoverage — they're custom, notapp-dialog. Ported the confirmed-correctapp-dialogpattern directly onto them. - Screen-reader announcements — payment status screens (creating/waiting/success/error/timeout) got
role="status"/role="alert"+aria-live. - Search combobox — added
role="combobox"/aria-autocomplete/aria-controls/aria-activedescendantso the existing arrow-key navigation is actually announced to screen readers (previously silent). - Tabs — product tabs had
role="tab"with notablist/tabpanelwrapper; completed the pattern. - Forms — review-form errors now
aria-describedby+role="alert";aria-requiredon review textarea and delivery select. - Icons —
app-icon(shared, app-wide) claimed "decorative by default" in its own contract but never actually appliedaria-hidden— fixed for real, affects every icon usage across the app. - Contrast —
--text-lightmeasured 3.39:1 (dexar theme) / 2.54:1 (lavero/novo) against the 4.5:1 requirement. Switched the 2 in-scope usages to--text-secondary(7.56:1 / 4.55:1).
Builder (a03260e)
- Skip link — Builder routes render outside the storefront app-shell entirely (bare
<router-outlet>), so the storefront fix didn't cover it. Added separately with its own#builder-main-contentlandmark. - Keyboard-operable drag-and-drop (WCAG 2.1.1) — Homepage section's block list and Footer section's columns/links use Angular CDK drag-drop with zero keyboard equivalent. Added move-up/move-down button fallbacks (Navigation and Widgets sections already had this from an earlier sprint).
- Undefined
--color-primarytoken — same bug class as the prior composition pass, missed there: 7 usages across 3 files silently fell back to hardcoded hex, never responding to tenant theming. Remapped to the real--primary-colortoken. - Forms — color-picker's
<input type="color">swatches (8 instances) had no accessible name; new-locale input relied on placeholder text alone (invisible to screen readers once a value is typed). - Screen-reader announcements — save-bar status/draft-restored notice and media-picker upload errors had no
aria-live/role.
Backoffice (565fd9b)
- Sidebar nav mislabeled —
<nav aria-label>reused the "Dashboard" translation key, so the entire admin sidebar announced itself as "Dashboard" to screen readers regardless of which section a user was in. New dedicated label. - Categories tree drag-and-drop (WCAG 2.1.1) — native HTML5 DnD reorder had no keyboard path; arrow keys only expand/collapse/select. Added move-up/move-down buttons per row, boundary-disabled, reusing the existing
reorder()facade method (no logic change). - Screen-reader loading announcements —
app-skeletonisaria-hiddenby design (correct for visual-only use), but 9 list pages (Products, Categories, Customers, Orders, Transactions, Users, Reviews, Monitoring, Analytics) had no accompanying live-region text, so screen-reader users got total silence during loads. Addedrole="status"/aria-live="polite"/aria-busy+ sr-only text. - Table row headers —
scope="col"was already complete from the prior pass; addedscope="row"to the primary identifying cell on 9 tables (product/category/customer name, order/transaction number, etc.) with matching CSS resets so the shared table's header styling doesn't visually leak onto them. - Dialogs, forms,
scope="col"— already correct across the board (all route throughapp-dialog/app-form-field), confirmed not re-touched.
Deliberately not fixed (flagged for a design-decision follow-up)
Failing color contrast that is a genuine brand/semantic color, not a bug — fixing these means changing what the palette looks like, which needs sign-off from whoever owns the theme, not an accessibility pass's unilateral call:
--border-colorfails 3:1 UI-component contrast in every theme (1.24–1.42:1) — pervasive token, hundreds of usages across the whole app.--success-color/--warning-color/--error-color/--info-colorfail 4.5:1 when used as plain text-on-white in a handful of places.- Builder save-bar's warning/error/info text-on-white — same category.
Other flagged items:
- Locale-tabs' partial tablist pattern (no roving-tabindex) — accepted precedent across all 3 surfaces, not fixed in any of them.
- No toast/success-error notification system exists anywhere in the app (backoffice save/delete has nothing to announce — a feature gap, not an accessibility regression of existing UI).
- Dashboard's per-card mini-skeletons — would need a page-level live region rather than per-widget, deferred.
- A handful of already-known partial-widget gaps carried from
docs/UI-COMPOSITION-REVIEW.md(monitoring events table, notifications dropdown, analyticslowStockProductsmissing skeleton) — pre-flagged, not newly found, not re-litigated here.
Verification
tsc --noEmit and npm run build green after all three commits. No live browser/screen-reader session available this session — recommend a manual pass with an actual screen reader (NVDA/VoiceOver) and automated tooling (axe-core/Lighthouse a11y score) against a deployed build before the client demo referenced in docs/FRONTEND-ROADMAP.md, since static-analysis ARIA correctness doesn't guarantee real-world screen-reader UX.