Files
SlipItIn/openwiki/architecture/overview.md
Tim Krampitz 01046b01e4 Neue Skills, Referenzen & OpenWiki-Doku integriert
Umfangreiche Erweiterung der Skill-Bibliothek: Neue Skills für Humanisierung (Englisch/PT-BR), Design-Validierung, AI-SEO und Coolify-Deployment inkl. Regelwerke, Presets, Pattern-Referenzen, Testfälle und Automatisierungsskripte. Zusätzliche Skills für Revenue-Centric Design, Pier Cloud, OKF, Lebenslauf- und LinkedIn-Optimierung sowie zahlreiche Referenzdateien, Checklisten und YAML/JSON/Markdown-Templates. Einführung einer vollständigen OpenWiki-Dokumentation mit Architektur-, Domain- und Workflow-Beschreibungen, zentralem Index und automatisierten Updates. Modularer Aufbau, restriktive Lizenzen und umfassende Qualitäts- und Evaluationsmechanismen für alle neuen Inhalte.
2026-07-26 14:00:58 +02:00

6.9 KiB

type, title, description, tags
type title description tags
Architecture System Architecture & Security Overview Technical architecture of SlipItIn, covering .NET Aspire orchestration, ASP.NET Core SignalR hub design, JWT authentication, and IDbContextFactory thread safety.
architecture
spire
signalr
jwt
efcore
security

System Architecture & Security Overview

SlipItIn is designed as a distributed, real-time application using modern .NET 10 architecture. This document details the orchestration model, backend service structure, security model, and concurrency safeguards.

The architectural foundation orchestrates services with .NET Aspire, while enforcing security & privacy on domain entities and serving real-time hub endpoints for all active game sessions. Source code structure for all architectural components can be found in the Source Code Map.


1. .NET Aspire Orchestration Model

The solution uses .NET Aspire to orchestrate application resources, services, and infrastructure dependencies:

  • AppHost (SlipItIn.AppHost/AppHost.cs):
    • Provisions a PostgreSQL database container (AddPostgres("pgsql").AddDatabase("postgresdb")).
    • Registers the backend project SlipItIn.Server with a direct reference to the PostgreSQL resource.
    • Registers the client project SlipItIn with service discovery references to SlipItIn.Server.
  • Service Defaults (SlipItIn.ServiceDefaults/Extensions.cs):
    • Configures OpenTelemetry logging, metrics (AspNetCore, HttpClient, Runtime), and tracing.
    • Exposes standardized health check endpoints (/health and /alive).
    • Enforces automatic HTTP resilience (AddStandardResilienceHandler()) and service discovery.

2. ASP.NET Core Backend Architecture (SlipItIn.Server)

The backend is an ASP.NET Core Web API & SignalR application providing REST endpoints for user management and real-time WebSockets for game state synchronization.

Key Components

  1. Program.cs:
    • Registers AddServiceDefaults(), AddNpgsqlDataSource("postgresdb"), and AddDbContextFactory<SlipItInDbContext>().
    • Configures JWT Bearer authentication with custom OnMessageReceived token resolution for SignalR.
    • Automatically executes database migrations (db.Database.Migrate()) at startup.
  2. AuthController.cs:
    • Manages user registration (/api/auth/register) and authentication (/api/auth/login).
    • Uses BCrypt.Net for secure password hashing.
    • Issues JWT tokens signed with Jwt:Key, containing ClaimTypes.NameIdentifier, ClaimTypes.Name, and ClaimTypes.Email.
  3. GameHub.cs:
    • Real-time SignalR hub mapped to /hubs/game.
    • Annotated with [Authorize] to reject unauthenticated WebSocket connections.
    • Extracts and verifies user claims, delegating state mutations to IGameService.
  4. GameService.cs:
    • Implements core business logic: game creation, player joins, card dealing, slip submission, challenge creation, and resolution.

3. JWT Authentication & SignalR Security

In real-time SignalR applications, clients can attempt to spoof player identifiers. SlipItIn eliminates this vulnerability through strict claim validation and authorization checks.

SignalR Token Extraction

Since WebSockets cannot pass custom HTTP headers during connection handshakes, Program.cs configures JWT query parameter extraction:

options.Events = new JwtBearerEvents
{
    OnMessageReceived = context =>
    {
        var accessToken = context.Request.Query["access_token"];
        var path = context.HttpContext.Request.Path;
        if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/hubs"))
        {
            context.Token = accessToken;
        }
        return Task.CompletedTask;
    }
};

Claims Validation & Access Control in GameHub.cs

Inside GameHub.cs, claims are extracted directly from the authenticated SignalR context:

  • GetAuthenticatedUserId(): Extracts Context.User?.FindFirst(ClaimTypes.NameIdentifier). Throws UnauthorizedAccessException if missing or invalid.
  • ValidatePlayerAccessAsync(playerId, authUserId): Queries the database to verify that Player.UserId matches the authenticated user ID.
  • ValidateHostAccessAsync(gameId, authUserId): Verifies that Game.HostId matches the authenticated user ID before allowing lobby configuration or game start.
  • ValidateChallengeTargetAccessAsync(challengeId, authUserId): Ensures only the accused player can resolve a challenge against them.

Real-Time Auth Flow Diagram

sequenceDiagram
    autonumber
    actor Client as MAUI Client
    participant Auth as AuthController
    participant Hub as GameHub
    participant Service as GameService
    participant DB as SlipItInDbContext

    Client->>Auth: POST /api/auth/login
    Auth->>DB: Query User & Verify BCrypt Hash
    Auth-->>Client: 200 OK (JWT Access Token)
    Client->>Hub: Connect WebSocket /hubs/game?access_token=JWT
    Hub->>Hub: Validate JWT Signature & Claims
    Client->>Hub: JoinLobby(lobbyCode)
    Hub->>Hub: GetAuthenticatedUserId()
    Hub->>Service: JoinGameAsync(lobbyCode, userId, connectionId)
    Service->>DB: Create IDbContext Session & Save Player
    Hub-->>Client: Broadcast "PlayerJoined" (GameStateDto)

4. Concurrency Safety: IDbContextFactory

SignalR hubs process concurrent requests from multiple clients over persistent connections. Using a standard Scoped DbContext in SignalR leads to thread conflict exceptions (InvalidOperationException: A second operation was started on this context instance before a previous operation completed).

Resolution via IDbContextFactory

SlipItIn solves this by registering EF Core with AddDbContextFactory<SlipItInDbContext>:

  • Every method call inside GameHub.cs, AuthController.cs, and GameService.cs creates a short-lived, isolated DbContext session using using var context = _contextFactory.CreateDbContext().
  • Benefit: Thread-safe database operations across simultaneous challenges, card transfers, and lobby updates without race conditions.

5. Data Privacy Isolation Model

To prevent players from inspecting opponent cards via network trace analysis, SlipItIn strictly separates public and private data DTOs:

  • GameStateDto (Public): Broadcast to all players in a lobby. Contains public game information (GameId, LobbyCode, Status, CurrentRound, RoundTimeRemaining) and player summaries (PlayerId, Username, Score, IsReady, CardCount). Crucially, no card text is included.
  • PlayerHandDto (Private): Direct unicast message sent only to the specific player's SignalR ConnectionId. Contains card text (CardId, PhraseId, Text, IsUsed).

This architecture guarantees that players cannot see opponent phrase cards, even if they inspect raw WebSocket packets.