# RpgRoller Fresh full-stack starter scaffold: - `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 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 ## 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) 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/**/*.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 Backend state persistence: - 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 Gameplay capabilities now include: - 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 - Startup migration coverage is validated against a copied temp-file instance of `RpgRoller/App_Data/rpgroller.development.db` before feature work is considered complete ## Prerequisites - .NET SDK 10.0+ - PowerShell 7+ - Node.js 22+ - Run `dotnet tool restore` once to enable the repo-local `dotnet-ef` command. - 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 1. Run the local CI parity script: ```powershell pwsh ./scripts/ci-local.ps1 ``` 2. Start the backend: ```powershell dotnet run --project RpgRoller/RpgRoller.csproj ``` 3. Open `http://localhost:5000` (or the port shown 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: ```powershell pwsh ./scripts/run-playwright.ps1 ``` - Run the Playwright suite directly when the app is already running: ```powershell npm run e2e ``` VS Code F5 debug profiles are available 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`). For migration authoring, use the local tool command form: ```powershell dotnet dotnet-ef migrations add --project RpgRoller/RpgRoller.csproj --startup-project RpgRoller/RpgRoller.csproj ``` ## 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. - 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`. ## Test and Coverage - Tests: ```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.