This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
Fan project for analyzing StarCraft II Direct Strike replays. The backend serves data to the website dsstats.pax77.org and a .NET MAUI desktop client distributed via the Microsoft Store.
# Build the server solution
dotnet build src/server/server.sln
# Run all tests
dotnet test src/tests/dsstats.tests/dsstats.tests.sln
# Run a single test by name
dotnet test src/tests/dsstats.tests/dsstats.tests.sln --filter "FullyQualifiedName~<TestMethodName>"
# Run the API (requires MySQL - see docker/ for local setup)
cd src/server/dsstats.api && dotnet run
# Run the web frontend
cd src/server/dsstats.web && dotnet run
# Start MySQL via Docker (WSL/Linux)
cd src/server/docker && docker-compose up -dThe solution targets .NET 10 with LangVersion=latest and nullable reference types enabled throughout.
dsstats.api— ASP.NET Core Web API. All routes prefixedapi10/. Handles replay uploads (two upload paths: legacyUploadDtoand newerUploadRequestDto), stats queries, player data, and builds.dsstats.web— Blazor Server app (interactive server render mode). Callsdsstats.apiover HTTP; does not access the database directly.dsstats.db— EF CoreDsstatsContext+ all entity models. Also containsStagingDsstatsContextwhich redirectsPlayerRatings,ReplayRatings, andReplayPlayerRatingsto*_tmptables for bulk rating recalculations.dsstats.dbServices— Scoped services implementing shared interfaces viaDsstatsContextdirectly. Used indsstats.api.dsstats.apiServices— HTTP client wrappers implementing the same interfaces asdsstats.dbServices, forwarding calls to the API. Used indsstats.web.dsstats.ratings— Elo-style rating calculation engine viaIRatingService(singleton).sc2arcade.crawler— Background service for crawling SC2 Arcade match data.dsstats.migrations.mysql/postgresql/sqlite— Provider-specific EF Core migration assemblies.
dsstats.shared— Shared DTOs, enums (Commander,RatingType,GameMode,StatsType, etc.), and all service interfaces (IStatsService,IReplayRepository,IPlayerService, etc.).dsstats.weblib— Shared Blazor component library (razor components, Chart.js integration viapax.BlazorChartJs).dsstats.parser— SC2 replay file parser producingReplayDto.
Uses MSTest with Moq. Tests that require a database use SQLite in-memory (via dsstats.migrations.sqlite):
var connection = new SqliteConnection("Filename=:memory:");
connection.Open();
services.AddDbContext<DsstatsContext>(o => o.UseSqlite(connection, options =>
options.MigrationsAssembly("dsstats.migrations.sqlite")));Test data (actual .SC2Replay files and .json metadata) is in src/tests/dsstats.tests/testdata/.
Interfaces in dsstats.shared/Interfaces/ are implemented twice — once in dsstats.dbServices (direct EF Core) and once in dsstats.apiServices (HTTP proxies). When adding a new data access feature, implement it in both.
Large services are split into domain-focused partial classes:
PlayerService.cs+PlayerService.Player.cs,PlayerService.CmdrStrength.cs,PlayerService.Distrubution.csRatingService.cs+RatingService.Calc.cs,RatingService.Pre.cs,RatingService.Arcade.cs,RatingService.Csv.csImportService.cs+ImportService.Candidates.cs,ImportService.Duplicates.cs,ImportService.Arcade.csReplayRepository.cs+ReplayRepository.Arcade.cs,ReplayRepository.Ratings.cs
New stat types require:
- A class inheriting
StatsProviderBase<T>indsstats.dbServices/Stats/ - Registration as
IStatsProviderinProgram.cs - A corresponding
StatsTypeenum value indsstats.shared/Enums.cs
StatsService dispatches to the appropriate provider by StatsType at runtime.
- Primary: MySQL 8.4 in production. Connection string config key:
dsstats:ConnectionString. DsstatsContextis always injected via DI (scoped).StagingDsstatsContextmaps rating tables to*_tmpvariants — use during rating recalculation jobs.DsstatsContext.Week(DateTime)is a mapped MySQLWEEK(..., 3)DB function; it cannot be called client-side.- All EF queries use
ToListAsync/FirstOrDefaultAsyncwith aCancellationToken. - Migrations are in separate assemblies per provider.
Uploads arrive at UploadController and are pushed onto a Channel<UploadJob> or Channel<ReplayUploadJob>. Background IHostedService implementations drain the channels. UploadService is a singleton.
- API routes:
[Route("api10/[controller]")]. Legacy aliasapi8/v1/[controller]exists onUploadControllerfor backward compatibility. - Authentication:
AuthenticationFilterAttributechecks theAuthorizationheader for a static key (singleton). - Caching:
IMemoryCachefor expensive stats queries (cache keys viaStatsRequest.GetMemKey(), 3-hour TTL). - Rate limiting: Fixed-window policy (
"fixed": 4 requests / 12 seconds, queue 2) on replay upload endpoints. - Production config: Loads
/data/localserverconfig.json.TimedHostedServiceonly runs in production. - SignalR hubs:
/hubs/upload(UploadHub) and/hubs/pickban(PickBanHub).