Pular para o conteúdo principal
Versão: main (dev) 🚧

Changelog

All notable changes to this template are documented in this file.

The format is based on Keep a Changelog, and this template adheres to Semantic Versioning.

[Unreleased]

[1.1.0] - 2026-06-30

Adds three cross-cutting infrastructure capabilities (Email/Cache, Microsoft Entra ID, Bus/Messaging) on top of DevPack 10.10.1, plus the BFF login fix. Scaffolds from dotnet new itlab-fullstack now include these out of the box.

Added

Materializes the abstractions shipped in DevPack 10.10.1 (the DevPack pin is bumped to 10.10.1).

  • Email & cache infrastructure. ICacheService implementations (MemoryCacheService/DistributedCacheService) selected by config via AddTemplateCache — memory by default, Redis when ConnectionStrings:Cache is set. Email senders (SmtpEmailService/SendGridEmailService, provider switch on EmailOptions.Provider) + an HTML template renderer + a file-system template repository via AddTemplateEmail. Generic Auth email templates (welcome, email-confirmation, password-reset) + a rebranded default layout under Api/Templates/Email, copied to the host output. New Infrastructure.Tests project.
  • Microsoft Entra ID — opt-in per-tenant scheme. Entra registered as a distinct "EntraId" scheme alongside the own-token "Bearer"; the Smart selector routes by token issuer. ReverseLookupEntraTenantValidator resolves the application tenant from the token's directory id (no current tenant exists during authentication). SigninWithEntra slice (local lookup by AzureAdObjectId, no auto-provisioning; issues the template's own token with idp=MicrosoftEntraID). AppUser.AzureAdObjectId/IdentityProvider + migration AddEntraIdentityColumns. Per-tenant Entra settings persistence (ClientSecret protected at rest) + public-config exposure. Opt-in Graph client factory (Kiota family pinned to 1.22.2 to clear GHSA-7j59-v9qr-6fq9). Entra is off by default.
  • Integration event bus. AddTemplateMessaging: the DevPack in-memory transport always (processors run in any host calling AddInfrastructure), plus the Azure Service Bus publisher (ServiceBusEventsBus, keyed EventBusType.External, System.Text.Json, routes by Args[0]) only when ConnectionStrings:ServiceBus/ServiceBusOptions:Namespace is set. Canonical OrderPlacedIntegrationEvent reference example: published from OrderCreated, consumed in-memory via an INotificationHandler and over Service Bus via an IDomainEventMessageHandler; the Worker hosts the receiver only when Service Bus is configured. Azure is off by default.

