🔧 Teknisk Projektbeskrivning

Arkitektur, tekniker och implementation

Imposter Online är en fullstack webbapplikation för realtidsspel, byggd med moderna webteknologier. Projektet demonstrerar implementation av WebSocket-kommunikation, tillståndshantering, PWA-funktionalitet och responsiv design.

📋 Projektöversikt

Imposter Online är ett multiplayer socialt deduktionsspel som körs helt i webbläsaren. Spelet stöder 3-10 spelare, har tre olika spellägen, inbyggd chatt och fungerar både online och offline.

Huvudfunktioner

  • Realtids multiplayer med WebSocket (Socket.io)
  • Tre spellägen: Pass & Play, Lokal Online, Remote Online
  • Offline-stöd med Pass & Play-läge (ingen server krävs)
  • Automatisk matchmaking för att hitta spelare
  • Inbyggd chatt mellan spelare
  • 8 olika ordkategorier med 20+ ord per kategori
  • Responsiv design för mobil och desktop
  • PWA-stöd för installation som app
  • Persistent speldata med Redis
  • Automatisk återanslutning vid nätverksavbrott

🛠️ Tekniker som används

HTML5

Semantisk markup, tillgänglighet (ARIA), strukturerad data (JSON-LD)

CSS3

Flexbox, Grid, Custom Properties, animationer, responsiv design

Vanilla JavaScript

ES6+, DOM-manipulation, Event handling, Async/Await

Node.js

JavaScript runtime för servern, v18+ LTS

Express.js

Minimalistiskt webbramverk för routing och middleware

Socket.io

Realtidskommunikation med WebSocket och fallback

Upstash Redis

Serverless Redis för persistent speldata och sessioner

Render.com

Molnbaserad hosting med automatisk deployment från GitHub

🏗️ Systemarkitektur

┌─────────────────────────────────────────────────────────────────────┐
│                          KLIENT (Webbläsare)                        │
├─────────────────────────────────────────────────────────────────────┤
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐              │
│  │   HTML5      │  │    CSS3      │  │  JavaScript  │              │
│  │  (index.html)│  │  (inline)    │  │  (inline)    │              │
│  └──────────────┘  └──────────────┘  └──────────────┘              │
│           │                │                 │                      │
│           └────────────────┼─────────────────┘                      │
│                            │                                        │
│                   ┌────────▼────────┐                               │
│                   │   Socket.io     │                               │
│                   │    Client       │                               │
│                   └────────┬────────┘                               │
└────────────────────────────┼────────────────────────────────────────┘
                             │ WebSocket / HTTP Long-polling
                             │
┌────────────────────────────┼────────────────────────────────────────┐
│                            │           SERVER (Node.js)             │
├────────────────────────────┼────────────────────────────────────────┤
│                   ┌────────▼────────┐                               │
│                   │   Socket.io     │                               │
│                   │    Server       │                               │
│                   └────────┬────────┘                               │
│                            │                                        │
│  ┌──────────────┐  ┌──────┴───────┐  ┌──────────────┐              │
│  │   Express    │  │  Game Logic  │  │   Matchmaking │              │
│  │   (Static)   │  │  (Rooms)     │  │   (Queue)     │              │
│  └──────────────┘  └──────┬───────┘  └──────────────┘              │
│                           │                                         │
└───────────────────────────┼─────────────────────────────────────────┘
                            │
                   ┌────────▼────────┐
                   │  Upstash Redis  │
                   │  (Persistent)   │
                   └─────────────────┘
          

Dataflöde

Skapa rum

Klient: createRoom Server: generera kod Redis: spara rum Klient: roomCreated

Spela omgång

Värd: startGame Server: tilldela roller Alla: gameState (reveal) Spelare: roleRevealed Alla: gameState (playing)

📁 Filstruktur

imposter-online/
├── index.js # Node.js server, Socket.io, spellogik
├── package.json # Dependencies och scripts
├── .env # Miljövariabler (Redis, Admin)

└── public/ # Statiska filer
    ├── index.html # Huvudapplikation (SPA)
    ├── manual.html # Spelmanual
    ├── projekt.html # Teknisk dokumentation
    ├── manifest.json # PWA manifest
    │
    └── gfx/ # Grafik och ikoner
        ├── imposter_delux_logo.webp
        ├── bg_stor.webp # Huvudbakgrund
        ├── bg_inuti.webp # Kortbakgrund
        ├── open_graph.jpg # Social delning
        ├── favicon.ico
        ├── web-app-manifest-192x192.png
        └── web-app-manifest-512x512.png

