Skip to main content

High-Level Architecture

Showdown Trivia is built as a real-time multiplayer trivia game using Go, following a clean architecture pattern with clear separation of concerns. The system consists of several key layers:
┌─────────────────────────────────────────────────────────┐
│                    HTTP Server                          │
│              (Go net/http + Gorilla)                    │
└────────────────────┬────────────────────────────────────┘

        ┌────────────┴────────────┐
        │                         │
┌───────▼───────┐        ┌───────▼────────┐
│  Web Layer    │        │  WebSocket Hub │
│  (handlers)   │        │  (real-time)   │
└───────┬───────┘        └───────┬────────┘
        │                        │
        └────────┬───────────────┘

        ┌────────▼─────────┐
        │   Core Services  │
        │  (business logic)│
        └────────┬─────────┘

    ┌────────────┼────────────┐
    │            │            │
┌───▼───┐  ┌────▼────┐  ┌────▼─────┐
│MongoDB│  │Trivia   │  │  Logger  │
│  DB   │  │API      │  │Prometheus│
└───────┘  └─────────┘  └──────────┘

Component Breakdown

The application is initialized in cmd/web/main.go:18 and follows this startup sequence:

1. Configuration Layer

Package: internal/config Loads environment variables and validates configuration:
  • PORT: HTTP server port
  • DB_URL: MongoDB connection string
  • LOG_LEVEL: Logging verbosity (debug, info, warn, error)
  • ENV: Environment mode (dev/prod)
// config/config.go:72
func NewConfig() (*Config, error) {
    config := Config{}
    if err := config.loadEnv(); err != nil {
        return nil, err
    }
    return &config, nil
}

2. Repository Layer

Package: internal/repository Handles all database operations using MongoDB:
  • Connection management with connection pooling
  • User repository with unique indexes on username and email
  • Graceful disconnection with timeout
Key files:
  • store.go:18 - Database initialization
  • store.go:42 - Store creation with indexes
  • user.go - User data access operations
The repository layer uses MongoDB with unique indexes to enforce data integrity at the database level.

3. Core Services Layer

Package: internal/core Contains business logic organized into domain services:

User Service

Location: internal/core/user/service.go Manages user operations:
  • User retrieval and authentication
  • User registration
  • User deletion
// user/service.go:20
func NewUserService(repo repository) *UserService {
    return &UserService{repo: repo}
}

Question Service

Location: internal/core/question/service.go Fetches trivia questions:
  • Retrieves questions from external Trivia API
  • Fetches available categories
  • Delegates to trivia API client

Game Service

Location: internal/core/game/game.go Core game logic (detailed in Game Engine):
  • Question flow management
  • Answer collection via channels
  • Scoring and winner calculation
  • Timer-based progression

4. External API Client

Package: internal/trivia_api Location: trivia_api.go:37 Integrates with OpenTDB for trivia questions:
  • Fetches multiple-choice questions by category
  • Retrieves available categories
  • Shuffles answer options randomly
  • Error handling for API responses
// trivia_api.go:37
func NewTriviaClient() *triviaClient {
    return &triviaClient{
        baseURL: "https://opentdb.com",
    }
}

5. Web Layer

Package: internal/web

App Structure

Location: web/app.go:23 The main application struct coordinates all components:
type App struct {
    port            int
    router          *http.ServeMux
    userService     user.UserServiceApi
    questionService question.QuestionServiceApi
    hub             *ws.Hub              // WebSocket hub
    store           *sessions.CookieStore
    logger          *slog.Logger
    m               *metrics.Metrics     // Prometheus metrics
    reg             *prometheus.Registry
}

HTTP Server

Location: web/app.go:53 Configured with:
  • Read timeout: 10 seconds
  • Write timeout: 30 seconds
  • Idle timeout: 1 minute
  • Graceful shutdown on SIGINT/SIGTERM

6. WebSocket Hub

Package: internal/web/ws Location: ws/hub.go:27 Manages real-time game rooms and connections (detailed in WebSocket System):
  • Room creation and lifecycle
  • Client connection management
  • Message broadcasting
  • Metrics tracking

