Skip to content

Angular Material 3 Migration Technical Plan

Completion definition

The programme ends with one coherent Material 3 experience, not a collection of token swaps.

  • Every reachable Angular Material component uses supported M3 theming APIs and resolved semantic roles.
  • About, Admin Console, My Account, project sub-sections and comparable multi-page areas use one adaptive hierarchy: a persistent left rail while content has sufficient room, replaced by a sticky route-aware selector in the section title/header bar when the rail would squeeze or overflow content.
  • Typography, density, spacing, surfaces, elevation, component hierarchy and interactive states are consistent across public and authenticated routes.
  • Light, dark and system-preference modes are complete application themes, including overlays and dynamic content; no session mixes M2 and M3 component generations.
  • Reachable Bootstrap compatibility, M2 APIs and private Angular Material paths are removed. Any deliberately retained compatibility code is unreachable, documented and guarded by an exact shrinking allowlist.
  • The final candidate passes whole-product visual, responsive, accessibility, browser and staging acceptance on an exact image.
  • Terms of Use is not implemented and is excluded from navigation, route inventories and visual baselines until a separate product implementation is approved.

Delivery rule and user gates

Deliver the smallest coherent vertical slices first, but do not expose a half-migrated production UI. Preparation PRs preserve the current live appearance. The first user-visible milestone is an atomic application-wide M3 light cutover. Dark/system theming and final consistency work follow in bounded PRs, and the programme is complete only after their proving release and compatibility cleanup.

No implementation slice outside an already assigned owner starts until this contract is reviewed. No cutover merge, staging activation or production deployment occurs without the coordinated implementation review gate. Historical PR boundaries are evidence only, not delivery constraints.

Authoritative semantic contract

  1. Angular M3 system roles emitted by mat.theme() are authoritative for the Angular application. Use --mat-sys-* for Material meanings such as surface, on-surface, primary, error and outline.
  2. --syrf-* is reserved for stable SyRF brand or domain meanings with no adequate Material role. Each role has one meaning and is emitted by the application theme; call sites do not redefine it.
  3. Identity CSS may share reviewed source colour values but does not own or override Angular runtime roles. Prototype/redesign token names are design inputs, not application contracts.
  4. Use documented Material Sass mixins, public component APIs and emitted system tokens. Tests and tooling must not read @angular/material/fesm*, bundles or private Sass partials.
  5. Meaningful control, focus and graph boundaries clear WCAG 1.4.11. outline-variant is only for decorative separation; status is never communicated by colour alone.
  6. During proving, a session selects one complete component-theme path. Light/dark/system mode may change semantic values, but never the meaning of a role.

Ownership ledger

One active writer owns each structural surface. M3 slices reauthor semantic intent on the owner's landed structure and do not replay preserved commits.

Owner Authoritative boundary Required coordination
PR #2994 Migration docs, scripts/theme-migration-contract.mjs, scripts/check-theme-migration.mjs, theme contract tests and package command Lands before new M3 implementation slices.
PR #2992 About/legal/Cookies plus shared page/section-navigation primitives consumed by comparable sections Current diff implements the adaptive wide-rail/compact-selector behavior and contains no Admin shell files.
Merged PR #3010/current main admin/admin.component.*, Admin Email Templates, Runtime Feature Flags and Admin responsive E2E Canonical landed Admin structure. M3 work does not duplicate these files; impersonation colours follow it.
Account Management convergence successor manage/manage.component.{ts,html,scss,spec.ts} plus a focused Account responsive E2E spec Current main has a responsive but bespoke rail/dropdown from #2819. After #2992 lands the shared primitive, align Account with the same contract without coupling it to Admin permissions.
PR #2990 Bulk Study Update history component plus its Systematic Searches integration Bounded interim history owner only; it is not the completed Study Management product.
PR #2993 Project Jobs hub product/interaction/technical planning only No code owner until its interaction design and permission projection are approved.
PR #2528 Broad Admin job-progress and study-management recovery source Do not merge as a unit. Reauthor useful components in bounded successors after #2990/#2993/#3010 decisions.
Study Management redesign task Full Study Management product discovery, domain behavior, route model and implementation inventory Separate product owner. M3 supplies only adaptive-navigation, theming and job visual-language contracts and assigns no Study Management files while inventory runs.
PR #2853 404 routing, interceptors and shared/not-found/** Record 404 baselines only after this structure lands or an explicit stack is agreed.
Merged PR #2467/current main Stage Review, reviewer presence and SignalR banners/dialogs Convert its two M2 banner partials in the shared-theme prerequisite slice.
PRs #2802, #2810 and #2812 plus preserved AF worktrees AF1/AF2 question, branch, outline and response-mode structure Question Preview and Annotation M3 work waits for these owners to settle.
PR #2533 or its successor Application/project navigation structure Do not combine its structural refactor with theme recovery. Reassess because its preserved head is stale and conflicting.

