Skip to content

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:

Terminal window
mkdir digibuzzer-klutch
cd digibuzzer-klutch
git init

Step 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 directory
WORKDIR /app
# Install build dependencies
RUN apk add --no-cache python3 make g++ git
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy application source
COPY . .
# Build application (if TypeScript or needs compilation)
RUN npm run build 2>/dev/null || echo "No build step needed"
# Production stage
FROM node:20-alpine
# Install runtime dependencies
RUN apk add --no-cache tini curl
# Set working directory
WORKDIR /app
# Copy from builder
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/public ./public
COPY --from=builder /app/package*.json ./
# Create data directory for persistent storage
RUN mkdir -p /app/data /app/logs && \
chown -R node:node /app
# Switch to non-root user
USER node
# Expose application port
EXPOSE 3000
# Health check
HEALTHCHECK --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 handling
ENTRYPOINT ["/sbin/tini", "--"]
# Start application
CMD ["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 });
// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));
// CORS configuration
const corsOptions = {
origin: process.env.ALLOWED_ORIGINS?.split(',') || '*',
credentials: true
};
app.use(require('cors')(corsOptions));
// Initialize services
const dbService = new DatabaseService(config.database);
const redisService = new RedisService(config.redis);
const buzzerService = new BuzzerService(dbService, redisService);
// Health check endpoint
app.get('/health', (req, res) => {
res.status(200).json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime()
});
});
// API routes
app.use('/api', routes);
// WebSocket connection handling
wss.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 server
const 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 shutdown
process.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 table
CREATE 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 table
CREATE 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 table
CREATE 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 indexes
CREATE 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:

Terminal window
# Server Configuration
NODE_ENV=production
PORT=3000
HOST=0.0.0.0
# Database Configuration
DB_HOST=postgres-app.klutch.sh
DB_PORT=8000
DB_NAME=digibuzzer
DB_USER=digibuzzer
DB_PASSWORD=your-secure-password
DB_SSL=true
# Redis Configuration
REDIS_HOST=redis-app.klutch.sh
REDIS_PORT=8000
REDIS_PASSWORD=
# Security
JWT_SECRET=your-secure-jwt-secret-key-min-32-characters
ALLOWED_ORIGINS=https://example-app.klutch.sh,https://yourdomain.com
# Buzzer Configuration
MAX_BUZZER_EVENTS=10000
EVENT_TTL=86400
# Optional: External Services
# SMTP_HOST=smtp.example.com
# SMTP_PORT=587
# SMTP_USER=noreply@example.com
# SMTP_PASSWORD=smtp-password

Step 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
```bash
npm install
npm run dev

Production Deployment

Build and run with Docker:

Terminal window
docker build -t digibuzzer .
docker run -p 3000:3000 --env-file .env digibuzzer

API Endpoints

  • GET /health - Health check
  • GET /api/events - Get buzzer events
  • POST /api/sessions - Create new session
  • WebSocket / - Real-time communication

License

MIT

### Step 8: Push to GitHub
Commit your files and push to GitHub:
```bash
git add .
git commit -m "Initial Digibuzzer setup for Klutch.sh deployment"
git remote add origin https://github.com/yourusername/digibuzzer.git
git branch -M main
git push -u origin main

Setting Up Database Dependencies

Digibuzzer requires both PostgreSQL and Redis to function. You’ll need to set these up before deploying Digibuzzer.

PostgreSQL Setup

    1. Deploy PostgreSQL on Klutch.sh

      Create a new app for PostgreSQL using the official PostgreSQL Docker image:

      FROM postgres:15-alpine
      ENV POSTGRES_DB=digibuzzer
      ENV POSTGRES_USER=digibuzzer
      # Set POSTGRES_PASSWORD via environment variables in Klutch.sh
      EXPOSE 5432
    2. 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)
    3. Set PostgreSQL Traffic Type

      • Traffic Type: Select TCP
      • Internal Port: 5432
      • External Port: 8000 (this is where you’ll connect from Digibuzzer)
    4. Note Connection Details

      Your PostgreSQL connection will be available at:

      Host: your-postgres-app.klutch.sh
      Port: 8000
      Database: digibuzzer
      Username: digibuzzer
      Password: (set in environment variables)

Redis Setup

    1. Deploy Redis on Klutch.sh

      Create a new app for Redis:

      FROM redis:7-alpine
      # Enable persistence
      CMD ["redis-server", "--appendonly", "yes", "--appendfsync", "everysec"]
      EXPOSE 6379
    2. Configure Redis Volume (optional but recommended)

      Attach a persistent volume for Redis data:

      • Mount Path: /data
      • Size: 5GB (adjust based on cache needs)
    3. Set Redis Traffic Type

      • Traffic Type: Select TCP
      • Internal Port: 6379
      • External Port: 8000 (connect from Digibuzzer on this port)
    4. Note Connection Details

      Your Redis connection will be:

      Host: your-redis-app.klutch.sh
      Port: 8000

