# Angular 22 Upgrade Plan (research only — not applied)
Feasibility assessment for upgrading from the current Angular 21.1.5 to Angular 22. **No upgrade was performed** — this is a plan, per mission instructions ("Do NOT upgrade automatically. Stop.").
## Current state (verified against `package.json` + npm registry, 2026-07-25)
Correction to the project's own status tracking: `docs/PROJECT_INDEX.md`/`CLAUDE.md` describe this as "Angular 18+" — the repo is actually already on **21.1.5**, one major behind the latest stable (22.1). This is a much smaller jump than "18→22" would imply.
## Verdict: upgrade is safe, with 2 concrete pre-requisites
Nothing found in this codebase blocks the jump on its own merits — the risk is entirely in the dependency chain, not the app code:
1.**`primeng@^21.0.3` peer-depends on `@angular/core@^21.0.7` only** — it does not accept Angular 22 today. **However**, this dependency is already dead code (`docs/KNOWN-ISSUES.md` item 12): its only consumer, `items-carousel`, was deleted during RC PERF-01, and its removal is already planned, just blocked on an unrelated `npm uninstall` failure (see #2). Once `primeng`/`primeicons` are actually removed from `package.json`, this blocker disappears entirely — no need to wait for/adopt `primeng@22`.
2.**`barry-cache@^0.1.0` in `package.json` no longer resolves** (`ETARGET`) — confirmed via `npm view barry-cache`: the real published range is now `0.9.3` (20 versions total), and `^0.1.0` doesn't intersect anything currently on the registry. This is what's been silently blocking `npm install`/`npm uninstall` all cycle (referenced in `docs/PERFORMANCE_REPORT.md`, `docs/KNOWN-ISSUES.md` item 12). **This must be fixed first** — bump `barry-cache` to a current version — or `ng update` itself will fail the same way `npm uninstall primeng` already does.
3.**Node.js**: this dev environment runs v22.16.0; Angular 22's CLI requires `^22.22.3 \| ^24.15.0 \| >=26.0.0`. A Node bump is required before `ng update` will even run, independent of the app.
Once those 3 are resolved, the app itself is well-positioned:
- 100% standalone components already (no NgModules to migrate).
- 190/191 components already `ChangeDetectionStrategy.OnPush` (per `docs/PERFORMANCE_REPORT.md`) — directly aligned with v22 making OnPush the default; this app barely changes behavior from that shift.
- Heavy existing signals usage (facades are signal-based per `docs/ARCHITECTURE.md`/ADR-007) — aligned with where Angular is going (Signal Forms, `resource()`), no fighting the framework.
- Zero usage found of the specific APIs v22 removes: `ComponentFactoryResolver`, `ComponentFactory`, `provideRoutes()`, `CanMatchFn` (grepped `src/app/**`, zero hits).
- Zone-based (not zoneless) via `provideZoneChangeDetection({eventCoalescing: true})` in `app.config.ts` — this continues to work under v22, no forced zoneless migration needed to upgrade.
## Benefits
- Bug fixes and perf improvements shipped between 21.1 and 22.1 (6+ months of patches this repo isn't getting).
- OnPush-by-default aligns with where this codebase already is — near-zero migration cost for that specific change, unlike a codebase still on default change detection.
- Keeps pace with `primeng`/ecosystem packages that are already moving to v22-only releases (relevant once primeng is actually removed and no longer a constraint either way).
- Closes the gap before the next major (v23) makes this a two-major jump instead of one.
## Risks / breaking changes relevant to this codebase
1.**Route parameter inheritance changes from `emptyOnly` to `always`.** No explicit `paramsInheritanceStrategy` override was found in `app.routes.ts` or `app.config.ts` — meaning this app is on the default, and the default is changing. **Concrete risk**: any component reading `ActivatedRoute.params`/`paramMap` that currently expects to NOT see a parent route's params (e.g. a child route under `/:lang/backoffice/:id/edit` reading only its own segment) could start receiving inherited params it didn't before. Needs a manual audit of nested routes with route params at each level — `src/app/app.routes.ts` has several (product detail, category, admin edit routes) — not just a blanket "run the test suite and hope."
2.**TypeScript 6.0 minimum** — current is 5.9.3, a straightforward `npm install typescript@^6.0.3` bump, but TS 6 does include its own (separate) breaking changes to check independently of Angular (stricter inference in some cases) — budget a pass for TS compiler errors post-bump, not just Angular's.
3.**`primeng`/`primeicons` removal must land first** (see Verdict #1) — sequencing matters: remove dead deps → fix `barry-cache` → bump Node → `ng update`, not the reverse.
4.**No automated test suite beyond the default Jasmine/Karma scaffold** was confirmed running in this session (`docs/SPRINT-PLAN.md` Sprint 29 notes: "Translation validation / lint... No lint script exists") — meaning post-upgrade regression detection leans entirely on `tsc --noEmit` + `ng build` + manual verification, the same constraint every other pass this cycle has worked under. The route-params risk above in particular needs *manual* route-by-route verification, not just a green build, since it's a runtime behavior change a type-checker can't catch.
## Migration steps (sequenced)
1.**Unblock tooling**: bump `barry-cache` in `package.json` to a currently-published version (`0.9.3` or latest at execution time) — verify with `npm view barry-cache versions` first.
2.**Remove dead `primeng`/`primeicons`** (already-planned, `docs/KNOWN-ISSUES.md` item 12) — now unblocked by step 1. Verify `npm run build` still green afterward (it was already confirmed code-dead in RC PERF-01, this just finishes the dependency removal).
3.**Bump Node.js** in the dev/CI environment to satisfy `^22.22.3 | ^24.15.0 | >=26.0.0`.
4.**Bump TypeScript** to `^6.0.3`, run `tsc --noEmit`, fix any TS-6-specific compiler errors before touching Angular.
5.**Run `ng update @angular/core@22 @angular/cli@22`** (and `@angular/cdk@22` if still a dependency) — let the official schematic handle the mechanical parts.
6.**Audit route-param inheritance** manually across every nested route with params in `app.routes.ts` (product detail, category, admin edit/detail routes) — the one behavior change with no automated safety net.
7.**Full verification pass**: `tsc --noEmit`, `npm run build`, `npm run arch:check`, plus a live browser walkthrough of the same route list used in `docs/RELEASE_REPORT.md` (storefront/builder/backoffice) — this upgrade deserves the same rigor as that pass, not just a build check.
8.**Commit, do not push** without explicit sign-off, same as every other pass this cycle.
- Step 5 (`ng update`): **0.5 day** — the schematic does most of the work given zero deprecated-API usage found.
- Step 6 (route-param audit): **0.5-1 day** — the one genuinely manual, judgment-requiring step; depends on how many nested-param routes actually exist and how many read parent params today (needs a route-by-route trace, not estimated further without doing that trace).
- Step 7 (verification): **0.5-1 day** — matches the RC walkthrough pass's effort, since that's the closest analog in this codebase's own history.
**Total: ~2-3.5 days** for one engineer, assuming no surprises in the route-param audit (the one genuinely unknown risk). This is a small-to-medium upgrade, not a large one — the app's existing standalone/signals/OnPush posture did the hard work already.
## Recommendation
Safe to schedule. Not urgent (still only one major behind), but low-risk and the gap only grows if deferred further. Do the two prerequisite fixes (`barry-cache`, `primeng` removal) regardless of upgrade timing — they're blocking other things too (this dependency chain is also what's stopping the `primeng` bundle-size win noted in `docs/PERFORMANCE_REPORT.md`).