Skip to content

v1.1.0

Latest

Choose a tag to compare

@github-actions github-actions released this 28 Sep 11:47
a7594bd

Version 1.1.0 moves the starter to Angular 22, Nx 23 and TypeScript 6 with strict mode on, and lets every signed-in user manage their own account. It is the largest release since 1.0.0, and it asks something of every fork: read Fork migration below before merging.

The first area is the toolchain. Angular 22.0, Nx 23.1 and TypeScript 6.0 land together, because each one requires the others (#534). Components now rely on Angular 22's default OnPush change detection, and a lint rule keeps it that way (#551). @ngrx/signals moves from a pinned pre-release to the stable 22.0.0 (#553). TypeScript's strict mode is now on across the workspace (#560). Turning it on also exposed a real bug: three API routes documented a generic "Forbidden" error instead of their actual reason for refusing (#555). Node.js moves to the 24.20.0 LTS release, and a new docs/node-support-policy.md explains why the starter follows the LTS line instead of adopting Node 26 (#535, #536). Prettier is pinned to one exact version, so formatting no longer depends on the day you installed (#559).

The second is account self-service. Any signed-in user can open /account and change their own name. A before → after summary is shown before anything is saved, and the new endpoint can only ever edit the caller's own account (#454). Changing the email address stays admin-only until the new address can be verified; that is planned for 1.2.0 (#588). The sidebar footer now shows the signed-in user, with a menu for Account, Settings and Log out (#586), and the desktop sidebar no longer collapses (#604). GET /api/auth/me now reads the account from the database instead of from the session token. A rename therefore appears on the next page load, and a disabled user is signed out on their next navigation instead of up to 15 minutes later (#454).

The third is user administration. Admins edit a user's profile, roles and status in one drawer, check the changes as a before → after list, and save them in a single transaction. A failed role change can no longer leave an edit half-applied (#453). The user and role drawers no longer accept an invalid form (#589). Permission descriptions now follow the selected language (#572), and the row actions menu is built on the new shared Menu component (#601).

The fourth is testing and CI. Until now the integration suite could not fail: a failing run still exited successfully. It now fails properly, so a fork may see failures that were already there (#585). The code generators work again; they had broken under ES modules (#590). The shared Playwright fixture no longer hangs at teardown (#557), and the upstream guard checks run again when a stacked pull request is retargeted (#583). On the release side, an unused nx release configuration is removed and a protection rule for version tags is specified (#486).

Documentation gains a single reference for Angular dependency injection (#482) and setup instructions for the Zed editor (#575).

Fork migration

Every fork:

  • #535 - You must use Node.js 24.20.0 or later (nvm use reads .nvmrc), and move any Node version pins in your own CI or deployment configuration to 24.20.
  • #534, #535 - After merging, you must reinstall from scratch with rm -rf node_modules package-lock.json && npm install. A partial install cannot resolve Angular 22's dependencies. If you add a dependency that runs install scripts, approve it in allowScripts (npm install-scripts ls lists the skipped ones).
  • #534 - You must add "rootDir": "../.." to compilerOptions in apps/<your-app>/tsconfig.app.json and apps/<your-app>/tsconfig.spec.json, and "rootDir": ".." to apps/<your-app>/e2e/tsconfig.json. These files do not change on merge, and without the setting TypeScript 6 fails npm run typecheck with TS6059 ("not under 'rootDir'"), because your app imports packages/* sources from outside its own folder. The production build still passes.
  • #534 - You must list the public hostnames your app serves, either in security.allowedHosts under the build target's options in apps/<your-app>/project.json (for example "security": { "allowedHosts": ["my-app.example.com"] }) or as new AngularAppEngine({ allowedHosts: [...] }) in apps/<your-app>/src/server.ts. Angular 22 answers 400 Bad Request (Header "host" with value "…" is not allowed.) to every SSR request whose host is not listed, where Angular 21 fell back to client-side rendering, so every page returns 400 while /api/* routes and healthchecks keep passing. The NG_ALLOWED_HOSTS environment variable has no effect, because the starter uses AngularAppEngine. If your app runs behind a trusted proxy that sets the forwarded headers and SSR needs the public host or protocol, also pass trustProxyHeaders: ['x-forwarded-host', 'x-forwarded-proto'] to new AngularAppEngine(): Angular 22 ignores X-Forwarded-* headers by default.
  • #551 - You must remove every changeDetection: ChangeDetectionStrategy.OnPush (and the ChangeDetectionStrategy import it leaves unused) from your own .ts files, including specs, stories and your app's copies of reference-app components, and from any page or ui-component generator templates you customised. A no-restricted-syntax rule in eslint.config.mjs now fails npm run lint on **/*.ts with "Angular 22 enables OnPush change detection by default — remove the redundant explicit changeDetection: ChangeDetectionStrategy.OnPush".
  • #560, #555, #556 - You must fix the errors that strict mode reports in your own app, including your copies of reference-app code. "strict": true is now in tsconfig.base.json, TypeScript 6 enables strict anyway unless it is set to false, and the errors fail both npm run typecheck and npm run build. Port getAuthenticatedUser(c) into src/api/middlewares/verify-access-token.middleware.ts and use it instead of (c as AuthenticatedContext).user in your role, user-management and user-role controllers and in verify-permissions.middleware.ts. In specs (verify-access-token.middleware.spec.ts, verify-permissions.middleware.spec.ts and the permission, role, user-role, user-management and auth controller specs), set and read the user through setAuthenticatedUser / readAuthenticatedUser from the new verify-access-token.middleware.mock.ts. Declare any 401, 403 or 500 response after ...commonResponses, in your copies of role.routes.ts (deleteRoleRoute, assignPermissionsRoute) and user-management.routes.ts (updateUserStatusRoute) and in your own routes: strict mode reports the earlier order as TS2783, and the spread would overwrite your description. Apply the null-safety fixes in verify-health.ts (responseTimeMs ?? undefined), nav-section.ts (@let sectionName = section().name), app.routes.server.spec.ts (match?.renderMode) and auth.mapper.spec.ts (createdAt: null, updatedAt: null). If your fork is not ready, set "strict": false in the compilerOptions of apps/<your-app>/tsconfig.json as a temporary, documented divergence; removing the key does not turn strict off.
  • #559 - After merging, you must run npm run format and commit the result. Prettier is now pinned to exactly 3.9.6, which reformats some arrow functions (your copy of domain/user-management/managed-user.mapper.ts among them), and the check target's prettier --check fails until you do.
  • #585 - You must copy the integration exit-code fix into your own app, because it does not arrive on merge. In apps/<your-app>/src/api/integration/setup/embedded-pg-test-db.ts, add import asyncExitHook from 'async-exit-hook' and call asyncExitHook.unhookEvent('beforeExit') and asyncExitHook.unhookEvent('exit') at module level. In global-setup.ts, drop the static import of ./embedded-pg-test-db and use await import('./embedded-pg-test-db') inside the branch that starts the cluster (setup) and the one that stops it (teardown). Until you do, your app's test-integration exits 0 even when tests or the global setup fail, and the new test-integration-setup-guard checks only the reference app. If you also copy embedded-pg-test-db.spec.ts, narrow the exclude in apps/<your-app>/vitest.config.ts from src/api/integration/** to src/api/integration/**/*.integration.spec.ts so the spec runs. Expect failures that already existed to appear in your app's first run after the copy.
  • #585 - Expect the reference app's test-integration to fail on your first run after merging if it was already failing, for example when INTEGRATION_TEST_ADMIN_PASSWORD is unset: those failures used to exit 0. npm run ci and npm run ci:verify gain the Batch 1 target test-integration-setup-guard, which starts embedded Postgres, and the CI test-integration job gains a guard step.
  • #601 - You must import RowAction from @resetshop/ui/row-actions-menu/row-actions-menu in your copies of users/users-list/users-list.ts and roles/roles-list/roles-list.ts, and in any code of your own. The row-action-item file and the RowActionItem component are deleted from packages/ui, so imports from @resetshop/ui/row-actions-menu/row-action-item fail to compile after merging. Use Menu (@resetshop/ui/menu/menu) where you used RowActionItem.
  • #534 - Wherever your code or specs call a canMatch guard directly (a CanMatchFn, or canMatch() on a class implementing CanMatch), you must pass the third currentSnapshot argument. Angular 22 makes it required, and two-argument calls fail the type-check.
  • #534 - If a component of yours declares both x = model() and an xChange output, you must replace the model with xInput = input(<initial>, { alias: 'x' }) plus x = linkedSignal(this.xInput). Angular 22 rejects the duplicate xChange output at build time.
  • #534, #551 - Angular 22 runs every component without a changeDetection setting as OnPush. You should check the components in your own code that had none, and make any that relied on the old eager checking work under OnPush (signals, immutable updates). A component that must stay eager keeps changeDetection: ChangeDetectionStrategy.Eager only with an eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection comment, because angular-eslint 22 reports any explicit Eager or the deprecated Default as a lint error.
  • #534 - You should remove withFetch() (and its import) from provideHttpClient(...) in apps/<your-app>/src/app/app.config.ts. Angular 22 deprecates it because fetch is now the default backend. Nothing fails while it stays, but a future major will remove it.
  • #534 - You should review template expressions a?.b whose result reaches a === null / !== null comparison, a pipe, a function-call argument or an input that tells null from undefined. In Angular 22, a?.b yields undefined instead of null when a is nullish.
  • #557 - You should add await page.unrouteAll({ behavior: 'ignoreErrors' }) right after await use(page) in the page fixture of apps/<your-app>/e2e/fixtures/index.ts. It removes the /api route handler before Playwright closes the context, which otherwise can hang Firefox end-to-end teardown past the test timeout under parallel load.

If your fork ships its own language files (the TranslationSchema type-check lists every missing or unknown key):

  • #454, #453, #482, #572 - You must add the top-level ACCOUNT.* keys, USERS.DETAIL.EDIT.* (including CONFIRM_DIALOG.*), DASHBOARD.USERS.NAV and PERMISSIONS.DESCRIPTIONS. PERMISSIONS.DESCRIPTIONS is a map keyed by permission identifier (module:resource:action); the type-check needs only the property ({} passes) and does not check its entries. When you copy the translated permission views, add one entry per identifier in your PERMISSION_DEFINITIONS, and copy their coverage spec providers/i18n/permission-descriptions.spec.ts, which checks them.
  • #453, #586 - You must remove USERS.DETAIL.PROFILE.{SAVE,SUCCESS_TOAST}, USERS.DETAIL.ROLES.{EDIT_BUTTON,DRAWER_TITLE,ROLES_LABEL,SUCCESS_TOAST} and DASHBOARD.HOME.DESCRIPTIONS.SETTINGS, rename DASHBOARD.SECTIONS.SETTINGS to DASHBOARD.SECTIONS.MAINTENANCE, and then update your code that still uses them. The type-check catches the translation.instant(...) calls in edit-user-roles-drawer.ts and user-profile-section.ts and the Record<string, TranslationKey> map in dashboard-home.ts. It does not catch the | translate pipes in edit-user-roles-drawer.ts, user-profile-section.ts and user-roles-section.ts, or the section name in dashboard.navigation.ts, which render the raw key instead: search your templates and navigation config for each removed key.
  • #453, #454, #572, #586 - You should remove the entries for the removed keys from your translation.mock.ts. It is a Record<string, string>, so the type-check does not flag it. When you copy specs from the reference app, also copy the entries they assert on (ACCOUNT.*, USERS.DETAIL.EDIT.*, HEALTH.NAV, DASHBOARD.HOME.DESCRIPTIONS.HEALTH) and the TranslationStub interface, or those specs see raw keys.

If your fork changed or reuses any of the following:

  • #534 - Your tsconfig.base.json, if it diverges from upstream: you must keep "ignoreDeprecations": "6.0", "types": ["*"] and "noUncheckedSideEffectImports": false in its compilerOptions. Without ignoreDeprecations, TypeScript 6 fails every project on the deprecated baseUrl (TS5101).
  • #534 - Your own components that implement FormValueControl with a two-way touched = model<boolean>(): you must change it to a touched = input<boolean>() and a touch = output<void>(), as packages/ui Select and Combobox now do.
  • #534 - Your own generators or Nx plugins: if they import @nx/devkit/src/*, @nx/js/src/*, @nx/eslint/src/*, @nx/web/src/* or @nx/angular/src/utils, you must switch to the package root or its /internal entry, and rename createNodesV2 / CreateNodesV2 to createNodes / CreateNodes. Nx 23 removed those subpaths.
  • #590 - Your own generators: you must follow the ES module rules and add them to the GENERATORS list in scripts/check-generators-load-as-esm.mjs. Locate templates with resolveTemplateDir(import.meta.url): lint now rejects __dirname and __filename under packages/generators/.
  • #453 - The Edit Roles drawer or the inline profile form, if you adopt the combined Edit User drawer: you should move your changes into edit-user-drawer.ts. If you copy the new UserManagementService, callers of updateUser / updateUserStatus must read .user from the UserUpdateResult it returns.
  • #453 - Your copy of the PATCH /api/users/{id} handler (user-management.controller.ts): you should add [USER_ROLE_ERRORS.ROLES_NOT_FOUND, 400] and [USER_ROLE_ERRORS.NON_REMOVABLE_ROLES, 400] to ERROR_STATUS_MAP and widen the status type of resolveErrorStatus to include 400. Unknown or non-removable role IDs otherwise surface as an unmapped 500.
  • #453 - Your component stylesheets: you should replace var(--color-*) references with the unprefixed theme variables (--foreground, --background, --border, …). Component CSS is not processed with the Tailwind theme, and the build declares no --color-* custom properties for it, neither the @theme inline tokens in tailwind.config.css nor Tailwind's default palette such as --color-black, so such a declaration silently resolves to nothing. This is why the dialog and drawer backdrops were transparent; the packages/ui stylesheets are fixed on merge.
  • #454 - Your copy of GET /api/auth/me (auth.controller.ts): it still answers from the access-token claims, so a renamed user sees their old name until the token refreshes, and a disabled or deleted user stays signed in until the token expires. To sign them out on their next navigation, as the reference app now does, you should add AuthService.getSessionUser(userId): Promise<UserData> (in auth.service.ts and the AuthService interface in interfaces.ts), which throws AuthError USER_NOT_FOUND for a missing or DELETED user and ACCOUNT_DISABLED for a non-ACTIVE one. In the handler, call it alongside the roles and must-change reads in Promise.all, answer the same 401 { error: 'Unauthorized' } for any AuthError, and rethrow anything else.
  • #586, #604 - The sidebar, if you port the new one (the user menu from @resetshop/ui/user-menu/user-menu, with no collapse): you must remove your uses of setSidebarCollapsed(), isSidebarCollapsed(), [collapsed] bindings and the Ctrl+B / Cmd+B shortcut. In end-to-end tests, open the menu with DashboardPage.userMenuTrigger and userMenuItem(name), and drop collapseButton / expandButton.
  • #482 - Your copy of dashboard.routes.ts: you should make pages share one store instance per section. Nest users and users/:id as children of a users parent route (title: 'DASHBOARD.USERS.NAV') that holds providers: [provideUsers(), provideRoles(), UsersStore, RolesStore, provideToast()], move the authorization children's providers onto the authorization parent, and remove the providers each page registered for itself.
  • #589 - Your copies of create-role-drawer.ts, edit-role-drawer.ts and create-user-drawer.ts, and any form of your own that checks form().errors().length === 0: you should use form().valid() instead. errors() lists only the form's own errors, not its fields', so the submit button stays enabled on invalid input.

Behaviour that changes with no action needed:

  • #534 - Angular 22 changes defaults that also apply to your app: provideClientHydration() enables incremental hydration, HttpClient uses the fetch backend, and child routes inherit all parent route params (paramsInheritanceStrategy: 'always'). Opt out with withNoIncrementalHydration(), withXhr() or withRouterConfig({ paramsInheritanceStrategy: 'emptyOnly' }) only if your app depends on the previous behaviour.
  • #453 - The reference app's PATCH /api/users/{id} answers 400 instead of 500 for unknown or non-removable role ids. Your app keeps the old behaviour unless you copy the fix (see above).
  • #486 - docs/release-process.md §6 specifies a protection ruleset for v* tags. Rulesets are not inherited by forks or mirrors, so create it in your repository if you want protected tags. The unused release block is removed from nx.json; if you run nx release, keep your own.

Full changes

See every merged pull request in v1.1.0.

Changes

Toolchain and runtime

  • #534 - Upgrades the starter to Nx 23.1, Angular 22 and TypeScript 6.
  • #560 - Enables TypeScript strict mode across the workspace.
  • #551 - Relies on Angular 22's default OnPush change detection and enforces it with a lint rule.
  • #553 - Moves @ngrx/signals from the 22.0.0-beta.0 pin to the stable 22.0.0.
  • #535 - Refreshes Node.js to the 24.20.0 LTS and adds an install-script allowlist.
  • #536 - Documents the Node.js support policy for forks.
  • #559 - Pins Prettier to one exact version and absorbs the one-time reformat.
  • #568 - Fixes the @swc/helpers version conflict so npm ls reports no errors.

Account and navigation

  • #454 - Adds the self-service Account page and makes /me read the account from the database.
  • #586 - Replaces the sidebar Logout button with a user menu for Account, Settings and Log out.
  • #604 - Removes the collapsible desktop sidebar.

User and role administration

  • #453 - Edits a user in one drawer, confirmed as a before → after list and saved in one transaction.
  • #589 - Stops the user and role drawers from submitting an invalid form.
  • #572 - Shows permission descriptions in the selected language.
  • #601 - Builds the row actions menu on the shared Menu component.

API and authorization

  • #556 - Adds a single accessor for reading the signed-in user in request handlers.
  • #555 - Keeps each route's own 403 description in the generated OpenAPI document.

Testing, CI and release

  • #585 - Makes the integration suite fail when its run fails.
  • #590 - Makes every code generator run as an ES module.
  • #557 - Stops the shared Playwright fixture from hanging at teardown.
  • #583 - Re-runs the upstream guard checks when a stacked pull request is retargeted.
  • #486 - Specifies the version-tag protection rule and removes the unused nx release configuration.

Documentation

  • #482 - Gathers the Angular dependency-injection guidance into one reference.
  • #575 - Documents delivering environment variables from the Zed editor.
  • #558 - Fixes the Cookie Security table in the authentication guide.

What's Changed

Merged PRs

Full Changelog: v1.0.2...v1.1.0