Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Database Reference

Rustmail uses SQLite for persistent storage. The database file db.sqlite is created automatically on first run.


Overview

The database stores:

  • Ticket threads and messages
  • Staff alerts and reminders
  • Scheduled closures
  • Panel sessions and permissions
  • API keys
  • Snippets

Tables

threads

Stores ticket information.

ColumnTypeDescription
idTEXTPrimary key (UUID)
user_idINTEGERDiscord user ID
user_nameTEXTUsername at ticket creation
channel_idTEXTDiscord channel ID
created_atDATETIMETicket creation timestamp
next_message_numberINTEGERCounter for message numbering
statusINTEGERTicket status (1=open, 0=closed)
user_leftBOOLEANWhether user left the server
closed_atDATETIMEClosure timestamp (nullable)
closed_byTEXTStaff who closed (nullable)
category_idTEXTCurrent category ID (nullable)
category_nameTEXTCurrent category name (nullable)
required_permissionsTEXTPermission requirements (nullable)

thread_messages

Stores all messages in tickets.

ColumnTypeDescription
idINTEGERPrimary key (auto-increment)
thread_idTEXTForeign key to threads
user_idINTEGERAuthor’s Discord ID
user_nameTEXTAuthor’s username
is_anonymousBOOLEANWhether sent anonymously
dm_message_idTEXTDiscord message ID in DM
inbox_message_idTEXTDiscord message ID in ticket channel
message_numberINTEGERSequential message number
created_atDATETIMEMessage timestamp
contentTEXTMessage content
thread_statusINTEGERThread status when sent

blocked_users

Stores blocked users who cannot create tickets.

ColumnTypeDescription
user_idTEXTPrimary key (Discord user ID)
user_nameTEXTUsername when blocked
blocked_byTEXTStaff who blocked
blocked_atDATETIMEBlock timestamp
expires_atDATETIMEBlock expiration

staff_alerts

Stores alert subscriptions for tickets.

ColumnTypeDescription
idINTEGERPrimary key
staff_user_idINTEGERStaff Discord ID
thread_user_idINTEGERTicket user Discord ID
created_atDATETIMEAlert creation time
usedBOOLEANWhether alert was triggered

reminders

Stores scheduled reminders.

ColumnTypeDescription
idINTEGERPrimary key
thread_idTEXTForeign key to threads
user_idBIGINTStaff Discord ID
channel_idBIGINTChannel Discord ID
guild_idBIGINTServer Discord ID
reminder_contentTEXTReminder message
trigger_timeINTEGERUnix timestamp to trigger
created_atINTEGERCreation Unix timestamp
completedBOOLEANWhether reminder fired

scheduled_closures

Stores scheduled ticket closures.

ColumnTypeDescription
idINTEGERPrimary key
thread_idTEXTForeign key to threads
scheduled_timeINTEGERUnix timestamp for closure
silentBOOLEANClose without notification
created_byTEXTStaff who scheduled

snippets

Stores saved response templates.

ColumnTypeDescription
idINTEGERPrimary key
keyTEXTUnique snippet identifier
contentTEXTSnippet text
created_byTEXTCreator Discord ID
created_atDATETIMECreation timestamp
updated_atDATETIMELast update timestamp

sessions_panel

Stores web panel sessions.

ColumnTypeDescription
session_idTEXTPrimary key (session token)
user_idTEXTDiscord user ID
access_tokenTEXTDiscord OAuth2 access token
refresh_tokenTEXTDiscord OAuth2 refresh token
expires_atINTEGERSession expiration Unix timestamp
avatar_hashTEXTUser’s avatar hash

api_keys

Stores API keys for external access.

ColumnTypeDescription
idINTEGERPrimary key
key_hashTEXTHashed API key (unique)
nameTEXTKey description
permissionsTEXTJSON array of permissions
created_atINTEGERCreation Unix timestamp
expires_atINTEGERExpiration timestamp (nullable)
last_used_atINTEGERLast usage timestamp (nullable)
is_activeINTEGERWhether key is active

panel_permissions

Stores granted panel permissions.

ColumnTypeDescription
idINTEGERPrimary key
subject_typeTEXT“user” or “role”
subject_idTEXTDiscord user/role ID
permissionTEXTPermission name
granted_byTEXTWho granted it
granted_atINTEGERGrant Unix timestamp

features_messages

Stores feature request tracking.

ColumnTypeDescription
idINTEGERPrimary key
message_idTEXTDiscord message ID
contentTEXTFeature description

thread_status

Stores thread status history.

ColumnTypeDescription
idINTEGERPrimary key
thread_idTEXTForeign key to threads
statusINTEGERStatus value
changed_atDATETIMEChange timestamp

Indexes

Performance indexes on frequently queried columns:

  • threads_id_key on threads(id)
  • thread_messages_id_key on thread_messages(id)
  • idx_api_keys_hash on api_keys(key_hash)
  • idx_api_keys_active on api_keys(is_active)
  • idx_snippets_key on snippets(key)
  • idx_panel_perms_subject on panel_permissions(subject_type, subject_id)
  • idx_panel_perms_permission on panel_permissions(permission)

Migrations

Database schema is managed through SQLx migrations in the migrations/ directory. Migrations run automatically on bot startup.

Migration files are named with timestamps:

migrations/
├── 20250815145017_create_tables.sql
├── 20250815161000_unique_open_and_metadata.sql
├── 20250816120000_message_number_unique_and_cleanup.sql
└── ...

Backup

The database is a single file (db.sqlite). To backup:

# Stop the bot first for consistency
cp db.sqlite db.sqlite.backup

For production, consider scheduled backups:

# Example cron job (daily at 3 AM)
0 3 * * * cp /opt/rustmail/db.sqlite /backups/rustmail-$(date +\%Y\%m\%d).sqlite

Direct Access

You can query the database directly with SQLite tools:

sqlite3 db.sqlite

# Example queries
sqlite3 db.sqlite "SELECT COUNT(*) FROM threads WHERE status = 1;"
sqlite3 db.sqlite "SELECT * FROM threads ORDER BY created_at DESC LIMIT 10;"

Warning: Avoid modifying data while the bot is running to prevent corruption.


Data Retention

Rustmail does not automatically delete old data. For compliance or storage management, you may need to implement your own retention policies:

-- Example: Delete closed tickets older than 1 year
DELETE FROM thread_messages
WHERE thread_id IN (
  SELECT id FROM threads
  WHERE status = 0
  AND closed_at < datetime('now', '-1 year')
);

DELETE FROM threads
WHERE status = 0
AND closed_at < datetime('now', '-1 year');