# 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)

| Package | Current | Latest available |
|---|---|---|
| `@angular/core` (+ animations/cdk/common/compiler/forms/platform-browser/router/service-worker) | 21.1.5 | 21.2.18 (latest 21.x) / 22.1.0-rc.0 (latest 22.x) |
| `typescript` | ~5.9.3 | 6.0.3 stable |
| `rxjs` | ~7.8.0 | compatible with both 21 and 22 |
| `zone.js` | ~0.16.0 | compatible with 22 (`~0.15.0 \|\| ~0.16.0` required) |
| `primeng` | ^21.0.3 | 22.0.0 stable exists |
| `@lucide/angular` | ^1.25.0 | no upper Angular bound (`>=17.0.0`) — not a blocker |
| Node.js (this environment) | v22.16.0 | Angular 22 CLI requires `^22.22.3 \|\| ^24.15.0 \|\| >=26.0.0` — **current Node does not satisfy this** |

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.

## Estimated effort

- Steps 1-4 (unblock tooling, remove dead deps, Node/TS bump): **0.5-1 day** — mechanical, low risk, mostly already-planned work.
- 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`).
