The Capinetta RP Bot System is composed of two independent Node.js processes — the General Bot and the Whitelist Bot — connected to a shared MariaDB database through a single Prisma ORM client. An optional Redis instance provides distributed caching for the Express web dashboard that ships with the General Bot. All processes are managed in production by PM2 viaDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Capinetta-RP/capinetta-discord-bot/llms.txt
Use this file to discover all available pages before exploring further.
ecosystem.config.js, which handles automatic restarts, log rotation, and per-process environment scoping.
Both bots share the same MariaDB database and the same Prisma schema, but their command and event registrations are entirely independent. Updating, restarting, or crashing one bot process has no effect on the other.
Process Architecture
The two main entry points define the boundary between the two bots.index-general.js — General Bot
This is the primary process. On startup it:
- Calls
loadEvents(client, "bot-general")to register all event listeners fromevents/bot-general/. - Calls
loadCommands(client, "bot-general")to populateclient.commandsfromcommands/bot-general/. - Pre-loads the global
warnMapfrom thewarnstable viagetWarnsFromDB()so warn counts survive bot restarts. - Calls
startDashboard(client)which starts the Express server (web/dashboard.js) with Passport Discord OAuth2, Redis caching, and EJS template rendering. - Logs in with
config.general.token.
Guilds, GuildMembers, GuildMessages, MessageContent, GuildVoiceStates, and GuildPresences. It also enables the Message, Channel, GuildMember, and User partials to handle events on uncached objects.
index-whitelist.js — Whitelist Bot
This is the secondary process. On startup it:
- Calls
loadEvents(client, "bot-whitelist")— events fromevents/bot-whitelist/. - Calls
loadCommands(client, "bot-whitelist")— commands fromcommands/bot-whitelist/. - Calls
initDB()to ensure the Prisma connection is live. - Logs in with
config.whitelist.token.
Guilds intent, as it only needs to respond to slash command interactions.
Directory Structure
Key Data Flows
Anti-Spam Flow
The spam detection system lives inevents/bot-general/messageCreate.js and uses an in-memory consecutiveMap attached to the General Bot client.
/warn escalation path is triggered: a Discord timeout is applied for config.general.warnTimeoutMinutes (default: 10 minutes) and the counter resets to 0.
Ticket Flow
The ticket system is the most complex module in the codebase and is fully encapsulated underutils/tickets/ to keep it isolated from the rest of the General Bot.
Whitelist Flow
Dashboard Flow
- Log cleanup job — runs every
LOGS_CLEANUP_INTERVALms, deletesactivity_logsrows older than 30 days. - Profile refresh job — runs every
CACHE_USER_PROFILE_REFRESHms, refreshes up toCACHE_USER_PROFILE_BATCHuser profiles from Discord API and updates theuserstable.
Dynamic Loaders
Both entry points use the same two handler modules, parameterised by the bot subdirectory name ("bot-general" or "bot-whitelist").
handlers/commandHandler.js
Scans commands/<subDir>/ recursively. For each .js file found, it require()s the file and checks that the exported object has both a data property (the SlashCommandBuilder instance) and an execute function. Valid commands are stored in client.commands (a discord.js Collection). Files missing either property log a [WARNING] and are skipped. New command files are auto-discovered on the next bot restart — no manual registration code required.
handlers/eventHandler.js
Scans events/<subDir>/ (flat directory, no recursion). For each .js file it reads the exported name and once properties. If once: true, the event is registered with client.once(); otherwise with client.on(). Both registration paths forward the client instance as the first argument to event.execute(), giving event handlers access to the full client without needing to import it separately.
Shared Utilities
These modules are imported by both bots and the dashboard.utils/database.js
Exports a singleton Prisma client instance and an
initDB() helper that calls prisma.$connect(). Both bots and the dashboard import from this single file, ensuring one connection pool is shared per process.utils/dataHandler.js
High-level CRUD helpers:
getGuildSettings, updateGuildSettings, saveWarnToDB, addWarnLog, getWarnsFromDB, upsertUser, and logActivity. Abstracts raw Prisma calls behind consistent function signatures.utils/logger.js
Exports
sendLog(client, guildId, embed) — looks up logsChannel from the DB for the given guild and sends an EmbedBuilder to that channel. Also exports logError(client, error, context, guildId) which writes to the system_errors table and sends a debug embed to debugChannel.utils/permissions.js
Validates Discord permission bits (
PermissionFlagsBits) and checks whether a given guild member holds any of the guild’s configured staffRoles. Used by ticket handlers and moderation commands to enforce access control beyond the base setDefaultMemberPermissions check.