Skip to main content

Welcome Contributors

Thank you for your interest in contributing to RaidBot! This guide will help you get started with development, code standards, and the contribution process.

Getting Started

Prerequisites

1

Install Node.js

RaidBot requires Node.js 18 or higher.
node --version
# Should output v18.0.0 or higher
Download from nodejs.org
2

Install Git

git --version
Download from git-scm.com
3

Create Discord Bot

  1. Go to Discord Developer Portal
  2. Create a new application
  3. Go to “Bot” section and create a bot
  4. Copy the bot token (you’ll need this later)
  5. Enable these intents:
    • Server Members Intent
    • Message Content Intent

Clone and Setup

# Fork the repository on GitHub first, then:
git clone https://github.com/YOUR_USERNAME/wizbot.git
cd wizbot
Use allowedGuildIds to restrict the bot to your test server during development.

Development Environment

Recommended tools:
  • Editor: VS Code with ESLint extension
  • Terminal: Any modern terminal with Node.js support
  • Git Client: Command line or GitHub Desktop
  • Discord: Desktop app for testing

Code Standards

Style Guide

RaidBot follows JavaScript Standard Style with some modifications.
  • Use 4 spaces for indentation (not tabs)
  • No semicolons (except where required)
  • Single quotes for strings
  • Max line length: 120 characters
// Good
const message = 'Hello world'
const user = await client.users.fetch(userId)

// Bad
const message = "Hello world";
const user=await client.users.fetch(userId);
  • Variables/Functions: camelCase
  • Constants: UPPER_SNAKE_CASE
  • Classes: PascalCase
  • Files: camelCase or kebab-case
// Variables and functions
const raidData = getRaidData(messageId)
function calculateStats(userId) { }

// Constants
const MAX_RAID_SIZE = 50
const DEFAULT_TIMEOUT_MS = 30000

// Classes
class RateLimiter { }
class CircuitBreaker { }
Add JSDoc comments for public functions:
/**
 * Calculate user statistics for a guild
 * @param {string} guildId - Discord guild ID
 * @param {string} userId - Discord user ID
 * @returns {Object} Statistics object with raid counts and roles
 */
function getUserStats(guildId, userId) {
    // Implementation
}
Always handle errors gracefully:
// Good
try {
    const message = await channel.messages.fetch(messageId)
    await message.edit({ embeds: [embed] })
} catch (error) {
    logger.error('Failed to update raid embed', {
        error,
        messageId,
        channelId: channel.id
    })
    // Graceful fallback or user notification
}

// Bad
const message = await channel.messages.fetch(messageId)
await message.edit({ embeds: [embed] }) // No error handling
Prefer async/await over Promise chains:
// Good
async function createRaid(interaction) {
    const channel = await getChannel(channelId)
    const message = await channel.send({ embeds: [embed] })
    await addReactions(message)
}

// Bad
function createRaid(interaction) {
    return getChannel(channelId)
        .then(channel => channel.send({ embeds: [embed] }))
        .then(message => addReactions(message))
}

Project Conventions

Logging
convention
Use the structured logger for all logging:
const { logger } = require('./utils/logger')

logger.info('Raid created', { raidId, guildId, userId })
logger.warn('Rate limit approaching', { userId, requests })
logger.error('Database error', { error, context: 'saveRaid' })
Never use console.log() in production code.
Database Access
convention
Always use prepared statements:
// Good
const stmt = prepare('SELECT * FROM raids WHERE guild_id = ?')
const raids = stmt.all(guildId)

// Bad - SQL injection risk
const raids = db.prepare(`SELECT * FROM raids WHERE guild_id = '${guildId}'`).all()
State Management
convention
Use state.js functions for all state operations:
const { setActiveRaid, getActiveRaid, deleteActiveRaid } = require('./state')

// Don't directly manipulate activeRaids Map
// Use the provided functions instead
setActiveRaid(messageId, raidData)
Discord API Calls
convention
Wrap Discord API calls with circuit breaker:
const { fetchWithBreaker, sendDMWithBreaker } = require('./utils/circuitBreaker')

const user = await fetchWithBreaker(
    () => client.users.fetch(userId),
    null // fallback value
)

const sent = await sendDMWithBreaker(user, 'Message content')

Development Workflow

Feature Development

1

Create feature branch

git checkout -b feature/my-new-feature
Branch naming:
  • feature/ - New features
  • fix/ - Bug fixes
  • refactor/ - Code improvements
  • docs/ - Documentation updates
2

Write tests first (TDD)

tests/myFeature.test.js
const test = require('node:test')
const assert = require('node:assert/strict')

test('should do something useful', () => {
    const result = myNewFunction()
    assert.equal(result, expected)
})
See the Testing Guide for details.
3

Implement feature

Write the minimum code to make tests pass.
utils/myFeature.js
/**
 * Brief description of what this does
 * @param {string} input - Description
 * @returns {string} Description
 */
function myNewFunction(input) {
    // Implementation
}

module.exports = { myNewFunction }
4

Test thoroughly

# Run tests
npm test

# Test in Discord
node bot.js
# Use your test server to verify functionality
5

Commit changes

git add .
git commit -m "feat: add new feature for X"
Use Conventional Commits:
  • feat: - New feature
  • fix: - Bug fix
  • refactor: - Code refactoring
  • docs: - Documentation
  • test: - Test changes
  • chore: - Maintenance

Commit Message Format

type(scope): brief description

Longer explanation if needed.
Explain WHY this change was made, not WHAT was changed.

Fixes #123
Examples:
feat(raids): add automatic waitlist promotion

