Deploying Digibuzzer
Introduction
Digibuzzer is a modern interactive notification and alert system designed for real-time communication and engagement. Whether you’re building a quiz platform, conducting live polls, managing event notifications, or creating interactive experiences that require instant feedback, Digibuzzer provides the tools needed to capture attention and facilitate immediate responses.
Digibuzzer excels with its:
- Real-Time Alerts: Instant notification delivery with WebSocket support for zero-delay communication
- Interactive Buzzer System: Perfect for quizzes, games, and competitions with first-responder tracking
- Multi-Channel Support: Deliver notifications across web, mobile, and desktop platforms
- Customizable Alerts: Flexible notification types including sound, visual, and haptic feedback
- Event Management: Track and log all buzzer events with timestamps and user attribution
- Analytics Dashboard: Monitor engagement metrics and response patterns in real-time
- Team Collaboration: Support for multiple users and team-based alert management
- Integration Ready: REST API and webhooks for seamless integration with existing systems
This comprehensive guide walks you through deploying Digibuzzer on Klutch.sh using Docker, covering installation, database setup, environment configuration, persistent storage, and production best practices.
Prerequisites
Before you begin deploying Digibuzzer, ensure you have the following:
- A Klutch.sh account
- A GitHub account with a repository for your Digibuzzer project
- Docker installed locally for testing (optional but recommended)
- Basic understanding of Docker, databases, and real-time applications
- A domain name for your Digibuzzer instance (recommended for production)
Understanding Digibuzzer Architecture
Before deployment, it’s helpful to understand Digibuzzer’s architecture:
- Application Server: Node.js backend handling WebSocket connections and HTTP requests
- Database: PostgreSQL or MongoDB for storing users, events, and configuration
- Redis: In-memory cache for real-time session management and pub/sub messaging
- WebSocket Server: Handles real-time bidirectional communication for instant alerts
- Static Assets: Frontend interface for buzzer controls and administration
For Klutch.sh deployment, we’ll containerize Digibuzzer with its dependencies, utilizing persistent volumes for data storage and Redis for real-time functionality.
Installation and Setup
Step 1: Create Your Project Directory
First, create a new directory for your Digibuzzer deployment project:
mkdir digibuzzer-klutchcd digibuzzer-klutchgit initStep 2: Create the Dockerfile
Create a Dockerfile in your project root. This example builds Digibuzzer from source:
FROM node:20-alpine AS builder
# Set working directoryWORKDIR /app
# Install build dependenciesRUN apk add --no-cache python3 make g++ git
# Copy package filesCOPY package*.json ./
# Install dependenciesRUN npm ci --only=production
# Copy application sourceCOPY . .
# Build application (if TypeScript or needs compilation)RUN npm run build 2>/dev/null || echo "No build step needed"
# Production stageFROM node:20-alpine
# Install runtime dependenciesRUN apk add --no-cache tini curl
# Set working directoryWORKDIR /app
# Copy from builderCOPY --from=builder /app/node_modules ./node_modulesCOPY --from=builder /app/dist ./distCOPY --from=builder /app/public ./publicCOPY --from=builder /app/package*.json ./
# Create data directory for persistent storageRUN mkdir -p /app/data /app/logs && \ chown -R node:node /app
# Switch to non-root userUSER node
# Expose application portEXPOSE 3000
# Health checkHEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD curl -f http://localhost:3000/health || exit 1
# Use tini as entrypoint for proper signal handlingENTRYPOINT ["/sbin/tini", "--"]
# Start applicationCMD ["node", "dist/index.js"]Step 3: Create Application Source Files
If you’re building Digibuzzer from scratch, create a basic application structure:
package.json:
{ "name": "digibuzzer", "version": "1.0.0", "description": "Interactive notification and alert system", "main": "dist/index.js", "scripts": { "start": "node dist/index.js", "dev": "ts-node src/index.ts", "build": "tsc", "test": "jest" }, "dependencies": { "express": "^4.18.2", "ws": "^8.14.2", "pg": "^8.11.3", "redis": "^4.6.10", "cors": "^2.8.5", "dotenv": "^16.3.1", "uuid": "^9.0.1", "bcrypt": "^5.1.1", "jsonwebtoken": "^9.0.2" }, "devDependencies": { "@types/node": "^20.8.0", "@types/express": "^4.17.20", "@types/ws": "^8.5.8", "typescript": "^5.2.2", "ts-node": "^10.9.1" }}src/index.ts:
import express from 'express';import { createServer } from 'http';import { WebSocketServer } from 'ws';import { config } from './config';import { DatabaseService } from './services/database';import { RedisService } from './services/redis';import { BuzzerService } from './services/buzzer';import routes from './routes';
const app = express();const server = createServer(app);const wss = new WebSocketServer({ server });
// Middlewareapp.use(express.json());app.use(express.urlencoded({ extended: true }));app.use(express.static('public'));
// CORS configurationconst corsOptions = { origin: process.env.ALLOWED_ORIGINS?.split(',') || '*', credentials: true};app.use(require('cors')(corsOptions));
// Initialize servicesconst dbService = new DatabaseService(config.database);const redisService = new RedisService(config.redis);const buzzerService = new BuzzerService(dbService, redisService);
// Health check endpointapp.get('/health', (req, res) => { res.status(200).json({ status: 'healthy', timestamp: new Date().toISOString(), uptime: process.uptime() });});
// API routesapp.use('/api', routes);
// WebSocket connection handlingwss.on('connection', (ws, req) => { console.log('New WebSocket connection');
ws.on('message', async (message) => { try { const data = JSON.parse(message.toString()); await buzzerService.handleBuzzerEvent(ws, data); } catch (error) { console.error('WebSocket error:', error); ws.send(JSON.stringify({ error: 'Invalid message format' })); } });
ws.on('close', () => { console.log('WebSocket connection closed'); buzzerService.handleDisconnection(ws); });});
// Start serverconst PORT = process.env.PORT || 3000;const HOST = process.env.HOST || '0.0.0.0';
async function start() { try { // Initialize database await dbService.connect(); await dbService.migrate();
// Initialize Redis await redisService.connect();
// Start server server.listen(PORT, HOST, () => { console.log(`Digibuzzer server running on http://${HOST}:${PORT}`); }); } catch (error) { console.error('Failed to start server:', error); process.exit(1); }}
// Graceful shutdownprocess.on('SIGTERM', async () => { console.log('SIGTERM received, shutting down gracefully'); server.close(async () => { await dbService.disconnect(); await redisService.disconnect(); process.exit(0); });});
start();src/config.ts:
export const config = { database: { host: process.env.DB_HOST || 'localhost', port: parseInt(process.env.DB_PORT || '5432'), database: process.env.DB_NAME || 'digibuzzer', user: process.env.DB_USER || 'digibuzzer', password: process.env.DB_PASSWORD || '', ssl: process.env.DB_SSL === 'true' }, redis: { host: process.env.REDIS_HOST || 'localhost', port: parseInt(process.env.REDIS_PORT || '6379'), password: process.env.REDIS_PASSWORD || undefined }, jwt: { secret: process.env.JWT_SECRET || 'change-me-in-production', expiresIn: process.env.JWT_EXPIRES_IN || '7d' }, buzzer: { maxEvents: parseInt(process.env.MAX_BUZZER_EVENTS || '1000'), eventTTL: parseInt(process.env.EVENT_TTL || '86400') // 24 hours }};tsconfig.json:
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "lib": ["ES2020"], "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "moduleResolution": "node" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"]}Step 4: Create Frontend Interface
Create a simple frontend in public/index.html:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Digibuzzer - Interactive Alert System</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; display: flex; justify-content: center; align-items: center; padding: 20px; }
.container { background: white; border-radius: 20px; padding: 40px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); max-width: 600px; width: 100%; }
h1 { color: #333; margin-bottom: 10px; font-size: 2.5em; }
.status { color: #666; margin-bottom: 30px; font-size: 1.1em; }
.status.connected { color: #10b981; }
.buzzer-btn { width: 200px; height: 200px; border-radius: 50%; border: none; background: linear-gradient(145deg, #ff6b6b, #ff5252); color: white; font-size: 1.5em; font-weight: bold; cursor: pointer; box-shadow: 0 10px 30px rgba(255, 82, 82, 0.4); transition: all 0.3s ease; margin: 20px auto; display: block; }
.buzzer-btn:hover { transform: scale(1.05); box-shadow: 0 15px 40px rgba(255, 82, 82, 0.6); }
.buzzer-btn:active { transform: scale(0.95); }
.buzzer-btn.pressed { background: linear-gradient(145deg, #10b981, #059669); animation: pulse 0.5s ease; }
@keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); } }
.events { margin-top: 30px; max-height: 300px; overflow-y: auto; }
.event { background: #f3f4f6; padding: 15px; border-radius: 10px; margin-bottom: 10px; }
.event-time { color: #6b7280; font-size: 0.9em; } </style></head><body> <div class="container"> <h1>🔔 Digibuzzer</h1> <p class="status" id="status">Connecting...</p>
<button class="buzzer-btn" id="buzzer"> BUZZ! </button>
<div class="events" id="events"></div> </div>
<script> const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const ws = new WebSocket(`${protocol}//${window.location.host}`); const statusEl = document.getElementById('status'); const buzzerBtn = document.getElementById('buzzer'); const eventsEl = document.getElementById('events');
ws.onopen = () => { statusEl.textContent = '✓ Connected'; statusEl.classList.add('connected'); };
ws.onclose = () => { statusEl.textContent = '✗ Disconnected'; statusEl.classList.remove('connected'); };
ws.onmessage = (event) => { const data = JSON.parse(event.data); if (data.type === 'buzzer_pressed') { addEvent(data); } };
buzzerBtn.addEventListener('click', () => { const event = { type: 'buzzer_press', timestamp: new Date().toISOString(), user: 'Anonymous' };
ws.send(JSON.stringify(event)); buzzerBtn.classList.add('pressed');
setTimeout(() => { buzzerBtn.classList.remove('pressed'); }, 500); });
function addEvent(data) { const eventEl = document.createElement('div'); eventEl.className = 'event'; eventEl.innerHTML = ` <div><strong>${data.user || 'Anonymous'}</strong> pressed the buzzer</div> <div class="event-time">${new Date(data.timestamp).toLocaleTimeString()}</div> `; eventsEl.insertBefore(eventEl, eventsEl.firstChild);
// Keep only last 10 events while (eventsEl.children.length > 10) { eventsEl.removeChild(eventsEl.lastChild); } } </script></body></html>Step 5: Create Database Migration Script
Create a migrations/001_initial.sql file:
-- Users tableCREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, username VARCHAR(255) UNIQUE NOT NULL, email VARCHAR(255) UNIQUE NOT NULL, password_hash VARCHAR(255) NOT NULL, role VARCHAR(50) DEFAULT 'user', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
-- Buzzer events tableCREATE TABLE IF NOT EXISTS buzzer_events ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id), session_id VARCHAR(255), event_type VARCHAR(50) NOT NULL, metadata JSONB, ip_address INET, user_agent TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
-- Sessions tableCREATE TABLE IF NOT EXISTS sessions ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, description TEXT, status VARCHAR(50) DEFAULT 'active', settings JSONB, created_by INTEGER REFERENCES users(id), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
-- Create indexesCREATE INDEX idx_buzzer_events_user_id ON buzzer_events(user_id);CREATE INDEX idx_buzzer_events_session_id ON buzzer_events(session_id);CREATE INDEX idx_buzzer_events_created_at ON buzzer_events(created_at);CREATE INDEX idx_sessions_status ON sessions(status);Step 6: Create Environment Configuration
Create a .env.example file to document required environment variables:
# Server ConfigurationNODE_ENV=productionPORT=3000HOST=0.0.0.0
# Database ConfigurationDB_HOST=postgres-app.klutch.shDB_PORT=8000DB_NAME=digibuzzerDB_USER=digibuzzerDB_PASSWORD=your-secure-passwordDB_SSL=true
# Redis ConfigurationREDIS_HOST=redis-app.klutch.shREDIS_PORT=8000REDIS_PASSWORD=
# SecurityJWT_SECRET=your-secure-jwt-secret-key-min-32-charactersALLOWED_ORIGINS=https://example-app.klutch.sh,https://yourdomain.com
# Buzzer ConfigurationMAX_BUZZER_EVENTS=10000EVENT_TTL=86400
# Optional: External Services# SMTP_HOST=smtp.example.com# SMTP_PORT=587# SMTP_USER=noreply@example.com# SMTP_PASSWORD=smtp-passwordStep 7: Create README Documentation
Create a README.md file:
# Digibuzzer - Interactive Notification System
Real-time notification and alert system with WebSocket support.
## Features
- Real-time buzzer functionality- WebSocket-based instant communication- User session management- Event tracking and analytics- Multi-user support- REST API for integrations
## Requirements
- Node.js 18+- PostgreSQL 13+- Redis 6+
## Environment Variables
See `.env.example` for all required configuration.
## Local Development
```bashnpm installnpm run devProduction Deployment
Build and run with Docker:
docker build -t digibuzzer .docker run -p 3000:3000 --env-file .env digibuzzerAPI Endpoints
GET /health- Health checkGET /api/events- Get buzzer eventsPOST /api/sessions- Create new session- WebSocket
/- Real-time communication
License
MIT
### Step 8: Push to GitHub
Commit your files and push to GitHub:
```bashgit add .git commit -m "Initial Digibuzzer setup for Klutch.sh deployment"git remote add origin https://github.com/yourusername/digibuzzer.gitgit branch -M maingit push -u origin mainSetting Up Database Dependencies
Digibuzzer requires both PostgreSQL and Redis to function. You’ll need to set these up before deploying Digibuzzer.
PostgreSQL Setup
-
Deploy PostgreSQL on Klutch.sh
Create a new app for PostgreSQL using the official PostgreSQL Docker image:
FROM postgres:15-alpineENV POSTGRES_DB=digibuzzerENV POSTGRES_USER=digibuzzer# Set POSTGRES_PASSWORD via environment variables in Klutch.shEXPOSE 5432 -
Configure PostgreSQL Volume
Attach a persistent volume to ensure your database persists:
- Mount Path:
/var/lib/postgresql/data - Size: At least 10GB (recommended 20GB+ for production)
- Mount Path:
-
Set PostgreSQL Traffic Type
- Traffic Type: Select TCP
- Internal Port:
5432 - External Port:
8000(this is where you’ll connect from Digibuzzer)
-
Note Connection Details
Your PostgreSQL connection will be available at:
Host: your-postgres-app.klutch.shPort: 8000Database: digibuzzerUsername: digibuzzerPassword: (set in environment variables)
Redis Setup
-
Deploy Redis on Klutch.sh
Create a new app for Redis:
FROM redis:7-alpine# Enable persistenceCMD ["redis-server", "--appendonly", "yes", "--appendfsync", "everysec"]EXPOSE 6379 -
Configure Redis Volume (optional but recommended)
Attach a persistent volume for Redis data:
- Mount Path:
/data - Size: 5GB (adjust based on cache needs)
- Mount Path:
-
Set Redis Traffic Type
- Traffic Type: Select TCP
- Internal Port:
6379 - External Port:
8000(connect from Digibuzzer on this port)
-
Note Connection Details
Your Redis connection will be:
Host: your-redis-app.klutch.shPort: 8000
Deploying to Klutch.sh
Now that your dependencies are set up, deploy the Digibuzzer application.
Deployment Steps
-
Log in to Klutch.sh
Navigate to klutch.sh/app and sign in to your account.
-
Create a New Project
Go to Create Project and give your project a meaningful name (e.g., “Digibuzzer Alert System”).
-
Create the Digibuzzer App
Navigate to Create App and configure the following settings:
-
Select Your Repository
- Choose GitHub as your Git source
- Select the repository containing your Dockerfile
- Choose the branch you want to deploy (usually
main)
-
Configure Traffic Type
- Traffic Type: Select HTTP (Digibuzzer serves a web application via HTTP)
- Internal Port: Set to
3000(the default port that Digibuzzer listens on)
-
Set Environment Variables
Add the following environment variables (use the connection details from your PostgreSQL and Redis deployments):
Server Configuration:
NODE_ENV:productionPORT:3000HOST:0.0.0.0
Database Configuration:
DB_HOST: Your PostgreSQL app hostname (e.g.,postgres-app.klutch.sh)DB_PORT:8000(external port for TCP traffic)DB_NAME:digibuzzerDB_USER:digibuzzerDB_PASSWORD: Strong password for databaseDB_SSL:true
Redis Configuration:
REDIS_HOST: Your Redis app hostname (e.g.,redis-app.klutch.sh)REDIS_PORT:8000(external port for TCP traffic)
Security:
JWT_SECRET: Generate a secure 32+ character random stringALLOWED_ORIGINS: Your Digibuzzer URL (e.g.,https://example-app.klutch.sh)
Buzzer Configuration:
MAX_BUZZER_EVENTS:10000EVENT_TTL:86400
-
Attach Persistent Volumes
Digibuzzer requires persistent storage for data and logs:
Data Volume:
- Click “Add Volume”
- Mount Path:
/app/data - Size: 10GB+ (adjust based on expected usage)
Logs Volume:
- Click “Add Volume”
- Mount Path:
/app/logs - Size: 5GB
-
Configure Resource Allocation
For Digibuzzer with real-time WebSocket connections:
- CPU: Minimum 1 CPU, recommended 2 CPUs for production
- Memory: Minimum 1GB RAM, recommended 2GB+ for active usage
- Instances: Start with 1 instance (scale horizontally as needed)
-
Deploy Your Application
Click “Create” to start the deployment. Klutch.sh will:
- Automatically detect your Dockerfile in the repository root
- Build the Docker image with Digibuzzer
- Attach the persistent volumes
- Configure networking to PostgreSQL and Redis
- Start your Digibuzzer container
- Assign a URL for external access
-
Wait for Deployment
The initial deployment may take 3-5 minutes as Digibuzzer:
- Installs Node.js dependencies
- Compiles TypeScript to JavaScript
- Connects to PostgreSQL and runs migrations
- Establishes Redis connection
- Starts the Express server and WebSocket server
Monitor the logs in the Klutch.sh dashboard to track progress.
-
Access Your Digibuzzer Instance
Once deployment is complete, navigate to your assigned URL:
https://example-app.klutch.shYou should see the Digibuzzer interface with the buzzer button and connection status.
Initial Configuration and Setup
After your Digibuzzer instance is running, complete the initial setup:
Testing the Buzzer Functionality
-
Open Multiple Browser Windows
Open your Digibuzzer URL in multiple browser windows or devices to test real-time synchronization.
-
Test Buzzer Press
Click the buzzer button in one window and verify that the event appears in all connected clients.
-
Verify WebSocket Connection
Check that the status indicator shows ”✓ Connected” in all windows.
-
Monitor Event Log
Confirm that buzzer events are logged and displayed in the event feed.
Creating Admin User
If you need to create an admin user for managing Digibuzzer:
# Access your container console via Klutch.sh# Then run:node dist/scripts/create-admin.js --username admin --email admin@example.comOr create a user via the API:
curl -X POST https://example-app.klutch.sh/api/users \ -H "Content-Type: application/json" \ -d '{ "username": "admin", "email": "admin@example.com", "password": "secure-password", "role": "admin" }'Environment Variables Reference
Complete reference of Digibuzzer environment variables:
| Variable | Description | Required | Default |
|---|---|---|---|
NODE_ENV | Node environment | Yes | production |
PORT | Application port | Yes | 3000 |
HOST | Bind host address | Yes | 0.0.0.0 |
DB_HOST | PostgreSQL host | Yes | None |
DB_PORT | PostgreSQL port | Yes | 5432 |
DB_NAME | PostgreSQL database name | Yes | digibuzzer |
DB_USER | PostgreSQL username | Yes | None |
DB_PASSWORD | PostgreSQL password | Yes | None |
DB_SSL | Enable SSL for database | No | false |
REDIS_HOST | Redis host | Yes | None |
REDIS_PORT | Redis port | No | 6379 |
REDIS_PASSWORD | Redis password | No | None |
JWT_SECRET | Secret key for JWT tokens | Yes | None |
JWT_EXPIRES_IN | JWT expiration time | No | 7d |
ALLOWED_ORIGINS | CORS allowed origins | No | * |
MAX_BUZZER_EVENTS | Maximum events to store | No | 1000 |
EVENT_TTL | Event time-to-live (seconds) | No | 86400 |
SMTP_HOST | SMTP server host | No | None |
SMTP_PORT | SMTP server port | No | 587 |
SMTP_USER | SMTP username | No | None |
SMTP_PASSWORD | SMTP password | No | None |
Production Best Practices
Security Recommendations
- HTTPS Only: Always use HTTPS for your Digibuzzer instance. Klutch.sh provides automatic TLS.
- Strong Secrets: Use a password manager to generate strong JWT secrets (minimum 32 characters).
- Environment Variables: Store all sensitive credentials as environment variables in Klutch.sh.
- Database Security: Use strong passwords for PostgreSQL and restrict access to database ports.
- CORS Configuration: Set
ALLOWED_ORIGINSto only include your trusted domains. - Rate Limiting: Implement rate limiting to prevent abuse of the buzzer API.
- Input Validation: Always validate and sanitize user inputs on both client and server.
- Regular Updates: Keep Node.js, dependencies, and base images updated.
- Authentication: Implement proper authentication for admin features and API access.
- Audit Logging: Log all significant events for security auditing.
Performance Optimization
- Redis Caching: Utilize Redis for session storage and real-time pub/sub messaging.
- Connection Pooling: Configure appropriate database connection pool sizes.
- WebSocket Compression: Enable WebSocket compression for reduced bandwidth.
- Static Asset Caching: Set proper cache headers for static assets.
- Database Indexing: Ensure proper indexes on frequently queried columns.
- Horizontal Scaling: Add more instances behind a load balancer for high traffic.
- CDN Integration: Use a CDN for static assets and improved global performance.
- Event Cleanup: Regularly clean up old events based on
EVENT_TTLsetting. - Monitoring: Monitor WebSocket connection counts and memory usage.
- Load Testing: Perform load testing to determine optimal resource allocation.
Monitoring and Maintenance
Monitor your Digibuzzer deployment for:
- Application Health: Use the
/healthendpoint for uptime monitoring - WebSocket Connections: Track active connections and connection failures
- Event Throughput: Monitor buzzer events per second
- Database Performance: Query response times and connection pool usage
- Redis Performance: Memory usage and pub/sub message rates
- Memory Leaks: Monitor Node.js memory consumption over time
- CPU Usage: Track CPU utilization under various load conditions
- Network Latency: Monitor WebSocket message latency
- Error Rates: Track application errors and exceptions
- Disk Usage: Monitor persistent volume usage
Backup and Disaster Recovery
-
Database Backups
Set up automated PostgreSQL backups:
Terminal window # Manual backuppg_dump -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME > digibuzzer-backup-$(date +%Y%m%d).sqlSchedule regular backups using cron or a backup service.
-
Redis Persistence
Redis is configured with AOF (Append Only File) persistence, which saves data to the volume at
/data. -
Volume Snapshots
Utilize Klutch.sh volume snapshot features to backup:
/app/data(application data)/app/logs(application logs)- PostgreSQL data volume
- Redis data volume
-
Restore Process
To restore from backup:
Terminal window # Restore databasepsql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME < digibuzzer-backup.sql# Restart application# Klutch.sh will automatically restart the container
Customization and Extensions
Adding Custom Features
Digibuzzer is designed to be extensible. Here are some common customizations:
Custom Buzzer Sounds:
Add custom sound files to public/sounds/ and update the frontend to play them on buzzer press.
Team/Group Support:
Extend the database schema to support teams:
CREATE TABLE teams ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
ALTER TABLE users ADD COLUMN team_id INTEGER REFERENCES teams(id);Leaderboard:
Track buzzer response times and create a leaderboard:
CREATE TABLE leaderboard ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id), session_id VARCHAR(255), response_time_ms INTEGER, rank INTEGER, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);Email Notifications:
Add email notifications for buzzer events by configuring SMTP:
import nodemailer from 'nodemailer';
const transporter = nodemailer.createTransport({ host: process.env.SMTP_HOST, port: parseInt(process.env.SMTP_PORT || '587'), auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASSWORD }});
async function sendBuzzerAlert(email: string, event: any) { await transporter.sendMail({ from: process.env.SMTP_USER, to: email, subject: 'Buzzer Alert!', text: `A buzzer was pressed at ${event.timestamp}` });}Integration with External Services
Webhooks:
Send buzzer events to external services:
async function sendWebhook(url: string, event: any) { await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(event) });}Slack Integration:
Post buzzer events to Slack:
async function postToSlack(webhookUrl: string, event: any) { await fetch(webhookUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: `🔔 Buzzer pressed by ${event.user} at ${new Date(event.timestamp).toLocaleString()}` }) });}REST API:
Expose a REST API for external integrations:
// Get recent eventsapp.get('/api/events', async (req, res) => { const limit = parseInt(req.query.limit as string) || 100; const events = await dbService.getRecentEvents(limit); res.json(events);});
// Trigger buzzer via APIapp.post('/api/buzzer/press', async (req, res) => { const { user, sessionId } = req.body; const event = await buzzerService.triggerBuzzer(user, sessionId); res.json(event);});Scaling Your Digibuzzer Instance
As your usage grows, you may need to scale your Digibuzzer deployment:
Vertical Scaling
Increase resources for your existing instance:
- Upgrade CPU: Move to 2, 4, or more CPUs for better performance
- Increase Memory: Scale to 4GB, 8GB, or more RAM for more connections
- Expand Storage: Increase volume sizes as data grows
Horizontal Scaling
For high-traffic deployments:
- Multiple Instances: Run multiple Digibuzzer app instances behind a load balancer
- Sticky Sessions: Configure load balancer for WebSocket sticky sessions
- Redis Pub/Sub: Use Redis for cross-instance messaging and synchronization
- Shared State: Ensure all state is stored in PostgreSQL or Redis, not in memory
- Database Read Replicas: Use PostgreSQL read replicas for read-heavy workloads
WebSocket Scaling Considerations
When scaling WebSocket applications:
// Use Redis pub/sub for broadcasting across instancesimport { createClient } from 'redis';
const publisher = createClient({ url: process.env.REDIS_URL });const subscriber = publisher.duplicate();
// Publish event to all instancespublisher.publish('buzzer-events', JSON.stringify(event));
// Subscribe to events from all instancessubscriber.subscribe('buzzer-events', (message) => { const event = JSON.parse(message); // Broadcast to local WebSocket clients broadcastToLocalClients(event);});Troubleshooting
Cannot Access Digibuzzer
- Check app status: Verify the app is running in Klutch.sh dashboard
- Verify port: Ensure internal port is set to
3000 - Traffic type: Confirm HTTP traffic type is selected
- Review logs: Check application logs for startup errors
- Database connectivity: Verify PostgreSQL is accessible
- Redis connectivity: Ensure Redis is reachable
WebSocket Connection Fails
- HTTPS/WSS: Ensure using secure WebSocket (wss://) with HTTPS
- CORS settings: Verify
ALLOWED_ORIGINSincludes your domain - Load balancer: Check load balancer supports WebSocket connections
- Timeout settings: Increase WebSocket timeout if needed
- Sticky sessions: Enable sticky sessions if using multiple instances
- Firewall: Verify no firewall blocking WebSocket connections
Database Connection Errors
- Connection refused: Verify PostgreSQL is running and accessible on port 8000
- Authentication failed: Check database credentials in environment variables
- Database not found: Ensure database exists; create with
createdb digibuzzer - Network issues: Verify both apps can communicate on Klutch.sh network
- Connection pool: Increase pool size if seeing pool exhaustion errors
- SSL errors: Verify
DB_SSLsetting matches PostgreSQL configuration
Redis Connection Errors
- Cannot connect: Verify Redis is running and accessible on port 8000
- Timeout errors: Check Redis performance and memory limits
- Memory issues: Increase Redis memory allocation
- Persistence problems: Verify Redis volume is correctly mounted
- Connection limit: Check Redis max clients configuration
Performance Issues
- High latency: Monitor network latency between services
- Memory leaks: Check for memory leaks in Node.js application
- Database slow: Review slow query logs and add indexes
- Redis memory: Monitor Redis memory usage and eviction policies
- Too many connections: Limit concurrent WebSocket connections
- CPU bottleneck: Scale vertically or horizontally
Events Not Syncing
- Redis pub/sub: Verify Redis pub/sub is working correctly
- WebSocket broadcast: Check broadcast logic is implemented
- Event queue: Monitor Redis queue for backlog
- Message size: Ensure messages aren’t too large for WebSocket frames
- Clock sync: Verify server time is synchronized (important for timestamps)
Advanced Configuration
Custom Domain Setup
To use a custom domain for your Digibuzzer instance:
- Add domain in Klutch.sh: Navigate to your app settings and add custom domain
- Configure DNS: Point your domain to the provided Klutch.sh address
- Update environment variable: Set
ALLOWED_ORIGINSto include your custom domain - Verify SSL: Klutch.sh automatically provisions SSL certificates
- Redeploy: Restart your app to pick up new configuration
Load Balancer Configuration
For high-availability deployments with multiple instances:
# Example Nginx configuration for WebSocket load balancingupstream digibuzzer_backend { ip_hash; # Enable sticky sessions for WebSocket server digibuzzer-1.klutch.sh:8000; server digibuzzer-2.klutch.sh:8000;}
server { listen 80; server_name buzzer.example.com;
location / { proxy_pass http://digibuzzer_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }}Analytics and Tracking
Add analytics to track usage:
// Track buzzer events in analytics serviceasync function trackEvent(event: BuzzerEvent) { // Example: Send to Google Analytics await fetch('https://www.google-analytics.com/collect', { method: 'POST', body: new URLSearchParams({ v: '1', tid: process.env.GA_TRACKING_ID, cid: event.userId, t: 'event', ec: 'buzzer', ea: 'press', el: event.sessionId }) });}Rate Limiting
Implement rate limiting to prevent abuse:
import rateLimit from 'express-rate-limit';
const buzzerLimiter = rateLimit({ windowMs: 60 * 1000, // 1 minute max: 10, // 10 requests per minute per IP message: 'Too many buzzer presses, please try again later'});
app.post('/api/buzzer/press', buzzerLimiter, async (req, res) => { // Handle buzzer press});Additional Resources
- Node.js Official Documentation
- PostgreSQL Documentation
- Redis Documentation
- WebSocket API Documentation
- Express.js Guide
- Klutch.sh Volumes Guide
- Klutch.sh Networking Guide
- Klutch.sh Custom Domains Guide
Conclusion
Deploying Digibuzzer on Klutch.sh with Docker provides a scalable, real-time notification system perfect for interactive applications, quizzes, events, and alert management. By following this comprehensive guide, you’ve set up a production-ready Digibuzzer instance with WebSocket support, database persistence, real-time synchronization, and proper security measures. Your alert system is now ready to handle real-time interactions at scale. Remember to monitor performance, maintain regular backups, keep dependencies updated, and scale resources as your usage grows. With Digibuzzer deployed on Klutch.sh, you have a powerful foundation for building engaging real-time experiences.