PostgreSQL
Volvox.Bot requires PostgreSQL 17 or later. The bot stores all configuration, conversation history, moderation cases, AI feedback, analytics, and other state in PostgreSQL.Connection string
SetDATABASE_URL to a standard PostgreSQL connection string:
SSL configuration
Use theDATABASE_SSL environment variable to control TLS behavior:
| Value | Behavior |
|---|---|
false / off / disable | SSL disabled |
no-verify | SSL enabled, server certificate not verified |
true / on / require | SSL enabled with full certificate verification |
| (unset) | Auto-detected: disabled for localhost, enabled with verification for all other hosts |
DATABASE_SSL=false automatically since PostgreSQL runs on the internal Docker network.
Connection pool
You can tune the connection pool with these optional variables:| Variable | Default | Description |
|---|---|---|
PG_POOL_SIZE | 5 | Maximum number of pool connections |
PG_IDLE_TIMEOUT_MS | 30000 | Time (ms) before an idle connection is closed |
PG_CONNECTION_TIMEOUT_MS | 10000 | Time (ms) to wait for a new connection |
PG_SLOW_QUERY_MS | 100 | Queries slower than this threshold are logged |
Migrations
Volvox.Bot uses node-pg-migrate to manage schema changes. Migration files live in themigrations/ directory.
The bot automatically runs pending migrations on startup, so you do not need to run them manually for normal operation. Manual migration commands are useful for verifying your database before first start or for rolling back changes.
Running migrations
pgmigrations table. If a migration has already been applied, it is skipped.
Migration files
All migration files are inmigrations/. Each file exports an up function that applies the change and a down function that reverses it.
001 — Initial schema
001 — Initial schema
Creates the full initial table set for the bot:
config— Guild and global key-value configuration storeconversations— AI conversation message historymod_cases— Moderation action records (warn, kick, ban, etc.)mod_scheduled_actions— Pending timed moderation actions (tempbans, timeouts)memory_optouts— Users who have opted out of AI memoryai_usage— Per-call AI token usage and cost trackinglogs— Structured application log storagebot_restarts— Restart history with uptime and versionhelp_topics— Guild-managed help topic contentscheduled_messages— Scheduled and recurring message jobsstarboard_posts— Starred messages forwarded to the starboard channelpolls— Poll questions, options, and votessnippets— Guild code snippet librarygithub_feed_state— Last-seen event ID per GitHub repository feedafk_status— Active AFK entries per user per guildafk_pings— Pings received while a user was AFKreputation— XP, level, and engagement counters per user per guilduser_stats— Message counts, reactions, and activity trackingshowcases— Community project showcase entriesshowcase_votes— One vote per user per showcasereviews— Code review requestschallenge_solves— Daily challenge completion recordsflagged_messages— Messages flagged for reviewtickets— Support ticket threadsaudit_logs— Admin action historyreminders— User reminders with optional recurrence
002 — Conversations: Discord message ID
002 — Conversations: Discord message ID
Adds a
discord_message_id column to the conversations table. This stores the native Discord message ID alongside each row so the dashboard can generate clickable jump URLs for individual messages.003 — AI feedback
003 — AI feedback
Creates the
ai_feedback table to store thumbs-up / thumbs-down reactions on AI-generated messages. Includes a per-user per-message unique constraint to prevent duplicate feedback. Gated behind ai.feedback.enabled in the guild config.004 — Performance indexes
004 — Performance indexes
Adds composite and trigram indexes to improve query performance:
idx_ai_feedback_guild_created— Composite index for feedback trend and recency queriesidx_conversations_content_trgm— GIN trigram index onconversations.contentfor fastILIKEsearch (installspg_trgm)idx_conversations_guild_created— Two-column index for the default 30-day conversation listingidx_flagged_messages_guild_message— Index for flagged message detail and flag endpoints
004 — Voice sessions
004 — Voice sessions
Creates the
voice_sessions table to track voice channel activity. Records join, leave, and move events with duration in seconds. A partial unique index prevents duplicate open sessions for the same user in the same guild after a crash. Gated behind voice.enabled in the guild config.005 — Webhook notifications
005 — Webhook notifications
Creates the
webhook_delivery_log table to record outbound webhook delivery attempts per endpoint. Stores the event type, payload, HTTP response code, and delivery status (success, failed, pending). Endpoint configurations live in the per-guild config JSON.006 — Command usage
006 — Command usage
Creates the
command_usage table for slash command analytics. Each row records the guild, user, command name, channel, and timestamp. Installs pgcrypto for UUID primary keys. Includes composite indexes for guild time-series, command popularity, per-user history, and channel-filtered analytics queries.007 — Command aliases
007 — Command aliases
Creates the
guild_command_aliases table. Each row maps a custom short name (e.g. w) to an existing bot command (e.g. warn) for a specific guild. Stores the Discord slash command ID returned after registering the alias so it can be cleanly removed later.008 — Reaction roles
008 — Reaction roles
Creates two tables for reaction role menus:
reaction_role_menus— One row per role menu message posted in Discordreaction_role_entries— One row per emoji → role mapping attached to a menu
009 — Role menu templates
009 — Role menu templates
010 — Temporary roles
010 — Temporary roles
Creates the
temp_roles table to track role assignments with an expiry time. The bot scheduler polls this table and removes roles when they expire. Includes a partial index for efficient pending-expiry queries.011 — Warnings
011 — Warnings
Creates the
warnings table for the comprehensive warning system. Each warning has a severity (low, medium, high), a point value, an optional expiry date, and a reference to its parent mod case. Includes partial indexes for active warnings and expiry polling.012 — Placeholder
012 — Placeholder
A no-op migration that occupies slot 012 to keep the numbering sequence monotonically increasing. This exists because two migrations were originally given the
004 prefix during concurrent development and were later renumbered to avoid conflicts.013 — Audit log
013 — Audit log
Adds a
user_tag column to the audit_logs table and creates an additional idx_audit_logs_guild_user index for filtering audit log entries by admin user within a guild.Redis
Redis is optional but strongly recommended. WhenREDIS_URL is not set, the bot logs a notice and falls back to in-memory state with no distributed caching.
What Redis is used for
- Config caching — Per-guild configuration is cached in Redis to avoid database reads on every message
- Rate limiting — Sliding-window rate limits for AI responses and commands
- Discord API response caching — Reduces repeated API calls for member and role data
- Session storage — OAuth2 session tokens for the web dashboard
- Reputation/XP — Short-lived counters before flushing to PostgreSQL
Connection string
In Docker Compose,
REDIS_URL is automatically set to redis://redis:6379 pointing at the internal redis service. You do not need to set it in .env for Docker deployments.Backup and restore
Backing up PostgreSQL
Usepg_dump to create a plain-SQL backup:
Restoring PostgreSQL
From a plain-SQL backup:Backing up Redis
Redis persists data to disk via RDB snapshots. In the Docker Compose setup theredisdata volume stores these snapshots. To force a manual snapshot: