Angular targets
Core 21.2.23, CLI and SSR 21.2.24, Material and CDK 21.2.14, and TypeScript 5.9.3 are valid targets.
TopFans web frontend · plan audit · 18 September 2026
The plan has a sound framework strategy, but it is not executable as written. Fix the peer-dependency procedure, pin a supported Node and npm pair, and strengthen the Firebase and build acceptance checks before using it.
Angular targets and most repository facts are right. The failure is operational: one fallback cannot work, the package manager runs on an unsupported Node version, and the current smoke matrix can miss Firebase regressions.
3 high, 6 medium, 4 low-priority corrections.
overrides cannot repair the peer conflicts that may block ng updatePhase 2 says to add an overrides block for @cotufa82/ng-ivs, @khajegan/ngx-audio-player, and ngx-stripe instead of using --force. npm overrides change dependency resolution. They do not rewrite a package's declared peer range, and Angular CLI performs its own compatibility check.
The Material update has the same issue. @khajegan/ngx-audio-player@17.1.0 declares @angular/material ^17.0.4, so ng update @angular/material@21 can fail its reverse peer check.
Correction: record the known exceptions, run both Angular update commands with --force when the CLI reports those exact stale peers, and prove runtime compatibility afterward. A fork or patched package manifest is the stricter alternative. npm 12's packageExtensions can change peer metadata for npm resolution, but it ties the repository to npm 12 and does not replace the Angular CLI decision.
npx ng update @angular/core@^21 @angular/cli@^21 --force
npx ng update @angular/material@^21 --force
Angular 21 accepts Node ^24.0.0, but npm 12.0.1 requires ^24.15.0 on the Node 24 line. Every registry and install command emitted that warning. Calling it unrelated and safe to ignore is the wrong policy for a migration that rewrites package-lock.json.
Correction: make Node 24.15.0 or newer the Phase 0 prerequisite, or use an npm release that supports Node 24.5. Pin the choice in the repository and CI with the team's normal Node-version file plus engines or packageManager.
The plan expects every login to POST a push token and then attach onMessage. Current code only calls setToken(), and therefore onMessage(), when the token differs from fc_token in local storage. A returning user with an unchanged token produces no POST and may get no foreground listener.
Correction: test both states. First clear fc_token and verify registration. Then reload with the saved token, verify that duplicate registration is avoided, and still prove an inbound foreground notification reaches the toast. The Firebase rewrite should attach one listener independently of whether the backend token POST is needed and retain its unsubscribe handle.
The plan calls isSupported() before Messaging, but the Remote Config Web SDK also exposes isSupported() because IndexedDB can exist yet reject open(), including private browsing contexts. Alias the two imports and check each product before initialization. Browser-only guards alone are insufficient.
AngularFire wraps SDK callbacks to re-enter Angular and schedule change detection. The plan removes those wrappers, then assumes Zone.js promise patching is enough. That is not a reliable contract for Messaging callbacks or future native async behavior.
Correction: explicitly use NgZone.run() around toast and template-state mutations, or move the state to signals and test updates without an unrelated click or navigation.
Phase 5 runs dev, QA, production, QA prerender, QA serverless, and one white-label build. It skips staging, production and staging full-prerender scripts, and the other serverless configurations present in package.json.
Correction: identify the scripts actually called by CI and deployment, then run those exact commands. At minimum, account for build-stage, prerender-all-staging, prerender-all-production, and each deployed serverless configuration. Keep one generated white-label build in the gate.
The matrix intentionally retains libraries with open Angular peer ranges. It also leaves ngx-scrollbar@9.0.2 even though ngx-scrollbar@19.1.5 is its Angular 21 line. That may be the right scope choice because the newer package has API changes, but it contradicts the stated outcome.
Correction: state the actual rule: upgrade Angular-coupled packages whose installed release rejects Angular 21, and explicitly defer broad API migrations. Put ngx-scrollbar, ngx-image-cropper, ngx-sharebuttons, and similar open-range packages in a named deferral table.
@fortawesome/angular-fontawesome@4.0.0 is the correct Angular 21 line, but it depends on @fortawesome/fontawesome-svg-core ^7.1.0. The project directly declares SVG core and icon packs from version 6. The install may leave duplicate core majors even though the wrapper supports version 6 icon definitions.
Correction: decide whether to deduplicate on SVG core 7 or retain the mixed tree deliberately. Check the two icons registered in SharedModule, faXTwitter and faCommentSms, and compare bundle output.
The plan correctly says @angular-devkit/build-angular:server and :karma still run in 21.2.24. It omits that Angular 21 marks the Webpack builders deprecated in favor of @angular/build. Keeping them is valid for this branch, but it does not fully clear the path to the next Angular major.
Correction: add a dated follow-up to migrate the serverless target and test builder. Treat warnings from those builders as expected only for this release.
There are eight @HostBinding uses in five files. The checklist omits signup-by-refer.component.ts and profile-skeleton.component.ts. It should also compile-check the dynamic host expressions in video-player-v2, as already noted.
The working tree has 8 modified files and 12 untracked HTML files, not 11. FirebaseService appears in 14 consumer files, not 15. Neither changes the migration strategy.
npm ls --depth=0With the installed npm 12.0.1, both npm ci --dry-run and npm ls --depth=0 completed successfully. Their peer declarations are still incompatible and Angular CLI may reject the update, but the plan should not claim an observed npm ls failure.
firebase: ^11.10.0 is a range, not a pin. Use 11.10.0 if the intent is exact parity. @angular-devkit/architect follows the 0.2102.24 version scheme, not 21.2.24.
Core 21.2.23, CLI and SSR 21.2.24, Material and CDK 21.2.14, and TypeScript 5.9.3 are valid targets.
Keeping Zone.js is sensible. The repository has exactly 46 TypeScript files referencing NgZone, and Angular 21's migration adds provideZoneChangeDetection() for an NgModule bootstrap.
CommonEngine already receives a concrete allowedHosts list, satisfying the patched Angular SSR behavior for GHSA-x288-3778-4hhx.
The only Angular 21 AngularFire release is 21.0.0-rc.0. It requires Angular 21 and Firebase 12.4. Replacing a four-function use case on Angular 20 first is a defensible isolation strategy.
Deferring zoneless, standalone conversion, Vitest, Quill 2, Firebase 12, and Stripe's companion major keeps unrelated migrations out of the framework hop.
The branch, base commit, Angular package versions, zero .spec.ts files, custom SSR setup, and 46-file NgZone count were verified.
Use Node 24.15 or newer with npm 12, pin both for local and CI use, commit or stash unrelated changes, run a clean install, record current peer exceptions, and capture build sizes.
Pin Firebase 11.10.0, initialize lazily in the browser, check Messaging and Remote Config support separately, re-enter Angular for UI mutations, and own the Messaging unsubscribe lifecycle.
Verify first registration with empty storage, then reload with the existing token and prove foreground messages still arrive without a duplicate backend POST. Check Remote Config in normal and restricted storage contexts.
Use the latest 21.x patches. Apply --force only for the documented stale peers. Verify provideZoneChangeDetection(), TypeScript 5.9, and generated configuration changes.
Update Material with the same peer exception policy. Upgrade the selected library set, account for Font Awesome SVG core 7, and put every retained old package in an explicit deferral table.
Fix TypeScript and all host-binding errors before library API errors. Run lint with Angular ESLint 21. Avoid the global host-binding escape hatch unless a specific library leaves no local fix.
Execute the scripts CI and deployment really use across QA, staging, production, prerender, SSR, serverless, and one generated white-label project. Check rendered HTML and server logs, not only exit codes.
Cover Firebase, Remote Config, routing, service worker, Material/CDK, PrimeNG, Font Awesome, the upgraded form and carousel libraries, plus the deferred audio, IVS, Stripe, editor, cropper, and scrollbar paths.
Merge gate: a supported Node and npm pair, reproducible npm ci, known peer exceptions documented, every deployed build path green, SSR host validation working, and Firebase proven for first-time and returning users.
| Item | Verified result |
|---|---|
| Angular 21 compatibility | Node ^20.19.0 || ^22.12.0 || ^24.0.0; TypeScript >=5.9 <6.0; RxJS ^6.5.3 || ^7.4.0. |
| Angular core 21.2.23 | Peers Zone.js ~0.15.0 || ~0.16.0; current 0.15.1 remains valid. |
| AngularFire 21 | Only 21.0.0-rc.0; peers Angular 21; depends on Firebase ^12.4.0. |
| Angular ESLint 21.4.0 | Accepts ESLint ^8.57 || ^9 || ^10; retaining ESLint 8.57 is valid. |
| Legacy builders | @angular-devkit/build-angular:server and :karma exist in 21.2.24 and are deprecated. |
| Angular Font Awesome 4 | Correct Angular 21 wrapper; depends on SVG core ^7.1.0. |
| ngx-scrollbar | Installed 9.0.2 has open Angular peers; 19.1.5 is the package's Angular 21 release and includes API changes. |