From 5370b16b58927a51a2c3dd225537818c54cc2fcf Mon Sep 17 00:00:00 2001
From: Nano Taboada <87288+nanotaboada@users.noreply.github.com>
Date: Sun, 8 Feb 2026 10:58:51 -0300
Subject: [PATCH 1/2] docs: standardize release workflow and improve
documentation quality
- Add comprehensive Release Management section to AGENTS.md
- Document CHANGELOG-first release workflow (3-step process)
- Add XML documentation comments to all model properties
- Reframe Features section to highlight reference project value
- Reorder features by development lifecycle importance
---
.github/workflows/dotnet-cd.yml | 4 +-
AGENTS.md | 71 +++++++++++++-
CHANGELOG.md | 96 ++++++++++++++++---
README.md | 58 +++++++----
.../Models/Player.cs | 33 +++++++
.../Models/PlayerRequestModel.cs | 24 +++++
.../Models/PlayerResponseModel.cs | 21 ++++
7 files changed, 266 insertions(+), 41 deletions(-)
diff --git a/.github/workflows/dotnet-cd.yml b/.github/workflows/dotnet-cd.yml
index 52cb801..2aaf160 100644
--- a/.github/workflows/dotnet-cd.yml
+++ b/.github/workflows/dotnet-cd.yml
@@ -138,10 +138,10 @@ jobs:
- name: Create GitHub Release
uses: softprops/action-gh-release@v2.5.0
with:
- name: "v${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }}"
+ name: "v${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }} ποΈ"
tag_name: ${{ steps.version.outputs.tag_name }}
body: |
- # ποΈ Release ${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }}
+ #Release ${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }} ποΈ
## Docker Images
diff --git a/AGENTS.md b/AGENTS.md
index 0100e7e..bd6f3ce 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -81,9 +81,11 @@ dotnet build && dotnet test
**Pre-commit checklist**:
-1. Run `dotnet build --configuration Release` - must build successfully
-2. Run `dotnet test` - all tests must pass
-3. Check code formatting and style
+1. Update CHANGELOG.md `[Unreleased]` section with your changes (Added/Changed/Fixed/Removed)
+2. Run `dotnet build --configuration Release` - must build successfully
+3. Run `dotnet test` - all tests must pass
+4. Check code formatting and style
+5. Follow conventional commit format (enforced by commitlint)
### Running the Application
@@ -153,6 +155,66 @@ curl http://localhost:5000/health
**First run behavior**: Container initializes SQLite database with seed data. Volume persists data between runs.
+## Release Management
+
+### CHANGELOG Maintenance
+
+**Important**: Update CHANGELOG.md continuously as you work, not just before releases.
+
+**For every meaningful commit**:
+
+1. Add your changes to the `[Unreleased]` section in CHANGELOG.md
+2. Categorize under the appropriate heading:
+ - **Added**: New features
+ - **Changed**: Changes in existing functionality
+ - **Deprecated**: Soon-to-be removed features
+ - **Removed**: Removed features
+ - **Fixed**: Bug fixes
+ - **Security**: Security vulnerability fixes
+3. Use clear, user-facing descriptions (not just commit messages)
+4. Include PR/issue numbers when relevant (#123)
+
+**Example**:
+
+```markdown
+## [Unreleased]
+
+### Added
+- User authentication with JWT tokens (#145)
+- Rate limiting middleware for API endpoints
+
+### Deprecated
+- Legacy authentication endpoint /api/v1/auth (use /api/v2/auth instead)
+
+### Fixed
+- Null reference exception in player service (#147)
+
+### Security
+- Fix SQL injection vulnerability in search endpoint (#148)
+```
+
+### Creating a Release
+
+When ready to release:
+
+1. **Update CHANGELOG.md**: Move items from `[Unreleased]` to a new versioned section:
+
+ ```markdown
+ ## [1.1.0 - bernabeu] - 2026-02-15
+ ```
+
+2. **Commit and push** CHANGELOG changes
+3. **Create and push tag**:
+
+ ```bash
+ git tag -a v1.1.0-bernabeu -m "Release 1.1.0 - BernabΓ©u"
+ git push origin v1.1.0-bernabeu
+ ```
+
+4. **CD workflow runs automatically** to publish Docker images and create GitHub Release
+
+See [CHANGELOG.md](CHANGELOG.md#how-to-release) for complete release instructions and stadium naming convention.
+
## CI/CD Pipeline
### Continuous Integration (dotnet.yml)
@@ -165,7 +227,7 @@ curl http://localhost:5000/health
2. **Restore**: `dotnet restore` with dependency caching
3. **Build**: `dotnet build --no-restore --configuration Release`
4. **Test**: `dotnet test --no-build --verbosity normal --settings .runsettings`
-5. **Coverage**: Upload coverage reports to Codecov and Codacy
+5. **Coverage**: Upload coverage reports to Codecov
**Local validation** (run this before pushing):
@@ -384,6 +446,7 @@ curl -X DELETE https://localhost:9000/players/1 -k
## Important Notes
+- **CHANGELOG maintenance**: Update CHANGELOG.md `[Unreleased]` section with every meaningful change
- **Never commit secrets**: No API keys, tokens, or credentials in code
- **Test coverage**: Maintain high coverage with xUnit tests
- **Commit messages**: Follow conventional commits (enforced by commitlint in CI)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b66de58..2a7c3b5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -44,30 +44,87 @@ This project uses famous football stadiums (A-Z) that hosted FIFA World Cup matc
### Added
+- Token efficiency strategy for Copilot/AI agents with optimized instruction loading and improved token counting script (#364)
+
### Changed
-### Fixed
+- Bump Swashbuckle.AspNetCore from 10.1.0 to 10.1.2
+- Bump docker/login-action from 3.6.0 to 3.7.0
+- Bump softprops/action-gh-release from 2.2.0 to 2.5.0
+- Bump actions/checkout from 6.0.1 to 6.0.2
+
+### Deprecated
### Removed
+### Fixed
+
+### Security
+
+---
+
+## [1.0.0 - azteca] - 2026-01-22
+
+Initial release. See [README.md](README.md) for complete feature list and documentation.
+
---
## How to Release
-To create a new release:
+To create a new release, follow these steps in order:
+
+### 1. Update CHANGELOG.md
+
+Move items from the `[Unreleased]` section to a new release section:
+
+```markdown
+## [X.Y.Z - STADIUM_NAME] - YYYY-MM-DD
+
+### Added
+- New features here
+
+### Changed
+- Changes here
+
+### Fixed
+- Bug fixes here
+
+### Removed
+- Removed features here
+```
+
+**Important:** Commit and push this change before creating the tag.
+
+### 2. Create and Push Version Tag
+
+```bash
+git tag -a vX.Y.Z-stadium -m "Release X.Y.Z - Stadium"
+git push origin vX.Y.Z-stadium
+```
+
+Example:
+
+```bash
+git tag -a v1.0.0-azteca -m "Release 1.0.0 - Azteca"
+git push origin v1.0.0-azteca
+```
+
+### 3. Automated CD Workflow
+
+The CD workflow automatically:
-1. Update this CHANGELOG with release notes under the appropriate version heading
-2. Create and push a version tag with stadium name:
+- β
Validates the stadium name against the A-Z list
+- β
Builds and tests the project in Release configuration
+- β
Publishes Docker images to GHCR with three tags (`:X.Y.Z`, `:stadium`, `:latest`)
+- β
Creates a GitHub Release with auto-generated notes from commits
- ```bash
- git tag -a v1.0.0-azteca -m "Release 1.0.0 - Azteca"
- git push origin v1.0.0-azteca
- ```
+### Pre-Release Checklist
-3. The CD workflow will automatically:
- - Build and test the project
- - Publish Docker images to GHCR with three tags (`:1.0.0`, `:azteca`, `:latest`)
- - Create a GitHub Release with auto-generated notes
+- [ ] CHANGELOG.md updated with release notes
+- [ ] CHANGELOG.md changes committed and pushed
+- [ ] Tag created with correct format: `vX.Y.Z-stadium`
+- [ ] Stadium name is valid (A-Z from table above)
+- [ ] Tag pushed to trigger CD workflow
---
@@ -81,10 +138,21 @@ To create a new release:
### Changed
- Changes in existing functionality
-### Fixed
-- Bug fixes
+### Deprecated
+- Soon-to-be removed features
### Removed
- Removed features
+### Fixed
+- Bug fixes
+
+### Security
+- Security vulnerability fixes
+
-->
+
+---
+
+[unreleased]: https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/compare/v1.0.0-azteca...HEAD
+[1.0.0 - azteca]: https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/releases/tag/v1.0.0-azteca
diff --git a/README.md b/README.md
index a95ec06..680ae43 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,6 @@
[](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/actions/workflows/dotnet-cd.yml)
[](https://sonarcloud.io/summary/new_code?id=nanotaboada_Dotnet.Samples.AspNetCore.WebApi)
[](https://dev.azure.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/_build/latest?definitionId=14&branchName=master)
-[](https://app.codacy.com/gh/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[](https://codecov.io/gh/nanotaboada/Dotnet.Samples.AspNetCore.WebApi)
[](https://www.codefactor.io/repository/github/nanotaboada/Dotnet.Samples.AspNetCore.WebApi)
[](https://opensource.org/licenses/MIT)
@@ -30,18 +29,14 @@ Proof of Concept for a RESTful API built with .NET 8 (LTS) and ASP.NET Core. Man
## Features
-- π RESTful CRUD operations for football player data
-- π Interactive API documentation
-- π¦ Fixed window rate limiting
-- β¨οΈ Input validation
-- β‘ In-memory caching (1-hour TTL)
-- πΏ Relational database with ORM
-- ποΈ Layered architecture pattern
-- β Asynchronous operations throughout
-- π Structured logging to console and file
-- π©Ί Health check endpoint for monitoring
-- π³ Full containerization support
-- β
Comprehensive unit tests
+- ποΈ **Clean layered architecture** - Repository pattern, dependency injection, and async operations throughout
+- π **Interactive API exploration** - Swagger UI documentation with health monitoring endpoints
+- β‘ **Performance optimizations** - In-memory caching, rate limiting, and efficient database queries
+- π§ͺ **High test coverage** - xUnit tests with automated reporting to Codecov and SonarCloud
+- π **Token-efficient documentation** - AGENTS.md + auto-loaded Copilot instructions for AI-assisted development
+- π³ **Full containerization** - Multi-stage Docker builds with Docker Compose orchestration
+- π **Complete CI/CD pipeline** - Automated testing, code quality checks, Docker publishing, and GitHub releases
+- ποΈ **Stadium-themed semantic versioning** - Memorable, alphabetical release names from World Cup venues
## Tech Stack
@@ -190,7 +185,7 @@ graph TB
Interactive API documentation is available via Swagger UI at `https://localhost:9000/swagger/index.html` when the server is running.
-> π‘ **Note:** Swagger documentation is only available in development mode for security reasons.
+> π‘ Swagger documentation is only available in development mode for security reasons.
**Quick Reference:**
@@ -273,7 +268,7 @@ docker compose build
docker compose up
```
-> π‘ **Note:** On first run, the container copies a pre-seeded SQLite database into a persistent volume. On subsequent runs, that volume is reused and the data is preserved.
+> π‘ On first run, the container copies a pre-seeded SQLite database into a persistent volume. On subsequent runs, that volume is reused and the data is preserved.
### Stop the application
@@ -304,18 +299,39 @@ Releases follow the pattern: `v{SEMVER}-{STADIUM}` (e.g., `v1.0.0-azteca`)
### Create a Release
-To create a new release, tag a commit and push the tag:
+To create a new release, follow this workflow:
+
+#### 1. Update CHANGELOG.md
+
+First, document your changes in [CHANGELOG.md](CHANGELOG.md):
+
+```bash
+# Move items from [Unreleased] to new release section
+# Example: [1.0.0 - azteca] - 2026-01-22
+git add CHANGELOG.md
+git commit -m "docs: prepare changelog for v1.0.0-azteca release"
+git push
+```
+
+#### 2. Create and Push Tag
+
+Then create and push the version tag:
```bash
git tag -a v1.0.0-azteca -m "Release 1.0.0 - Azteca"
git push origin v1.0.0-azteca
```
+#### 3. Automated CD Workflow
+
This triggers the CD workflow which automatically:
-1. Builds and tests the project in Release configuration
-2. Publishes Docker images to GitHub Container Registry with three tags
-3. Creates a GitHub Release with auto-generated changelog
+1. Validates the stadium name
+2. Builds and tests the project in Release configuration
+3. Publishes Docker images to GitHub Container Registry with three tags
+4. Creates a GitHub Release with auto-generated changelog from commits
+
+> π‘ Always update CHANGELOG.md before creating the tag. See [CHANGELOG.md](CHANGELOG.md#how-to-release) for detailed release instructions.
### Pull Docker Images
@@ -332,7 +348,7 @@ docker pull ghcr.io/nanotaboada/dotnet-samples-aspnetcore-webapi:azteca
docker pull ghcr.io/nanotaboada/dotnet-samples-aspnetcore-webapi:latest
```
-> π‘ **Note:** See [CHANGELOG.md](CHANGELOG.md) for the complete stadium list (A-Z) and release history.
+> π‘ See [CHANGELOG.md](CHANGELOG.md) for the complete stadium list (A-Z) and release history.
## Environment Variables
@@ -366,7 +382,7 @@ For containerized production deployment:
STORAGE_PATH=/storage/players-sqlite3.db
```
-> π‘ **Note:** Additional environment variables (`ASPNETCORE_ENVIRONMENT=Production` and `ASPNETCORE_URLS=http://+:9000`) are set in the `Dockerfile`.
+> π‘ Additional environment variables (`ASPNETCORE_ENVIRONMENT=Production` and `ASPNETCORE_URLS=http://+:9000`) are set in the `Dockerfile`.
## Command Summary
diff --git a/src/Dotnet.Samples.AspNetCore.WebApi/Models/Player.cs b/src/Dotnet.Samples.AspNetCore.WebApi/Models/Player.cs
index 2cb144c..32257d8 100644
--- a/src/Dotnet.Samples.AspNetCore.WebApi/Models/Player.cs
+++ b/src/Dotnet.Samples.AspNetCore.WebApi/Models/Player.cs
@@ -10,25 +10,58 @@ namespace Dotnet.Samples.AspNetCore.WebApi.Models;
///
public class Player
{
+ ///
+ /// The unique identifier for the Player.
+ ///
public Guid Id { get; set; } = Guid.NewGuid();
+ ///
+ /// The first name of the Player.
+ ///
public string? FirstName { get; set; }
+ ///
+ /// The middle name of the Player, if any.
+ ///
public string? MiddleName { get; set; }
+ ///
+ /// The last name of the Player.
+ ///
public string? LastName { get; set; }
+ ///
+ /// The date of birth of the Player.
+ ///
public DateTime? DateOfBirth { get; set; }
+ ///
+ /// The squad number assigned to the Player.
+ ///
public int SquadNumber { get; set; }
+ ///
+ /// The playing position of the Player.
+ ///
public string? Position { get; set; }
+ ///
+ /// The abbreviated form of the Player's position.
+ ///
public string? AbbrPosition { get; set; }
+ ///
+ /// The team to which the Player belongs.
+ ///
public string? Team { get; set; }
+ ///
+ /// The league where the team plays.
+ ///
public string? League { get; set; }
+ ///
+ /// Indicates whether the Player is in the starting 11.
+ ///
public bool Starting11 { get; set; }
}
diff --git a/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerRequestModel.cs b/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerRequestModel.cs
index cdc6928..3046dd5 100644
--- a/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerRequestModel.cs
+++ b/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerRequestModel.cs
@@ -12,19 +12,43 @@ namespace Dotnet.Samples.AspNetCore.WebApi.Models;
///
public class PlayerRequestModel
{
+ ///
+ /// The first name of the Player.
+ ///
public string? FirstName { get; set; }
+ ///
+ /// The middle name of the Player, if any.
+ ///
public string? MiddleName { get; set; }
+ ///
+ /// The last name of the Player.
+ ///
public string? LastName { get; set; }
+ ///
+ /// The date of birth of the Player.
+ ///
public DateTime? DateOfBirth { get; set; }
+ ///
+ /// The squad number assigned to the Player (required).
+ ///
public required int SquadNumber { get; set; }
+ ///
+ /// The abbreviated form of the Player's position.
+ ///
public string? AbbrPosition { get; set; }
+ ///
+ /// The team to which the Player belongs.
+ ///
public string? Team { get; set; }
+ ///
+ /// The league where the team plays.
+ ///
public string? League { get; set; }
}
diff --git a/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerResponseModel.cs b/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerResponseModel.cs
index a285228..3f3c4bf 100644
--- a/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerResponseModel.cs
+++ b/src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerResponseModel.cs
@@ -10,17 +10,38 @@ namespace Dotnet.Samples.AspNetCore.WebApi.Models;
///
public class PlayerResponseModel
{
+ ///
+ /// The full name of the Player (combined first, middle, and last names).
+ ///
public string? FullName { get; set; }
+ ///
+ /// The formatted birth date of the Player.
+ ///
public string? Birth { get; set; }
+ ///
+ /// The squad number (dorsal) of the Player.
+ ///
public int Dorsal { get; set; }
+ ///
+ /// The playing position of the Player.
+ ///
public string? Position { get; set; }
+ ///
+ /// The club (team) to which the Player belongs.
+ ///
public string? Club { get; set; }
+ ///
+ /// The league where the club plays.
+ ///
public string? League { get; set; }
+ ///
+ /// Indicates whether the Player is in the starting 11 (formatted as string).
+ ///
public string? Starting11 { get; set; }
}
From 5ad6131c462ee155d2c85530d579c1aa0d02b3ec Mon Sep 17 00:00:00 2001
From: Nano Taboada <87288+nanotaboada@users.noreply.github.com>
Date: Sun, 8 Feb 2026 11:06:17 -0300
Subject: [PATCH 2/2] fix(cd): add space after # in release heading for valid
Markdown
---
.github/workflows/dotnet-cd.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/dotnet-cd.yml b/.github/workflows/dotnet-cd.yml
index 2aaf160..08f72c9 100644
--- a/.github/workflows/dotnet-cd.yml
+++ b/.github/workflows/dotnet-cd.yml
@@ -141,7 +141,7 @@ jobs:
name: "v${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }} ποΈ"
tag_name: ${{ steps.version.outputs.tag_name }}
body: |
- #Release ${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }} ποΈ
+ # Release ${{ steps.version.outputs.semver }} - ${{ steps.version.outputs.stadium }} ποΈ
## Docker Images