π AI-powered collaborative storytelling through real-time multiplayer adventures! Built entirely around Redis as the high-performance real-time data layer, this project pushes the boundaries of interactive AI gaming.
Real-Time AI Dungeon Master - The ultimate AI-powered multiplayer game, leveraging Redis for seamless real-time state management and dynamic storytelling.
Built for the Redis AI Challenge π
Competing in the "Real-Time AI Innovators" challenge prompt, demonstrating how Redis accelerates the future of AI through high-impact use cases like real-time feature streaming, semantic caching, and advanced state management.
- π― Project Overview
- Features
- Architecture
- π§ Semantic Lore System
- Prerequisites
- Quick Start
- ποΈ Service Architecture & Container Details
- Docker Deployment
- API Endpoints
- Development
- Project Structure
- Redis Data Structures
- π§ Redis CLI Commands & Data Access
- π Real Redis Data Examples
- π Understanding Redis Data Structure
- π Data Analysis Insights
- π Redis Command Summary
- Environment Variables
- π Troubleshooting
- Contributing
- Support
This project was built for the Redis AI Challenge for the "Real-Time AI Innovators" challenge prompt. The goal was to build an innovative AI-powered application using Redis as the real-time data layer, going beyond simple chatbots to explore high-impact use cases like real-time multiplayer gaming with AI-driven storytelling.
- Challenge: Redis AI Challenge
- Prompt: Real-Time AI Innovators
- Focus: Real-time multiplayer AI dungeon master using Redis for state management, event streaming, and pub/sub broadcasting
- Technology Stack: Redis, Node.js, React, OpenAI API, Socket.IO, Docker, TypeScript, Tailwind CSS, Vite, nginx
This project showcases how Redis accelerates the future of AI by implementing several high-impact use cases:
- Redis Streams (XADD, XRANGE) capture every player action as immutable events
- Real-time event processing feeds AI context for intelligent responses
- Continuous learning from player interactions to improve storytelling
- Redis Hashes (HSET, HGETALL) store game state and context for rapid retrieval
- Intelligent prompt construction using cached game history
- Reduced API calls through context-aware response generation
- Redis Pub/Sub (PUBLISH, SUBSCRIBE) enables instant narrative broadcasting to all players
- Synchronized game state across multiple players in real-time
- Zero-latency updates for immersive multiplayer experiences
- Redis Sets track active players in each session with
SADD
,SREM
,SCARD
- Redis Keys enable session discovery with pattern matching (
KEYS game:*:state
) - Redis DEL provides session cleanup and data management
- Redis JSON powers semantic lore search with embeddings
- Redis Connection Management with dual clients (main + subscriber) for optimal performance
- Redis JSON (JSON.SET, JSON.GET) stores AI-generated lore with embeddings
- Semantic similarity search using cosine similarity for contextual responses
- Multi-type lore management (characters, locations, items, world rules, quests)
- Tag-based indexing for efficient lore retrieval and categorization
- Contextual AI responses that reference relevant lore based on player actions
Note: For detailed Redis feature descriptions, see the Features section below.
- Complex game logic with persistent world state
- Multiplayer coordination with real-time player tracking
- Dynamic storytelling that adapts to collective player actions
- Session persistence with automatic rejoining capabilities
- Semantic search for contextual AI responses
This demonstrates how Redis can power sophisticated AI applications that go far beyond simple question-answer interactions, creating truly interactive and collaborative AI experiences.
This project was specifically built for the Redis AI Challenge and demonstrates several key innovations in AI-powered applications using Redis:
- Challenge: Redis AI Challenge
- Prompt: Real-Time AI Innovators
- Focus: Real-time multiplayer AI dungeon master using Redis for state management, event streaming, and pub/sub broadcasting
- Technology Stack: Redis, Node.js, React, OpenAI API, Socket.IO, Docker, TypeScript, Tailwind CSS, Vite, nginx
This project showcases how Redis accelerates the future of AI through:
- Real-time multiplayer gaming with instant state synchronization
- Semantic lore system with AI-powered contextual responses
- Event streaming for complete game history and replay capability
- Advanced Redis data structures (Streams, Hashes, Sets, JSON) for optimal performance
- Beyond simple chatbots - creating truly interactive AI experiences
- Real-time Multiplayer: Multiple players can join the same game session
- AI Dungeon Master: Powered by OpenAI GPT models for dynamic storytelling
- Session Management: Create and join game sessions via unique URLs
- Session Discovery: Browse and join active sessions with player counts
- Session Persistence: Automatic rejoining via localStorage and URL parameters
- Session Deletion: Remove inactive or unwanted sessions
- Redis Streams (XADD, XRANGE): Immutable event logging for game history
- Captures every player action as immutable events
- Enables complete game history and replay capability
- Feeds AI context for intelligent responses
- Redis Hashes (HSET, HGETALL): Fast game state management and caching
- Stores game state and context for rapid retrieval
- Enables intelligent prompt construction using cached game history
- Reduces API calls through context-aware response generation
- Redis Pub/Sub (PUBLISH, SUBSCRIBE): Real-time narrative broadcasting
- Enables instant narrative broadcasting to all players
- Synchronizes game state across multiple players in real-time
- Provides zero-latency updates for immersive multiplayer experiences
- Redis Sets (SADD, SREM, SCARD): Player tracking and session management
- Tracks active players in each session
- Enables session discovery with pattern matching
- Redis Keys (KEYS): Session discovery with pattern matching
- Enables session browser functionality
- Provides session cleanup and data management
- Redis DEL: Session cleanup and data management
- Removes all session data when deleting
- Enables automatic cleanup of inactive sessions
- Redis JSON (JSON.SET, JSON.GET): Semantic lore system with embeddings
- Powers semantic lore search with embeddings
- Enables semantic similarity search using cosine similarity
- Provides multi-type lore management (characters, locations, items, world rules, quests)
- Supports tag-based indexing for efficient lore retrieval and categorization
- WebSocket Communication: Real-time updates across all connected players
- Cross-platform Synchronization: All players see the same game state
- Zero-latency Updates: Immersive multiplayer experiences
- Connection Recovery: Automatic reconnection with session preservation
- Context-Aware Storytelling: AI adapts to collective player actions
- Multi-session AI Context: Session-specific prompts and responses
- Fallback Responses: Graceful handling when AI services are unavailable
- Error-Specific Handling: Rate limits, quotas, and network issues
- Real-time Narrative Generation: Immediate broadcasting to all players
- Semantic Lore System: AI-generated lore with semantic search capabilities
- Contextual AI Responses: References relevant lore based on player actions
- Docker Containerization: Scalable deployment with docker-compose
- Health Monitoring: Redis connection status and system health checks
- Rate Limiting: Prevents AI API abuse and ensures fair usage
- Error Handling: Graceful degradation with comprehensive error messages
- Environment Validation: Pre-startup validation of all required services
- Graceful Shutdown: Proper cleanup of connections and resources
- Modern UI: Beautiful React interface with Tailwind CSS
- Theme Support: Dark/light mode with theme persistence
- Toast Notifications: User feedback for all actions
- Loading States: Visual feedback during AI processing
- Error Boundaries: Crash protection and recovery
- Responsive Design: Works on desktop and mobile devices
- Player-Driven Narrative: Collective actions influence the story
- Real-time Collaboration: Shared storytelling experiences
- Event History Preservation: Complete game state replay capability
- Session State Caching: Instant game resumption
- Player Context Preservation: Maintains context across reconnections
- Semantic Lore Search: AI-powered contextual responses using embeddings
- Multi-type Lore Management: Characters, locations, items, world rules, and quests
- Tag-based Lore Indexing: Efficient categorization and retrieval system
graph TD
subgraph Players
A[Player 1] --> C{Frontend UI}
B[Player 2] --> C{Frontend UI}
end
subgraph Backend Infrastructure
D[Node.js App Server] -- Manages --> E[Game Logic]
E -- Interacts with --> F[Redis Core]
E -- Sends prompts to --> G[LLM Service]
end
subgraph Redis Core
F -- Uses --> H[Hashes for State]
F -- Uses --> I[Streams for Events]
F -- Uses --> J[Pub/Sub for Broadcasts]
F -- Uses --> K[JSON for Lore]
end
C -- WebSocket --> D
D -- Pub/Sub --> C
G -- Returns narrative --> D
style C fill:#4f46e5,stroke:#1e1b4b,stroke-width:2px,color:#ffffff
style D fill:#059669,stroke:#064e3b,stroke-width:2px,color:#ffffff
style F fill:#dc2626,stroke:#7f1d1d,stroke-width:2px,color:#ffffff
style G fill:#7c3aed,stroke:#581c87,stroke-width:2px,color:#ffffff
sequenceDiagram
participant Player
participant Frontend
participant Backend
participant Redis
participant LLM
Player->>Frontend: Types command "attack goblin"
Frontend->>Backend: Sends command via WebSocket
Backend->>Redis: XADD to session stream (event log)
Backend->>Redis: HGETALL player/NPC stats (hashes)
Redis-->>Backend: Returns state data
Backend->>LLM: Constructs & sends prompt
LLM-->>Backend: Returns narrative & state changes
Backend->>Redis: HSET to update state (hashes)
Backend->>Redis: PUBLISH narrative to session channel
Redis-->>Backend: Broadcasts to subscribers
Backend->>Frontend: Relays narrative via WebSocket
Frontend->>Player: Displays new story text
The application uses a multi-container Docker setup with nginx as a reverse proxy:
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β Browser βββββΊβ nginx βββββΊβ React β
β β β (frontend) β β (frontend)β
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β
βΌ
βββββββββββββββ βββββββββββββββ
β Backend βββββΊβ Redis β
β (Node.js) β β (Cache) β
βββββββββββββββ βββββββββββββββ
Container Details:
- Frontend Container (nginx-based): Multi-stage build serving React app with API proxying
- Backend Container (Node.js): Express server with Socket.IO for real-time communication
- Redis Container: In-memory data store with RedisJSON module for advanced features
The application includes a sophisticated semantic lore system that enhances AI responses with contextual knowledge:
- Characters: NPCs, allies, enemies, and their backstories
- Locations: Places, dungeons, cities, and their descriptions
- Items: Weapons, artifacts, magical objects, and their properties
- World Rules: Magic systems, laws, customs, and game mechanics
- Quests: Missions, objectives, and storylines
- Embedding Generation: Uses OpenAI's text-embedding-3-small model
- Cosine Similarity: Finds most relevant lore based on semantic similarity
- Contextual Retrieval: Automatically selects relevant lore for AI responses
- Tag-based Indexing: Efficient categorization and filtering
- Multi-type Search: Search across all lore types or filter by specific type
- JSON.SET: Stores lore entries with embeddings and metadata
- JSON.GET: Retrieves complete lore entries with all fields
- Type Indexing: Uses Redis Sets for efficient type-based queries
- Tag Indexing: Uses Redis Sets for tag-based filtering
- Pattern Matching: Uses KEYS for flexible lore discovery
- Automatic Lore Selection: AI responses include relevant lore context
- Dynamic Storytelling: Lore influences narrative generation
- Consistent World Building: Maintains lore consistency across sessions
- Player-Driven Discovery: Lore reveals based on player actions
- Node.js 18+
- Redis 7+ (with RedisJSON module)
- OpenAI API Key
# 1. Clone the Repository
git clone https://github.com/ntanwir10/realtime_ai_dungeon_master
cd realtime_ai_dungeon_master
# 2. Set Up Environment Variables
cp backend/.env.example backend/.env
# Edit backend/.env and add your OpenAI API key
# 3. Start Everything with Docker
docker-compose up --build
# 4. Access the Application
# Frontend: http://localhost:5173
# Backend API: http://localhost:3001
# Redis: localhost:6379
What this starts:
- β Redis with RedisJSON module (port 6379)
- β Backend Node.js server (port 3001)
- β Frontend React app with nginx (port 5173)
- β All networking between containers
# 1. Clone the Repository
git clone https://github.com/ntanwir10/realtime_ai_dungeon_master
cd realtime_ai_dungeon_master
# 2. Set Up Environment Variables
cp backend/.env.example backend/.env
# Edit backend/.env and add your OpenAI API key
# 3. Install Dependencies
cd backend && npm install
cd ../frontend && npm install
# 4. Start Redis with RedisJSON
docker run -d -p 6379:6379 redislabs/rejson:latest
# 5. Start the Application
# Terminal 1 - Backend
cd backend
npm run dev
# Terminal 2 - Frontend
cd frontend
npm run dev
# 6. Access the Application
# Frontend: http://localhost:5173
# Backend API: http://localhost:3001
# Start all services
docker-compose up --build
# Start in background
docker-compose up -d --build
# Stop all services
docker-compose down
# View logs
docker-compose logs -f
# Restart specific service
docker-compose restart backend
- Port: 6379
- Image:
redislabs/rejson:latest
- Purpose: Database with RedisJSON module
- Data: Game sessions, events, lore, player tracking
- Features: JSON storage, semantic search, pub/sub
- Port: 3001
- Image: Custom Node.js/TypeScript
- Purpose: API server with Socket.IO
- Features: Game logic, AI integration, WebSocket handling
- Health Check:
http://localhost:3001/api/health
- Port: 5173
- Image: nginx serving React app
- Purpose: Web interface
- Features: UI, WebSocket client, session management
- Proxy: Routes
/api/*
to backend,/socket.io/*
to backend
Browser β Frontend (5173) β Backend (3001) β Redis (6379)
The application uses a truly OS-agnostic multi-container Docker setup that automatically adapts to any platform (macOS, Linux, Windows) without manual configuration.
graph TD
subgraph "Docker Containers"
A[Frontend Container<br/>nginx + React<br/>Port 5173] --> B[Backend Container<br/>Node.js + TypeScript<br/>Port 3001]
B --> C[Redis Container<br/>RedisJSON<br/>Port 6379]
end
subgraph "Platform Support"
D[macOS ARM64] --> A
E[macOS AMD64] --> A
F[Linux AMD64] --> A
G[Linux ARM64] --> A
H[Windows AMD64] --> A
end
- Multi-stage build: Builds React app with Node.js, serves with nginx
- OS-agnostic: Automatically uses host platform architecture
- Port 5173: Serves the React application
- API Proxy: Routes
/api/*
requests to backend - WebSocket Proxy: Routes
/socket.io/*
to backend - SPA Support: Handles client-side routing
- Port 3001: Express server with Socket.IO
- TypeScript: Direct execution with
tsx
(no compilation step) - Health checks: Built-in monitoring and status endpoints
- Redis integration: Session and state management
- Rate limiting: IPv6-compatible rate limiting
- Port 6379: In-memory data store with RedisJSON module
- Session storage: Game state and player data
- Event streaming: Real-time updates via Redis Streams
- Lore system: Semantic search with embeddings
# Automatically uses host platform
docker-compose up --build
# Run in background
docker-compose up -d --build
# Stop services
docker-compose down
# Build for all platforms using Docker Bake
docker buildx bake all
# Build specific services for all platforms
docker buildx bake backend-all
docker buildx bake frontend-all
# Build for specific platforms
docker buildx build --platform linux/amd64,linux/arm64 .
# Backend for specific platform
docker buildx build --platform linux/amd64 -t ai-dungeon-backend ./backend
# Frontend for specific platform
docker buildx build --platform linux/arm64 -t ai-dungeon-frontend ./frontend
- Automatic platform detection: No fixed platform specifications
- Service orchestration: Redis, Backend, Frontend
- Volume management: Persistent Redis data
- Health checks: Built-in monitoring
- Production optimizations: Health checks, restart policies
- Environment-specific: Production environment variables
- Service dependencies: Proper startup order
- Docker Bake configuration: Advanced build management
- Platform targets: linux/amd64, linux/arm64
- Build optimization: Parallel builds, caching
- Production ready: Optimized for deployment
# OS-agnostic base image
FROM node:18-alpine AS base
# Multi-stage build for optimization
FROM base AS deps
# Install dependencies
FROM base AS runner
# Production image with TypeScript execution
CMD ["npx", "tsx", "src/server.ts"]
# Build stage
FROM node:18-alpine AS builder
# Build React application
# Production stage
FROM nginx:alpine AS production
# Serve with nginx + API proxying
Platform | Architecture | Support | Performance |
---|---|---|---|
macOS | ARM64 (Apple Silicon) | β Native | βββββ |
macOS | AMD64 (Intel) | β Native | βββββ |
Linux | AMD64 | β Native | βββββ |
Linux | ARM64 | β Native | βββββ |
Windows | AMD64 (WSL2) | β Native | ββββ |
Windows | AMD64 (Native) | β Native | ββββ |
- No manual configuration: Works on any system out of the box
- Native performance: Uses host architecture for optimal speed
- Future-proof: Automatically supports new architectures
- Single command:
docker buildx bake all
builds for all platforms - Registry ready: Push to Docker Hub for cross-platform distribution
- CI/CD friendly: Integrates with GitHub Actions, GitLab CI, etc.
- Fast builds: Local development uses host platform
- Hot reloading: TypeScript execution without compilation
- Easy debugging: Direct access to container logs
# Check Docker platform support
docker buildx ls
# Create multi-platform builder
docker buildx create --name multiplatform --use
# Inspect image platforms
docker buildx imagetools inspect your-image:tag
# Clean Docker cache
docker system prune -a
# Rebuild without cache
docker-compose build --no-cache
# Check build logs
docker-compose logs --tail=100
# Check container health
docker-compose ps
# View container logs
docker-compose logs -f backend
# Access container shell
docker-compose exec backend sh
Creates a new game session.
Request:
{
// No body required
}
Response:
{
"success": true,
"sessionId": "abc123def4",
"message": "Game session created successfully"
}
Response Fields:
success
(boolean): Alwaystrue
on successful creationsessionId
(string): Unique 10-character alphanumeric session identifiermessage
(string): Human-readable success message
Error Response:
{
"success": false,
"message": "Failed to create game session",
"error": "Internal server error"
}
Error Fields:
success
(boolean): Alwaysfalse
on errormessage
(string): Human-readable error messageerror
(string, optional): Detailed error in development mode
Status Codes:
201
- Session created successfully500
- Internal server error
Retrieves all active game sessions.
Request:
GET /api/sessions
Query Parameters:
- None required
Response:
{
"success": true,
"sessions": [
{
"sessionId": "abc123def4",
"playerCount": 2,
"createdAt": 1703123456789,
"lastActivity": 1703123456789
}
]
}
Response Fields:
success
(boolean): Alwaystrue
on successful retrievalsessions
(array): Array of active session objectssessionId
(string): Unique session identifierplayerCount
(number): Number of active players (0-10)createdAt
(number): Unix timestamp when session was createdlastActivity
(number): Unix timestamp of last activity
Error Response:
{
"success": false,
"message": "Failed to get active sessions"
}
Status Codes:
200
- Sessions retrieved successfully500
- Internal server error
Gets detailed information about a specific session.
Request:
GET /api/sessions/abc123def4
Path Parameters:
sessionId
(string, required): 10-character alphanumeric session identifier
Response:
{
"success": true,
"session": {
"sessionId": "abc123def4",
"playerCount": 2,
"createdAt": 1703123456789,
"lastActivity": 1703123456789,
"players": ["socket_id_1", "socket_id_2"],
"gameState": {
"narrative": "You find yourself in a dark cave...",
"events": [
{
"id": "event_1",
"playerId": "socket_id_1",
"command": "explore the cave",
"narrative": "As you explore the cave...",
"timestamp": 1703123456789
}
],
"currentLocation": "Dark Cave Entrance",
"inventory": ["torch", "rope"],
"health": 100,
"experience": 50
}
}
}
Response Fields:
success
(boolean): Alwaystrue
on successful retrievalsession
(object): Detailed session informationsessionId
(string): Unique session identifierplayerCount
(number): Number of active playerscreatedAt
(number): Unix timestamp when session was createdlastActivity
(number): Unix timestamp of last activityplayers
(array): Array of connected player socket IDsgameState
(object): Current game statenarrative
(string): Current story narrativeevents
(array): Array of game events (max 50)currentLocation
(string): Player's current locationinventory
(array): Player's inventory itemshealth
(number): Player's health points (0-100)experience
(number): Player's experience points
Error Response (404):
{
"success": false,
"message": "Session not found"
}
Status Codes:
200
- Session details retrieved successfully404
- Session not found500
- Internal server error
Deletes a specific game session.
Request:
DELETE /api/sessions/abc123def4
Path Parameters:
sessionId
(string, required): 10-character alphanumeric session identifier
Response:
{
"success": true,
"message": "Session deleted successfully"
}
Response Fields:
success
(boolean): Alwaystrue
on successful deletionmessage
(string): Human-readable success message
Error Response (404):
{
"success": false,
"message": "Session not found"
}
Status Codes:
200
- Session deleted successfully404
- Session not found500
- Internal server error
System health check endpoint.
Request:
GET /api/health
Response:
{
"status": "healthy",
"timestamp": "2024-01-15T10:30:45.123Z",
"uptime": 3600.5,
"redis": "connected",
"environment": "production",
"version": "1.0.0"
}
Response Fields:
status
(string): Health status (healthy
orunhealthy
)timestamp
(string): ISO 8601 timestamp of health checkuptime
(number): Server uptime in secondsredis
(string): Redis connection status (connected
ordisconnected
)environment
(string): Current environment (development
,production
, etc.)version
(string): Application version
Error Response (503):
{
"status": "unhealthy",
"timestamp": "2024-01-15T10:30:45.123Z",
"error": "Redis connection failed"
}
Status Codes:
200
- System healthy503
- System unhealthy
The application uses Socket.IO for real-time communication. All events are prefixed with game:
.
Join a game session.
Request:
{
"sessionId": "abc123def4"
}
Request Fields:
sessionId
(string, required): 10-character alphanumeric session identifier
Validation Rules:
sessionId
must be exactly 10 characterssessionId
must be alphanumeric only- Session must exist and be active
Server Response:
{
"sessionId": "abc123def4",
"playerId": "socket_id_123",
"timestamp": 1703123456789
}
Response Fields:
sessionId
(string): The session ID that was joinedplayerId
(string): Unique socket ID for this playertimestamp
(number): Unix timestamp of join event
Error Response:
{
"message": "Session not found or inactive",
"timestamp": 1703123456789
}
Send a command to the AI Dungeon Master.
Request:
{
"command": "explore the cave entrance"
}
Request Fields:
command
(string, required): Player's action command
Validation Rules:
command
must be non-empty stringcommand
must be trimmed of whitespacecommand
maximum length: 1000 characters- Player must be joined to a session
Server Response:
- No direct response
- AI narrative is broadcast via
game:update
event
Error Response:
{
"message": "Command cannot be empty",
"timestamp": 1703123456789
}
Confirmation that player successfully joined a session.
Event:
{
"sessionId": "abc123def4",
"playerId": "socket_id_123",
"timestamp": 1703123456789
}
Event Fields:
sessionId
(string): The session ID that was joinedplayerId
(string): Unique socket ID for this playertimestamp
(number): Unix timestamp of join event
Notification when another player joins the session.
Event:
{
"playerId": "socket_id_456",
"sessionId": "abc123def4",
"timestamp": 1703123456789
}
Event Fields:
playerId
(string): Socket ID of the player who joinedsessionId
(string): Session ID where player joinedtimestamp
(number): Unix timestamp of join event
Notification when a player leaves the session.
Event:
{
"playerId": "socket_id_456",
"sessionId": "abc123def4",
"timestamp": 1703123456789
}
Event Fields:
playerId
(string): Socket ID of the player who leftsessionId
(string): Session ID where player lefttimestamp
(number): Unix timestamp of leave event
AI narrative response broadcast to all players in the session.
Event:
{
"sessionId": "abc123def4",
"narrative": "As you explore the cave entrance, you notice ancient runes carved into the stone walls. The air is thick with mystery and the faint sound of dripping water echoes from deeper within the cavern.",
"playerId": "socket_id_123",
"command": "explore the cave entrance",
"timestamp": 1703123456789,
"gameState": {
"currentLocation": "Cave Entrance",
"inventory": ["torch", "rope", "ancient key"],
"health": 95,
"experience": 75
}
}
Event Fields:
sessionId
(string): Session ID where update occurrednarrative
(string): AI-generated story response (max 2000 characters)playerId
(string): Socket ID of player who sent the commandcommand
(string): Original command that triggered the responsetimestamp
(number): Unix timestamp of update eventgameState
(object, optional): Updated game statecurrentLocation
(string): Player's current locationinventory
(array): Player's inventory itemshealth
(number): Player's health points (0-100)experience
(number): Player's experience points
Error notification for various game-related issues.
Event:
{
"message": "Failed to process command. Please try again.",
"timestamp": 1703123456789,
"errorCode": "COMMAND_PROCESSING_ERROR"
}
Event Fields:
message
(string): Human-readable error messagetimestamp
(number): Unix timestamp of error eventerrorCode
(string, optional): Machine-readable error code
Common Error Codes:
SESSION_NOT_FOUND
- Session doesn't existCOMMAND_PROCESSING_ERROR
- AI processing failedRATE_LIMIT_EXCEEDED
- Too many commandsINVALID_COMMAND
- Command validation failedCONNECTION_ERROR
- WebSocket connection issue
All API endpoints return consistent error responses:
HTTP Error Responses:
-
400
- Bad Request (invalid parameters){ "success": false, "message": "Invalid session ID format", "error": "Session ID must be exactly 10 characters" }
-
404
- Not Found (session doesn't exist){ "success": false, "message": "Session not found" }
-
429
- Too Many Requests (rate limit exceeded){ "success": false, "message": "Too many requests from this IP, please try again later.", "retryAfter": 900 }
-
500
- Internal Server Error{ "success": false, "message": "Internal server error", "error": "Database connection failed" }
-
503
- Service Unavailable (health check failures){ "status": "unhealthy", "timestamp": "2024-01-15T10:30:45.123Z", "error": "Redis connection failed" }
Rate Limiting:
- 100 requests per 15 minutes per IP address
- Returns
429
status with retry information - Applies to all REST API endpoints
- WebSocket events have separate rate limiting
WebSocket Error Handling:
- Connection errors are handled gracefully
- Automatic reconnection attempts (exponential backoff)
- Session state is preserved during disconnections
- Error events include error codes for programmatic handling
CORS Configuration:
- Configured for development and production origins
- Supports credentials for authenticated requests
- Methods: GET, POST, DELETE, OPTIONS
Rate Limiting:
- Prevents abuse with configurable limits
- Separate limits for REST API and WebSocket events
- IP-based rate limiting with configurable windows
Input Validation:
- All commands and session IDs are validated
- SQL injection protection through parameterized queries
- XSS protection through input sanitization
- Command length limits (1000 characters max)
Error Sanitization:
- Sensitive information is filtered in production
- Stack traces only shown in development mode
- Generic error messages in production
Connection URL: ws://localhost:3001
(or your server URL)
Connection Options:
const socket = io('http://localhost:3001', {
transports: ['websocket', 'polling'],
timeout: 60000,
pingInterval: 25000,
pingTimeout: 60000,
reconnection: true,
reconnectionAttempts: 5,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000
});
Connection States:
connected
- Successfully connected to serverdisconnected
- Connection lostconnecting
- Attempting to reconnecterror
- Connection error occurred
Reconnection Behavior:
- Automatic reconnection on connection loss
- Exponential backoff (1s, 2s, 4s, 8s, 16s)
- Maximum 5 reconnection attempts
- Session state preserved during reconnection
Event Acknowledgment:
// Send command with acknowledgment
socket.emit('game:command', { command: 'explore cave' }, (response) => {
if (response.success) {
console.log('Command sent successfully');
} else {
console.error('Command failed:', response.message);
}
});
cd backend
npm run dev # Start development server
npm run build # Build for production
npm run test:phase1 # Run Phase 1 tests
cd frontend
npm run dev # Start development server
npm run build # Build for production
npm run preview # Preview production build
realtime_ai_dungeon_master/
βββ backend/
β βββ src/
β β βββ server.ts # Express server with Socket.IO
β β βββ gameService.ts # Game logic and AI integration
β β βββ loreService.ts # Lore system with semantic search
β β βββ redisClient.ts # Redis connection management
β β βββ utils/
β β βββ envValidation.ts # Environment validation utilities
β β βββ errorHandler.ts # Error handling and logging
β β βββ rateLimiter.ts # Rate limiting with IPv6 support
β βββ scripts/
β β βββ test_phase1.ts # Phase 1 verification tests
β β βββ test_complete.ts # Complete implementation tests
β βββ Dockerfile # Backend container configuration
β βββ tsconfig.json # TypeScript configuration
β βββ .env.example # Environment variables template
β βββ package.json
βββ frontend/
β βββ src/
β β βββ components/
β β β βββ GameView.tsx # Main game interface
β β β βββ CommandInput.tsx # Command input component
β β β βββ StoryLog.tsx # Story display component
β β β βββ LandingPage.tsx # Session management UI
β β β βββ ErrorBoundary.tsx # Error handling component
β β β βββ ToastProvider.tsx # Toast notifications
β β β βββ theme-provider.tsx # Theme management
β β β βββ theme-toggle.tsx # Theme toggle component
β β βββ @/components/ui/ # Reusable UI components
β β βββ types/
β β β βββ toast.ts # Toast type definitions
β β βββ App.tsx # Main application component
β β βββ main.tsx # Application entry point
β β βββ index.css # Global styles
β β βββ App.css # App-specific styles
β βββ public/ # Static assets
β βββ Dockerfile # Frontend container configuration
β βββ nginx.conf # Nginx configuration for production
β βββ tsconfig.json # TypeScript configuration
β βββ vite.config.ts # Vite configuration
β βββ tailwind.config.js # Tailwind CSS configuration
β βββ postcss.config.js # PostCSS configuration
β βββ eslint.config.js # ESLint configuration
β βββ package.json
βββ docker-compose.yml # Full stack deployment
βββ .gitignore # Root gitignore
βββ README.md # Main project documentation
game:{sessionId}:state
- Current game state and metadatastatus
: Session status (active, ended)created_at
: Timestamp when session was createdlast_activity
: Timestamp of last activity
game:{sessionId}:events
- Immutable log of all game eventsplayerId
: ID of the player who performed the actionevent
: JSON stringified event datatimestamp
: When the event occurred
game:{sessionId}:players
- Active players in the session- Uses
SADD
to add players - Uses
SREM
to remove players - Uses
SCARD
to count active players
- Uses
game:{sessionId}:updates
- Real-time narrative broadcasts- JSON messages with narrative content
- Broadcast to all players in the session
- Uses
KEYS game:*:state
to find all active sessions - Pattern matching for session discovery
- Enables session browser functionality
- Uses
DEL
for session cleanup - Removes all session data when deleting
- Automatic cleanup of inactive sessions
lore:{id}
- AI-generated lore entries with embeddingsid
: Unique lore identifiertype
: Lore type (character, location, item, world_rule, quest)title
: Lore titlecontent
: Detailed lore contentembedding
: Vector embedding for semantic searchtags
: Array of tags for categorizationcreated_at
: Timestamp when lore was createdupdated_at
: Timestamp when lore was last updated
lore:type:{type}
- Index of lore entries by type- Uses
SADD
to add lore IDs to type index - Uses
SMEMBERS
to get all lore of a specific type
- Uses
lore:tag:{tag}
- Index of lore entries by tag- Uses
SADD
to add lore IDs to tag index - Uses
SMEMBERS
to get all lore with a specific tag
- Uses
# Connect to Docker Redis (if using docker-compose)
docker exec -it $(docker ps -q --filter "ancestor=redislabs/rejson") redis-cli
# Connect to local Redis
redis-cli
# Connect to Redis with password
redis-cli -a your_password
# Connect to remote Redis
redis-cli -h your_redis_host -p 6379
# List all lore entries
KEYS lore:*
# Get lore by type
KEYS lore:world_rule_*
# View lore content
JSON.GET lore:world_rule_1703123456789_abc123
# Search lore by tag
KEYS lore:tag:magic
# Get all lore of a specific type
SMEMBERS lore:type:character
# Get all lore with a specific tag
SMEMBERS lore:tag:magic
# Test RedisJSON module
JSON.SET test $ '{"hello": "world"}'
JSON.GET test
# List all active sessions
KEYS game:*:state
# Get session details
HGETALL game:abc123def4:state
# View session events
XRANGE game:abc123def4:events - + COUNT 20
# Check player count
SCARD game:abc123def4:players
# List all players in session
SMEMBERS game:abc123def4:players
# Delete specific session
DEL game:abc123def4:state game:abc123def4:events game:abc123def4:players
# Delete all sessions
DEL $(redis-cli KEYS "game:*")
# Clear all data (DANGER!)
FLUSHALL
# Check memory usage
INFO memory
# Monitor all Redis commands in real-time
MONITOR
# Watch specific patterns
PSUBSCRIBE game:*:updates
# See database statistics
INFO keyspace
# Count all keys
DBSIZE
# See all Redis info
INFO
# Pretty print JSON (if you have jq installed)
redis-cli --raw JSON.GET lore:world_rule_1703123456789_abc123 | jq .
# Get specific session info
HGET game:97oZyf91Wr:state status
# Get session creation time
HGET game:97oZyf91Wr:state created_at
# Get last activity time
HGET game:97oZyf91Wr:state last_activity
# Count events in a session
XLEN game:97oZyf91Wr:events
# Get latest event only
XREVRANGE game:97oZyf91Wr:events + - COUNT 1
# 1. Connect to Redis
docker exec -it $(docker ps -q --filter "ancestor=redislabs/rejson") redis-cli
# 2. See active sessions
KEYS game:*:state
# 3. Get session details
HGETALL game:abc123def4:state
# 4. See recent events
XRANGE game:abc123def4:events - + COUNT 5
# 5. Check players
SMEMBERS game:abc123def4:players
# 6. See lore entries
KEYS lore:*
# 7. View specific lore
JSON.GET lore:world_rule_1703123456789_abc123
# List all keys in Redis
redis-cli KEYS "*"
# Output:
# 1) "game:97oZyf91Wr:events"
# 2) "game:97oZyf91Wr:state"
# 3) "game:97oZyf91Wr:players"
# 4) "game:IXJCDOUBfw:state"
# 5) "game:IXJCDOUBfw:events"
# Total keys in database
redis-cli DBSIZE
# Output: (integer) 5
# Get session details
redis-cli HGETALL "game:97oZyf91Wr:state"
# Output:
# 1) "status"
# 2) "active"
# 3) "created_at"
# 4) "1754535502551"
# 5) "last_activity"
# 6) "1754542615439"
# Explanation:
# - Session ID: 97oZyf91Wr
# - Status: active (session is currently running)
# - Created: January 6, 2025 at 12:25:02 UTC
# - Last Activity: January 6, 2025 at 14:30:15 UTC
# View recent events in a session
redis-cli XRANGE "game:97oZyf91Wr:events" - + COUNT 5
# Output:
# 1) 1) "1754535510729-0"
# 2) 1) "playerId"
# 2) "pGX0DZIp7ubmiV0aAAAG"
# 3) "event"
# 4) "{\"action\":\"command\",\"target\":\"check inventory\"}"
# 5) "timestamp"
# 6) "1754535510728"
# Explanation:
# - Event ID: 1754535510729-0 (timestamp-sequence)
# - Player ID: pGX0DZIp7ubmiV0aAAAG (Socket.IO socket ID)
# - Action: "check inventory" (player command)
# - Timestamp: January 6, 2025 at 12:25:10 UTC
# List all players in a session
redis-cli SMEMBERS "game:97oZyf91Wr:players"
# Output:
# 1) "artUPKpsNEKy4rEWAAAJ"
# 2) "dqg5atiR-udkCpCDAAAM"
# 3) "NV2U_rEpGCMJY3eEAAAM"
# Count players in session
redis-cli SCARD "game:97oZyf91Wr:players"
# Output: (integer) 3
# Explanation:
# - 3 active players in session 97oZyf91Wr
# - Each player has a unique Socket.IO socket ID
# - Players can join/leave dynamically
# Check Redis memory usage
redis-cli INFO memory
# Output:
# used_memory:987184
# used_memory_human:964.05K
# used_memory_rss:5488640
# used_memory_rss_human:5.23M
# mem_fragmentation_ratio:5.66
# Explanation:
# - Total memory used: 964.05K
# - RSS memory: 5.23M
# - Memory fragmentation: 5.66 (normal range)
# - Efficient memory usage for game data
# Check for lore entries
redis-cli KEYS "lore:*"
# Output: (empty array)
# Explanation:
# - No lore entries currently exist
# - Lore system is ready but not populated
# - Lore would be created as AI generates world content
# Get session details for second session
redis-cli HGETALL "game:IXJCDOUBfw:state"
# Output:
# 1) "status"
# 2) "active"
# 3) "created_at"
# 4) "1754542615441"
# 5) "last_activity"
# 6) "1754543782187"
# View events in second session
redis-cli XRANGE "game:IXJCDOUBfw:events" - + COUNT 3
# Output:
# 1) 1) "1754542631165-0"
# 2) 1) "playerId"
# 2) "NV2U_rEpGCMJY3eEAAAM"
# 3) "event"
# 4) "{\"action\":\"command\",\"target\":\"look around\"}"
# 5) "timestamp"
# 6) "1754542631164"
# 2) 1) "1754542637961-0"
# 2) 1) "playerId"
# 2) "NV2U_rEpGCMJY3eEAAAM"
# 3) "event"
# 4) "{\"action\":\"command\",\"target\":\"check inventory\"}"
# 5) "timestamp"
# 6) "1754542637960"
# 3) 1) "1754542646477-0"
# 2) 1) "playerId"
# 2) "NV2U_rEpGCMJY3eEAAAM"
# 3) "event"
# 4) "{\"action\":\"command\",\"target\":\"help\"}"
# 5) "timestamp"
# 6) "1754542646476"
# Check players in second session
redis-cli SMEMBERS "game:IXJCDOUBfw:players"
# Output: (empty array)
# Explanation:
# - Session IXJCDOUBfw is active but has no current players
# - Recent events show player commands: "look around", "check inventory", "help"
# - Player NV2U_rEpGCMJY3eEAAAM was active but may have disconnected
# Get keyspace information
redis-cli INFO keyspace
# Output:
# db0:keys=5,expires=0,avg_ttl=0,subexpiry=0
# Explanation:
# - 5 total keys in database
# - No expired keys (expires=0)
# - No TTL set on keys (avg_ttl=0)
# - Clean database state
# Count events in first session
redis-cli XLEN "game:97oZyf91Wr:events"
# Output: (integer) 1
# Count events in second session
redis-cli XLEN "game:IXJCDOUBfw:events"
# Output: (integer) 4
# Get latest event from first session
redis-cli XREVRANGE "game:97oZyf91Wr:events" + - COUNT 1
# Output:
# 1) 1) "1754535510729-0"
# 2) 1) "playerId"
# 2) "pGX0DZIp7ubmiV0aAAAG"
# 3) "event"
# 4) "{\"action\":\"command\",\"target\":\"check inventory\"}"
# 5) "timestamp"
# 6) "1754535510728"
# Explanation:
# - Session 97oZyf91Wr: 1 event (single command)
# - Session IXJCDOUBfw: 4 events (more active)
# - Latest event: "check inventory" command
# - Event timestamps show recent activity
- Session Keys:
game:{sessionId}:{type}
game:97oZyf91Wr:state
- Session metadatagame:97oZyf91Wr:events
- Event streamgame:97oZyf91Wr:players
- Player set
status
: "active" | "ended" - Session statuscreated_at
: Unix timestamp - When session was createdlast_activity
: Unix timestamp - Last player activity
- Event ID:
{timestamp}-{sequence}
(e.g., "1754535510729-0") - Player ID: Socket.IO socket identifier
- Event Data: JSON string with action and target
- Timestamp: Unix timestamp of event
- Player IDs: Socket.IO socket IDs (e.g., "artUPKpsNEKy4rEWAAAJ")
- Dynamic Membership: Players can join/leave anytime
- Real-time Count: Use SCARD for current player count
- Small Footprint: ~964KB for 2 active sessions
- Efficient Storage: Redis streams for events, sets for players
- Fast Access: O(1) lookups for session state and player counts
- Active Sessions: 2 sessions currently running
- Session Duration: Sessions created ~2 hours ago, still active
- Player Activity: One session has 3 players, another has 0 (disconnected)
- Command Types: "check inventory", "look around", "help" commands
- Event Frequency: Regular player activity with timestamps
- Command Variety: Different types of player actions
- Player Engagement: Active players using various commands
- Session Persistence: Events preserved even when players disconnect
- Memory Usage: 964KB for 2 sessions (very efficient)
- Key Count: 5 keys total (clean database)
- No Expired Keys: Clean state, no TTL issues
- Fast Access: O(1) operations for all queries
Command | Purpose | Example |
---|---|---|
KEYS game:*:state |
List all sessions | game:97oZyf91Wr:state |
HGETALL game:{id}:state |
Get session details | Status, timestamps |
HGET game:{id}:state status |
Get session status | "active" or "ended" |
Command | Purpose | Example |
---|---|---|
XRANGE game:{id}:events - + |
View all events | Player commands |
XLEN game:{id}:events |
Count events | (integer) 4 |
XREVRANGE game:{id}:events + - COUNT 1 |
Latest event | Most recent command |
Command | Purpose | Example |
---|---|---|
SMEMBERS game:{id}:players |
List players | Socket IDs |
SCARD game:{id}:players |
Count players | (integer) 3 |
SADD game:{id}:players {playerId} |
Add player | Join session |
SREM game:{id}:players {playerId} |
Remove player | Leave session |
Command | Purpose | Example |
---|---|---|
DBSIZE |
Total keys | (integer) 5 |
INFO memory |
Memory usage | 964.05K |
INFO keyspace |
Database stats | keys=5,expires=0 |
MONITOR |
Real-time activity | Watch commands |
Command | Purpose | Example |
---|---|---|
DEL game:{id}:* |
Delete session | Remove all session data |
FLUSHALL |
Clear all data | DANGER - removes everything |
KEYS "*" |
List all keys | See entire database |
REDIS_URL=redis://localhost:6379
PORT=3001
NODE_ENV=development
OPENAI_API_KEY=your_openai_api_key_here
VITE_API_URL=http://localhost:3001
# Check if ports are available
lsof -ti:3001,5173,6379
# Clean up and restart
docker-compose down
docker system prune -f
docker-compose up --build
# Check Docker logs
docker-compose logs
# Check if Redis is running
redis-cli PING
# Check Redis logs
docker logs $(docker ps -q --filter "ancestor=redislabs/rejson")
# Test RedisJSON module
redis-cli JSON.SET test $ '{"hello": "world"}'
# Check if port 3001 is in use
lsof -ti:3001
# Kill process using port 3001
sudo lsof -ti:3001 | xargs kill -9
# Check backend logs
docker-compose logs backend
# Check if port 5173 is in use
lsof -ti:5173
# Check frontend logs
docker-compose logs frontend
# Test nginx configuration
docker exec -it $(docker ps -q --filter "ancestor=ai-dungeon-frontend") nginx -t
# Test RedisJSON functionality
redis-cli JSON.SET lore:test $ '{"id": "test", "type": "test", "title": "Test"}'
redis-cli JSON.GET lore:test
# Check if lore entries exist
KEYS lore:*
# Verify lore type indexing
SMEMBERS lore:type:world_rule
# Find processes using port 3001
lsof -ti:3001
# Kill any process using port 3001
sudo lsof -ti:3001 | xargs kill -9
# Or kill Node.js processes
pkill -f "tsx src/server.ts"
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
For issues and questions, please open an issue on GitHub.