Overview
Version 2 · Expand overview beyond auth: add Story/Media/Lookup feature areas, three-database data layer, and cross-links to the new architecture/database/api/user-guide pages
QDG CMS API
A .NET 9 Web API that provides content management services for QDG and affiliated sites: story/article authoring, an image/video gallery backed by Wasabi (S3-compatible) storage, and reference-data lookups for editor dropdowns. Authentication is not owned locally — it is delegated to the centralized QDBAuth service, with this API managing only opaque session cookies.
Architecture
Clean/onion architecture with four projects in QDG-CMS-BE.sln:
- QDG.CMS.API — ASP.NET Core entry point: controllers, Serilog bootstrap logging, Swagger/OpenAPI, API versioning (
Asp.Versioning), CORS, and the custom session authentication handler. - QDG.CMS.Application — application layer: DTOs, service interfaces/implementations, lookup providers, settings (
AuthSettings,WasabiSettings), mappings, and validation helpers. - QDG.CMS.Domain — domain entities (
Story,Media) and enums (StoryAccessScope,MediaType). - QDG.CMS.Infrastructure — data access (Dapper repositories across three MySQL databases), health checks, and external service clients (auth, Wasabi storage).
See Architecture for the full request-flow and layering detail, Database for schema, API Reference for every endpoint, and User Guide for running and using the API.
Feature areas
- Auth — session login via the centralized QDBAuth service (login + TOTP), opaque
qdg_sessioncookie issued locally. - Stories — CRUD for
tblcms(the CMS article table shared with the public Racing.CMS API), including parent/child story linking, site/news-type mapping sync, and restricted-content tag validation. - Media — CRUD for
tblphotos(Image Gallery + Video Gallery, one table discriminated bytype), with a two-phase presigned-URL upload flow against Wasabi. - Lookups — read-only reference data for editor dropdowns: CMS-side (sites, authors, contributors, news types) and racing reference data from the
qdbdatabase (horses, trainers, jockeys, courses, races).
Data & storage
Three separate MySQL databases, same server/credentials but distinct connection strings and DI marker interfaces (IDbConnectionFactory, IQdbConnectionFactory, IPhotoGalleryConnectionFactory), all backed by the same DbConnectionFactory/Dapper implementation:
- cms —
tblcmsand related mapping/reference tables. - qdb — horse/trainer/jockey/course/race reference data.
- photogallery —
tblphotos(photo + video rows).
Wasabi (S3-compatible) object storage holds the actual media files; WasabiHealthCheck verifies connectivity alongside MySqlHealthCheck at /health.
Cross-cutting
- Structured logging via Serilog (console sink, bootstrap + request logging).
/healthendpoint returns a JSON report of tagged checks (db,ready,storage).- CORS locked to an
AllowedOriginsallow-list, credentials enabled. - API versioning via
Asp.Versioning, all routes underapi/v{version}/....
Deployment
Manual workflow_dispatch GitHub Actions pipeline (.github/workflows/deploy.yml) builds the dev branch as a self-contained win-x64 publish and deploys to an on-prem IIS site (QdgCmsApi), with pre-deploy backup, post-deploy /health check, and automatic rollback to the latest backup on failure. Runs on a self-hosted Windows runner.