Deploying to Klutch.sh

Now that your dependencies are set up, deploy the Digibuzzer application.

Deployment Steps

    1. Log in to Klutch.sh

      Navigate to klutch.sh/app and sign in to your account.

    2. Create a New Project

      Go to Create Project and give your project a meaningful name (e.g., “Digibuzzer Alert System”).

    3. Create the Digibuzzer App

      Navigate to Create App and configure the following settings:

    4. Select Your Repository

      • Choose GitHub as your Git source
      • Select the repository containing your Dockerfile
      • Choose the branch you want to deploy (usually main)
    5. 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)
    6. Set Environment Variables

      Add the following environment variables (use the connection details from your PostgreSQL and Redis deployments):

      Server Configuration:

      • NODE_ENV: production
      • PORT: 3000
      • HOST: 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: digibuzzer
      • DB_USER: digibuzzer
      • DB_PASSWORD: Strong password for database
      • DB_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 string
      • ALLOWED_ORIGINS: Your Digibuzzer URL (e.g., https://example-app.klutch.sh)

      Buzzer Configuration:

      • MAX_BUZZER_EVENTS: 10000
      • EVENT_TTL: 86400
    7. 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
    8. 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)
    9. 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
    10. 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.

    11. Access Your Digibuzzer Instance

      Once deployment is complete, navigate to your assigned URL:

      https://example-app.klutch.sh

      You 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

    1. Open Multiple Browser Windows

      Open your Digibuzzer URL in multiple browser windows or devices to test real-time synchronization.

    2. Test Buzzer Press

      Click the buzzer button in one window and verify that the event appears in all connected clients.

    3. Verify WebSocket Connection

      Check that the status indicator shows ”✓ Connected” in all windows.

    4. 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:

Terminal window
# Access your container console via Klutch.sh
# Then run:
node dist/scripts/create-admin.js --username admin --email admin@example.com

Or create a user via the API:

Terminal window
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:

VariableDescriptionRequiredDefault
NODE_ENVNode environmentYesproduction
PORTApplication portYes3000
HOSTBind host addressYes0.0.0.0
DB_HOSTPostgreSQL hostYesNone
DB_PORTPostgreSQL portYes5432
DB_NAMEPostgreSQL database nameYesdigibuzzer
DB_USERPostgreSQL usernameYesNone
DB_PASSWORDPostgreSQL passwordYesNone
DB_SSLEnable SSL for databaseNofalse
REDIS_HOSTRedis hostYesNone
REDIS_PORTRedis portNo6379
REDIS_PASSWORDRedis passwordNoNone
JWT_SECRETSecret key for JWT tokensYesNone
JWT_EXPIRES_INJWT expiration timeNo7d
ALLOWED_ORIGINSCORS allowed originsNo*
MAX_BUZZER_EVENTSMaximum events to storeNo1000
EVENT_TTLEvent time-to-live (seconds)No86400
SMTP_HOSTSMTP server hostNoNone
SMTP_PORTSMTP server portNo587
SMTP_USERSMTP usernameNoNone
SMTP_PASSWORDSMTP passwordNoNone

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_ORIGINS to 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_TTL setting.
  • 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 /health endpoint 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

    1. Database Backups

      Set up automated PostgreSQL backups:

      Terminal window
      # Manual backup
      pg_dump -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME > digibuzzer-backup-$(date +%Y%m%d).sql

      Schedule regular backups using cron or a backup service.

    2. Redis Persistence

      Redis is configured with AOF (Append Only File) persistence, which saves data to the volume at /data.

    3. Volume Snapshots

      Utilize Klutch.sh volume snapshot features to backup:

      • /app/data (application data)
      • /app/logs (application logs)
      • PostgreSQL data volume
      • Redis data volume
    4. Restore Process

      To restore from backup:

      Terminal window
      # Restore database
      psql -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 events
app.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 API
app.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 instances
import { createClient } from 'redis';
const publisher = createClient({ url: process.env.REDIS_URL });
const subscriber = publisher.duplicate();
// Publish event to all instances
publisher.publish('buzzer-events', JSON.stringify(event));
// Subscribe to events from all instances
subscriber.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_ORIGINS includes 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_SSL setting 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:

  1. Add domain in Klutch.sh: Navigate to your app settings and add custom domain
  2. Configure DNS: Point your domain to the provided Klutch.sh address
  3. Update environment variable: Set ALLOWED_ORIGINS to include your custom domain
  4. Verify SSL: Klutch.sh automatically provisions SSL certificates
  5. 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 balancing
upstream 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 service
async 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


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.