Rupa is a comprehensive TypeScript Discord bot with modern development practices, database integration, and robust architecture. Built with scalability and maintainability in mind.
- TypeScript for type safety and better development experience
- Discord.js v14 for Discord API integration
- KnexJS + better-sqlite3 for database operations with migration support
- Singleton Database Service for centralized database management
- Winston Logger for comprehensive logging
- Command Handler System with slash commands support
- Event Management System for Discord events
- Environment Configuration management
- Error Handling and graceful shutdown
- Input Validation utilities
- Code Quality Tools (ESLint, Prettier)
- Node.js 18.0.0 or higher
- npm or yarn package manager
- Discord Bot Token and Application ID
-
Clone the repository
git clone <repository-url> cd rupa
-
Install dependencies
npm install
-
Setup environment variables
cp .env.example .env
Edit
.envand fill in your Discord bot credentials:DISCORD_TOKEN=your_discord_bot_token_here CLIENT_ID=your_discord_client_id_here GUILD_ID=your_test_guild_id_here_optional DATABASE_PATH=./data/bot.db LOG_LEVEL=info NODE_ENV=development
-
Build the project
npm run build
-
Deploy commands to Discord
# Deploy commands globally (takes up to 1 hour to propagate) npm run deploy-commands # For guild-specific deployment (instant), set GUILD_ID in .env first npm run deploy-commands
-
Start the bot
npm start
Start the bot in development mode with hot reload:
npm run dev# Run linting
npm run lint
# Fix linting issues
npm run lint:fix
# Format code
npm run format# Run database migrations
npm run migrate# Deploy slash commands to Discord
npm run deploy-commands
# Remove all guild-specific commands (requires GUILD_ID in .env)
npm run remove-guild-commands
# Remove all global commands
npm run remove-global-commands
# Remove both guild and global commands
npm run remove-all-commandssrc/
βββ commands/ # Slash commands
β βββ general/ # General purpose commands
β βββ moderation/ # Moderation commands
β βββ index.ts # Command registry
βββ events/ # Discord event handlers
β βββ ready.ts # Bot ready event
β βββ interactionCreate.ts # Command interactions
β βββ guildEvents.ts # Guild-related events
βββ services/ # Business logic services
β βββ database/ # Database service layer
β β βββ DatabaseService.ts # Singleton DB service
β β βββ models/ # Database models
β β βββ migrations/# Database migrations
β βββ logger/ # Logging service
β βββ config/ # Configuration management
β βββ DiscordBot.ts # Main bot service
βββ types/ # TypeScript type definitions
βββ utils/ # Utility functions
βββ index.ts # Application entry point
Global Commands:
- Comment out or remove
GUILD_IDin.env - Commands available in all servers
- Takes up to 1 hour to propagate
- Use for production deployment
Guild-Specific Commands:
- Set
GUILD_IDin.envto your test server ID - Commands appear immediately in specified server
- Perfect for development and testing
- Guild commands take precedence over global commands
- Development: Use guild-specific deployment for instant testing
- Testing: Deploy to test server using
GUILD_ID - Production: Remove guild commands and deploy globally
- Updates: Redeploy commands when structure changes, restart bot for logic changes
- Switch Guild to Global:
npm run remove-guild-commandsβ removeGUILD_IDβnpm run deploy-commands - Switch Global to Guild:
npm run remove-global-commandsβ setGUILD_IDβnpm run deploy-commands - Clean Start:
npm run remove-all-commandsβnpm run deploy-commands
/ping- Check bot latency and API response time/info- Display bot information and statistics/help- Show available commands and their descriptions/userinfo [user]- Display user profile information/serverinfo- Display server information and statistics
/kick <user> [reason]- Kick a member from the server/ban <user> [reason] [delete_days]- Ban a member from the server/clear <amount> [user]- Bulk delete messages
The bot uses SQLite3 with KnexJS for database operations. The database includes:
- Users Table - Store Discord user information
- Guilds Table - Store server-specific settings
- User_Guilds Table - Junction table for user-server relationships
-- Users table
CREATE TABLE users (
id VARCHAR(20) PRIMARY KEY,
username VARCHAR(32) NOT NULL,
discriminator VARCHAR(4) NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Guilds table
CREATE TABLE guilds (
id VARCHAR(20) PRIMARY KEY,
name VARCHAR(100) NOT NULL,
prefix VARCHAR(5) DEFAULT '!',
settings TEXT DEFAULT '{}',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- User-Guild junction table
CREATE TABLE user_guilds (
user_id VARCHAR(20) NOT NULL,
guild_id VARCHAR(20) NOT NULL,
roles TEXT DEFAULT '[]',
joined_at DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, guild_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (guild_id) REFERENCES guilds(id) ON DELETE CASCADE
);The bot uses Winston for comprehensive logging with multiple levels:
- error - Error messages and exceptions
- warn - Warning messages
- info - General information
- debug - Detailed debug information
Logs are output to:
- Console (with colors in development)
- Files (in production):
logs/combined.log,logs/error.log
- System logs (startup, shutdown, errors)
- Command execution logs
- Database operation logs
- Discord API interaction logs
- Security-related logs
Configuration is managed through environment variables:
| Variable | Description | Default | Required |
|---|---|---|---|
DISCORD_TOKEN |
Bot token from Discord Developer Portal | - | β |
CLIENT_ID |
Discord application client ID | - | β |
GUILD_ID |
Test guild ID for development | - | β |
DATABASE_PATH |
SQLite database file path | ./data/bot.db |
β |
LOG_LEVEL |
Logging level (error/warn/info/debug) | info |
β |
NODE_ENV |
Environment (development/production) | development |
β |
- Create a new command file in the appropriate category folder:
// src/commands/general/example.ts
import { SlashCommandBuilder, CommandInteraction } from 'discord.js';
import { ICommand } from '@/types/bot';
export const exampleCommand: ICommand = {
data: new SlashCommandBuilder()
.setName('example')
.setDescription('An example command'),
async execute(interaction: CommandInteraction): Promise<void> {
await interaction.reply('Hello, World!');
},
};- Export the command from the category index file:
// src/commands/general/index.ts
export { exampleCommand } from './example';- Add the command to the main commands array:
// src/commands/index.ts
import { exampleCommand } from './general';
export const commands: ICommand[] = [
// ... other commands
exampleCommand,
];- Deploy the updated commands:
# For development (instant, requires GUILD_ID in .env)
npm run deploy-commands
# For production (global, takes up to 1 hour)
# Remove or comment GUILD_ID in .env, then:
npm run deploy-commands- Create a new event handler:
// src/events/messageCreate.ts
import { Message } from 'discord.js';
import { logger } from '@/services/logger';
export async function handleMessageCreate(message: Message): Promise<void> {
if (message.author.bot) return;
// Handle the message
logger.info(`Message received: ${message.content}`);
}- Register the event in your bot initialization:
// In your bot setup
client.on(Events.MessageCreate, handleMessageCreate);- Command structure changes (name, description, options)
- Adding or removing commands
- Changing command permissions
- Logic changes within command execution
- Response message updates
- Bug fixes that don't affect command structure
- Use guild deployment during development for instant feedback
- Test thoroughly in guild before global deployment
- Global commands overwrite previous global commands (no duplicates)
- Guild and global commands are managed separately
The bot includes comprehensive error handling:
- Global error handlers for unhandled promises and exceptions
- Command-specific error handling with user-friendly messages
- Database error recovery with connection retry logic
- Discord API error handling with rate limit respect
- Graceful shutdown on process termination
To test your bot:
- Create a test Discord server
- Invite your bot with appropriate permissions
- Use the
GUILD_IDenvironment variable for faster command deployment - Test commands in the server
- Send Messages
- Use Slash Commands
- Embed Links
- Read Message History
- Manage Messages (for moderation commands)
- Kick Members (for kick command)
- Ban Members (for ban command)
- View Channels
- Connect (for voice features, if implemented)
- Enable Developer Mode in Discord (User Settings β Advanced β Developer Mode)
- Right-click on your server name
- Select "Copy Server ID"
- Use this ID as
GUILD_IDin your.envfile for development
-
Set environment to production:
NODE_ENV=production
-
Build the project:
npm run build
-
Start with PM2 or similar process manager:
pm2 start dist/index.js --name rupa-bot
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist/ ./dist/
COPY data/ ./data/
CMD ["node", "dist/index.js"]- Fork the repository
- Create a feature branch
- Make your changes
- Run linting and tests
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
If you encounter any issues or have questions:
- Check the logs for error messages
- Ensure all environment variables are set correctly
- Verify bot permissions in Discord
- Check Discord API status
- Review the documentation
- Clone the repository
- Install dependencies (
npm install) - Copy and configure
.envfile with Discord credentials - Set
GUILD_IDin.envfor development (optional but recommended) - Build the project (
npm run build) - Run database migrations (
npm run migrate) - Deploy commands (
npm run deploy-commands) - Start the bot (
npm startornpm run dev) - Test basic commands in Discord
- Verify bot permissions in your server
- Customize commands and features as needed
- Deploy globally when ready for production
Happy coding! π