When a user removes their signup, the next person on the waitlist
is automatically promoted and notified via DM.

Fixes #45
fix(database): prevent race condition in concurrent signups

Added mutex locks per raid to ensure atomic signup operations.
This prevents duplicate signups when multiple users react simultaneously.

Fixes #67
refactor(logger): switch to structured logging

Replaced console.log calls with structured logger for better
production debugging and log aggregation.

Pull Request Process

Before Submitting

Submit Pull Request

1

Push to your fork

git push origin feature/my-new-feature
2

Create PR on GitHub

  1. Go to the original repository
  2. Click “New Pull Request”
  3. Select your branch
  4. Fill out the PR template
3

PR Description Template

## Description
Brief description of what this PR does.

## Changes
- Added X feature
- Fixed Y bug
- Refactored Z module

## Testing
- [ ] Unit tests added/updated
- [ ] Tested in Discord server
- [ ] Edge cases covered

## Screenshots
(If UI changes, add screenshots)

## Related Issues
Fixes #123
Related to #456
4

Address review feedback

Make requested changes and push updates:
git add .
git commit -m "fix: address review feedback"
git push origin feature/my-new-feature

PR Review Checklist

Reviewers will check:
  • Code quality and readability
  • Test coverage
  • Error handling
  • Performance implications
  • Security considerations
  • Documentation completeness

Common Contributions

Adding a New Command

1

Create command file

commands/mycommand.js
const { SlashCommandBuilder } = require('discord.js')

module.exports = {
    data: new SlashCommandBuilder()
        .setName('mycommand')
        .setDescription('What this command does'),
    requiresManageGuild: true, // Optional
    async execute(interaction) {
        // Implementation
    }
}
2

Register in index.js

commands/index.js
module.exports = [
    require('./availability'),
    require('./create'),
    require('./mycommand'), // Add here
    // ...
]
3

Add tests

tests/mycommand.test.js
const test = require('node:test')
const assert = require('node:assert/strict')
const { execute } = require('../commands/mycommand')

test('should handle valid input', async () => {
    // Test implementation
})

Adding a Database Migration

1

Add migration to runMigrations()

db/database.js
const migrations = [
    // Existing migrations...
    { 
        table: 'raids', 
        column: 'my_new_column', 
        sql: 'ALTER TABLE raids ADD COLUMN my_new_column TEXT' 
    }
]
2

Update schema.sql

db/schema.sql
CREATE TABLE IF NOT EXISTS raids (
  message_id TEXT PRIMARY KEY,
  -- existing columns...
  my_new_column TEXT
);
3

Test migration

# Delete test database
rm data/wizbot.db*

# Restart bot to run migrations
node bot.js

# Verify schema
sqlite3 data/wizbot.db "PRAGMA table_info(raids);"

Fixing a Bug

1

Write failing test

Reproduce the bug in a test:
tests/bugfix.test.js
test('should handle edge case correctly', () => {
    // This test should fail initially
    const result = functionWithBug(edgeCase)
    assert.equal(result, expected)
})
2

Fix the bug

Make the minimal change to fix the issue:
function functionWithBug(input) {
    // Add null check
    if (!input) return null
    
    // Rest of logic
}
3

Verify fix

npm test
# All tests should pass

Issue Guidelines

Reporting Bugs

Use the bug report template:
**Description**
Clear description of the bug.

**Steps to Reproduce**
1. Run command `/create`
2. Enter invalid date
3. See error

**Expected Behavior**
Should show helpful error message.

**Actual Behavior**
Bot crashes with unhandled exception.

**Environment**
- Node.js version: v20.0.0
- Discord.js version: 14.24.2
- Operating System: Ubuntu 22.04

**Logs**
[2026-03-03T10:30:00] [ERROR] Unhandled error…

Feature Requests

**Feature Description**
Clear description of the proposed feature.

**Use Case**
Who would benefit and how?

**Proposed Implementation**
(Optional) How you think it could work.

**Alternatives Considered**
Other solutions you thought about.

Code Review

What We Look For

  • Does the code do what it’s supposed to?
  • Are edge cases handled?
  • Are there any logic errors?
  • Are there tests for new functionality?
  • Do tests cover edge cases?
  • Do all tests pass?
  • Is the code easy to understand?
  • Are variable names descriptive?
  • Is the logic clear and simple?
  • Are there any performance concerns?
  • Could this cause memory leaks?
  • Are database queries optimized?
  • Are user inputs validated?
  • Are SQL queries using prepared statements?
  • Are Discord permissions checked?

Giving Feedback

When reviewing code:
  • Be respectful and constructive
  • Explain WHY something should change
  • Suggest alternatives when criticizing
  • Acknowledge good solutions
Good feedback:
Consider using a Map instead of an array here for O(1) lookups. With 100+ raids, the array.find() could become a bottleneck.
Bad feedback:
This is slow, use a Map.

Community

Getting Help

  • Documentation: Start with these developer guides
  • Issues: Search existing issues on GitHub
  • Discord: Join the community server (link in README)

Recognition

Contributors are recognized in:
  • GitHub contributors page
  • Release notes for significant contributions
  • In-bot /changelog command

License

By contributing, you agree that your contributions will be licensed under the ISC License.

Quick Reference

Architecture

Understand the system design

Project Structure

Navigate the codebase

Testing Guide

Write and run tests

Commands Reference

See all available commands

Thank You

Thank you for contributing to RaidBot! Every contribution, whether it’s code, documentation, bug reports, or feature requests, helps make the bot better for everyone.

Build docs developers (and LLMs) love