Skip to content

Releases: ResetShop/angular-nx-standalone-starter

v1.1.0

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 shou...
Read more

v1.0.2

Choose a tag to compare

@github-actions github-actions released this 24 Jul 21:23
5b40072

Version 1.0.2 gives private forks a one-command way to take upstream updates, moves the starter to a develop/main branch model with an automated release pipeline, and makes Node.js 24 the only supported runtime. It also removes Nx Cloud, adds and tightens several repository-wide guards, and records the Railway deployment in the repository. Several of these changes ask something of every fork: read Fork migration below before merging.

The first area is the fork and release workflow. A client project that must stay private cannot be a GitHub fork of a public repository, so it lives as a private mirror. Run inside a mirror, npm run upstream:pull fetches upstream, prints the CHANGELOG changes since the last merge, merges upstream/main, resolves lockfile-only conflicts and finishes with npm run ci:verify; the separate fork-init tool creates the mirror in the first place ([#540]). Upstream now develops on develop and reaches main only through an automated release pull request, so every advance of main is a tagged release with its own CHANGELOG section. A new /release-workflow skill prepares each release by promoting the ## [Unreleased] section to the new version and bumping package.json, and two workflows open the release pull request and publish the tag and GitHub Release ([#539]). Structured issue forms and a refreshed pull request template make new issues easier to triage ([#504]).

The second is toolchain and CI. Node.js 24 LTS is now the only supported runtime: engines.node is ^24.18.0, and a new .nvmrc pins 24.18.0 ([#537]). Nx Cloud is removed and tasks use the local Nx cache only, so a stray access token can no longer fail CI or report a private mirror's runs to the starter's public Nx Cloud workspace ([#542]). The repository-wide guards now run as one Nx check target, both locally and in a new remote CI job, so a push that skipped the pre-commit hook no longer skips them ([#527]). One of those guards is new: code comments must explain the code as it is now, and an issue or pull request number in a comment fails the build ([#499]). The lint rule against direct process.env access now allows eight named files instead of three whole directories, and the integration tests read their settings through the typed environment schemas ([#501]).

The third is styling. Components whose host styling is a fixed set of utilities now declare it with host: { class } instead of :host { @apply … } ([#489]). Component stylesheets no longer carry the @reference "#tailwind-theme" line: a PostCSS plugin adds it at build time to every stylesheet that uses @apply, and the ui-component generator stops writing it ([#523]). The dashboard header and the health page now use the theme's semantic tokens instead of hardcoded grays, so both render correctly in dark mode ([#520], [#513]).

The fourth is deployment. A root railway.json records the Railway build command, start command and health check in the repository, so a deploy that cannot reach its database no longer replaces a healthy one ([#514]). Storybook can be served from a second Railway service by a small static server that uses only Node built-ins ([#547]). Vercel-specific wording and a dead Speed Insights stub are removed from the code and documentation ([#545]). A deploy that restarted in a loop on its startup database check turned out to have a connection configuration problem in the deploy environment; correcting that configuration resolved it, with no code change ([#511]).

Fork migration

Every fork:

  • [#537] - Use Node.js 24.18.0 or later (nvm use reads the new .nvmrc), move the Node version pins in your own CI workflows and deployment platform to 24.18, then run npm install to pick up @types/node ^24.13.3. engines.node is now ^24.18.0: an older runtime gets an engines warning from npm, and fails the install if your .npmrc sets engine-strict=true.
  • [#542] - Delete the NX_CLOUD_ACCESS_TOKEN secret from your repository's Actions secrets and unset the token in your shells: nx.json no longer has upstream's nxCloudId, and .github/workflows/ci.yml sets NX_NO_CLOUD: 'true' and uses the local Nx cache only. If your fork uses its own Nx Cloud workspace, keep your own nxCloudId when you resolve the nx.json merge and remove NX_NO_CLOUD from your ci.yml.
  • [#539] - When you resolve the merge, keep nx.json defaultBase pointing at your own primary branch (upstream's is now "develop"), and point the new push: branches: [develop] trigger in .github/workflows/ci.yml at your primary branch or remove it. Keep merging from upstream/main only; develop is upstream's integration branch.
  • [#501] - Move direct process.env reads out of your app's code. npm run lint now allows them, in every app under apps/, only in src/api/config/env-utils.ts, env-utils.spec.ts, runtime.ts, runtime.spec.ts, src/test-setup.ts, src/api/integration/setup/global-setup.ts, src/api/integration/setup/env-helpers.ts and src/db/seed.ts. Copy the reference app's versions of src/api/config/runtime.ts, runtime.spec.ts, env-utils.spec.ts and db.env.spec.ts, of env-helpers.ts, auth-helpers.ts, db-helpers.ts and global-setup.ts in src/api/integration/setup/, of src/api/integration/auth/login.integration.spec.ts and of src/db/seed.ts into your app. Route any other read through the typed <domain>Env proxy (seed<Domain>Env in tests), or add a justified explicit entry to the allowlist in eslint.config.mjs.
  • [#499] - Rewrite every issue or pull request number (#<n>, any length) in the // and /* … */ comments of .ts and generator .ts.template files under apps/ and packages/ as a present-state explanation, or move a durable cross-reference to CHANGELOG.md or docs/. scripts/check-no-issue-refs-in-comments.mjs now fails the pre-commit hook, npm run ci and npm run ci:verify; run node scripts/check-no-issue-refs-in-comments.mjs to list the offending lines.
  • [#499], [#527] - Expect the new check job in .github/workflows/ci.yml to fail your first remote CI run if your tree contains a .env* file, an issue number in a code comment, or a file that is not Prettier-formatted; remote CI did not run these guards before. Run npm run format and the two scripts/check-*.mjs guards before pushing the merge.
  • [#514] - If you deploy on Railway, edit the new root railway.json before your next deploy: Railway config-as-code overrides your service's settings, and the file builds and starts the reference app (buildCommand: npm run build, startCommand: node dist/reference-app/server/server.mjs, healthcheckPath: /api/health/v1). Make it build your app, start dist/<your-app>/server/server.mjs and check a health path your app serves, or delete the file.

If your fork changed or reuses any of the following:

  • [#523] - Component stylesheets: you may delete @reference "#tailwind-theme" from your components. The new root PostCSS plugin postcss-inject-tailwind-reference.js, registered first in .postcssrc.json, adds it at build time to every stylesheet that uses @apply and declares no @reference of its own, and the ui-component generator no longer emits it. If you @import a stylesheet of your own into tailwind.config.css and it uses @apply without its own @reference "tailwindcss", add its path suffix to themeEntrySuffixes in postcss-inject-tailwind-reference.js; a missed file shows up as a Tailwind circular-reference build error.
  • [#523] - Your global stylesheet: if the stylesheet that @imports tailwind.config.css (for example apps/<your-app>/src/styles.css) also uses @apply, move those rules into a separate stylesheet or write them as plain CSS. The plugin injects @reference "#tailwind-theme" into any stylesheet that uses @apply, and in the one that imports the theme that drops the --font-sans and --font-mono tokens, so text falls back to Tailwind's default fonts.
  • [#513], [#520] - The health page or the dashboard shell: apply the dark-mode fixes to your copies. In pages/dashboard/pages/health/health.ts, change border-1 border-gray-200 to border border-border and bg-gray-100 to bg-muted. In dashboard.ts, change the <header appHeader> classes border-b-1 border-gray-200 dark:border-white/10 dark:bg-black/95 to border-b border-border bg-background. In the Header component's host classes, change dark:text-gray-50 to text-foreground.
  • [#527] - The ci / ci:verify scripts in the root package.json: move any guard you added there into the commands array of the new root check target (nx.targets.check) instead of an && chain, then take upstream's ci / ci:verify, which start with nx run-many -t check stylelint lint typecheck.

Behaviour that changes with no action needed:

  • [#539] - Upstream now integrates on develop and releases to main only through an automated release pull request, so each advance of upstream/main is one tagged, documented release. The prepare-release-pr.yml and release.yml workflows run only in the upstream repository. Upstream also relies on main branch protection and on Railway deploying the explicit main branch; forks do not inherit these settings, so create them if you want the same guarantee.
  • [#504], [#539] - The new issue templates apply labels your repository may not have: 🦟 bug, 🏎️ enhancement, 📝 documentation, 🛠️ tooling, 🎨 ui-ux, 💼 management, ✍️ draft, 📦 epic, 🧩 initiative and 🚀 release. GitHub skips a missing label, so create these labels, or change the templates' labels: arrays, only if you want them applied.
  • [#504] - Claude Code no longer adds co-author or attribution trailers to commits and pull requests: the shared .claude/settings.json sets includeCoAuthoredBy: false and gitAttribution: false. Override them in your .claude/settings.local.json if you want attribution.

Full changes...

Read more

v1.0.1

Choose a tag to compare

@rolivencia rolivencia released this 19 Jun 19:51
565add0

Version 1.0.1 prepares the starter for going public: it adopts the Apache-2.0 license, adds community-health files, removes hard-coded credentials, and cleans up the environment configuration and the integration-test teardown (#488). Several of these changes ask something of every fork, so read Fork migration below before merging. The v1.0.1 tag and GitHub Release were published before the package.json version bump and this section; the section was written afterwards.

The first area is public readiness. The starter is now licensed under Apache-2.0, with LICENSE.md, NOTICE.md and a license field in every package.json (#490). CONTRIBUTING.md, SECURITY.md and CODE_OF_CONDUCT.md state the contribution policy: issues are welcome from anyone, pull requests come from ResetShop members, and vulnerabilities are reported privately. A workflow that runs only on the upstream repository closes pull requests from outside the organization (#493). A CODEOWNERS file routes reviews to the maintainers (#488). A personal email and a stray log file are removed from the tree, and the root package.json gains project metadata (#494). The README's setup guide is corrected and now points to files and symbols instead of line numbers, so it no longer goes stale with each edit (#492).

The second is credentials and setup. The database seed no longer creates an administrator from a password hash committed to the repository. It reads SEED_ADMIN_EMAIL and SEED_ADMIN_PASSWORD, prompts for them in a terminal, or stops with a clear error. npm install no longer runs migrations and the seed, so an install no longer fails on a machine without a database (#491). CI reads the integration-test admin password from a masked Secret instead of a Variable that public workflow logs could show (#508).

The third is backend configuration. The authentication environment schema is split into token, password and security schemas, and CRON_SECRET moves to the cron schema. A process that needs only the password cost or the lockout settings no longer exits when the PASETO keys are unset, and the variable names do not change (#497). The seed and permission-sync scripts use the same database connector as the API, so a dropped idle connection no longer crashes them (#502).

The fourth is integration testing. The suite now closes its database pool, always stops the embedded Postgres and removes its temporary directories, so it no longer leaves orphaned node processes holding memory, and CI's peak memory is bounded (#517).

Fork migration

Every fork:

  • #491 - After npm install, run npm run drizzle:push-migrations and then npm run drizzle:seed yourself (with PG_CONNECTION_STRING set), and add both steps to any CI, Docker or deployment pipeline that relied on npm install to migrate and seed. postinstall now runs only node scripts/setup-skills.mjs.
  • #491 - Wherever npm run drizzle:seed runs without a terminal (CI, Docker, deployment), set SEED_ADMIN_EMAIL and SEED_ADMIN_PASSWORD (12–128 characters); SEED_ADMIN_FIRST_NAME and SEED_ADMIN_LAST_NAME are optional and default to Admin and User. With neither the variables nor a terminal, the seed exits with an error; in a terminal it prompts for them, with the password masked.
  • #508 - In your repository's Settings → Secrets and variables → Actions, create INTEGRATION_TEST_ADMIN_PASSWORD as a Secret and delete the Variable of the same name. The test-integration and e2e jobs in ci.yml now read secrets.INTEGRATION_TEST_ADMIN_PASSWORD and fail without it. PG_TEST_CONNECTION_STRING stays a Variable.
  • #488, #493 - Replace the owners in .github/CODEOWNERS (@juanblas09 @rolivencia) with your own maintainers, or delete the file. Repoint or delete the two links in .github/ISSUE_TEMPLATE/config.yml: they lead to the upstream repository's security advisories and CONTRIBUTING.md.
  • #493, #494 - If your repository is public, replace or delete CONTRIBUTING.md, SECURITY.md and CODE_OF_CONDUCT.md, and replace the description, author, repository, homepage and bugs fields of the root package.json: they describe ResetShop and the upstream repository, and arrive on merge.
  • #517 - Copy the integration-test teardown into apps/<your-app>: src/api/integration/setup/integration-setup.ts, global-setup.ts and embedded-pg-test-db.ts; the new DependencyContainer.teardownDb() in src/api/container/container.ts, which integration-setup.ts calls; teardownTimeout: 30_000 in vitest.integration.config.ts; and pool: 'forks' with maxWorkers: Number(process.env['VITEST_MAX_WORKERS']) || 2 in vitest.config.ts. Without them, integration workers can linger as orphaned node processes, and on Windows the embedded-Postgres temporary directories leak.

If your fork changed or reuses any of the following:

  • #497 - @config/auth.env (authEnv, parseAuthEnv, seedAuthEnv, resetAuthEnv, AuthEnv) is removed. Import PASETO_* and COOKIE_SECURE from @config/token.env (tokenEnv, TokenEnv, seedTokenEnv), BCRYPT_COST from @config/password.env (passwordEnv), AUTH_MAX_FAILED_ATTEMPTS, AUTH_LOCKOUT_DURATION and AUTH_CHANGE_PASSWORD_RATE_LIMIT_* from @config/security.env (securityEnv), and CRON_SECRET from @config/cron.env (cronEnv). createAuthConfig now takes (tokenSource, securitySource, cronSource), and createPasetoConfig takes a TokenEnv.
  • #502 - Standalone database scripts that build new Pool() and drizzle(pool) by hand: use createDrizzlePgConnector() and the DrizzleTransaction type from src/api/helpers/drizzle-postgres-connector.ts. Create the connector inside the entry function, and close it with db.$client.end() in a finally that runs before process.exit.
  • #491 - Your own copy of the seed script: copy src/db/seed.ts, the new src/db/seed-admin-credentials.ts and the four SEED_ADMIN_* fields of src/api/config/app.env.ts into apps/<your-app>, so it stops creating an administrator from a password hash committed to the repository.

Behaviour that changes with no action needed:

  • #497 - Environment variable names and defaults are unchanged. A process that reads only BCRYPT_COST, the lockout settings or CRON_SECRET no longer exits when PASETO_SECRET_KEY or PASETO_ISSUER is unset.
  • #490 - The root package.json license is now "Apache-2.0", and LICENSE.md and NOTICE.md arrive on merge. They cover the starter code; the license of your own code is yours to set.
  • #491 - The seed stays idempotent by email and never overwrites existing rows. On a database seeded before 1.0.1, running it with a different SEED_ADMIN_EMAIL creates a second administrator and keeps admin@sistema.com.
  • #491 - The process.env lint allowlist now also covers apps/**/src/db/**/*.ts.
  • #517 - npm run ci and npm run ci:verify run the test and build batch with --maxParallel=3, and the reference app's unit tests use at most 2 workers. Set VITEST_MAX_WORKERS to raise the limit.

Full changes

See every merged pull request in v1.0.1.

Changes

Public readiness

  • #490 - Adopts the Apache-2.0 license with LICENSE.md, NOTICE.md and a license field in every package.json.
  • #493 - Adds the contribution, security and conduct policies, and closes pull requests from outside the ResetShop organization.
  • #488 - Adds a CODEOWNERS file that routes reviews to the maintainers.
  • #494 - Removes a personal email and a committed log file, and adds project metadata to the root package.json.
  • #492 - Corrects the README setup guide and replaces its line-number citations with durable file and symbol references.

Credentials and setup

  • #491 - Takes the seed administrator's credentials from environment variables or a prompt, and stops running migrations and the seed on npm install.
  • #508 - Reads the integration-test admin password in CI from a masked Secret.

Backend configuration

  • #497 - Splits the authentication environment schema into token, password and security schemas, and moves CRON_SECRET to the cron schema.
  • #502 - Moves the seed and permission-sync scripts onto the shared database connector.

Integration testing

  • #517 - Closes the database pool, stops the embedded Postgres and removes its temporary directories at the end of the integration suite, and bounds CI memory.

What's Changed

Read more

v1.0.0

Choose a tag to compare

@rolivencia rolivencia released this 10 Jun 19:18
3c7fbf4

Version 1.0.0 is the first release of the starter under the fork-distribution model, and it consolidates everything merged since 1.0.0-beta.3. It replaces .env files with a validated environment contract, completes the password flows, adds a user detail page, a public landing page and end-to-end coverage of the reference app, and makes the dashboard usable on phones. Many of these changes ask something of every fork: read Fork migration below before merging.

The first area is environment configuration. Every backend variable is now declared in one of six Zod-validated schemas under src/api/config/ and read through a <domain>Env object such as dbEnv.PG_CONNECTION_STRING; a missing or invalid value stops the process at start-up with a clear message ([#354]). The work landed in steps: configuration is injected where tests need other values ([#440]), every production read moves to the new objects ([#441]), the database scripts and drizzle-kit read them too ([#442]), and the old validation code is removed ([#443]). A lint rule now rejects any other process.env read ([#444]), and a guard fails the commit hook and npm run ci when a .env* file is in the tree ([#354]). @resetshop/hono-core no longer carries app-specific configuration ([#258]). The token-cleanup interval is now a duration string such as 24h, like the other time settings ([#259]), and the production build no longer fails because a rate limiter read the configuration too early ([#450]).

The second is authentication. Users flagged to change their password are sent to a change-password page before they reach the dashboard ([#388]). A user who forgot their password can request a single-use reset link by email ([#428]). The request answers the same way, and just as fast, whether or not the account exists ([#433]), and its confirmation no longer lingers when the user comes back to the page ([#434]). The login and reset pages show a countdown while an account is locked or requests are rate-limited ([#436]). The login response now carries the user's roles and permissions, so permission-gated navigation is right from the first page ([#322]). Behind these, AuthService is split into focused services ([#420]) and password hashing sits behind one module ([#385]). Generating a temporary password no longer fails in development ([#371]) or makes a test fail at random ([#429]).

The third is user and role administration. Admins can reset a user's password; the new temporary password is emailed, never returned or logged ([#214]). Editing a user moves from a drawer to a detail page at /dashboard/users/:id, which stops admins from removing their own admin role ([#212]). The user API moves to plural paths, /api/users*, like its siblings ([#455]). Creating a user writes the identity, the password and the roles in one transaction, so a failure leaves nothing half-created ([#387]). Row actions move into a ⋮ menu ([#401]), and actions an admin cannot take on their own account are hidden ([#389]). The Spanish copy of the welcome email and the interface is corrected ([#251]).

The fourth is navigation and feedback. The root path / now serves a public, server-rendered landing page instead of redirecting to the login page ([#19]), and its unreachable "Go to dashboard" link is removed ([#468]). The placeholder Welcome page is removed ([#458]). A user denied a page sees a toast that says why, and a user with no permissions sees an explanation instead of an empty dashboard ([#323]). The deny toast now appears exactly once ([#471]), the 403 toast appears on every page ([#480]), and the sidebar no longer flickers on logout ([#325]).

The fifth is responsive layout. The dashboard now works on phones. Form inputs no longer trigger the iOS zoom and touch targets reach 44 px ([#338]), the auth pages fill the screen ([#339]), the sidebar behaves as an overlay ([#340]), and data tables switch to cards on narrow screens, with an optional table/cards toggle ([#341]). Pagination ([#342], [#366]), page layout and breadcrumbs ([#343], [#368]), and drawers, dialogs, toasts and dropdowns ([#344]) are sized for small screens. Shared packages/ui components show English text when no translations are loaded, as in Storybook ([#363]), and the reason ToastNotification has no unit test is documented ([#369]).

The sixth is end-to-end testing. The reference app gains a Playwright suite that runs against a seeded test database ([#261]). It covers authentication ([#459]), the landing page ([#460]), the dashboard shell and permission filtering ([#461]), users ([#462]), roles ([#463]), permissions ([#464]), theme and language ([#465]) and the health page ([#466]). It runs with npm run test:e2e and in its own CI job, outside npm run ci.

The seventh is toolchain and CI. Nx moves to 22.7.5 and Angular to 21.2 ([#424]). Integration tests no longer need Docker: they start an embedded Postgres 17 when no test database is configured ([#321]). npm run ci now checks formatting first ([#374]), and npm run ci:verify runs the same checks through the Nx cache for repeated runs ([#404]). CI uses the Nx Cloud remote cache ([#406]), reads its test-database settings from repository Variables, and runs test, lint and a new type-check job over every project ([#319]). Bugs left over from the monorepo restructure, including stale README paths, are fixed ([#313], [#315]).

The last is generators, agents and documentation. A new ui-component generator scaffolds shared components, and a lint rule requires every Storybook story to show its source ([#348]). The drizzle-schema and page generators write kebab-case paths ([#330], [#331]), every generator has unit tests ([#317]), and the generators are documented for people and agents ([#333]). The /issue-workflow skill takes an issue from branch to pull request, and npm install offers to install the Angular agent skill ([#349]). The agents load their references in parallel and only as needed ([#407], [#410]), run independent advisors in parallel ([#408]), verify with the cached CI ([#405]), and review with a new maintainability lens ([#409]). The domain-model reference gains strategic DDD patterns and corrected examples ([#207], [#380]), and the Bruno error cases use cookie authentication ([#384]).

Fork migration

Every fork:

  • [#354], [#441], [#444] - Copy apps/reference-app/src/api/config/ (the db, auth, email, http, app and cron *.env.ts files and env-utils.ts) into your app, add "@config/*": ["src/api/config/*"] to its tsconfig.json and tsconfig.spec.json, and add '@config': '/src/api/config' to the resolve.alias of its vitest.config.ts. Then replace every process.env read outside src/api/config/, src/test-setup.ts and src/api/integration/ with the matching <domain>Env.<VAR>, for example httpEnv.CORS_ORIGIN, httpEnv.CORS_MAX_AGE and httpEnv.PORT in server.ts. npm run lint now fails on every such read, not only on new ones.
  • [#258], [#441], [#443] - @resetshop/hono-core no longer exports environment, isServerless or EnvironmentConfig, and your app imports them in cron-jobs.ts, refresh-token.repository.ts, helpers/drizzle-postgres-connector.ts, db/seed.ts and db/sync-permissions.ts. Import isServerless from @config/http.env, replace environment.database.pg.connectionString with dbEnv.PG_CONNECTION_STRING (@config/db.env) and environment.basePath with httpEnv.BASE_HREF (@config/http.env), and use DbEnv, HttpEnv or AuthEnv where you typed EnvironmentConfig.
  • [#354] - Move every .env* file out of the repository root and out of apps/<your-app>/: the pre-commit hook, npm run ci and npm run ci:verify fail while one exists. Deliver values with an env file outside the repository and Node's --env-file, an IDE run configuration, a shell export or direnv, as docs/environment-variables.md describes. That document also lists every variable, replacing the deleted .env.example.
  • [#259] - Rename TOKEN_CLEANUP_INTERVAL_MS to TOKEN_CLEANUP_INTERVAL and give it a duration string (86400000 becomes 24h) wherever you set it (your env file outside the repository, CI variables, deployment). If only the old name is set, the cleanup job silently uses the 24-hour default.
  • [#428] - Run npm run drizzle:push-migrations against each database (npm install also runs it) to create the new password_reset_token table.
  • [#319], [#459] - In your repository's Settings → Secrets and variables → Actions → Variables, add PG_TEST_CONNECTION_STRING = postgresql://postgres:postgres@localhost:5432/test_db and INTEGRATION_TEST_ADMIN_PASSWORD = any test-only password. The test-integration and e2e jobs in ci.yml read them as vars.*. Then delete the Secrets of the same names.
  • [#406] - In nx.json, replace nxCloudId with your own Nx Cloud workspace and add its token, copied verbatim from the dashboard, as the NX_CLOUD_ACCESS_TOKEN Actions secret, or leave the secret unset to use only the local cache. A token that does not match the workspace makes the cacheable CI jobs fail with 401.
  • [#325] - In your app's app.config.ts, replace the inline NAVIGATION_PERMISSION_CHECK provider with provideAuth(withNavigationPermissionCheck()), copying withNavigationPermissionCheck() from the reference app's providers/auth/auth.provider.ts. The inline provider makes the sidebar flicker on logout.
  • [#348] - Add parameters: { docs: { canvas: { sourceState: 'shown' } } } to the default export of every *.stories.ts in your app; npm run lint fails on stories without it.
  • [#424] - In your app's vitest.config.ts, set server.fs.allow to [searchForWorkspaceRoot(process.cwd())], imported from vite. Under Angular 21.2, specs that render packages/ui components otherwise fail with Denied ID …?raw.
  • [#321] - In your app's project.json, remove node scripts/skip-if-no-db.mjs && from th...
Read more