From bc51012738c75cb91f0bbc93d1b9fb8893fe0c67 Mon Sep 17 00:00:00 2001
From: "Christopher D. Cavell" <28095137+cdcavell@users.noreply.github.com>
Date: Mon, 29 Jun 2026 13:42:48 -0500
Subject: [PATCH 01/11] chore: bump shared version to 2.2.0
---
Directory.Build.props | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Directory.Build.props b/Directory.Build.props
index 0da3fed..6db21f1 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -5,12 +5,12 @@
enable
latest
- 2.1.0
+ 2.2.0
$(VersionPrefix)
$(VersionPrefix)-$(VersionSuffix)
- 2.1.0.0
- 2.1.0.0
+ 2.2.0.0
+ 2.2.0.0
$(Version)+$(RepositoryUrl)
true
From 749e1e22aa6d79efa6abde5fb8d709db9845d39f Mon Sep 17 00:00:00 2001
From: "Christopher D. Cavell" <28095137+cdcavell@users.noreply.github.com>
Date: Mon, 29 Jun 2026 13:43:21 -0500
Subject: [PATCH 02/11] chore: update template package metadata for 2.2.0
---
NetCoreApplicationTemplate.Template.csproj | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/NetCoreApplicationTemplate.Template.csproj b/NetCoreApplicationTemplate.Template.csproj
index 4c78b74..8e61b23 100644
--- a/NetCoreApplicationTemplate.Template.csproj
+++ b/NetCoreApplicationTemplate.Template.csproj
@@ -13,8 +13,8 @@
LICENSE.txt
PACKAGE-README.md
PACKAGE-ICON.png
- Minor 2.1.0 release of the NetCoreApplicationTemplate dotnet new template. This release adds an optional template-owned audit storage seam, documents audit storage extension paths, improves no-op SaveChanges handling, expands production authentication and middleware guidance, adds optional application/domain layering guidance, and refreshes documentation/image assets while preserving the stable 2.x package identity and default scaffold behavior.
- 2.1.0
+ Minor 2.2.0 release of the NetCoreApplicationTemplate dotnet new template. This release refactors EF Core SaveChanges preparation into an application-owned save pipeline invoked through a composite SaveChangesInterceptor, reduces repeated ChangeTracker enumeration, documents the EF Core save pipeline extension model, clarifies application-managed concurrency stamp portability, and refreshes package/documentation image assets while preserving the stable 2.x package identity and default scaffold behavior.
+ 2.2.0
$(VersionPrefix)
Template
From b53bc5fa26358a4b05b8aea86a17af2cf120879f Mon Sep 17 00:00:00 2001
From: "Christopher D. Cavell" <28095137+cdcavell@users.noreply.github.com>
Date: Mon, 29 Jun 2026 13:43:47 -0500
Subject: [PATCH 03/11] chore: update citation metadata for 2.2.0
---
CITATION.cff | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/CITATION.cff b/CITATION.cff
index a3f733f..ca287a8 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -1,8 +1,8 @@
cff-version: 1.2.0
message: "If you use this software, please cite it using the metadata below."
title: "NetCoreApplicationTemplate"
-version: "2.1.0"
-date-released: "2026-06-27"
+version: "2.2.0"
+date-released: "2026-06-29"
repository-code: "https://github.com/cdcavell/NetCoreApplicationTemplate"
url: "https://cdcavell.github.io/NetCoreApplicationTemplate/"
type: software
From 09762f24f69221d256e2b82e4dd459c28ca5caee Mon Sep 17 00:00:00 2001
From: "Christopher D. Cavell" <28095137+cdcavell@users.noreply.github.com>
Date: Mon, 29 Jun 2026 13:44:39 -0500
Subject: [PATCH 04/11] chore: update Zenodo metadata for 2.2.0
---
.zenodo.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.zenodo.json b/.zenodo.json
index b99df0c..d6dd3d7 100644
--- a/.zenodo.json
+++ b/.zenodo.json
@@ -1,6 +1,6 @@
{
"title": "NetCoreApplicationTemplate",
- "version": "2.1.0",
+ "version": "2.2.0",
"upload_type": "software",
"description": "A reusable ASP.NET Core application template for secure, maintainable, production-oriented .NET applications. It organizes startup composition, middleware ordering, structured logging, forwarded headers, security headers, rate limiting, centralized error handling, authentication and authorization foundations, EF Core data access patterns, CI validation, template packaging, and DocFX documentation.",
"creators": [
From 658f92a4456b7926dbd1206bdde5f9c6cf47d5e0 Mon Sep 17 00:00:00 2001
From: "Christopher D. Cavell" <28095137+cdcavell@users.noreply.github.com>
Date: Mon, 29 Jun 2026 13:44:59 -0500
Subject: [PATCH 05/11] docs: add changelog entry for 2.2.0
---
CHANGELOG.md | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9e628d7..012e477 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,30 @@ All notable changes to this project are documented in this file.
This project follows Semantic Versioning using the format `MAJOR.MINOR.PATCH`.
+## 2.2.0 - 2026-06-29
+
+### Added
+
+* Added `IApplicationSaveChangesPipeline` and `ApplicationSaveChangesPipeline` to move EF Core save preparation out of `ApplicationDbContext` and into an application-owned persistence pipeline.
+* Added `ApplicationSaveChangesInterceptor` as the composite EF Core save lifecycle interceptor for invoking the save pipeline through `SavingChanges` / `SavingChangesAsync` and `SavedChanges` / `SavedChangesAsync` hooks.
+* Added EF Core save pipeline documentation covering default pipeline order, extension seams, audit lifecycle safety, and the decision to keep a composite interceptor by default.
+* Added ADR 0004 documenting the decision to keep the composite SaveChanges interceptor until a concrete consumer or maintenance need justifies specialized interceptors.
+* Added tests that verify sync and async save-pipeline invocation through `ApplicationDbContext`.
+
+### Changed
+
+* Reduced repeated EF Core `ChangeTracker` inspection by materializing Added/Modified/Deleted entries once and reusing that list across string canonicalization, lookup normalization, timestamp normalization, concurrency stamping, and audit entry creation.
+* Reduced `ApplicationDbContext` save overrides to optimistic-concurrency exception handling around EF Core's native save flow.
+* Kept `ConcurrencyStamp` as the default application-managed optimistic concurrency token and documented why that remains the portable SQLite / SQL Server baseline.
+* Updated package icon and favicon image assets used for repository, NuGet package, and documentation branding.
+* Updated release metadata, package README examples, template packaging docs, citation metadata, and Zenodo metadata for `2.2.0`.
+
+### Notes
+
+* This is a minor release because it introduces and documents a clearer EF Core save-pipeline extension seam while preserving the stable `2.x` package identity, template short name, template options, and default scaffold behavior.
+* The default generated scaffold continues to use the same package identity, template identity, authentication options, data-access options, and local SQLite development path.
+* SQL Server-only consumers may still replace the application-managed concurrency token with provider-native rowversion behavior when appropriate, but the template default remains provider-portable.
+
## 2.1.0 - 2026-06-27
### Added
From e7c083a1671a1280eb8329e88bd81ea007e564d4 Mon Sep 17 00:00:00 2001
From: "Christopher D. Cavell" <28095137+cdcavell@users.noreply.github.com>
Date: Mon, 29 Jun 2026 13:46:26 -0500
Subject: [PATCH 06/11] docs: update README for release 2.2.0
---
README.md | 195 ++----------------------------------------------------
1 file changed, 5 insertions(+), 190 deletions(-)
diff --git a/README.md b/README.md
index 4e6ee89..4e87756 100644
--- a/README.md
+++ b/README.md
@@ -19,9 +19,9 @@ This repository provides a working application baseline with common infrastructu
## Current Release
-Current release: __[Release 2.1.0](https://github.com/cdcavell/NetCoreApplicationTemplate/releases/tag/v2.1.0)__
+Current release: __[Release 2.2.0](https://github.com/cdcavell/NetCoreApplicationTemplate/releases/tag/v2.2.0)__
-Tag: `v2.1.0`
+Tag: `v2.2.0`
## Project Goals
@@ -163,7 +163,7 @@ The scaffolded consumer output intentionally excludes repository-maintainer cont
Install the published template package:
```powershell
-dotnet new install NetCoreApplicationTemplate::2.1.0
+dotnet new install NetCoreApplicationTemplate::2.2.0
```
### Pack and Install Locally
@@ -177,7 +177,7 @@ dotnet pack ./NetCoreApplicationTemplate.Template.csproj --configuration Release
Install the generated package:
```powershell
-dotnet new install ./artifacts/template-package/NetCoreApplicationTemplate.2.1.0.nupkg
+dotnet new install ./artifacts/template-package/NetCoreApplicationTemplate.2.2.0.nupkg
```
Generate a consumer project:
@@ -234,7 +234,7 @@ The non-default scaffold preserves the template's core guardrails, including str
Update the installed template by installing a newer package version:
```powershell
-dotnet new install NetCoreApplicationTemplate::2.1.0
+dotnet new install NetCoreApplicationTemplate::2.2.0
```
Uninstall the template package:
@@ -257,188 +257,3 @@ Package-based install remains the preferred validation path because it more clos
## Documentation
Detailed documentation is maintained in the `docs` folder and published with DocFX.
-
-- [Documentation source](docs/index.md)
-- [Published documentation](https://cdcavell.github.io/NetCoreApplicationTemplate/)
-- [Architecture Decision Records](https://cdcavell.github.io/NetCoreApplicationTemplate/adr/)
-- Generated API reference is available through the published documentation navigation.
-
-Documentation areas include:
-
-- [Getting Started](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/getting-started.html)
-- __Release Readiness and Compatibility__
- - [v1.0 Migration Guide](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/v1-migration-guide.html)
- - [Public Surface](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/public-surface-v1.html)
- - [Production Deployment Checklist](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/production-deployment-checklist.html)
- - [Runtime Readiness](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/runtime-readiness.html)
- - [Build Quality and Reproducibility](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/build-quality.html)
- - [Container Release Publishing](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/container-publish.html)
- - [Template Packaging](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/template-packaging.html)
-- __Application Basics__
- - [Project Structure](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/project-structure.html)
- - [Optional Application and Domain Layers](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/optional-application-domain-layers.html)
- - [Configuration](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/configuration.html)
- - [Deployment Notes](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/deployment.html)
- - [Docker Development](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/docker.html)
-- __Middleware Pipeline__
- - [Middleware Pipeline](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/middleware.html)
- - [Error Handling](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/error-handling.html)
- - [Security Headers](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/security-headers.html)
- - [Forwarded Headers](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/forwarded-headers.html)
- - [Rate Limiting](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/rate-limiting.html)
- - [Health Checks](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/health-checks.html)
-- [API Versioning](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/api-versioning.html)
-- __Observability__
- - [Logging](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/logging.html)
- - [Telemetry](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/telemetry.html)
-- __Authentication and Authorization__
- - [Authentication](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/authentication.html)
- - [Production Authentication Hardening](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/authentication-hardening.html)
- - [Authorization](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/authorization.html)
-- [Data Access](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/data-access.html)
-- [GitHub Workflow](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/github-workflow.html)
-
-## Repository Governance
-
-Repository-level guidance is maintained in root-level files:
-
-- [Contributing](CONTRIBUTING.md)
-- [Security Policy](SECURITY.md)
-- [Changelog](CHANGELOG.md)
-- [Third-Party Asset Notices](ASSETS-LICENSES.md)
-
-Pull requests targeting `main` require passing CI and Code Owner review for owned paths; stale approvals are dismissed when new reviewable commits are pushed.
-
-## Repository Structure
-
-```text
-/
-├── .github/
-│ ├── workflows/
-│ │ └── GitHub Actions CI and documentation publishing workflows
-│ ├── ISSUE_TEMPLATE/
-│ │ └── Issue templates
-│ ├── dependabot.yml
-│ └── pull_request_template.md
-│
-├── .template.config/
-│ └── dotnet new template metadata
-│
-├── .template.content/
-│ └── consumer scaffold content
-│
-├── docs/
-│ ├── adr/
-│ │ └── Architecture decision records
-│ ├── articles/
-│ │ └── DocFX conceptual documentation
-│ ├── images/
-│ │ └── Documentation and README images
-│ └── docfx.json
-│
-├── scripts/
-│ └── Utility scripts for setup, build, or maintenance
-│
-├── src/
-│ ├── ProjectTemplate.Infrastructure/
-│ └── ProjectTemplate.Web/
-│
-├── tests/
-│ └── ProjectTemplate.Web.Tests/
-│
-├── .dockerignore
-├── .editorconfig
-├── .gitattributes
-├── CHANGELOG.md
-├── CITATION.cff
-├── CONTRIBUTING.md
-├── Dockerfile
-├── docker-compose.yml
-├── LICENSE.txt
-├── NetCoreApplicationTemplate.slnx
-├── NetCoreApplicationTemplate.Template.csproj
-├── PACKAGE-README.md
-├── README.md
-└── SECURITY.md
-```
-
-## Local Documentation Build
-
-Restore local tools:
-
-```powershell
-dotnet tool restore
-```
-
-Build the DocFX site:
-
-```powershell
-dotnet tool run docfx -- docs/docfx.json
-```
-
-Serve the generated site locally:
-
-```powershell
-dotnet tool run docfx -- serve docs/_site
-```
-
-## GitHub Actions
-
-The repository currently includes workflows for:
-
-- Restoring dependencies.
-- Building the solution in Release configuration.
-- Verifying formatting.
-- Running tests.
-- Generating test result and coverage artifacts.
-- Enforcing a 75% minimum line coverage threshold in CI.
-- Failing CI when coverage regresses below the threshold.
-- Packing the template package.
-- Installing the generated `.nupkg` into a clean SDK environment.
-- Scaffolding a consumer project with `dotnet new netcoreapp-template`.
-- Validating expected consumer files and excluded maintainer files.
-- Building and testing scaffolded output on Linux, Windows, and macOS.
-- Running CodeQL analysis.
-- Building and publishing DocFX documentation to GitHub Pages.
-
-Template smoke testing runs on pull requests, supported branch pushes, manual workflow dispatch, and release-style version tags matching `v*.*.*`.
-
-See [GitHub Workflow](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/github-workflow.html), [Template Packaging](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/template-packaging.html), and [ADR-0003](docs/adr/0003-record-release-surface-and-distribution-strategy.md) for details.
-
-## Versioning
-
-This project follows Semantic Versioning using the format:
-
-```text
-MAJOR.MINOR.PATCH
-```
-
-Version numbers are centrally managed through project build metadata so assemblies, future packages, and releases can share a consistent version identity.
-
-See [ADR-0003: Record Release Surface and Distribution Strategy](docs/adr/0003-record-release-surface-and-distribution-strategy.md) for the release-surface decision.
-
-## Citation
-
-If you use this repository, please cite it using the metadata in [`CITATION.cff`](./CITATION.cff) or one of the following:
-
-- Author ORCID: [0009-0002-2113-0245](https://orcid.org/0009-0002-2113-0245)
-- Zenodo Concept DOI: [10.5281/zenodo.20373042](https://doi.org/10.5281/zenodo.20373042)
-- Suggested plain-text citation:
-
-```text
-Cavell, Christopher D. NetCoreApplicationTemplate. Version 2.1.0. Zenodo. MIT License. https://doi.org/10.5281/zenodo.20373042
-```
-
-## Roadmap
-
-The project is a reusable .NET application template with a stable `2.1.0` package baseline. Future work may include additional provider modules, expanded examples, optional template parameters, and continued hardening of the documented release surface.
-
-See [Template Packaging](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/template-packaging.html) for the current packaging direction.
-
-## License
-
-This project is licensed under the MIT License.
-
-See [LICENSE.txt](LICENSE.txt) for full license details.
-
-Third-party assets, libraries, templates, icons, fonts, images, or other externally sourced materials used by this project are documented in [ASSETS-LICENSES.md](ASSETS-LICENSES.md).
From e9bab03266f40bae9be3883c23444a0316e8c11b Mon Sep 17 00:00:00 2001
From: "Christopher D. Cavell" <28095137+cdcavell@users.noreply.github.com>
Date: Mon, 29 Jun 2026 13:47:05 -0500
Subject: [PATCH 07/11] docs: update package README for 2.2.0
---
PACKAGE-README.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/PACKAGE-README.md b/PACKAGE-README.md
index f22de4e..8f2db2b 100644
--- a/PACKAGE-README.md
+++ b/PACKAGE-README.md
@@ -20,13 +20,13 @@ This README is intended for NuGet package consumers. The full repository README
Install the template package from NuGet:
```text
-dotnet new install NetCoreApplicationTemplate::2.1.0
+dotnet new install NetCoreApplicationTemplate::2.2.0
```
For local package validation, install a packed package directly:
```text
-dotnet new install ./artifacts/template-package/NetCoreApplicationTemplate.2.1.0.nupkg
+dotnet new install ./artifacts/template-package/NetCoreApplicationTemplate.2.2.0.nupkg
```
## Generate a project
@@ -79,7 +79,7 @@ dotnet test --configuration Release
Install the newer package version with the same package identity:
```text
-dotnet new install NetCoreApplicationTemplate::2.1.0
+dotnet new install NetCoreApplicationTemplate::2.2.0
```
## Uninstall
From 01adb5da1481489a23bc758085fd47355e95e7f9 Mon Sep 17 00:00:00 2001
From: "Christopher D. Cavell" <28095137+cdcavell@users.noreply.github.com>
Date: Mon, 29 Jun 2026 13:47:57 -0500
Subject: [PATCH 08/11] docs: update template packaging docs for 2.2.0
---
docs/articles/template-packaging.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/articles/template-packaging.md b/docs/articles/template-packaging.md
index 897fa62..cfbb207 100644
--- a/docs/articles/template-packaging.md
+++ b/docs/articles/template-packaging.md
@@ -16,7 +16,7 @@ Package-based validation is preferred because it verifies the actual distributio
| Template identity | `CDCavell.NetCoreApplicationTemplate.CSharp` |
| Template group identity | `CDCavell.NetCoreApplicationTemplate` |
| Source replacement token | `ProjectTemplate` |
-| Current package version | `2.1.0` |
+| Current package version | `2.2.0` |
The `2.0.0` release moved the public NuGet package ID to `NetCoreApplicationTemplate`. The internal template identity and group identity remain unchanged for template metadata continuity.
@@ -92,13 +92,13 @@ dotnet pack ./NetCoreApplicationTemplate.Template.csproj --configuration Release
Install the published package from NuGet:
```powershell
-dotnet new install NetCoreApplicationTemplate::2.1.0
+dotnet new install NetCoreApplicationTemplate::2.2.0
```
Install a locally packed package:
```powershell
-dotnet new install ./artifacts/template-package/NetCoreApplicationTemplate.2.1.0.nupkg
+dotnet new install ./artifacts/template-package/NetCoreApplicationTemplate.2.2.0.nupkg
```
## Create a New Project from the Template
From 4dfffc8e444e6ef915bd26967aff940378f2b38d Mon Sep 17 00:00:00 2001
From: "Christopher D. Cavell" <28095137+cdcavell@users.noreply.github.com>
Date: Mon, 29 Jun 2026 13:49:15 -0500
Subject: [PATCH 09/11] docs: include branch coverage tests in 2.2.0 changelog
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 012e477..5e8b237 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ This project follows Semantic Versioning using the format `MAJOR.MINOR.PATCH`.
* Added EF Core save pipeline documentation covering default pipeline order, extension seams, audit lifecycle safety, and the decision to keep a composite interceptor by default.
* Added ADR 0004 documenting the decision to keep the composite SaveChanges interceptor until a concrete consumer or maintenance need justifies specialized interceptors.
* Added tests that verify sync and async save-pipeline invocation through `ApplicationDbContext`.
+* Added branch-focused tests for `ApplicationSaveChangesInterceptor`, including constructor null-guard, non-`ApplicationDbContext`, and bounded after-save follow-up branches.
### Changed
From 32d26ba7382d69a5904e99d25c5ebc5c107e5da4 Mon Sep 17 00:00:00 2001
From: "Christopher D. Cavell" <28095137+cdcavell@users.noreply.github.com>
Date: Mon, 29 Jun 2026 13:51:09 -0500
Subject: [PATCH 10/11] docs: restore full README release references
---
README.md | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 185 insertions(+)
diff --git a/README.md b/README.md
index 4e87756..7924cc6 100644
--- a/README.md
+++ b/README.md
@@ -257,3 +257,188 @@ Package-based install remains the preferred validation path because it more clos
## Documentation
Detailed documentation is maintained in the `docs` folder and published with DocFX.
+
+- [Documentation source](docs/index.md)
+- [Published documentation](https://cdcavell.github.io/NetCoreApplicationTemplate/)
+- [Architecture Decision Records](https://cdcavell.github.io/NetCoreApplicationTemplate/adr/)
+- Generated API reference is available through the published documentation navigation.
+
+Documentation areas include:
+
+- [Getting Started](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/getting-started.html)
+- __Release Readiness and Compatibility__
+ - [v1.0 Migration Guide](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/v1-migration-guide.html)
+ - [Public Surface](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/public-surface-v1.html)
+ - [Production Deployment Checklist](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/production-deployment-checklist.html)
+ - [Runtime Readiness](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/runtime-readiness.html)
+ - [Build Quality and Reproducibility](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/build-quality.html)
+ - [Container Release Publishing](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/container-publish.html)
+ - [Template Packaging](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/template-packaging.html)
+- __Application Basics__
+ - [Project Structure](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/project-structure.html)
+ - [Optional Application and Domain Layers](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/optional-application-domain-layers.html)
+ - [Configuration](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/configuration.html)
+ - [Deployment Notes](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/deployment.html)
+ - [Docker Development](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/docker.html)
+- __Middleware Pipeline__
+ - [Middleware Pipeline](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/middleware.html)
+ - [Error Handling](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/error-handling.html)
+ - [Security Headers](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/security-headers.html)
+ - [Forwarded Headers](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/forwarded-headers.html)
+ - [Rate Limiting](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/rate-limiting.html)
+ - [Health Checks](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/health-checks.html)
+- [API Versioning](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/api-versioning.html)
+- __Observability__
+ - [Logging](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/logging.html)
+ - [Telemetry](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/telemetry.html)
+- __Authentication and Authorization__
+ - [Authentication](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/authentication.html)
+ - [Production Authentication Hardening](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/authentication-hardening.html)
+ - [Authorization](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/authorization.html)
+- [Data Access](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/data-access.html)
+- [GitHub Workflow](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/github-workflow.html)
+
+## Repository Governance
+
+Repository-level guidance is maintained in root-level files:
+
+- [Contributing](CONTRIBUTING.md)
+- [Security Policy](SECURITY.md)
+- [Changelog](CHANGELOG.md)
+- [Third-Party Asset Notices](ASSETS-LICENSES.md)
+
+Pull requests targeting `main` require passing CI and Code Owner review for owned paths; stale approvals are dismissed when new reviewable commits are pushed.
+
+## Repository Structure
+
+```text
+/
+├── .github/
+│ ├── workflows/
+│ │ └── GitHub Actions CI and documentation publishing workflows
+│ ├── ISSUE_TEMPLATE/
+│ │ └── Issue templates
+│ ├── dependabot.yml
+│ └── pull_request_template.md
+│
+├── .template.config/
+│ └── dotnet new template metadata
+│
+├── .template.content/
+│ └── consumer scaffold content
+│
+├── docs/
+│ ├── adr/
+│ │ └── Architecture decision records
+│ ├── articles/
+│ │ └── DocFX conceptual documentation
+│ ├── images/
+│ │ └── Documentation and README images
+│ └── docfx.json
+│
+├── scripts/
+│ └── Utility scripts for setup, build, or maintenance
+│
+├── src/
+│ ├── ProjectTemplate.Infrastructure/
+│ └── ProjectTemplate.Web/
+│
+├── tests/
+│ └── ProjectTemplate.Web.Tests/
+│
+├── .dockerignore
+├── .editorconfig
+├── .gitattributes
+├── CHANGELOG.md
+├── CITATION.cff
+├── CONTRIBUTING.md
+├── Dockerfile
+├── docker-compose.yml
+├── LICENSE.txt
+├── NetCoreApplicationTemplate.slnx
+├── NetCoreApplicationTemplate.Template.csproj
+├── PACKAGE-README.md
+├── README.md
+└── SECURITY.md
+```
+
+## Local Documentation Build
+
+Restore local tools:
+
+```powershell
+dotnet tool restore
+```
+
+Build the DocFX site:
+
+```powershell
+dotnet tool run docfx -- docs/docfx.json
+```
+
+Serve the generated site locally:
+
+```powershell
+dotnet tool run docfx -- serve docs/_site
+```
+
+## GitHub Actions
+
+The repository currently includes workflows for:
+
+- Restoring dependencies.
+- Building the solution in Release configuration.
+- Verifying formatting.
+- Running tests.
+- Generating test result and coverage artifacts.
+- Enforcing a 75% minimum line coverage threshold in CI.
+- Failing CI when coverage regresses below the threshold.
+- Packing the template package.
+- Installing the generated `.nupkg` into a clean SDK environment.
+- Scaffolding a consumer project with `dotnet new netcoreapp-template`.
+- Validating expected consumer files and excluded maintainer files.
+- Building and testing scaffolded output on Linux, Windows, and macOS.
+- Running CodeQL analysis.
+- Building and publishing DocFX documentation to GitHub Pages.
+
+Template smoke testing runs on pull requests, supported branch pushes, manual workflow dispatch, and release-style version tags matching `v*.*.*`.
+
+See [GitHub Workflow](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/github-workflow.html), [Template Packaging](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/template-packaging.html), and [ADR-0003](docs/adr/0003-record-release-surface-and-distribution-strategy.md) for details.
+
+## Versioning
+
+This project follows Semantic Versioning using the format:
+
+```text
+MAJOR.MINOR.PATCH
+```
+
+Version numbers are centrally managed through project build metadata so assemblies, future packages, and releases can share a consistent version identity.
+
+See [ADR-0003: Record Release Surface and Distribution Strategy](docs/adr/0003-record-release-surface-and-distribution-strategy.md) for the release-surface decision.
+
+## Citation
+
+If you use this repository, please cite it using the metadata in [`CITATION.cff`](./CITATION.cff) or one of the following:
+
+- Author ORCID: [0009-0002-2113-0245](https://orcid.org/0009-0002-2113-0245)
+- Zenodo Concept DOI: [10.5281/zenodo.20373042](https://doi.org/10.5281/zenodo.20373042)
+- Suggested plain-text citation:
+
+```text
+Cavell, Christopher D. NetCoreApplicationTemplate. Version 2.2.0. Zenodo. MIT License. https://doi.org/10.5281/zenodo.20373042
+```
+
+## Roadmap
+
+The project is a reusable .NET application template with a stable `2.2.0` package baseline. Future work may include additional provider modules, expanded examples, optional template parameters, and continued hardening of the documented release surface.
+
+See [Template Packaging](https://cdcavell.github.io/NetCoreApplicationTemplate/articles/template-packaging.html) for the current packaging direction.
+
+## License
+
+This project is licensed under the MIT License.
+
+See [LICENSE.txt](LICENSE.txt) for full license details.
+
+Third-party assets, libraries, templates, icons, fonts, images, or other externally sourced materials used by this project are documented in [ASSETS-LICENSES.md](ASSETS-LICENSES.md).
From ad0249af0e7af1282371833fa4c1bd55ad0b99db Mon Sep 17 00:00:00 2001
From: Chris Cavell
Date: Mon, 29 Jun 2026 14:16:49 -0500
Subject: [PATCH 11/11] fix: workflow hygiene issue for future release
automations.
---
.github/workflows/publish-release.yml | 144 +++++++++++++-------------
1 file changed, 74 insertions(+), 70 deletions(-)
diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml
index 92c7c30..9ee88bc 100644
--- a/.github/workflows/publish-release.yml
+++ b/.github/workflows/publish-release.yml
@@ -1,71 +1,75 @@
-name: Update README release section
-
-on:
- release:
- types: [published]
-
-permissions:
- contents: write
- pull-requests: write
-
-jobs:
- update-readme:
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout repository
+name: Update README release section
+
+on:
+ release:
+ types: [published]
+
+permissions:
+ contents: write
+ pull-requests: write
+
+jobs:
+ update-readme:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- with:
- ref: main
-
- - name: Update README release section
- shell: bash
- env:
- RELEASE_TAG: ${{ github.event.release.tag_name }}
- RELEASE_NAME: ${{ github.event.release.name }}
- RELEASE_URL: ${{ github.event.release.html_url }}
- run: |
- python <<'PY'
- from pathlib import Path
- import os
- import re
-
- readme = Path("README.md")
- text = readme.read_text(encoding="utf-8")
-
- tag = os.environ["RELEASE_TAG"]
- name = os.environ["RELEASE_NAME"] or tag
- url = os.environ["RELEASE_URL"]
-
- replacement = f"""
- Current release: __[{name}]({url})__
-
- Tag: `{tag}`
- """
-
- pattern = r".*?"
-
- updated, count = re.subn(
- pattern,
- replacement,
- text,
- flags=re.DOTALL,
- )
-
- if count == 0:
- raise SystemExit("README release markers were not found.")
-
- if updated != text:
- readme.write_text(updated, encoding="utf-8")
- PY
-
- - name: Create pull request
- uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8
- with:
- commit-message: "Update README latest release section"
- title: "Update README latest release section"
- body: |
- Updates the README latest release section after publishing `${{ github.event.release.tag_name }}`.
- branch: docs/update-latest-release
- base: main
- delete-branch: true
+ with:
+ ref: main
+ fetch-depth: 0
+ clean: true
+
+ - name: Update README release section
+ shell: bash
+ env:
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
+ RELEASE_NAME: ${{ github.event.release.name }}
+ RELEASE_URL: ${{ github.event.release.html_url }}
+ run: |
+ python <<'PY'
+ from pathlib import Path
+ import os
+ import re
+
+ readme = Path("README.md")
+ text = readme.read_text(encoding="utf-8")
+
+ tag = os.environ["RELEASE_TAG"]
+ name = os.environ["RELEASE_NAME"] or tag
+ url = os.environ["RELEASE_URL"]
+
+ replacement = f"""
+ Current release: __[{name}]({url})__
+
+ Tag: `{tag}`
+ """
+
+ pattern = r".*?"
+
+ updated, count = re.subn(
+ pattern,
+ replacement,
+ text,
+ flags=re.DOTALL,
+ )
+
+ if count == 0:
+ raise SystemExit("README release markers were not found.")
+
+ if updated != text:
+ readme.write_text(updated, encoding="utf-8")
+ PY
+
+ - name: Create pull request
+ uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8
+ with:
+ commit-message: "Update README latest release section"
+ title: "Update README latest release section"
+ body: |
+ Updates the README latest release section after publishing `${{ github.event.release.tag_name }}`.
+ branch: docs/update-latest-release
+ base: main
+ delete-branch: true
+ add-paths: |
+ README.md