Live at bldleague.pl
A web application for managing a BLD (Blindfolded) speedcubing league. Tracks seasons, leagues, rounds, matches, and player standings. The UI is in Polish.
Built with ASP.NET Core 10 (Razor Pages), PostgreSQL, and WCA OAuth authentication.
- League and season management (multiple leagues run simultaneously within a season)
- 1v1 match tracking with WCA-rules Ao5 scoring
- Scramble management (shared across leagues per round)
- Round and season standings with automatic refresh
- Admin panel for full CRUD over all entities
- CSV import/export for bulk data management
- Authentication via World Cube Association OAuth — only pre-registered WCA members can log in
- .NET 10 SDK
- PostgreSQL — or Docker (see below)
docker compose up --buildThis starts the app on port 8080 and a PostgreSQL 17 database. Migrations are applied automatically on startup.
-
Configure the connection string in
src/Web/appsettings.json:{ "ConnectionStrings": { "Default": "Host=localhost;Database=bldleague;Username=postgres;Password=postgres" } } -
Configure WCA OAuth credentials (obtain from WCA Developers) in
src/Web/appsettings.json:{ "WCA": { "ClientId": "<your-client-id>", "ClientSecret": "<your-client-secret>" } } -
Run the app:
dotnet run --project src/Web
The database is migrated automatically on startup.
All settings are configured in src/Web/appsettings.json.
| Key | Description |
|---|---|
ConnectionStrings:Default |
PostgreSQL connection string |
WCA:ClientId |
WCA OAuth application client ID |
WCA:ClientSecret |
WCA OAuth application client secret |
SuperAdmin:WcaId |
WCA ID of the initial admin user (optional, seeded on first run) |
SuperAdmin:FullName |
Display name of the initial admin user (optional) |
For Docker/production, use environment variables with double-underscore notation, e.g. ConnectionStrings__Default.
Login is handled via WCA OAuth. Users must be pre-registered in the database by an admin before they can log in — unknown WCA members are rejected. If SuperAdmin is configured, that user is seeded automatically on first startup as the initial admin.
Roles:
- Admin — full access to the admin panel
- User — read-only public access (no admin panel)
The solution follows Clean Architecture with four projects:
src/
├── Domain/ — entities, value objects, scoring logic (no dependencies)
├── Application/ — CQRS handlers via MediatR, repository interfaces, result types
├── Infrastructure/ — EF Core + PostgreSQL, repository implementations, migrations
└── Web/ — ASP.NET Core Razor Pages, WCA OAuth, admin panel
Key patterns:
- CQRS via MediatR — every operation is a typed
*Request/*RequestHandler - Repository + Unit of Work — all data access behind interfaces
- Result pattern —
CommandResult.Ok()/.Fail()instead of exceptions for control flow - Auto-migrations —
EnsureMigratedHelperapplies pending migrations on startup
dotnet ef migrations add MigrationName --project src/Infrastructure --startup-project src/Webdotnet build BldLeague.slnx
dotnet run --project src/WebVendored under src/Web/wwwroot/lib/ — the files are checked into the repo, so no npm or other frontend tooling is needed:
- Bootstrap (MIT) — the only CSS framework; also provides the JS for dropdowns, collapses, tabs, and tooltips.
- Bootstrap Icons (MIT) — icon font used across all pages.
- jQuery (MIT) + jquery-validation / jquery-validation-unobtrusive (MIT) — client-side validation of Razor Pages forms.
- stackmat (MIT) — decodes the audio-jack signal of a Stackmat/SpeedStacks timer in the browser; powers the Stackmat input method of the result submission timer. Do not upgrade without re-testing against real hardware (see the comment in
src/Web/wwwroot/js/timer-drivers/stackmat.js). - DSEG (SIL OFL 1.1) — seven-segment display font used for the submission timer's time display.
- Chart.js (MIT) — renders the Progresja charts on the user profile, statistics, and player comparison pages.
- Tom Select (Apache-2.0) — searchable user picker on the admin league-season roster page.
No dependency is loaded from a CDN — the site is fully self-contained.
Versions live in the .csproj files; this list is package + purpose only.
- MediatR (Application) — CQRS request/handler dispatch between the Web and Application layers.
- Microsoft.EntityFrameworkCore + Npgsql.EntityFrameworkCore.PostgreSQL (Infrastructure) — ORM and its PostgreSQL provider.
- EFCore.NamingConventions (Infrastructure) — snake_case table/column naming for PostgreSQL.
- Microsoft.Extensions.Hosting.Abstractions + Microsoft.Extensions.Options.ConfigurationExtensions (Infrastructure) — hosted-service and options wiring for the round-standings refresh background service.
- Microsoft.EntityFrameworkCore.Design (Web) — design-time support for
dotnet ef migrations.