All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
This project uses famous football stadiums (A-Z) that hosted FIFA World Cup matches (with notable fallbacks where necessary):
| Letter | Stadium Name | Location | Tag Name |
|---|---|---|---|
| A | Azteca | Mexico (1970, 1986, 2026) | azteca |
| B | Bernabéu | Spain (1982) | bernabeu |
| C | Centenario | Uruguay (1930) | centenario |
| D | Düsseldorf (Merkur Spiel-Arena) | Germany (2006) | dusseldorf |
| E | Ekaterinburg Arena | Russia (2018) | ekaterinburg |
| F | Frankfurt Waldstadion | Germany (1974, 2006) | frankfurt |
| G | Gelsenkirchen | Germany (2006) | gelsenkirchen |
| H | Hard Rock Stadium | USA (2026) | hardrock |
| I | Ibn Batouta Stadium | Morocco (2030) | ibnbatouta |
| J | Johannesburg Soccer City | South Africa (2010) | johannesburg |
| K | Kazan Arena | Russia (2018) | kazan |
| L | Lusail | Qatar (2022) | lusail |
| M | Maracanã | Brazil (1950, 2014) | maracana |
| N | Nantes Beaujoire | France (1998) | nantes |
| O | Olympiastadion Berlin | Germany (1974, 2006) | olympiastadion |
| P | Parc des Princes | France (1938, 1998) | parcdesprinces |
| Q | Qatar 974 | Qatar (2022) | qatar974 |
| R | Rose Bowl | USA (1994) | rosebowl |
| S | San Siro | Italy (1934, 1990) | sansiro |
| T | Toronto BMO Field | Canada (2026) | toronto |
| U | Ullevi | Sweden (1958) | ullevi |
| V | Volgograd Arena | Russia (2018) | volgograd |
| W | Wembley | England (1966) | wembley |
| X | Xiamen Egret Stadium | (famous fallback) | xiamen |
| Y | Yokohama International Stadium | Japan (2002) | yokohama |
| Z | Zentralstadion Leipzig | Germany (1974, 2006) | zentralstadion |
DATABASE_PROVIDERenvironment variable (sqlitedefault,postgresopt-in) to select the database engine at startup (issue #249).- PostgreSQL 17 support via
Npgsql.EntityFrameworkCore.PostgreSQL10.0.1; migrations inMigrations/Npgsql/use proper PostgreSQL column types (uuid,boolean,timestamp with time zone). ProviderSpecificMigrationsAssemblythat filters the EF Core migration set to the active provider's namespace, ensuringMigrateAsync()applies the correct migrations for both SQLite and PostgreSQL.postgresDocker Compose profile and service (postgres:17-alpine), started only whenDATABASE_PROVIDER=postgresis set; the API service usesdepends_onwithrequired: falseso SQLite mode incurs no dependency on the postgres service..env.exampledocumentingDATABASE_PROVIDER,DATABASE_URL, andPOSTGRES_PASSWORD..envadded to.gitignore.- ADR-0014 (
adr/0014-configurable-database-provider.md) documenting the decision; supersedes ADR-0003.
AddDbContextPoolWithSqliterenamed toAddDbContextPoolinServiceCollectionExtensions; now readsDATABASE_PROVIDERand wires eitherUseSqliteorUseNpgsqlaccordingly.compose.yaml:apiservice receivesDATABASE_PROVIDERandDATABASE_URLenvironment variables;postgres-datanamed volume added.scripts/entrypoint.sh: SQLite file-presence check is skipped whenDATABASE_PROVIDER=postgres.- ADR-0003 status updated to "Superseded by ADR-0014".
README.md: added Database section documenting SQLite and PostgreSQL modes.
- Populate
BuildTargetModelin Npgsql seed migration designer files so Npgsql's SQL generator can resolve column types when applyingInsertDataoperations. - Suppress
PendingModelChangesWarningfor the postgres provider path — hand-crafted designer files cannot replicate Npgsql-injected runtime annotations (Relational:MaxIdentifierLength,UseIdentityByDefaultColumn), causing a false-positive that abortedMigrateAsync()at startup. - Normalize
DATABASE_PROVIDERto lowercase inentrypoint.shviatrsoPOSTGRES,Postgres, etc. are handled consistently withAddDbContextPool. - Trim and normalize
DATABASE_PROVIDERinAddDbContextPoolbefore the provider switch; add explicitsqlite/empty case; throwInvalidOperationExceptionfor unrecognized values so typos no longer silently fall through to SQLite. - Move
Npgsql.EntityFrameworkCore.PostgreSQLpackage from the "Development dependencies"ItemGroupto "Runtime dependencies".
2.1.2 - Frankfurt - 2026-04-26
- Field validation failures now return
422 Unprocessable Entity(RFC 4918) instead of400 Bad Request;400 Bad Requestis now reserved for malformed requests (unparseable JSON, route/body mismatch); unsupported media types return415 Unsupported Media Type(RFC 9110 §15.5.16) via the[Consumes]attribute. Error responses follow the Problem Details format (RFC 9457).
- Remove
## How to Releasesection fromCHANGELOG.md; capitalize release codenames in##version headers and reference links (#468)
2.1.1 - Ekaterinburg - 2026-04-12
-
Extract
testjob fromreleasein CD pipeline so tests run in isolation before any publish step; addlinux/arm64to build platforms; addid-token: writeandattestations: writepermissions torelease; setprovenance: mode=maxand attest the image digest withactions/attest-build-provenance@v4.1.0(push-to-registry: true); add--no-mergesto the changeloggit logcommand; add empty changelog guard; normalize first-release message to"No changes (first release)"(#465) -
Add
adr/0013-testing-strategy.mddocumenting the decision to implement the full test pyramid as a deliberate educational choice (#421) -
Add
test/.../Integration/PlayerWebApplicationTests.cswith 14 HTTP-layer integration tests covering all player endpoints and/healthviaWebApplicationFactory<Program>backed by in-memory SQLite; includesUtilities/TestAuthHandler.csto bypass[Authorize]onGET /players/{id:Guid}; exposeProgramto the test project viapublic partial class Program {}inProgram.cs; addMicrosoft.AspNetCore.Mvc.Testingto the test project (#421) -
Add
test/.../Integration/PlayerRepositoryTests.cswith 9 integration tests coveringRepository<T>(GetAllAsync,FindByIdAsync,RemoveAsync) andPlayerRepository(FindBySquadNumberAsync,SquadNumberExistsAsync); all tests useDatabaseFakes.MigrateAsync()on in-memory SQLite and are tagged[Trait("Category", "Integration")](#461) -
Add
ValidateAsync_SquadNumberNegative_ReturnsValidationErrortest to exercise theGreaterThan(0)rule with a negative value, which passesNotEmpty()but fails the greater-than rule (#427) -
Add
ValidateAsync_FirstNameEmptyInUpdateRuleSet_ReturnsValidationErrortest to verify the"Update"rule set enforces structural field validation (#427) -
Add
adr/directory with 12 Architecture Decision Records documenting architectural choices, technology decisions, and design trade-offs (#372) -
Add ADR index and template at
adr/README.md(#372) -
Add Architecture Decisions section to
README.mdreferencing the ADR index (#372) -
Add ADR guidance section to
CONTRIBUTING.md(#372) -
Add ADR context loading instructions to
.github/copilot-instructions.md(#372)
- Call
.DisableRateLimiting()onMapHealthChecks("/health")to enforce the exemption from the global rate limiter at the endpoint level, ensuring health check probes are never throttled (#451) - Move
UseCors()beforeMapControllers()inProgram.csto follow the standard ASP.NET Core middleware pipeline order; add anInfrastructureservice registration section separating cross-cutting concerns (health checks, CORS, rate limiting, Swagger) from theControllerssection; add descriptive phrases to top-level section banners; add inline comments explaining the purpose and ordering rationale of each middleware; document the dev-only CORS policy intent in bothProgram.csandServiceCollectionExtensions.AddCorsDefaultPolicy(#451) - Replace pre-seeded
storage/players-sqlite3.dbbinary blob with EF CoreMigrateAsync()at startup: schema and seed data are now applied automatically before the first request is served;STORAGE_PATHenv var controls the database file path (Docker volume path in production,AppContext.BaseDirectory/storage/locally); the committed database file,Dockerfiledb copy step, andscripts/run-migrations-and-copy-database.shhave been removed (#459) - Recreate EF Core migrations using
HasData()inOnModelCreating: three self-contained migrations (InitialCreateDDL,SeedStarting11DML,SeedSubstitutesDML) generated by EF Core with literalInsertDatavalues — no migration calls application methods;NormalizePlayerDatasetpatch migration eliminated by folding corrections into seed data from the start (#459) - Replace
DatabaseFakes.CreateTable()(placeholder schema) andDatabaseFakes.Seed()(manual insert bypassing migrations) withDatabaseFakes.MigrateAsync(), which applies the full EF Core migration chain on in-memory SQLite (#459) - Switch runtime base image from
mcr.microsoft.com/dotnet/aspnet:10.0(Debian) tomcr.microsoft.com/dotnet/aspnet:10.0-alpine(before: 113.4 MB → after: 73.9 MB compressed; measured viadocker manifest inspectanddocker save | wc -c); replaceapt-getwithapkanduseradd/groupaddwithadduser/addgroupaccordingly (#456) - Refactor
scripts/entrypoint.sh: addlog()helper with timestamp prefix, replace rawechocalls, and print API base URL on startup (#456) - Rename
ValidateAsync_SquadNumber_BelongsToPlayerBeingUpdated_ReturnsNoErrorstoValidateAsync_SquadNumberBelongsToPlayerBeingUpdated_ReturnsNoErrorsto align with the 3-segment naming convention for service/validator tests (#427) - Make CSharpier step in
/pre-commitconditional (skip with a note if not installed), consistent with the Docker and CodeRabbit steps (#427) - Add "Verify tag commit is reachable from master" step to CD workflow using
git merge-base --is-ancestorbefore any build or publish steps (#439) - Rename five controller test methods to normalize data-state vocabulary:
NonExisting→Nonexistentfor the POST 201 scenario,NonExisting→Unknownfor the four 404-by-lookup scenarios (#452) - Add XML doc
<remarks>block toPlayerFakesdocumenting the three-term data-state vocabulary (existing,nonexistent,unknown) (#452)
GET /playersnow returns200 OKwith an empty list[]when no players exist, instead of404 Not Found(#425)- AutoMapper
Player → PlayerResponseModelprofile now explicitly ignores theIdsource member viaForSourceMember, making the exclusion intentional rather than implicit (#425)
2.1.0 - Dusseldorf - 2026-03-29
- Add SonarCloud configuration via
.sonarcloud.propertieswith explicit CPD exclusions for migrations, generated code, test files, and structurally repetitive production files (#426, #435) - Add bug report issue template (
.github/ISSUE_TEMPLATE/bug_report.md) (#426)
- Normalize player dataset: add Lo Celso (squad 27), correct Fernández/Mac Allister/Messi team data, replace random UUIDs with deterministic UUID v5 values (#435)
- Align CRUD test fixtures: Lo Celso (squad 27) for Create and Delete, Messi (squad 10) for Retrieve, Damián Martínez (squad 23) for Update (#435)
- Bump
codecov/codecov-actionfrom 5.5.2 to 5.5.3 (#423)
- Scope
BeUniqueSquadNumbervalidator to"Create"rule set to prevent false rejection of validPUTrequests (#424)
2.0.0 - Centenario - 2026-03-18
- Refactor error responses to use RFC 7807 Problem Details (#418)
- Add
/squadNumber/path segment to PUT and DELETE routes — breaking change (#418) - Extract
NotFoundTitleconstant and remove redundant null-conditional operator (#418) - Rename test methods to follow Microsoft .NET naming standard (#396)
- Upgrade AutoMapper from 14.x to 16.1.1 (#414) — see Security section
- Bump FluentAssertions from 8.8.0 to 8.9.0 (#417)
- Bump coverlet.collector from 8.0.0 to 8.0.1 (#419)
- Bump softprops/action-gh-release from 2.6.0 to 2.6.1 (#416)
- Add squad number mismatch guard in
PutAsyncand update README (#418) - Strengthen test assertions for Problem Details responses (#418)
- Fix broken 201 assertion in controller test for
Post_Players_NonExisting(#396) - Add missing edge case tests for
UpdateAsync,DeleteAsync, andDateOfBirthboundary validation (#396)
- Sanitize player data before logging to prevent log forging
- Upgrade AutoMapper from 14.x to 16.1.1 to resolve high-severity security vulnerability GHSA-rvv3-g6hj-g44x (#414)
1.1.0 - Bernabeu - 2026-02-09
- Upgrade to .NET 10 LTS from .NET 8 (#368)
- Update Microsoft.AspNetCore.OpenApi to 10.0.0
- Update Microsoft.EntityFrameworkCore.Sqlite to 10.0.0
- Update Microsoft.EntityFrameworkCore.Design to 10.0.0
- Update Microsoft.VisualStudio.Web.CodeGeneration.Design to 10.0.0
- Update Docker images to .NET 10 SDK and runtime (now based on Ubuntu 24.04 LTS instead of Debian 12)
- Update Dockerfile user creation commands for Ubuntu compatibility (
groupadd/useraddinstead ofadduser) - Update CI/CD pipelines to use .NET 10 SDK
- Token efficiency strategy for Copilot/AI agents with optimized instruction loading and improved token counting script (#364)
- 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
1.0.0 - Azteca - 2026-01-22
Initial release. See README.md for complete feature list and documentation.