12 KiB
TECH - Kickoff Blueprint from Pick'n'Play
This document extracts the implementation patterns, conventions, and guardrails from the current codebase so a new webapp can start with proven structure and avoid known pitfalls.
Scope covered:
- Backend (
Program.cs,Endpoints/*,Infrastructure/*,Data/*,Domain/*,Contracts/*) - Frontend (
wwwroot/*) - Tooling and CI (
scripts/*,.github/workflows/ci.yml, npm tooling) - Tests (
GameList.Tests/*) - Review carryover (
REVIEW.mdunresolved topics)
1) Stack and baseline choices
- ASP.NET Core Minimal API on .NET 10.
- EF Core + SQLite in current project (single-node deployment).
- Cookie authentication (
HttpOnly,SameSite=Strict, secure in production). - Static frontend (HTML/CSS/JS modules), no frontend framework.
- OpenAPI generated from backend and consumed by generated JS client.
- xUnit integration-heavy test suite with in-memory SQLite 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 legacy compatibility retained.
2.5 Data and invariants
- Strong DB model with explicit constraints:
- Unique normalized username
- Unique owner partial index
- Unique vote key
(PlayerId, SuggestionId) - Seeded singleton app state row
- DB-level guardrails (trigger) complement app-level checks:
- Suggestion limit enforced in DB (
suggestion_limit_exceeded) to survive concurrent writes.
- Suggestion limit enforced in DB (
- 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 Workflow and permission model
- Phases (
Suggest,Vote,Results) drive endpoint access and UX behavior. - Effective phase can be derived from persisted phase + global
resultsOpen. - Reconciliation helper functions centralize phase alignment rules.
- Admin abilities are intentionally constrained per operation (e.g., only specific transitions allowed).
Keep centralization of workflow rules. Avoid spreading phase/permission checks inline.
2.7 Frontend architecture
- ES module split by concern:
- API wrapper
- Data loaders
- UI composition
- Feature-specific renderers/handlers
- Shared utils and runtime dependency injection
- Single runtime state object with deliberate clear/reset logic.
- Refresh scheduler:
- Serialized refreshes (no overlap)
- Adaptive polling backoff
- SSE-triggered immediate refresh for state mutations
- Visibility-aware refresh suppression
- API client is generated from OpenAPI operation ids, not handwritten endpoints.
- Internationalization:
- translation file validation at startup
- language-specific FAQ markdown loading with fallback to default language
2.8 Frontend safety and rendering hygiene
- Safe rendering helpers:
escapeHtmlfor template interpolationsafeUrlfor links/media
- Sensitive modal content set via
textContent, not interpolated HTML. - Trusted output patterns covered by regression tests.
Maintain this as a non-negotiable standard for any user-supplied content path.
2.9 Testing strategy patterns
- Full-stack integration tests via
WebApplicationFactory. - Real migrations applied to in-memory SQLite 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.10 Tooling and contract discipline
- OpenAPI generated during build (
openapi/GameList.json). - JS client generated from OpenAPI with required operation-id checks.
- Separate lint + format + tests + coverage threshold checks.
- Build configured with warnings as errors in CI/local script.
3) Concrete feature set currently implemented
Use this as a reusable "starter scope menu" for the new app:
- Auth:
- register/login/logout
- owner bootstrap via admin key
- immutable display name post-registration
- 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- phase next/prev
- SSE state invalidation
- etag conditional state reads
- Suggestions:
- create/update/delete/mine/all
- phase gating + admin override behavior
- suggestion cap + joker path
- link metadata exposure
- screenshot URL and reachability validation
- Votes:
- vote upsert
- finalize/unfinalize
- linked suggestion vote fan-out
- conflict handling on concurrent insert/update
- Results:
- gated by phase + admin-open flag
- ordered leaderboard with aggregates and voter metadata
- per-user own vote context
- Admin:
- results open/close toggle with phase realignment
- vote status panel
- joker grant
- player phase correction
- admin role grant/revoke (owner protected)
- player delete with cascades and password confirmation
- link/unlink suggestions with vote reset and unfinalize behavior
- reset/factory reset with password confirmation
4) REVIEW.md unresolved topics -> new-project design defaults
This section translates outstanding review risks into early decisions for the new app.
4.1 Data store scalability
Review concern:
- SQLite bottlenecks under higher write concurrency and multi-node scaling.
New-project default:
- Start with PostgreSQL (or SQL Server) for production profile.
- Keep provider abstraction and provider-specific migration strategy from day one.
- Keep SQLite only as local dev/test convenience if needed.
4.2 Workflow extensibility
Review concern:
- Workflow transitions are hard-coded in many places.
New-project default:
- Define transitions in a single state-machine table/model.
- Drive backend authorization and frontend navigation from same transition metadata.
- Add tests that validate the transition table itself.
4.3 Authorization model growth
Review concern:
- Role booleans (
IsAdmin,IsOwner) limit future permission expansion.
New-project default:
- Use role/permission tables or claims-based capabilities.
- Keep owner as a protected capability, not a special-case boolean spread across code.
- Use policy-based authorization with explicit capability names.
4.4 Frontend maintainability
Review concern:
- String-template-heavy UI + global mutable state can become fragile.
New-project default:
- Move to TypeScript (or strict JSDoc typing) early.
- Keep module boundaries by feature.
- Keep explicit escaping/safe-url guards and DOM
textContentstandards. - If not using framework, introduce a small typed view-model layer.
4.5 In-memory cache bounds
Review concern:
- Unbounded dictionaries may grow under high-cardinality traffic.
New-project default:
- Replace unbounded maps with bounded
MemoryCache(size + TTL + eviction). - For distributed deployments, use Redis with cardinality and TTL controls.
4.6 Linking/results query scaling
Review concern:
- Link and result workflows currently pull full sets into memory.
New-project default:
- Persist link-group ids and compute aggregates in SQL.
- Add pagination/windowing for large result sets.
- Benchmark query plans on realistic volumes.
4.7 External URL validation latency
Review concern:
- Reachability validation happens synchronously on write path.
New-project default:
- Accept user URL quickly, validate asynchronously (job queue/background worker), store validation status.
- Optionally proxy or prefetch media through controlled media service.
5) Topics from REVIEW that are already fixed and should be carried forward
- Polling amplification has been reduced through SSE + etag conditional reads.
- CSRF protection is explicit (same-origin validation for authenticated mutating requests).
- Password hashing is versioned and modernized (Argon2id current, transparent upgrades).
- CSP is tightened compared to prior permissive baseline (no inline style allowance, no insecure image origins).
- API drift risk reduced with OpenAPI generation + generated frontend client.
These are not optional add-ons; they should be baseline in the new app.
6) New-project starter checklist
- Bootstrap:
- choose production DB provider first
- define transition/state-machine model before endpoint coding
- define permission/capability model before admin features
- 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
- generated client wired into frontend
- 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.
- Generated API client from OpenAPI.
- 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.