Files
RpgRoller/README.md

9.6 KiB

RpgRoller

RpgRoller is an ASP.NET Core + Blazor Server app for lightweight tabletop campaign play, character sheets, and dice workflows.

  • RpgRoller/: web app, API endpoints, domain model, EF Core persistence, Blazor components, and static assets
  • RpgRoller.Tests/: xUnit coverage for API behavior, services, hosting, payload budgets, and persistence/migration paths
  • RpgRoller.sln: solution used by local development and repo scripts

Test layout:

  • RpgRoller.Tests/Api/: endpoint and host-facing integration tests
  • RpgRoller.Tests/Services/: service and rules-engine tests
  • RpgRoller.Tests/Support/: shared harnesses, builders, and test host helpers

Code Organization

Backend:

  • RpgRoller/Program.cs: app bootstrap, JSON options, compression, API/component mapping, and optional PathBase
  • RpgRoller/Hosting/: service registration, startup initialization, SQLite path resolution, and schema upgrades
  • RpgRoller/Api/: minimal API endpoint groups, request mappings, cookie/session helpers, and result mapping
  • RpgRoller/Services/: gameplay and account workflows behind IGameService
  • RpgRoller/Services/GameService.cs: facade over composed domain services
  • RpgRoller/Services/GameAuthService.cs: registration, login, logout, session lookup, and GetMe
  • RpgRoller/Services/GameCampaignService.cs: campaign creation, listing, roster reads, campaign options, and deletion
  • RpgRoller/Services/GameCharacterService.cs: character creation, updates, activation, deletion, transfer, and owner-scoped reads
  • RpgRoller/Services/GameSkillService.cs: skill-group CRUD, skill CRUD, sheet shaping, and ruleset validation
  • RpgRoller/Services/GameRollService.cs: skill/custom rolls, compact log pages, roll detail, and campaign state snapshots
  • RpgRoller/Services/GameUserAdministrationService.cs: username reads, admin user listing, role updates, and account deletion
  • RpgRoller/Services/GameStateStore.cs, GameStateCloneFactory.cs, and GamePersistenceService.cs: in-memory runtime state, campaign-state version tracking, and SQLite load/save boundaries
  • RpgRoller/Services/GameAuthorization.cs, GameContextResolver.cs, and GameDtoMapper.cs: shared authorization, session/campaign resolution, and backend read-model mapping
  • RpgRoller/Services/RollEngine.cs, StandardRollEngine.cs, D6RollEngine.cs, RolemasterRollEngine.cs, RollBreakdownFormatter.cs, and CampaignLogSummaryBuilder.cs: ruleset-specific dice execution, breakdown formatting, and compact campaign-log summaries
  • RpgRoller/Services/SkillDefinitionValidator.cs, RoleSerializer.cs, RollVisibilityParser.cs, and CustomRollOptionsResolver.cs: shared rules and parsing helpers

Frontend:

  • RpgRoller/Components/: Blazor app shell, routes, layout, page components, and query/client helpers
  • RpgRoller/Components/Pages/Home.razor: gateway that switches between loading, auth, and authenticated workspace views
  • RpgRoller/Components/Pages/Home.razor.cs: gateway/session orchestration for Home
  • RpgRoller/Components/Pages/Workspace.razor: authenticated workspace UI
  • RpgRoller/Components/Pages/Workspace.razor.cs: workspace composition root, coordinator wiring, lifecycle, and JS-invokable entry points
  • RpgRoller/Components/Pages/WorkspaceState.cs: workspace UI state plus pure computed and formatting projections used directly by the Razor view
  • RpgRoller/Components/Pages/WorkspaceSessionCoordinator.cs, WorkspaceCampaignCoordinator.cs, WorkspaceCampaignScopeCoordinator.cs, WorkspacePlayCoordinator.cs, WorkspaceAdminCoordinator.cs, WorkspaceLiveStateController.cs, WorkspaceFeedbackService.cs, and WorkspaceToast.cs: session/bootstrap, campaign scope, play/log, admin, live update, and toast concerns used by Workspace
  • RpgRoller/Components/Pages/HomeControls/: workspace and auth child components, forms, header, panels, and modal controls
  • RpgRoller/Components/RpgRollerApiClient.cs: browser API client for write actions
  • RpgRoller/Components/WorkspaceQueryService.cs: server-side read model access for workspace data
  • RpgRoller/wwwroot/js/rpgroller-api.js: browser interop for session storage, SSE wiring, and DOM helpers
  • RpgRoller/wwwroot/styles.css: app styling and responsive layout

Current repo note:

  • TASKS.md records the completed decomposition work and the final execution notes for this refactor.
  • This README describes the code as it exists today. It does not treat blueprint items in TASKS.md as finished unless they are already present in the repo.

