Skip to main content

Server Architecture

The Backgammon.Server project provides the real-time multiplayer backend.

Technology Stack

  • ASP.NET Core - Web framework
  • SignalR - Real-time WebSocket communication
  • DynamoDB - NoSQL database
  • HybridCache - In-memory + Redis caching
  • JWT - Authentication tokens

Service Layer

GameSessionManager

Manages active game sessions in memory.

public interface IGameSessionManager
{
GameSession CreateGame(string creatorId, string creatorName);
GameSession? GetGame(string gameId);
GameSession? GetGameByPlayer(string playerId);
void RemoveGame(string gameId);
}

GameSession

Holds game state and player connections.

public class GameSession
{
public string Id { get; }
public GameEngine Engine { get; }

// Multi-tab support: multiple connections per player
public HashSet<string> WhiteConnections { get; }
public HashSet<string> RedConnections { get; }

public GameState GetState(string? connectionId);
}

GameActionOrchestrator

Coordinates game actions with proper broadcasting.

public interface IGameActionOrchestrator
{
Task<MoveResult> MakeMoveAsync(GameSession session, string connectionId, int from, int to);
Task RollDiceAsync(GameSession session, string connectionId);
Task EndTurnAsync(GameSession session, string connectionId);
}

MatchService

Manages match lifecycle.

public interface IMatchService
{
Task<Match> CreateMatchAsync(MatchConfig config, string creatorId);
Task CompleteGameAsync(string matchId, GameResult result);
Task<string> StartNextGameAsync(string matchId);
}

EloRatingService

Calculates rating changes after matches.

public interface IEloRatingService
{
(int newWinnerRating, int newLoserRating) CalculateNewRatings(
int winnerRating,
int loserRating,
bool isGammon);
}

SignalR Hub

IGameHub (Client → Server)

Methods clients can invoke:

Task JoinGame(string? gameId);
Task RollDice();
Task MakeMove(int from, int to);
Task EndTurn();
Task OfferDouble();
Task AcceptDouble();
Task DeclineDouble();
// ... 60+ more methods

IGameHubClient (Server → Client)

Events pushed to clients:

Task GameUpdate(GameState gameState);
Task GameStart(GameState gameState);
Task GameOver(GameState gameState);
Task DoubleOffered(DoubleOfferDto offer);
Task MatchCompleted(MatchCompletedDto data);
// ... 20+ more events

REST API Endpoints

Minimal API endpoints in Program.cs:

EndpointDescription
GET /healthHealth check
GET /api/gamesList available games
POST /api/auth/registerUser registration
POST /api/auth/loginUser login
GET /api/users/{id}Get user profile
GET /api/friendsGet friends list
GET /api/themesGet board themes

DynamoDB Schema

Single-table design with composite keys:

EntityPKSK
UserUSER#{userId}PROFILE
GameGAME#{gameId}METADATA
MatchMATCH#{matchId}METADATA
FriendshipUSER#{userId}FRIEND#{status}#{friendId}

Global Secondary Indexes

  1. GSI1: Username lookups
  2. GSI2: Email lookups
  3. GSI3: Game/Match status queries
  4. GSI4: Correspondence turn tracking

Authentication Flow

  1. Client sends JWT in query string: /gamehub?access_token=xxx
  2. JwtBearerEvents.OnMessageReceived extracts token
  3. Token validated against signing key
  4. ClaimsPrincipal attached to connection context

Anonymous users are automatically created and receive a JWT for session continuity.