Notable changes to the kit, newest first.
2026-05-27
- Dependencies updated to latest for the v10 release — .NET Aspire 13.3.5 (Hosting packages + AppHost SDK), Finbuckle.MultiTenant 10.1.0, MailKit/MimeKit 4.17.0, AWSSDK.S3 4.0.23.4, Scalar.AspNetCore 2.14.14, and SonarAnalyzer 10.27. Builds clean with warnings-as-errors and the full test suite (unit + Testcontainers integration) stays green.
- Template packaging fixes — scaffolded Dockerfiles and dev-machine packing —
dotnet new fsh/fsh newpacked extensionless files (everyDockerfile) to a doubled nested path, so scaffolded projects got aDockerfiledirectory instead of a file anddeploy/docker(docker compose up) was broken. Also made the IDE-cache excludes (.vs/.idea/.vscode) recursive sodotnet packno longer fails (or bundles IDE junk) when packing the template on a developer machine. Scaffolded output now builds and self-hosts cleanly. - Scaffolded apps log in out of the box, get isolated data volumes, and start on
main— threefsh new/ Aspire DX fixes: the AppHost migrator now runsapply --seed, so the root admin (admin@root.com) is seeded automatically — previously a freshly-run app came up with an empty user table and nobody could log in; each app’s Docker volumes are namespaced by app name (e.g.myapp-postgres-data) instead of sharing a literalpostgres-data, so two FSH-based apps on one machine no longer clobber each other’s database; andfsh newinitializes git onmainrather than following the machine’s git default (oftenmaster). - Demo logins (
acme/globex) work on a fresh Aspire launch — the dashboard’s demo-login panel advertised accounts that were never seeded: the AppHost migrator ran onlyapply --seed(which seeds the root admin), while theacme/globexdemo tenants are created by the dev-onlyseed-demoverb. Aspire now runsseed-demoas a dedicated demo-seeder step after migration — soadmin@acme.com/Password123!works the moment the dashboard loads. Also fixes the migrator crashing at startup in Development (its trimmed service graph tripped the DI container’s build-time validation) and corrects the verb’s environment gate toDOTNET_ENVIRONMENT(the migrator is a generic-host console app, not a web host). - Aspire resource names are namespaced per app — the AppHost’s resource/container names (API, migrator, demo-seeder, admin, dashboard) now derive from the app’s namespace, like the Docker volume names already did. A scaffolded
Acme.Storeshowsacme-store-apietc. instead of the kit’s literalfsh-*, so two FSH-based apps on one machine don’t collide. (This repo resolves tofsh-starter-*; thepostgres/redis/minioinfra and thefsh-dbdatabase keep stable names.) - Stale sessions resolve cleanly instead of erroring — both React apps (admin + dashboard) treated an expired token left in
localStorageas signed-in, firing protected requests that 401’d in a loop (SecurityTokenExpiredException). On boot they now attempt one silent token refresh: success restores the session, failure routes to/login. Long-lived sessions still refresh transparently mid-use. - CI split into path-scoped backend + frontend pipelines — the single
ci.ymlis replaced bybackend.yml(runs only onsrc/**changes) andfrontend.yml(runs only onclients/**), so a client-only change never builds or tests the API, and vice versa. The SDK is pinned to the .NET 10 GA release via a rootglobal.json(no more preview channel). Unit and integration tests each run once, and the coverage gate merges their results instead of re-running the whole solution. The React apps get real CI for the first time — ESLint,tsc/Vite build, and the Playwright E2E suites (admin + dashboard) on Node 22. Branch protection requires the always-resolvingBackend CI/Frontend CIgate jobs. See CI/CD. - Consolidated to a single
mainbranch — the repo now uses one long-lived default branch,main; thedevelopbranch is retired. Branch from and targetmain; stable releases are cut fromv*tags. See Contributing. - Removed the redundant root
docker-compose.yml— local development is covered by .NET Aspire and production bydeploy/docker/, so the overlapping root compose file (added 2026-05-24) was dropped. - Missing required request parameters now return
400, not500— calling a tenant-scoped endpoint without thetenantheader (and any other endpoint missing a required header/route/query parameter, or sent with an unreadable/oversized body) raised an ASP.NETBadHttpRequestExceptionthat the global exception handler rendered as a generic500 Internal Server Error. The handler now honours the framework’s own status code, so these surface as a proper400 Bad Request(or413, etc.) with aProblemDetailsbody. Fixes #1245.
2026-05-24
- Cache/store engine switched from Redis to Valkey 8 — the BSD-licensed, Linux Foundation fork of Redis. It’s a drop-in over the Redis protocol (RESP): the
StackExchange.Redisclient and everyCachingOptions:Redisconfig key are unchanged. Applies to .NET Aspire, both Docker Compose files, and the integration-test container. - RedisInsight cache browser is now auto-wired in Aspire, connected to the Valkey instance so you can inspect cache keys, TTLs, and the SignalR backplane in local dev with no manual configuration.
- Docker Compose hardening — the production
deploy/dockerstack now provisions the MinIO bucket before the API starts (fixes a first-uploadNoSuchBucket); the dev rootdocker-compose.ymlnow runs the DB migrator (apply --seed) so the API never boots against an empty schema.