PR #2992's historical selector-at-all-widths form is not the reference. Its current diff follows the content-driven pattern: wide rail, compact sticky selector, identical destinations/current state, one page title, keyboard/focus/Escape support, native route/history/Back behavior and no page overflow. Its breakpoint and focus evidence still require review before integration. PR #2992's temporary Terms metadata is also not desired behavior: Terms stays absent until the product and route exist.

Historical source inventory

Source Recovery decision
PR #2322 Do not merge or rebase. Retain research and validation ideas only; its Angular 21 implementation and broad Bootstrap/dark-mode coupling are obsolete.
PRs #2751, #2753, #2754, #2756, #2771 and #2777 Merged foundations. Preserve current-main category-theme behavior, semantic tokens and contrast checks.
PR #2750 and PR #2755 Drop. The shim was removed and the duplicate is superseded.
PR #2775 Reauthor Contact/FAQ semantic intent without its contract-script changes.
PR #2784 Reauthor Stage Overview as a dedicated chart/accessibility slice.
PR #2791 Reauthor Data Export error-dialog intent; discard inline theme overrides and private-package parsing tests.
PR #2805 Reauthor account colours on PR #2992's landed Account shell.
PR #2811 Reauthor impersonation colours on PR #3010's landed Admin shell.
PR #2813 Reauthor About/legal colours on PR #2992's landed structure.
PR #2990 Preserve its bounded Bulk Study Update history intent; do not represent it as the completed Study Management implementation.
PR #2993 Preserve the central project Jobs hub concept as a separate planning dependency; do not hold or absorb #2990.
PR #2528 (and closed #2511/#1865) Salvage status/progress/error presentation and tests only. Split Admin monitoring, study entry points and shared state by current owners.
feat/m3-question-preview-colours Retain intent only; reauthor after Question Management/AF owners settle.
fix/m3-outline-variant-boundaries Retain the WCAG boundary findings; reauthor after AF2 outline owners settle.

Task boundaries and dependency graph

#2994 contract
  ├─ shared theme prerequisites ─┬─ public/data/chart leaf slices
  │                             └─ SignalR semantic states
  ├─ #2992 adaptive About/shared primitive ─┬─ About/legal colours
  │                                         └─ Account shell convergence ── Account colours
  ├─ merged #3010 adaptive Admin ─────────── impersonation colours
  │                               └─ Admin job-monitoring successor
  ├─ #2990 focused history ──────── study/job visual slices
  ├─ #2993 approved hub design ──── additive project Jobs hub
  ├─ #2853 404 structure ──────────── 404 colours/baseline
  └─ AF/navigation owners settle ──── Question/AF/project-navigation slices

all light slices + compatibility retirement
  → atomic M3 light cutover
  → dark/system theme completion
  → whole-product consistency audit
  → proving release
  → M2 bridge/switch cleanup

Wave 0 — contract and structural reconciliation

  1. Land PR #2994 after its executable boundary, current-main baseline and review findings are green.
  2. In parallel, finish the already-owned structural PRs:
  3. PR #2992: adaptive About hierarchy plus shared primitives, excluding Admin files;
  4. merged PR #3010/current main: the canonical adaptive Admin hierarchy and overflow baseline;
  5. an Account Management successor: consume the landed shared section primitive in manage/manage.component.*, replace the bespoke in-body dropdown with the sticky route-aware header selector, and preserve Account routes and behavior;
  6. PR #2990: focused Bulk Study Update history on Systematic Searches;
  7. PR #2993: Jobs hub design and permission decisions, with no implementation ownership yet;
  8. the separate Study Management redesign task: product scope and file inventory, without M3 implementation changes;
  9. PR #2853: 404 ownership;
  10. existing AF/navigation owners: their current structural decisions only.

Exit: each moving surface has one owner, #2992 contains no Admin implementation, Account has an explicit successor boundary, and breakpoint behavior is accepted at wide, intermediate, 200%, 320px and 400%-equivalent layouts.

Wave 1 — smallest safe parallel M3 wave

These slices use the settled semantic contract, have disjoint component files and can start in parallel after PR #2994 is review-approved. Shared-theme prerequisite work lands first when a slice needs the global theme file.

