From ae85c369ba6bd7313a4ff79a7f47f2cf5e2106da Mon Sep 17 00:00:00 2001 From: Frank Tovar Date: Tue, 24 Feb 2026 20:35:53 +0100 Subject: [PATCH] Add TECH kickoff blueprint from current architecture --- TECH.md | 319 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 TECH.md diff --git a/TECH.md b/TECH.md new file mode 100644 index 0000000..efa62dc --- /dev/null +++ b/TECH.md @@ -0,0 +1,319 @@ +# 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.md` unresolved 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 (`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 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. +- 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 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: + - `escapeHtml` for template interpolation + - `safeUrl` for 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 (`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.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 `textContent` standards. +- 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. +