8.2 KiB
8.2 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 +WebApplicationFactoryintegration 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 inGameService - 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 (
MapXEndpointsper 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
ProblemDetailspayloads witherrorextension 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:
- Forwarded headers
- Rate limiter
- HSTS + HTTPS redirect (prod)
- Security headers writer
- Base path
- Global exception handling
- Authentication
- Ensure player still exists
- CSRF origin/referer checks
- Authorization
- State change notifier middleware
- Static files
- 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 return304. - 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
429payload. - 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 queriesExecuteUpdateAsync/ExecuteDeleteAsyncfor 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.razorandComponents/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<TModel>containers in leaf controls (HomeControls/*) rather than parallel form/error/message property sets inHome. - Concern controls execute their own auth/campaign/character/skill mutation workflows and notify
Homeonly for shared-state refresh/orchestration. - Shared browser API interop is centralized in
RpgRollerApiClientand reused byHomeplus concern controls. - Browser API calls and SSE are handled via
wwwroot/js/rpgroller-api.jsinterop. - 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 (
StubHttpMessageHandlerandIHttpClientFactoryreplacement). - 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.