7. Middleware

Location: web/middleware.go Provides cross-cutting concerns:
Authentication (requireAuth:12)
  • Session validation
  • Username extraction from session
  • Redirect to signin if unauthorized
Panic Recovery (recoverPanic:30)
  • Catches panics in handlers
  • Logs errors
  • Prevents server crashes
Request Duration (requestDuration:45)
  • Prometheus metrics collection
  • Tracks request timing by HTTP method

Request Flow

Standard HTTP Request Flow

1. Client HTTP Request

2. Router (http.ServeMux)

3. Middleware Chain
   ├→ recoverPanic (error handling)
   ├→ requireAuth (if protected route)
   └→ requestDuration (metrics)

4. Handler
   ├→ Parse request/form data
   ├→ Call service layer
   └→ Render response

5. Service Layer
   ├→ Business logic
   ├→ Repository calls
   └→ External API calls

6. Response (HTML/WebSocket)

WebSocket Request Flow

1. HTTP Upgrade Request

2. Handler (CreateWs/JoinWs)

3. Hub.CreateRoom() or Hub.JoinRoom()

4. WebSocket Upgrade

5. Client Created
   ├→ Start readMessage() goroutine
   ├→ Start writeMessage() goroutine
   └→ Add to room

6. Real-time bidirectional communication
WebSocket connections are upgraded from HTTP requests and managed by separate goroutines for concurrent read/write operations.

Technology Stack

Core Technologies

ComponentTechnologyPurpose
LanguageGo 1.xServer implementation
HTTP Servernet/httpStandard library HTTP server
Routerhttp.ServeMuxRequest routing
WebSocketgorilla/websocketReal-time communication
DatabaseMongoDBUser data persistence
Sessionsgorilla/sessionsCookie-based sessions
TemplatestemplType-safe HTML templates
Logginglog/slogStructured logging
MetricsPrometheusApplication monitoring

External Services

  • OpenTDB API - Trivia question provider
  • MongoDB Atlas (optional) - Cloud database hosting

Key Design Patterns

The codebase follows clean architecture principles:
  • Core domain is independent of external concerns
  • Service interfaces enable dependency injection
  • Repository pattern abstracts data access
  • Use cases defined in service layer
Go concurrency is used extensively:
  • Goroutines for WebSocket read/write loops
  • Channels for game events and answer collection
  • Mutexes (RWMutex) for thread-safe access to shared state
  • Select statements for multiplexing channel operations
Game events flow through channels:
  • Game emits messages to Message channel
  • Clients listen on egress channels
  • Answers sent via AnswerCh channel
  • Non-blocking event distribution

Routes Overview

Location: web/routes.go:15

Public Routes

  • GET /signin - Sign in page
  • POST /signin - Authentication
  • GET /signup - Registration page
  • POST /signup - User registration
  • GET /static/* - Static assets
  • GET /metrics - Prometheus metrics

Protected Routes (require authentication)

  • GET /home - User dashboard
  • GET /create - Game creation form
  • POST /create - Create game
  • GET /join/{id} - Join game page
  • POST /signout - Sign out
  • /activegames - List active games (HTMX)

WebSocket Endpoints

  • /wscreate - Create game room with WebSocket
  • /wsjoin/{id} - Join existing room via WebSocket
All WebSocket endpoints require authentication and upgrade HTTP connections to WebSocket protocol.

Deployment Considerations

Environment Variables

PORT=8080
DB_URL=mongodb://localhost:27017
LOG_LEVEL=info
ENV=prod

Graceful Shutdown

The server implements graceful shutdown (web/app.go:63):
  • Listens for SIGINT/SIGTERM signals
  • 5-second timeout for existing connections
  • Closes database connections cleanly
  • Logs shutdown events

Monitoring

Prometheus metrics exposed at /metrics include:
  • Active WebSocket connections
  • Request duration by method
  • Custom game metrics

Next Steps

WebSocket System

Deep dive into real-time communication architecture

Game Engine

Understand game logic and state management

Build docs developers (and LLMs) love