Merge recommendation
Yes. Merge it now under the agreed validation plan.
I found no newly introduced blocking defect in the core bootstrap conversion. The missing BootstrapContext from the earlier plan is fixed, and both main application builds pass.
The maintainer confirmed that serverless is unused and that tenant and event replay checks will happen after merging, once the change is deployed. Those checks remain unverified, but they are now scheduled deployment checks rather than merge prerequisites.
This recommendation replaces the earlier hold based on that clarification. The reviewed code and test results are unchanged. GitHub reports the same reviewed head open and mergeable, with no listed status checks. The active Express SSR path passed the fresh-render check.
Findings
No new P1 or P2 code defect confirmed in the reviewed changes.
Fresh SSR succeeds, with warnings inherited from the base
A direct request to /creators?key=x returns HTTP 200 with the header, creator route content, and Angular hydration attributes. The development build has zero prerendered routes, so this response exercises the new server bootstrap. It does not reuse a prerendered page.
The server logs NG05001 because hydration and blocking initial navigation are both configured, and NG0100 for a header theme binding that changes during checking. I built the base commit and requested the same route. It returns HTTP 200 and logs the same codes and theme error. These are existing issues, not findings against this conversion.
Serverless is unused
TopFans:serverless:dev stops before compilation because the referenced environment.dev.ts is absent. That environment file is also absent from the base commit. I left environment files unchanged.
TopFans:serverless:production reaches compilation but fails on SCSS imports such as @use 'tools' as *. The separate target lacks the main build's SCSS include paths. I ran the same target on the base commit. Both versions fail on the same 98 styles, so this is an existing build failure.
The maintainer confirmed that serverless is unused. These failures are retained here as historical test results. They do not block the active Express deployment or this merge.
Firebase retirement changes every direct function request
The function now returns HTTP 501. That is intentional in the PR, rather than an accidental leftover import.
The checked-in Hosting rewrite points to /index.html and does not invoke this function. With serverless excluded from the used deployment paths by the maintainer, this intentional retirement is outside the active Express deployment and is not a merge blocker.
Migration contracts
| Contract | Review result |
|---|---|
| Client and shell | AppComponent becomes standalone and imports its template dependencies. bootstrapApplication replaces module bootstrap. Delayed startup and the smooth-scroll polyfill remain. |
| Server bootstrap | The bootstrap forwards context as the third argument, matching Angular's SSR requirement. Named and default exports both exist. The server DOM and Zone imports retain their order. |
| Root providers | Zone change detection, shared providers, the white-label initializer, HTTP interceptor order, PrimeNG, pipes, services, base href, and URL serializer remain in the application config. |
| Store | The five reducer keys and both disabled immutability checks remain. The browser exposes all five keys after startup. |
| Hydration | withEventReplay() and withNoHttpTransferCache() remain on the config shared by client and server. Provider preservation is confirmed. Replay and DOM reuse still need their own checks. |
| Third-party setup | Animations move to provideAnimations(). Modal, Toastr, and Stripe configuration move through importProvidersFrom. Service-worker script, enabled flag, and registration strategy remain. |
| Serverless API | The renderer now uses renderApplication with the shared bootstrap. The named bootstrap is re-exported. This unused path has no runtime acceptance result. |
| Scope | The root NgModules and compiler entryModule are removed. Routes and decorator APIs are unchanged. Source scans find no remaining root-module bootstrap references. |
Checks and limits
These results come from detached checkouts of the PR head and base. I used the main checkout's installed Angular 21.2.23 dependencies and a 10 GB Node heap. Compilation and browser startup are separate from full product acceptance.
| Check | Result |
|---|---|
| TypeScript | tsc -p tsconfig.app.json --noEmit and the corresponding server config check both pass. |
| Angular template compilation | ngc -p tsconfig.app.json --noEmit passes. |
| Main development build | Application build passes in 30.7 seconds with prerendering disabled. |
| Main production build | Application build passes in 51.6 seconds with prerendering disabled. The initial browser bundle is 8.93 MB. |
| Fresh development SSR | /creators?key=x returns HTTP 200, rendered shell and route content, and hydration attributes. No NG0401. |
| Base SSR comparison | Base development build passes in 41.2 seconds. The same request returns HTTP 200 and reproduces NG05001 and the same NG0100 theme error. |
| Browser startup | Root and header Angular instances exist. The development toolbar instantiates. Zone change detection is active. |
| Shared modal | The existing screenshot-information modal opens and closes. Its injected common service and router are the same instances used by the root component. |
| Store keys | userProfile, refreshKeys, otherUserProfile, cache, and apiCache are present at runtime. |
| Whitespace and stale references | The diff passes the whitespace check. No remaining root-module bootstrap references or application @NgModule declarations. |
| Serverless development build | Unused deployment path. The attempted build fails because environment.dev.ts is absent in the checked-in source. |
| Serverless production build | Unused deployment path. Head and base both fail on the same 98 SCSS imports. No new failing stylesheet in the PR. |
| Prerender, DOM reuse, and event replay | Scheduled after deployment. Rendered hydration data and a running browser do not prove that Angular reused every SSR node or replayed an early interaction. |
| Generated white-label project | Scheduled after deployment. No generated-tenant build or fresh tenant SSR render in this review. |
| Signed-in routes and integrations | Authenticated lazy-route modals, Stripe initialization, toast behavior, and production service-worker registration were not exercised. |
The shared-modal check covers one public root service path. It does not cover every modal or the shared pipe providers used by signed-in features. The browser check confirms startup after the SSR response, but makes no claim about early event replay.
After deployment
- Build and freshly render one existing generated tenant. Confirm tenant configuration and branding, rather than only dist-folder selection.
- Prerender representative routes. Check DOM reuse on a prerendered page and a freshly rendered page. Queue a click before hydration finishes and verify replay.
- Exercise a shared modal from an authenticated lazy route, plus Toastr, Stripe startup, and service-worker registration. Add results and the tested commit to the PR.
The first two checks are the maintainer's agreed validation after deployment. The integration smoke checks can accompany that pass. No further code fix was identified in this review.