Runtime and Persistence

  • Persistence uses EF Core with SQLite (Microsoft.EntityFrameworkCore.Sqlite).
  • The default database file is RpgRoller/App_Data/rpgroller.db.
  • ConnectionStrings__RpgRoller overrides the SQLite path for local runs, tests, or temporary environments.
  • Startup applies pending EF Core migrations through Database.Migrate().
  • The app loads runtime state into memory during startup and persists successful state changes back to SQLite.
  • RpgRoller/App_Data/rpgroller.development.db is a checked-in migration coverage fixture used by hosting tests that copy it to a temporary file before validation.

Product Capabilities

  • Supported campaign rulesets: D6 System, D&D 5e, and Rolemaster
  • Account registration, login, session-based auth, and role-aware authorization
  • Admin tools for user listing, role updates, account deletion, and direct SQLite database download
  • Campaign creation, roster reads, participant-scoped visibility, and owner/admin deletion
  • Character creation, activation, owner transfer, campaign reassignment or unlinking, and owner/admin deletion
  • Skill groups with reusable defaults plus skill and skill-group create, edit, reassign, and delete flows
  • Owner-scoped play workspace that lists only the current user's characters while preserving GM/admin management capabilities
  • Campaign log paging, lazy-loaded roll detail, compact summaries, and live state refresh through SSE
  • Custom roll submission from the play screen without creating a persisted skill
  • Instant skill filtering in the character panel
  • Campaign management owner labels based on display names

Rolemaster support:

  • Standard expressions such as d10, 15d10, 2d10+48, and d100-15
  • Open-ended percentile expressions such as d100!+85
  • Conditional FumbleRange handling for open-ended percentile skills and skill-group defaults
  • Open-ended high chaining and low-end subtraction with ordered die metadata in roll detail
  • Compact log badges and summaries for open-ended/fumble-related events

Local Development

Prerequisites:

  • .NET SDK 10.0+
  • PowerShell 7+
  • Node.js 22+

Initial setup:

dotnet tool restore
npm ci
npm exec playwright install chromium

Run locally:

  1. Start the app:
    dotnet run --project RpgRoller/RpgRoller.csproj
    
  2. Open http://localhost:5000 or the URL printed in the console.

Playwright helpers:

  • Run the checked-in smoke suite against an isolated temporary SQLite database:
    pwsh ./scripts/run-playwright.ps1
    
  • Run Playwright directly when the app is already running:
    npm run e2e
    

VS Code launch profiles in .vscode/launch.json:

  • RpgRoller: Server
  • RpgRoller: Server + Edge (F5)
  • RpgRoller: Server + Firefox (F5)

Environment overrides:

  • Set ConnectionStrings__RpgRoller to point at a custom SQLite database.
  • Set PathBase to host the app under a sub-path such as /rpgroller.

Migration authoring:

dotnet dotnet-ef migrations add <MigrationName> --project RpgRoller/RpgRoller.csproj --startup-project RpgRoller/RpgRoller.csproj

SQLite migration rule:

  • Keep table-rebuild operations separate from unrelated schema or data changes so EF Core does not emit non-transactional migration warnings.

Frontend Runtime

  • The UI runs as Blazor Server with interactive components.
  • Static assets are linked through Blazor's @Assets[...] pipeline for fingerprinted cache-busting URLs.
  • Workspace reads are resolved server-side through WorkspaceQueryService; browser interop stays limited to browser-only concerns.
  • Live workspace refresh compares separate roster, per-character sheet, and log versions so unrelated changes do not trigger full reloads.
  • Campaign log data is loaded in bounded slices: campaign summaries, one selected roster, one selected character sheet, and a 25-row incremental log window from /api/campaigns/{campaignId}/log/page.
  • Log rows return compact summary data first and lazy-load full detail from /api/rolls/{rollId} when expanded.
  • Newly appended local rolls auto-expand in the play workspace and reuse the roll response as the initial detail payload.
  • Custom roll submission uses the selected character context; D6 uses baseline wild-die/fumble behavior, while D&D 5e and Rolemaster use the submitted expression directly.
  • API JSON contracts use the source-generated RpgRollerJsonSerializerContext.
  • HTTP JSON responses are gzip-compressed when the client advertises support.
  • The OpenAPI contract source lives at openapi/RpgRoller.json.

Test and Coverage

  • Test command:
    dotnet test RpgRoller.Tests/RpgRoller.Tests.csproj --collect:"XPlat Code Coverage" --settings RpgRoller.Tests/coverlet.runsettings
    
  • Coverage gate:
    pwsh ./scripts/check-coverage.ps1 -MinLineRate 0.90 -MinBranchRate 0.70
    
  • Local parity script:
    pwsh ./scripts/ci-local.ps1
    
  • Regression tests enforce payload budgets for character sheet reads, initial and incremental campaign log loads, roll mutation responses, and lazy-loaded Rolemaster roll detail payloads.
  • RpgRoller.Tests/coverlet.runsettings measures the full RpgRoller backend assembly.