Files
RpgRoller/TECH.md

8.5 KiB

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<T> + 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.
  • Razor components are split into markup-first .razor files with behavior/state in paired .razor.cs code-behind classes.
  • Home.razor + Home.razor.cs are intentionally minimal and only manage loading/auth/workspace view-mode switching.
  • Authenticated workspace UI plus workspace state/behavior are centralized in Components/Pages/Workspace.razor.
  • Form UX state uses reusable FormState<TModel> 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 the workspace host 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, Workspace, and 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.