Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/content/docs/changelog/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/content/docs/compare/fsh-vs-abp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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 <name>` | `abp new <name>` (Studio offers a GUI) |
| Stars (May 2026) | 6.4k★ | 14.2k★ |
Expand Down
2 changes: 1 addition & 1 deletion src/content/docs/compare/fsh-vs-blazorplate.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
2 changes: 1 addition & 1 deletion src/content/docs/compare/fsh-vs-clean-architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
4 changes: 2 additions & 2 deletions src/content/docs/getting-started/introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion src/content/docs/testing/unit-tests.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down