From 4690c8b5e11a52bd9e9edfa87e484d7c2d50915a Mon Sep 17 00:00:00 2001 From: Frank Tovar Date: Sun, 5 Apr 2026 00:31:46 +0200 Subject: [PATCH] docs: refresh README wording --- README.md | 206 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 107 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index 44255ab..b1d54ca 100644 --- a/README.md +++ b/README.md @@ -1,161 +1,169 @@ # RpgRoller -Fresh full-stack starter scaffold: +RpgRoller is an ASP.NET Core + Blazor Server app for lightweight tabletop campaign play, character sheets, and dice workflows. -- `RpgRoller/`: ASP.NET Core backend + Blazor frontend host (`Components` + `wwwroot`) -- `RpgRoller.Tests/`: xUnit integration-heavy test project -- `RpgRoller.sln`: solution used by local CI script +- `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/`: API integration tests grouped by feature concern -- `RpgRoller.Tests/Services/`: service-level tests grouped by domain concern -- `RpgRoller.Tests/Support/`: shared test harnesses/builders/helpers +- `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`: thin app bootstrap only -- `RpgRoller/Hosting/`: service registration + startup initialization -- `RpgRoller/Api/`: endpoint mapping modules and auth/session filter helpers -- `RpgRoller/Services/`: game workflows with explicit method parameters (no API DTO dependencies) -- `RpgRoller/Services/SkillDefinitionValidator.cs`, `RoleSerializer.cs`, `RollVisibilityParser.cs`, and `CustomRollOptionsResolver.cs`: extracted pure backend rule helpers used by `GameService` -- `RpgRoller/Services/GameStateStore.cs`, `GameStateCloneFactory.cs`, and `GamePersistenceService.cs`: extracted runtime-state ownership and SQLite load/save boundaries used by `GameService` -- `RpgRoller/Services/GameAuthService.cs`: extracted auth/session workflow ownership while `GameService` stays on the existing `IGameService` contract -- `RpgRoller/Services/GameCampaignService.cs`: extracted campaign creation, visibility reads, roster reads, and deletion workflows behind the same facade contract -- `RpgRoller/Services/GameCharacterService.cs`: extracted character creation, transfer, activation, deletion, and owner-scoped listing workflows behind the same facade contract -- `RpgRoller/Services/GameSkillService.cs`: extracted skill-group CRUD, skill CRUD, sheet shaping, and ruleset-specific validation orchestration behind the same facade contract -- `RpgRoller/Services/GameRollService.cs`: extracted roll execution, log shaping, roll detail visibility, and campaign-state snapshot reads behind the same facade contract -- `RpgRoller/Services/GameUserAdministrationService.cs`: extracted username reads, admin user listings, role updates, and account deletion workflows behind the same facade contract +- `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 and SQLite load/save boundaries +- `RpgRoller/Services/SkillDefinitionValidator.cs`, `RoleSerializer.cs`, `RollVisibilityParser.cs`, and `CustomRollOptionsResolver.cs`: shared rules and parsing helpers Frontend: -- `RpgRoller/Components/`: Blazor root app, routes, layout and page components -- `RpgRoller/Components/Pages/Home.razor`: minimal gateway page (loading/auth/workspace switch) -- `RpgRoller/Components/Pages/Home.razor.cs`: single `Home` code-behind with only gateway/session-view orchestration -- `RpgRoller/Components/Pages/Workspace.razor`: authenticated workspace UI and workspace-specific state/logic -- `RpgRoller/Components/Pages/WorkspaceState.cs`, `WorkspaceToast.cs`, `WorkspaceFeedbackService.cs`, `WorkspaceSessionCoordinator.cs`, `WorkspaceAdminCoordinator.cs`, `WorkspaceCampaignCoordinator.cs`, `WorkspaceCampaignScopeCoordinator.cs`, `WorkspacePlayCoordinator.cs`, and `WorkspaceLiveStateController.cs`: extracted workspace UI state, toast records, feedback/status handling, session/bootstrap orchestration, admin user actions, campaign-management/modal flows, campaign-scope loading, play/log coordination, and live-state reconciliation while `Workspace` remains the behavior owner -- `RpgRoller/Components/**/*.razor.cs`: component code-behind classes (state, handlers, parameters, injected dependencies); `.razor` files remain markup-focused -- `RpgRoller/Components/Pages/Home.Models.cs`: reusable `FormState` + page form models -- `RpgRoller/Components/Pages/HomeControls/`: auth, campaign management, play-screen, and modal controls extracted from `Home.razor` -- Form ownership model: controls own transient form/error state and execute their concern-specific API mutations directly -- Skill create/edit workflow ownership: `CharacterPanel` (characters own skills in UI and behavior) -- `RpgRoller/Components/RpgRollerApiClient.cs`: shared browser API client used by `Home`, `Workspace`, and leaf controls -- `RpgRoller/wwwroot/js/rpgroller-api.js`: browser-side API + SSE + session storage interop for Blazor -- `RpgRoller/wwwroot/styles.css`: responsive UX styling and theme tokens +- `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 and JS-invokable entry points +- `RpgRoller/Components/Pages/WorkspaceState.cs`: workspace UI state and computed projections +- `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 -Backend state persistence: +Current repo note: -- EF Core with SQLite (`Microsoft.EntityFrameworkCore.Sqlite`) -- Development DB: `RpgRoller/App_Data/rpgroller.development.db` -- Default DB: `RpgRoller/App_Data/rpgroller.db` -- Database schema is created/upgraded automatically on startup via EF Core migrations (`Database.Migrate`) -- Runtime state is loaded once at startup into memory and written back to SQLite on successful state changes +- `TASKS.md` tracks the remaining GameService and Workspace decomposition work. +- 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. -Gameplay capabilities now include: +## Runtime and Persistence -- Instant skill filtering in the character panel (filters live while typing and hides non-matching skills/groups) -- Supported campaign rulesets include D6 System, D&D 5e, and Rolemaster -- Skill groups per character with skill prototypes (create/edit/delete groups, assign/reassign skills, and prefill new skill forms from group defaults) -- Skill and skill-group deletion flows -- GM-driven character owner transfer within campaign management flows -- Character owner selection in edit modal backed by existing-username dropdown data -- Role-aware authorization with admin role support (including admin user/role management) -- Admin workspace tools include direct download of the live SQLite database file -- Campaign deletion by campaign owner or admin (unlinks characters from the campaign and clears campaign log entries) -- User deletion by admin also deletes campaigns owned by that user and unlinks all characters from those deleted campaigns -- Play screen visibility is owner-scoped: only owned characters are listed, and private log entries are visible only to the roller -- Campaign management owner labels use account display names (no GUID fallback rendering) -- Character edit flow supports unlinking from campaigns (owner/GM/admin) and assigning to any existing campaign via expanded campaign options -- Campaign management supports character deletion by character owner or admin -- Shared top header control across all authenticated workspace screens (play, campaign management, admin) -- Admin user management is integrated into workspace screen toggles (`Play`, `Campaign Management`, `Admin`) -- Rolemaster expression validation now accepts generic standard expressions such as `d10`, `2d10+48`, `15d10`, and `d100-15`; `d100!+85` remains the special open-ended percentile form -- Rolemaster open-ended percentile skills and skill-group defaults now persist a nullable `FumbleRange` field, while D6 and D&D rows migrate forward unchanged -- Rolemaster create/edit forms now keep the expression authoritative, show generic Rolemaster syntax help, and reveal `FumbleRange` only when the expression is an open-ended percentile roll -- Rolemaster roll execution now supports generic standard Rolemaster rolls (`NdS+x`, with implicit count `1` for `dS`) plus open-ended percentile (`d100!+x`) with recursive high-end chaining and low-end subtraction based on `FumbleRange`; low-end trigger rolls are shown for auditability but do not count toward the total -- Compact campaign-log summaries stay dense for Rolemaster rolls, while lazy-loaded roll detail includes ordered die metadata for each open-ended follow-up step -- Play screen campaign logs now include a detached bottom custom-roll panel below the scrollable log feed; it records arbitrary expressions against the selected character without creating a skill, and invalid expressions stay inline on the field with tooltip/error styling instead of using error toasts -- Startup migration coverage is validated against a copied temp-file instance of `RpgRoller/App_Data/rpgroller.development.db` before feature work is considered complete +- 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. -## Prerequisites +## 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+ -- Run `dotnet tool restore` once to enable the repo-local dotnet commands. -- Run `npm ci` once to install the repo-local Playwright toolchain. -- Run `npm exec playwright install chromium` once to install the browser used by local smoke tests. -## Local Development +Initial setup: -1. Run the local CI parity script: - ```powershell - pwsh ./scripts/ci-local.ps1 - ``` -2. Start the backend: +```powershell +dotnet tool restore +npm ci +npm exec playwright install chromium +``` + +Run locally: + +1. Start the app: ```powershell dotnet run --project RpgRoller/RpgRoller.csproj ``` -3. Open `http://localhost:5000` (or the port shown in the console). +2. Open `http://localhost:5000` or the URL printed in the console. Playwright helpers: -- Install/update browser dependencies: - ```powershell - npm exec playwright install chromium - ``` -- Run the checked-in smoke test against an isolated temp SQLite database: +- Run the checked-in smoke suite against an isolated temporary SQLite database: ```powershell pwsh ./scripts/run-playwright.ps1 ``` -- Run the Playwright suite directly when the app is already running: +- Run Playwright directly when the app is already running: ```powershell npm run e2e ``` -VS Code F5 debug profiles are available in `.vscode/launch.json`: +VS Code launch profiles in `.vscode/launch.json`: - `RpgRoller: Server` - `RpgRoller: Server + Edge (F5)` - `RpgRoller: Server + Firefox (F5)` -To use a custom SQLite database path, set `ConnectionStrings__RpgRoller`. -To run under a subfolder (for example `/rpgroller`), set `PathBase` (for example `PathBase=/rpgroller`). +Environment overrides: -For migration authoring, use the local tool command form: +- 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: ```powershell dotnet dotnet-ef migrations add --project RpgRoller/RpgRoller.csproj --startup-project RpgRoller/RpgRoller.csproj ``` -For SQLite migrations, keep table-rebuild operations isolated from unrelated schema/data changes. If a migration needs both a rebuild-triggering change (for example `AlterColumn`) and another independent operation, split them into separate migrations so EF Core does not emit non-transactional migration warnings. +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 -- Runtime frontend is Blazor Server with interactive components. -- Browser interop is in `RpgRoller/wwwroot/js/rpgroller-api.js`. -- Root static assets such as `styles.css` are linked through Blazor's `@Assets[...]` pipeline so deploys get fingerprinted cache-busting URLs automatically. -- Workspace reads are resolved server-side through scoped query services; browser interop remains for browser-only concerns such as session storage, SSE wiring, and DOM helpers. -- Live workspace refreshes now compare separate roster, per-character sheet, and log versions so unrelated state changes do not force a full roster + sheet + log reload. -- Workspace campaign data is loaded in bounded slices: visible campaign summaries, a selected campaign roster, a selected character sheet, and a 25-row incremental log window backed by `/api/campaigns/{campaignId}/log/page`. -- Campaign log rows now ship compact summary data first, including structured special-event badges for wild dice spikes, natural 1/20 results, and Rolemaster rare/fumble triggers, and lazy-load dice + breakdown detail through `/api/rolls/{rollId}` only when a row is expanded. -- Newly appended campaign-log rolls auto-expand in the play workspace, with the roll response reused as the initial detail payload for the local roller to avoid an extra detail fetch. -- The campaign log footer supports custom roll submission for the currently selected character; D6 custom rolls use the baseline one-wild-die/fumble behavior, while D&D 5e and Rolemaster rely only on the submitted expression. -- Hot API contracts share a source-generated `System.Text.Json` context, and HTTP JSON responses are gzip-compressed when the client advertises support. -- OpenAPI contract source remains at `openapi/RpgRoller.json`. +- 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 -- Tests: +- Test command: ```powershell dotnet test RpgRoller.Tests/RpgRoller.Tests.csproj --collect:"XPlat Code Coverage" --settings RpgRoller.Tests/coverlet.runsettings ``` -- Regression tests enforce payload budgets for the hottest contracts: character sheet reads, initial log page loads, incremental log updates, roll mutation responses, and lazy-loaded Rolemaster roll detail payloads. - Coverage gate: ```powershell pwsh ./scripts/check-coverage.ps1 -MinLineRate 0.90 -MinBranchRate 0.70 ``` -- Coverage collector scope: - - `RpgRoller.Tests/coverlet.runsettings` now measures the full backend assembly (`RpgRoller`), not only service namespace files. +- Local parity script: + ```powershell + 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.