Fixed

  • Login deadlock with a stale/expired session cookie (ADR-008). Reported by the first consumer: an invalid session cookie locked the user out of login — BffAntiforgeryMiddleware required a CSRF token because the cookie was present, while GET /v1/auth/csrf required authentication to issue one, so the user could neither log in nor obtain a token (logout, also auth-gated, didn't help; the cookie is HttpOnly). Two complementary fixes, both template-side (no DevPack change): the middleware now validates CSRF only when the cookie authenticates the caller (Cookies.ContainsKey(...) && User.Identity.IsAuthenticated), not on mere presence — a stale cookie carries no authority, so login is no longer gated; and GET /v1/auth/csrf is now AllowAnonymous so the SPA can obtain a token before login. Common trigger: a session cookie (no Max-Age) outliving its 8h ticket on an open tab, or Data Protection key rotation. Covered by BffAntiforgeryMiddlewareTests (unit) + AntiforgeryTests (integration metadata).

[1.0.1] - 2026-06-12

Fixes from the first real scaffold consumption (all caught by a consumer project and re-validated by the release pipeline's scaffold smoke).

Added

  • Dev reverse proxy to the Vite dev server. With Spa:DevServerUrl configured (shipped in appsettings.Development.json.sample), the API reverse-proxies every non-API request to Vite via Microsoft.AspNetCore.SpaServices.Extensions (HMR websocket included): browse https://localhost:52106 with dotnet run + pnpm dev — same origin as production, BFF cookie works natively, no CORS. Reserved API prefixes stay out of the proxy (unknown /v1 routes still 404); without the setting (production, tests) the published-SPA fallback applies unchanged.

Fixed

  • pnpm 11 settings. node-linker=hoisted lived in .npmrc, which pnpm 11 no longer reads for pnpm settings — scaffolds installed with the isolated linker (.pnpm virtual store) and tripped AV file locks on locked-down Windows machines. Now nodeLinker: hoisted in pnpm-workspace.yaml; the dead .npmrc was removed. The msw postinstall approval also moved to its pnpm 11 home (allowBuilds, replacing the removed onlyBuiltDependencies).
  • Vite dev proxy targets the HTTPS endpoint. Proxying the HTTP port tripped UseHttpsRedirection's 307; the browser followed the redirect out of the Vite origin and, with credentials: same-origin, the login Set-Cookie was ignored — session 200 / /v1/auth/me 401. The proxy now targets https://localhost:52106 with secure: false.

[1.0.0] - 2026-06-12

First release published to the ITLab.Template feed as ITLab.Template.Next.Templates (install with dotnet new install ITLab.Template.Next.Templates).

Added

  • Template package (templatepack/). ITLab.Template.Next.Templates nupkg (PackageType=Template) so consumers install from the ITLab.Template feed (dotnet new install ITLab.Template.Next.Templates) instead of cloning. Packs .template.config + src/tests/infra/.github + root files, shipping dotfiles and excluding bin/obj/node_modules/dist and repo-only docs/examples. Validated end-to-end: install from the nupkg → scaffold → 38 backend tests + SPA 8 tests + build green. Publishing pipeline at .azure/template-publish.yml (tag release/template/vX.Y.Z): build + solution tests → pack → scaffold smoke from the packed nupkg (dotnet new install, build, backend + SPA tests) → push to the ITLab.Template feed.

  • Frontend SPA (ADR-007). src/ITLab.Template.Next.Spa: React + Vite + TypeScript + Tailwind v4 + shadcn/ui, served same-origin by the API so the ADR-006 BFF cookie works without CORS — UseStaticFiles + SPA fallback (reserved prefixes /v1, /health, /.well-known, /openapi, /scalar return 404, never HTML). Publish-time integration: the Api csproj builds the SPA (pnpm, override seams for CI) and bundles dist into wwwroot; dev uses the Vite proxy. Typed API client via committed OpenAPI spec + openapi-typescript/openapi-fetch (hermetic codegen); session bootstrap from GET /v1/auth/me with CSRF middleware (X-XSRF-TOKEN) and global 401 handling — no token ever touches JavaScript. UI canon: login (react-hook-form + zod), protected shell with route guard, and Orders as living reference (paginated table, create dialog, approve — role-gated while the API stays the enforcement). Tests: Vitest + Testing Library + MSW (8). dotnet new scaffolds the SPA renamed end-to-end (folder, csproj SpaRoot, brand, titles), excluding node_modules/dist.

  • GET /v1/auth/me — current authenticated user (id, name, roles) projected from ICurrentUser, for SPA session hydration and UI gating; works for both cookie and Bearer schemes.

  • OpenAPI response schemas. Endpoints now declare .Produces<T>(...) (the doc previously had no response schemas — IResult is opaque); /v1/auth/csrf returns a typed CsrfTokenResponse; Asp.Versioning ApiExplorer substitutes the version in paths (/v1/orders, not /v{version}/orders). Benefits Scalar UI and the SPA codegen alike.

  • Phase 3 packaging — dotnet new itlab-fullstack. .template.config/template.json declares the template with sourceName: ITLab.Template.Next, classifications Web/WebAPI/Worker/DDD/CQRS, and sources.modifiers.exclude that keeps examples/, docs/, **/bin/, **/obj/, IDE state and per-dev appsettings.Development.json out of generated projects. Smoke-tested end-to-end (dotnet new itlab-fullstack -n Probe builds Debug + Release clean and passes 20/20 tests against renamed namespaces).

  • Local authentication, dual-scheme (ADR-006, supersedes ADR-003; DevPack bumped to 10.4.0). The template ships with working auth — local ASP.NET Core Identity (AppUser/AppRole over BaseIdentityDbContext, tables in the identity schema without the AspNet prefix) issuing its own asymmetric (RSA) JWTs. Two schemes coexist via a forwarding selector: a BFF HttpOnly session cookie for browsers (/v1/auth/session*, CSRF-protected via BffAntiforgeryMiddleware + /v1/auth/csrf) and Bearer JWT validated through a published JWKS (/.well-known/jwks.json) for mobile (/v1/auth/token*, rotating refresh tokens) and service-to-service (/v1/auth/clients/token, client-credentials). Signing key is ephemeral in Development and a required PEM in production (fail-early). IdentitySeeder seeds canonical roles + an optional admin from Identity:Admin:*. Authorization (RolePermissions + RoleBasedPermissionEvaluator) is unchanged across schemes. External-JWT resource-server (ADR-003) remains as a documented opt-in swap.

  • DB-backed permission resolver. RolePermission entity + DbRolePermissionResolver with IMemoryCache (5 min TTL per role). Seed via RolePermissionConfiguration.HasData (Admin/Operator/Viewer × Orders.*) honored by both relational migrations and EF Core InMemory. Documented in ADR-004.

  • Order concurrency token. byte[] RowVersion mapped via IsRowVersion() in the entity config plus a dedicated migration AddOrderConcurrencyToken. Concurrent updates raise DbUpdateConcurrencyException instead of silently overwriting; integration tests via EF InMemory cannot exercise the race (documented caveat) — cover with Testcontainers.MsSql when it matters.

  • OpenTelemetry observability. AddTemplateObservability helper in Infrastructure ships baseline (resource, HttpClient, Runtime, EF Core ActivitySource, OTLP exporter); Api adds AddAspNetCoreInstrumentation() in its own composition root. Endpoint follows OTel env-var standard (OTEL_EXPORTER_OTLP_ENDPOINT, default http://localhost:4317).

  • Bearer security scheme in OpenAPI. BearerSecuritySchemeTransformer declares the scheme + document-wide requirement so Scalar UI auto-renders the Authorize button.

  • Split health probes. /health/live (no checks — process is alive) and /health/ready (filters checks tagged ready, includes AddDbContextCheck<AppDbContext>). Both anonymous and opted out of rate limiting.

  • Rate limiting. Built-in fixed-window per-IP partition with 1000 req/min default, configurable via RateLimiting:PermitLimit/WindowSeconds. /health/* opts out via .DisableRateLimiting().

  • CORS (opt-in). Registered only when Cors:AllowedOrigins contains at least one entry; defaults allow any method/header + credentials + 10 min preflight cache.

  • API versioning. Asp.Versioning.Http 10.0.0 with URL-segment primary reader (/v{version:apiVersion}/orders) and X-Api-Version header fallback. Default version 1.0, ReportApiVersions enabled. Health probes stay unversioned.

  • Docker + docker-compose. Multi-stage Dockerfile per project (Api/Worker), .dockerignore, docker-compose.yml orchestrating sql, api, worker and otel-collector. BuildKit secret mounts ~/.nuget/NuGet/NuGet.Config so dotnet restore can hit the private feed inside the build.

  • GitHub Actions CI workflow (.github/workflows/ci.yml). Restore (using AZURE_DEVOPS_PAT secret) + build Debug + build Release + tests with TRX logger + XPlat Code Coverage.

  • examples/Customers/ opt-in reference (ADR-005). Domain with Email/Cpf value objects (Cpf delegates to DevPack Guard.Against.InvalidCpf), uniqueness pre-check + unique index, deactivation as state transition. 8-step copy recipe in the per-example README. Not shipped via dotnet new.

  • Architecture Decision Records under docs/adrs/ (5 ADRs covering vertical slices, English-only source, JWT Bearer, DB-backed roles, examples opt-in).

  • appsettings.Development.json.sample as the copy-from reference (.env.sample pattern). Local appsettings.Development.json stays gitignored; the sample carries plausible Authority/Audience values for IdP-less local runs.

  • Setup section in README with prerequisites, primeiro-run sequence, NuGet feed credential setup and Docker/docker-compose recipes.

  • CLAUDE.md as the live contract for AI agents — vertical slices, returns/validation, domain events policy, permissions convention, authentication, observability, rate limiting, CORS, API versioning, EF, tests.

  • LICENSE (ITLab proprietary internal).

Changed

  • Canon PedidosOrders (English-only). All identifiers, methods, events, DTOs, EF table names, migration names, endpoint paths and test class/method names refactored to English. Markdown docs (CLAUDE.md, README, docs/) intentionally remain in Portuguese. Documented in ADR-002.
  • ITLabTemplateNextPermissionsPermissions. Short class identifier so sourceName: ITLab.Template.Next substitution does not need custom symbols at dotnet new time.
  • DevPack 10.2.3 → 10.3.0. Migrate Result/Error to ITLab.Template.DevPack.Core namespace per the 10.3 BREAKING change. Drop four local shims now shipped by the package: ResultHttpExtensions, IdentityContextMiddleware, ScopedDispatchDomainEventsInterceptor and the TestAuthenticationHandler (latter moves to the new ITLab.Template.DevPack.Testing nupkg).
  • Order constructor chains : base(id) (DevPack 10.3 AuditedSoftDeletableEntity<TKey> ctor).
  • OrdersEndpoints uses MapPaginatedGet<TQuery, TDto> for the paginated GET (replaces ~26 LOC of manual query-string binding).
  • Program.cs uses app.UseDevPackIdentityContext() instead of a local middleware to bridge HttpContext.User into AsyncLocalCurrentUserAccessor.
  • IntegrationTestFactory inherits WebApplicationFactoryBase<Program, AppDbContext> from ITLab.Template.DevPack.Testing — body collapses to a single class declaration. Overrides ConfigureAdditionalServices to inject JwtOptions and call EnsureCreated so the HasData seed populates the in-memory database.

Removed

  • PlaceholderAuthenticationHandler and the #if !DEBUG / #error gate — superseded by JWT Bearer (ADR-003).
  • InMemoryRolePermissionResolver — superseded by DbRolePermissionResolver (ADR-004).
  • Api/Extensions/ResultHttpExtensions.cs, Api/Middleware/IdentityContextMiddleware.cs, Infrastructure/Persistence/Interceptors/ScopedDispatchDomainEventsInterceptor.cs, tests/.../Setup/TestAuthenticationHandler.cs — all canonical in DevPack 10.3.0 now.
  • "Known doc-vs-binary mismatches in DevPack 10.2.3" section from CLAUDE.md — fixed in 10.3.

Phases overview (historical)

This template went through three phases before its first release:

  • Phase 1 — initial skeleton. Project structure, base configuration, NuGet packages. Pre-this-changelog.
  • Phase 2 — canon Orders + DevPack 10.3 absorption. Vertical-slice canon shipped, English-only refactor applied, JWT Bearer + DB-backed roles + observability + concurrency + Docker + CI all landed under the Unreleased bucket above.
  • Phase 3 — dotnet new packaging. .template.config/template.json shipped, smoke test verified end-to-end. Ready for first tagged release.