# TECH - Kickoff Blueprint ## 0) Current scaffold status - Root solution: `RpgRoller.sln` - Backend/full-stack project: `RpgRoller` (Minimal API + Blazor frontend host) - Frontend source: `RpgRoller/Components/*` + `RpgRoller/wwwroot/*` - Test project: `RpgRoller.Tests` (xUnit + `WebApplicationFactory` integration tests) - Test file split: concern-based API tests (`RpgRoller.Tests/Api/*`), service tests (`RpgRoller.Tests/Services/*`), and shared helpers (`RpgRoller.Tests/Support/*`) - Persistence: EF Core + SQLite (`RpgRoller/Data/RpgRollerDbContext.cs`) with in-memory runtime cache in `GameService` - OpenAPI source: `openapi/RpgRoller.json` - Local CI parity entrypoint: `scripts/ci-local.ps1` - API endpoint modules: `RpgRoller/Api/*Endpoints.cs` + shared session/auth helpers - Service boundary model: API request DTOs are mapped to explicit service method parameters before workflow execution - Current backend features: auth/session, campaign/character/skill management (including d6 wild-dice/fumble skill options), ruleset-aware rolls, filtered campaign logs, and SSE state updates. - Current frontend features: Blazor-based authenticated campaign workspace with live log updates, full roll workflow controls, and die-state visualization for roll outcomes. ## 1) Stack and baseline choices - ASP.NET Core Minimal API on .NET 10. - EF Core with SQLite file persistence in current project (single-node deployment). - Game state is hydrated once on startup and then served from in-memory state; writes are persisted back to SQLite after successful mutations. - Cookie authentication (`HttpOnly`, `SameSite=Strict`, secure in production). - Blazor frontend host with Razor components and minimal JS interop for browser APIs. - OpenAPI generated from backend as contract documentation. - xUnit integration-heavy test suite with isolated SQLite test databases and coverage gates. ## 2) Architecture patterns to keep ### 2.1 API shape and layering - Route mapping in thin endpoint modules (`MapXEndpoints` per feature area). - Domain logic in workflow services (`*WorkflowService`) instead of endpoint lambdas. - Service responses normalized via `ServiceResult` + `ServiceError`, then mapped to HTTP at the edge. - Consistent `ProblemDetails` payloads with `error` extension for machine-usable errors. - Endpoint-level concerns handled by endpoint filters (`AdminOnlyFilter`, `PhaseRequirementFilter`, `PhaseOrJokerFilter`). Keep this split: - Endpoint adapters: auth, deserialization, HTTP mapping only. - Workflow services: validation, query/update rules, transactions. - Helpers: shared utility and security-sensitive routines. ### 2.2 Middleware pipeline discipline - Security and behavior depend on middleware ordering; keep explicit ordering. - Important current order: 1. Forwarded headers 2. Rate limiter 3. HSTS + HTTPS redirect (prod) 4. Security headers writer 5. Base path 6. Global exception handling 7. Authentication 8. Ensure player still exists 9. CSRF origin/referer checks 10. Authorization 11. State change notifier middleware 12. Static files 13. Endpoint mapping ### 2.3 State synchronization - Event-driven invalidation with SSE (`/api/events/state`) plus heartbeats. - Conditional reads for state (`ETag` + `If-None-Match`) to return `304`. - In-process notifier (`StateChangeNotifier`) with monotonic version and etag stamp. - Mutation middleware (`StateChangeNotificationMiddleware`) emits invalidation only for successful mutating API calls. This pattern is a strong baseline for low to medium scale and should be the default in the new app. ### 2.4 Security baseline - Cookie auth with short/medium session sliding expiration plus absolute lifetime cap. - Explicit same-origin CSRF checks for authenticated mutating API calls. - Rate limiting on auth-sensitive and admin-sensitive surfaces with custom `429` payload. - Security headers on all responses (`CSP`, `X-Content-Type-Options`, `X-Frame-Options`, `Referrer-Policy`, `Permissions-Policy`). - Forwarded headers restricted to configured trusted proxies/networks only. - Owner/admin protection rules enforced in business logic and DB constraints. - Destructive admin operations require password re-confirmation. - Password hashing is versioned and supports transparent upgrade on successful auth. - Current hash defaults to Argon2id, with forward compatibility retained via versioning. ### 2.5 Data and invariants - Strong DB models backed by SQLite - DB-level guardrails (trigger) to complement app-level checks - EF patterns: - `AsNoTracking()` for read-only queries - `ExecuteUpdateAsync` / `ExecuteDeleteAsync` for efficient bulk operations - Explicit transactions for multi-step destructive/admin operations - Conflict handling around unique constraints ### 2.6 Frontend architecture - Blazor component tree rooted in `Components/App.razor` and `Components/Pages/Home.razor`. - Home page logic split by concern with partials (`Home.State/Auth/Campaign/Character/Skill/Lifecycle/Realtime/Api/Presentation/Validation.cs`) to keep churn localized. - Form UX state uses reusable `FormState` containers in leaf controls (`HomeControls/*`) rather than parallel form/error/message property sets in `Home`. - Concern controls execute their own auth/campaign/character/skill mutation workflows and notify `Home` only for shared-state refresh/orchestration. - Skill management workflows are owned by `CharacterPanel` to keep character-skill behavior cohesive. - Shared browser API interop is centralized in `RpgRollerApiClient` and reused by `Home` plus concern controls. - Browser API calls and SSE are handled via `wwwroot/js/rpgroller-api.js` interop. - UI state is maintained server-side per circuit with session/tab persistence for campaign + screen selection. - SSE-driven campaign refresh with reconnect backoff and explicit offline/manual-refresh fallback. ### 2.7 Testing strategy patterns - Full-stack integration tests via `WebApplicationFactory`. - Real migrations applied to in-memory Database during test host startup. - HTTP side effects mocked deterministically (`StubHttpMessageHandler` and `IHttpClientFactory` replacement). - Coverage-focused tests for: - auth/security rules - middleware behavior - filter behavior - link/vote/result edge cases - OpenAPI operation id stability - CI-local parity script (`scripts/ci-local.ps1`) mirrors pipeline flow. ### 2.8 Tooling and contract discipline - OpenAPI generated during build (`openapi/RpgRoller.json`). - Separate build + tests + coverage threshold checks. - Build configured with warnings as errors in CI/local script. ## 3) Concrete feature set Use this as a reusable "starter scope menu" for the new app: - Auth: - register/login/logout - owner bootstrap via admin key - auth options endpoint for registration UX - Identity/session: - cookie claim identity with admin claim - stale/deleted-account cookie invalidation - absolute session lifetime enforcement - State: - `/api/state`, `/api/me` - SSE state invalidation - etag conditional state reads ## 4) New-project starter checklist - Security: - cookie or token strategy finalized with CSRF model - rate limiting partitions and thresholds defined - strict CSP and security headers in first commit - versioned password hashing with migration strategy - trusted proxy/host settings explicit - Contract: - OpenAPI generation enabled in build - operation-id stability tested - Data integrity: - enforce critical invariants both app-side and DB-side - transaction boundaries for multi-entity admin actions - Frontend: - module boundaries and state refresh model defined - escaping/url-safe helpers mandatory - i18n structure and fallback behavior in place - Testing: - integration test host with real migrations - deterministic stubs for network dependencies - coverage gate enforced in local + CI scripts ## 7) Keep/avoid quick reference Keep: - Thin endpoints + workflow services. - Shared service result abstraction. - Explicit middleware order. - SSE + ETag state sync. - DB-enforced invariants. - Regression tests for security-sensitive UI rendering. Avoid: - Hard-coded workflow transitions scattered in backend/frontend. - Boolean-only role model for long-term products. - Unbounded in-memory caches. - Synchronous external network checks on hot write paths. - Manual API contract duplication between docs/frontend/backend.