Slice Exact boundary Dependencies
Shared theme/SignalR prerequisite src/global-styles/syrf-theme.scss; the idle and surplus banner *-theme.scss, component SCSS and focused specs Current main/#2467. Remove both temporary M2 exceptions without changing reviewer-state behavior. Sole owner of the global theme in this wave.
Public information info/contact-us/*.{html,scss,spec.ts} and info/faq/*.{scss,spec.ts} only Merged responsive PR #2819. Use existing roles; no contract-script or global-token edits.
Data Export errors project/data-export/shared/export-error-details-dialog/*.{html,scss,spec.ts} only Public Material APIs and current emitted roles. No inline component theme block or private-package tests.
Stage Overview stage/stage-overview/current-progress-pie/**, member-progress/*.scss, member-time-progress/*.{ts,spec.ts}, time-progress/*.{ts,scss,spec.ts} Merged responsive PR #2819. Must include cached computed-role resolution, Highcharts accessibility registration, shape-plus-text status and rendered SVG proof.

The smallest safe launch is the shared-theme/SignalR prerequisite plus Public Information and Data Export. Stage Overview may run in parallel only with a dedicated chart owner and rendered-browser evidence; otherwise defer it rather than enlarging a leaf PR.

Wave 2 — structure-dependent section slices

| Slice | Exact boundary | Must wait for | | About/legal/Cookies colours | about/** colour/state styles and focused colour/accessibility tests; no layout markup | PR #2992 merged. | | Account adaptive convergence | manage/manage.component.{ts,html,scss,spec.ts} plus a new focused Account responsive E2E spec; no profile/password/domain behavior | PR #2992 shared primitive merged. Reuse its generic primitive and the landed #3010 behavior contract, not Admin components or permissions. | | My Account colours | manage/** colour/state styles and focused tests; no shell/navigation structure | Account adaptive convergence merged. | | Impersonation colours | admin/impersonation/*.scss, its colour spec and core/components/impersonation-banner/*.scss | Landed #3010 Admin baselines accepted. | | 404 visual system | shared/not-found/** colour/state styles and visual baseline only | PR #2853 merged or explicit stack. | | Comparable section hierarchy | Project and other multi-page section shell files assigned after an inventory names one owner per route group | Shared adaptive primitive settled; do not overlap PR #2533 or active feature navigation. |

Wave 3 — high-churn feature surfaces

  • Question Preview, AF1 and AF2 colours, boundaries and density after PRs #2802/#2810/#2812 and successor worktrees settle.
  • SignalR disconnect, idle, surplus and access-denied states after the Wave 1 banner prerequisite; preserve live-region semantics and prove two-browser state transitions.
  • Bulk PDF Upload statuses: map reusable statuses to shared domain roles and keep genuinely feature-specific roles local and documented.
  • Application and project navigation visual states after the active navigation owner lands.
  • Study Management is a dependent product slice owned by its separate redesign task. M3 does not claim project/project-admin/systematic-searches/**, studies/** or domain behavior while that owner inventories scope. Once its plan and file boundaries are accepted, its implementation consumes this programme's adaptive-navigation, supported-token, responsive table/list and job visual-language contracts.
  • Admin job monitoring after merged PR #3010: a #2528 successor may own admin/job-progress/** and the minimum admin.routes.ts addition, but must not modify the Admin shell or absorb project job entry screens.
  • A central project Jobs/history hub, if approved from PR #2993, owns a new project/project-jobs/** route plus minimal project-route/navigation integration. It is additive: Systematic Searches, All Studies and other owning screens retain launch/retry/cancel/delete actions, and #2990 remains independently shippable.

Each slice owns component-local files. Any new shared token is proposed in a separate, serial theme-contract change so parallel PRs cannot assign incompatible meanings.

Long-running-job visual-language contract

  • Preserve raw server status text; group it only for consistent icon, semantic role and filtering. Unknown future values render as Unknown, never Running.
  • Use icon/shape plus text for queued, active, completed, failed, cancelled and unknown states.
  • Determinate progress has an accessible value; indeterminate progress states what is happening; zero, missing and complete values are not conflated.
  • Errors use a concise summary with keyboard-accessible bounded disclosure. Full diagnostic data is not dumped into a table cell or announced repeatedly.
  • Show initiator and start/update/completion timestamps consistently, with an unambiguous absolute value available to assistive technology even if the visible value is relative.
  • Wide tables become coherent cards or use a labelled contained scroller on narrow/high-zoom layouts. Actions, status and the newest relevant timestamp remain discoverable without page overflow.
  • Systematic Searches, All Studies, Bulk Study Update history, Admin job monitoring and a future central Jobs hub share this language. Study Management remains a separate product programme and these surfaces remain separate code PRs unless file ownership is genuinely disjoint.

Wave 4 — compatibility and consistency preparation

  • Replace reachable .btn-*, .panel-* and .progress-bar usage while preserving category-theme behavior protected by PR #2756.
  • Remove reachable inline colours and private component-token overrides.
  • Remove the three legacy-bootstrap imports only after rendered Annotation Designer/Form proof.
  • Audit typography scale, density, spacing, surface/elevation hierarchy and hover/focus/pressed/ selected/disabled/error/loading states. Fix inconsistencies in route-group-owned PRs, not a cross-application mega-diff.

Exit: migration checks intentionally expect no legacy imports or temporary M2 banner exceptions; all reachable feature surfaces have accepted light-theme evidence.

Wave 5 — atomic M3 light cutover

  • Emit the M3 component theme for the entire Angular application through a single activation path.
  • Prove CDK overlays, dialogs, menus, drawers and portals use the same theme as their trigger page.
  • Keep an application-level M2 proving switch or the prior known-good web image for rollback.
  • Do not delete the M2 bridge in this PR.

Exit: every session is wholly M3 light when enabled and the complete route matrix is accepted on the exact candidate image.

Wave 6 — dark and system completion

  • Emit a real dark M3 system/component theme rather than reusing light tokens.
  • Add explicit light, dark and system-preference selection with persisted, accessible control behavior and correct initial rendering.
  • Prove overlays, charts, status cues, images, forced colours and browser colour-scheme integration in every mode.
  • Reconcile shared source values with Identity without coupling Angular to Identity CSS.

Exit: light, dark and system modes pass the same automated, visual and accessibility matrix.

Wave 7 — whole-product consistency audit and cleanup

  • Compare every public, account, admin, project, stage, Question Management, AF1/AF2 and SignalR state against the completion definition.
  • Include Systematic Searches, All Studies, Bulk Study Update history, Admin job progress and any approved project Jobs hub in the same consistency audit.
  • Verify adaptive hierarchy, typography, density, spacing, surfaces, elevation and component states as a single product, including cross-route transitions.
  • Run one proving release before deleting the M2 bridge and activation switch.
  • Delete compatibility code in a small follow-up with an ordinary revert path.

Validation matrix

Automated

  • production Angular build, changed-file lint and full web unit suite;
  • pnpm run check:theme-migration and pnpm run check:contrast;
  • every referenced semantic token defined and concretely resolved in compiled light and dark CSS;
  • component behavior/semantics tested through rendered DOM and public APIs;
  • Chromium, Firefox and WebKit E2E for theme-sensitive critical flows;
  • axe checks on representative public and authenticated routes.

Responsive and adaptive hierarchy

Compare current-main staging with the exact-head preview using identical users and seeded data:

  • widths 320, 375/390, 480, 600, 768, 960, 1280 and 1440 pixels;
  • breakpoint-adjacent intermediate widths, short-height states, 200% zoom and 400%-equivalent reflow;
  • wide rail and compact sticky selector generated from the same destinations and current route;
  • one page-level heading, active/current state, focus return, Escape, keyboard and touch activation, native route/history/Back, sticky access after scroll and no page-level horizontal overflow;
  • contained scrolling for intrinsically wide tables, code, charts and previews.

Visual and interaction states

  • approved screenshots for light, dark and system modes on desktop and mobile;
  • hover, focus-visible, pressed, active, selected, expanded, disabled, error, loading and empty states;
  • shell/nav/drawer, public/legal/cookie/404, account/manage/impersonation, project/stage charts, Data Export, Systematic Searches, All Studies, job progress/history, Question Management, AF1/AF2 and SignalR reviewer states;
  • visual-regression thresholds reviewed by a human; no baseline is accepted solely because pixels changed uniformly.

Accessibility

  • WCAG AA text contrast and 3:1 meaningful control/graph boundaries in every theme;
  • keyboard order, visible focus, focus return, dialog trapping and touch target behavior;
  • headings, landmarks, accessible names/descriptions, current state and live regions;
  • 200%/400% zoom, forced colours, reduced motion and non-colour status cues;
  • rendered Highcharts SVG keyboard and screen-reader behavior.

Staging proof and review gate

  • exact image SHA and configuration recorded;
  • no console errors, hydration/theme flash or unresolved token fallbacks;
  • authenticated evidence for protected routes and two-browser SignalR behavior;
  • desktop/mobile screenshots and accessibility results attached to the coordinated review;
  • no unresolved review threads, duplicate file owners or unreviewed exceptions;
  • explicit implementation-review approval before merge and separate rollout approval before staging or production activation.

Integration order, rollout and rollback

Merge order follows dependencies, not PR age: contract → structural owners/shared prerequisite → disjoint leaf slices → structure-dependent/high-churn slices → compatibility retirement → atomic M3 light cutover → dark/system completion → whole-product audit → cleanup.

Rollout uses exact-head preview → guarded staging → explicit acceptance → production web image. A pre-cleanup rollback selects the complete M2 application path. After cleanup, rollback uses the prior known-good web image or a normal revert. This programme has no schema or API data rollback.