🎨 Frontend

Single Page Application (SPA)

Hela spelet är byggt som en SPA där olika "skärmar" visas/döljs med CSS-klasser. Detta ger snabb navigering utan sidladdningar.

// Skärmhantering function showScreen(screenId) { document.querySelectorAll('.screen').forEach(s => s.classList.remove('active') ); document.getElementById(screenId).classList.add('active'); }

Tillståndshantering

Speldata hanteras via en global gameState-variabel som uppdateras från servern via Socket.io. En central render()-funktion uppdaterar UI baserat på aktuellt tillstånd.

CSS-arkitektur

CSS använder Custom Properties (CSS Variables) för konsekvent färgschema och enkel tematisering. Responsiv design implementeras med Flexbox, Grid och media queries.

⚙️ Backend

Express.js Server

Servern hanterar statiska filer, health checks för hosting och admin-dashboard.

const express = require('express'); const app = express(); // Statiska filer app.use(express.static(path.join(__dirname, 'public'))); // Health check för Render app.get('/health', (req, res) => { res.status(200).json({ status: 'ok' }); });

Spellogik

All spellogik körs på servern för att förhindra fusk. Servern hanterar rollfördelning, turordning, röstning och resultatberäkning.

💾 Databas (Redis)

Upstash Redis

Redis används för att persistent lagra spelrum och möjliggöra återanslutning. Upstash är en serverless Redis-tjänst som ger låg latens och automatisk skalning.

Datastruktur

// Rum lagras som JSON i Redis { code: "ABCD", players: [...], phase: "lobby" | "reveal" | "playing" | "voting" | "ended", settings: { category, imposterCount, roundTime, gameMode }, secretWord: "Lejon", clues: [...], votes: {...} }

🔌 Realtidskommunikation

Socket.io Events

Kommunikationen sker via namngivna events. Klienten skickar åtgärder och servern svarar med uppdaterat tillstånd.

Klient → Server

createRoom, joinRoom, startGame, submitClue, vote, chatMessage

Server → Klient

roomCreated, gameState, error, chatMessage

Återanslutning

Socket.io hanterar automatisk återanslutning. Sessionsdata sparas i sessionStorage för att möjliggöra återgång till pågående spel.

🎮 Spellogik

Spelflöde

Lobby Reveal Playing Voting Ended

Rollfördelning

Imposters väljs slumpmässigt med Fisher-Yates shuffle. Servern säkerställer att rätt antal imposters tilldelas baserat på inställningar.

Vinnarlogik

Civilister vinner om de röstar ut en imposter. Impostern vinner om fel person röstas ut, röstningen blir oavgjord, eller om de gissar rätt ord efter att ha blivit avslöjad.

🔍 SEO & PWA

Sökmotoroptimering

  • Semantisk HTML5 med korrekta heading-nivåer
  • Meta-taggar för description, keywords, author
  • Open Graph för Facebook, LinkedIn
  • Twitter Card för Twitter/X
  • Strukturerad data (JSON-LD) för WebApplication och FAQ
  • Canonical URL för att undvika duplicerat innehåll

Progressive Web App

  • Web App Manifest för installation
  • Ikoner i flera storlekar (192x192, 512x512)
  • Theme color för mobilwebbläsare
  • Apple Web App meta-taggar
  • Offline-läge med Pass & Play

🚀 Deployment

Render.com

Applikationen hostas på Render.com med automatisk deployment från GitHub. Vid varje push till main-branchen byggs och deployas appen automatiskt.

Miljövariabler

UPSTASH_REDIS_REST_URL="https://xxx.upstash.io" UPSTASH_REDIS_REST_TOKEN="xxx" ADMIN_KEY="hemlig-admin-nyckel" PORT="3000"

Health Check

Render pingar /health endpoint regelbundet. Om servern inte svarar startas den om automatiskt.

🔒 Säkerhet

  • All spellogik körs på servern (förhindrar klientmanipulation)
  • Input-validering för alla användardata
  • HTML-escaping för chat och ledtrådar (förhindrar XSS)
  • Rumskoder genereras kryptografiskt säkert
  • Admin-dashboard skyddas med hemlig nyckel
  • Rate limiting på Socket.io-events