# ADR 0013 — Frontend strangler migration to Vite + TypeScript + React, with the design system frozen verbatim | | | |---|---| | **Status** | **Accepted** — 2026-07-30 | | **Scope** | What happens to the existing browser-only prototype: which parts are preserved unchanged, which are replaced, in what order, and what the coexistence rules are while both exist | | **Owner** | Talha Ahmed owns the build toolchain, the API client generation and the migration order. Ahmed Mujtaba owns the port of the `js/ui.js` primitives to typed components, the stylelint token rule, the Zod schema layer and the Vitest component suite — each independently demonstrable, each with a Talha review checkpoint | | **Consistent with** | `_decisions.md` Part 1 → *Frontend: retain, harden, migrate or rebuild*; *Immediate XSS hardening of the prototype* (ADR 0014, the separate immediate step); *Testing, CI and delivery process* (`react/no-danger`, stylelint, `tsc --noEmit`, Vitest, Playwright) | | **Related ADRs** | 0014 (the Phase 0 hardening this decision deliberately does **not** wait for), 0015 (the backend analogue — boundaries enforced by a tool, not by discipline), 0016 (the CI that makes both enforceable), 0012 (the built bundle is served as static files by the `web` process behind the platform CDN) | --- ## Context This is the one decision in the package where the repository is not greenfield. Everything else — backend, database, queue, auth, CI — is chosen from nothing (`_repo-findings.md` §B). Here there is 7,400 lines of real, working, verified work, and the honest answer is that **the two halves of it deserve opposite verdicts.** ### What exists, split by verdict | Asset | Size / evidence | Verdict | |---|---|---| | `css/styles.css` — tokenised design system, dual light/dark themes, Utopia brand palette and type hierarchy, responsive 320px → ultrawide, WCAG 2.1 AA verified across 23 routes × 2 themes (8,459 text nodes, 0 failures), 44px touch targets, safe-area and `dvh` handling | 1,269 lines, 93 design tokens across 159 custom-property declarations and 470 `var(--…)` references (measured, `01` §12; supersedes the "424" figure) (`_repo-findings.md` §G) | **Preserve verbatim.** Expensive, verified, brand-compliant, and portable because it uses semantic class names (`.card`, `.dt`, `.badge`) not utility classes | | `js/charts.js` — dependency-free canvas engine: line/area, bar, grouped bar, doughnut, horizontal bar, sparkline, reading colours from CSS custom properties so it re-themes automatically | 347 lines (`js/charts.js:339` export list) | **Retain as-is** behind one thin wrapper | | `js/ui.js` primitives — `modal`, `toast`, `dataTable`, `badge`, `avatar`, `avatarStack`, `scoreChip`, `pbar`, `fieldError`, `clearErrors`, icon set | 251 lines (`js/ui.js:251`) | **Port one-for-one**, keeping the same class names so the CSS keeps matching | | The 23-route information architecture — module breakdown, navigation grouping, screen inventory | `js/app.js:7-16` | **Preserve as the route table and the Phase 1+ screen backlog** | | The rendering layer — 34 `innerHTML` assignments across 14 files, no HTML escaping anywhere, inline handlers with interpolated ids, 22 ordered `