diff --git a/src/content/docs/changelog/index.mdx b/src/content/docs/changelog/index.mdx index 41babd1c..cf4928c7 100644 --- a/src/content/docs/changelog/index.mdx +++ b/src/content/docs/changelog/index.mdx @@ -13,6 +13,7 @@ Notable changes to the kit, newest first. ## 2026-09-25 +- **Dependencies: .NET Aspire 13.5.4 and every NuGet package to latest.** The AppHost SDK and `Aspire.Hosting.*` move 13.4.0 → 13.5.4 together (mixing 13.4 and 13.5 packages fails at runtime). The .NET 10 platform packages (ASP.NET Core, EF Core, Extensions, SignalR) go 10.0.8 → 10.0.12, OpenTelemetry 1.15 → 1.19, Asp.Versioning 10.2, Npgsql EF 10.0.3, Scalar 2.17, QuestPDF 2026.9, Hangfire 1.8.25, MailKit/MimeKit 4.18, Testcontainers 4.15, and the rest to latest stable. Three majors: **StackExchange.Redis 3.3** (the same API as 2.13.17 on a rewritten IO core, now **RESP3 by default** - Valkey and ElastiCache both speak it; `Execute("FLUSHALL")`-style admin commands now need `AllowAdmin`), **NSubstitute 6** and **xunit.runner.visualstudio 4** (still runs xUnit v2). `Microsoft.OpenApi` and `MessagePack` stay on their 2.x lines on purpose. The new SonarAnalyzer adds **S8969** (redundant null-forgiving `!`), which is fatal under warnings-as-errors: the kit's own code is cleaned up, but **if you've added code, expect S8969 build errors after pulling** - delete the flagged `!`, and the compiler will tell you if one was actually needed. Asp.Versioning 10.2's `AV0029`/`AV0030` advisories and Aspire's `ASPIRE010` (CLI bundle) are suppressed; the kit keeps one OpenAPI document per version and runs Aspire via `dotnet run`. On the first launch Aspire 13.5 recreates the persistent Postgres and Valkey containers; data volumes are kept and the Postgres image stays on 18, so no wipe is needed. See [#1396](https://github.com/fullstackhero/dotnet-starter-kit/pull/1396). - **Identity: password-reset and e-mail-confirmation links now resolve the correct front-end per request (breaking for Production config).** **Upgrade note - set `FrontendOptions:DefaultOrigin` before you upgrade, or Production won't boot.** In `Production` the API now refuses to start when `FrontendOptions:DefaultOrigin` is missing or not an absolute `http(s)` URL (`Missing required configuration 'FrontendOptions:DefaultOrigin' in Production…`), alongside the existing fail-fast on `DatabaseOptions:ConnectionString`, `CachingOptions:Redis` and `JwtOptions:SigningKey`. Point it at your tenant dashboard. The shipped deployment paths set it for you: `deploy/docker/docker-compose.yml` derives it from `FSH_DASHBOARD_URL`, and the AWS Terraform stack from `dashboard_url` (falling back to `admin_url`) - so the action is for deployments that roll their own hosting. The DbMigrator is unaffected. The reset link was built from a single configured `OriginOptions.OriginUrl` - which points at the API and ships empty in production, so `forgot-password` threw `Origin URL is not configured` - and the confirmation link was built from the request host and pointed straight at the API's `GET /confirm-email` route. Neither could target the right SPA when the kit serves more than one front-end (the admin console and the tenant dashboard on different origins). Link resolution now goes through a dedicated **`FrontendOptions`** (`AllowedOrigins` + `DefaultOrigin`), kept separate from CORS. **Self-service** flows (`forgot-password`, `self-register`) build the link from the request `Origin` header, validated against `FrontendOptions:AllowedOrigins` and returned as the canonical entry - so each user gets a link back to the app they started from; because forgot-password is anonymous a forged or unlisted `Origin` is rejected with **`400`** once the list is non-empty, and a request with no `Origin` (curl, mobile, server-to-server) falls back to `DefaultOrigin` - as does every request while the list is empty, since there is then nothing to validate against. **Operator-driven** flows (`register`, `resend-confirmation-email`) target `DefaultOrigin` - the recipient's app - so a tenant user provisioned from the admin console gets a link into the tenant app, not the console. The confirmation e-mail now lands on the SPA `/confirm-email` page (which then calls the API) instead of the raw API route. Also list every SPA origin in `FrontendOptions:AllowedOrigins`; both settings ship empty in `appsettings.Production.json`, and the shipped deploys fill the list from the same SPA URLs (`FSH_ADMIN_URL` / `FSH_DASHBOARD_URL`, or the Terraform site URLs - `api_extra_cors_origins` deliberately stays off it). Outside Production the host still boots without `DefaultOrigin` and logs one startup `Error`, but link building has no fallback, so those flows answer `500` until it is set. The two fallback tiers an earlier revision carried were removed on review - the request host is caller-supplied, so a password-reset link built from it delivers a working token to a domain the attacker named, and the API's own origin returns `404` for the SPA pages these links now target. `CorsOptions:AllowedOrigins` and `OriginOptions:OriginUrl` keep their own roles (browser CORS; the API's public base for avatar URLs). See [#1377](https://github.com/fullstackhero/dotnet-starter-kit/pull/1377). - **Object storage: MinIO replaced with RustFS for local dev, Docker Compose, and integration tests (breaking for docker-compose).** The `minio/minio` and `minio/mc` images were removed from Docker Hub and `quay.io/minio` now refuses anonymous pulls, so fresh clones could no longer bring up the stack. The kit now ships [RustFS](https://rustfs.com) (`rustfs/rustfs:1.0.0`, S3-compatible, Apache-2.0) on the same ports - **9000** (S3 API) and **9001** (web console) - with bucket bootstrap done by a pinned `amazon/aws-cli:2.37.3` init container. Nothing changes in application code: the API still talks to it through the `s3` storage provider with `ForcePathStyle`, and production can keep pointing at AWS S3 or any other S3-compatible store. See PR [#1390](https://github.com/fullstackhero/dotnet-starter-kit/pull/1390). - **Aspire:** the `minio` / `minio-init` resources are now `rustfs` / `rustfs-init`, and the AppHost parameters are renamed `minio-user` / `minio-password` → `rustfs-user` / `rustfs-password` (default `rustfsadmin`). If you set the old parameters in user secrets or config, rename them. The data volume is now `{appPrefix}-rustfs-data`, so local uploads start empty; delete the old `*-minio-data` volume when you no longer need it. diff --git a/src/content/docs/compare/fsh-vs-abp.mdx b/src/content/docs/compare/fsh-vs-abp.mdx index c9183389..cc2c5fe7 100644 --- a/src/content/docs/compare/fsh-vs-abp.mdx +++ b/src/content/docs/compare/fsh-vs-abp.mdx @@ -32,7 +32,7 @@ ABP Framework and fullstackhero both target the same problem - getting a product | ORM | EF Core 10 (PostgreSQL via Npgsql by default; SQL Server provider available) | EF Core with abstraction layer + LINQ via repository pattern | | Background jobs | Hangfire 1.8 | ABP's `IBackgroundJobManager` (multiple providers) | | Realtime | SignalR + Server-Sent Events | SignalR via ABP modules | -| Observability | Serilog 4 + OpenTelemetry 1.15 (OTLP exporter), pre-wired | OpenTelemetry support; configuration via ABP modules | +| Observability | Serilog 4 + OpenTelemetry 1.19 (OTLP exporter), pre-wired | OpenTelemetry support; configuration via ABP modules | | Frontend included | React + Vite admin and dashboard, in the repo | MVC + Razor / Blazor / Angular options - Lepton theme is paid in ABP Commercial | | CLI scaffolding | `fsh new ` | `abp new ` (Studio offers a GUI) | | Stars (May 2026) | 6.4k★ | 14.2k★ | diff --git a/src/content/docs/compare/fsh-vs-blazorplate.mdx b/src/content/docs/compare/fsh-vs-blazorplate.mdx index a34b3fef..c3ab1793 100644 --- a/src/content/docs/compare/fsh-vs-blazorplate.mdx +++ b/src/content/docs/compare/fsh-vs-blazorplate.mdx @@ -30,7 +30,7 @@ BlazorPlate is a paid commercial multi-tenant SaaS starter for .NET, sold as a o | Frontend | React 19 + Vite admin console + tenant dashboard (both in the repo) | Blazor Server + Blazor WebAssembly | | i18n | Not built-in | 20+ languages, RTL support | | Background jobs | Hangfire 1.8 | Hangfire | -| Observability | Serilog 4 + OpenTelemetry 1.15 (OTLP) | Serilog | +| Observability | Serilog 4 + OpenTelemetry 1.19 (OTLP) | Serilog | | Realtime | SignalR (Valkey backplane) + Server-Sent Events | SignalR | | File storage | Tenant-scoped S3 abstraction (RustFS locally) | File storage primitives | | Email | MailKit / SendGrid | Email service | diff --git a/src/content/docs/compare/fsh-vs-clean-architecture.mdx b/src/content/docs/compare/fsh-vs-clean-architecture.mdx index b0bfa829..599d545d 100644 --- a/src/content/docs/compare/fsh-vs-clean-architecture.mdx +++ b/src/content/docs/compare/fsh-vs-clean-architecture.mdx @@ -27,7 +27,7 @@ The Clean Architecture templates by Jason Taylor and Steve Smith (Ardalis) are t | Multitenancy | Not included | Not included | Finbuckle 10 with EF Core global query filter, IGlobalEntity opt-out, tenant-aware cache + jobs + outbox | | Auditing | Not included | Not included | EF SaveChanges interceptor + per-entity before/after + queryable `/audits` | | Background jobs | Not included | Not included | Hangfire 1.8 with tenant context preserved | -| Observability | Console logging | Serilog example | Serilog 4 + OpenTelemetry 1.15 (OTLP) pre-wired | +| Observability | Console logging | Serilog example | Serilog 4 + OpenTelemetry 1.19 (OTLP) pre-wired | | Caching | Not included | Not included | HybridCache (in-memory + Valkey) with tenant-scoped invalidation | | API browser | Swagger | Swagger | Scalar (OpenAPI 3.1) on `/scalar/` | | Frontend | Angular 21 / React 19 (sample) | None (API-only) | React 19 + Vite admin + dashboard, in the repo | diff --git a/src/content/docs/getting-started/introduction.mdx b/src/content/docs/getting-started/introduction.mdx index a6141164..25c7a209 100644 --- a/src/content/docs/getting-started/introduction.mdx +++ b/src/content/docs/getting-started/introduction.mdx @@ -145,10 +145,10 @@ The API never mutates data on startup. Demo data (acme/globex tenants, sample ca | Storage | Local filesystem or S3-compatible (AWS SDK) | | Messaging | RabbitMQ client (optional) | | Logging | Serilog 4 (structured) | -| Tracing / metrics | OpenTelemetry 1.15 (OTLP exporter) | +| Tracing / metrics | OpenTelemetry 1.19 (OTLP exporter) | | API docs | OpenAPI 10 + Scalar UI | | Errors | `ProblemDetails` (RFC 9457) via global exception handler | -| Orchestration | .NET Aspire 13.4 (Postgres + Valkey + RustFS + API + both React apps) | +| Orchestration | .NET Aspire 13.5 (Postgres + Valkey + RustFS + API + both React apps) | ### Frontends diff --git a/src/content/docs/testing/unit-tests.mdx b/src/content/docs/testing/unit-tests.mdx index 11fd6b7b..910923fe 100644 --- a/src/content/docs/testing/unit-tests.mdx +++ b/src/content/docs/testing/unit-tests.mdx @@ -20,7 +20,7 @@ Unit tests in fullstackhero are **fast, in-process, no infrastructure**. They te |---|---| | xUnit 2.x | Test runner, `[Fact]` / `[Theory]` discovery | | Shouldly 4.x | Readable assertions - `result.ShouldBe(...)`, `.ShouldThrow<>()`, `.ShouldSatisfyAllConditions(...)` | -| NSubstitute 5.x | Mocking service interfaces, verifying calls | +| NSubstitute 6.x | Mocking service interfaces, verifying calls | | AutoFixture 4.x | Random DTO / fixture generation | All four come from the kit's `Directory.Packages.props` central package management.