Database Schema
Solstice uses MongoDB for all persistent state. The database is initialized in internal/database/db.go and accessed globally via the database package.
Connection
The MongoDB URI is resolved from environment variables in this priority order:
MONGO_URI → MONGO_URL → DATABASE_URLThe database name defaults to solstice and is derived from the connection URI.
Collections
served_chats
Tracks all groups where the bot has been added.
{
"_id": ObjectId,
"chat_id": -1001234567890 // int64 - Telegram chat ID
}Operations:
AddServedChat(chatID)- Upsert on group joinGetServedChats()- Returns all chat IDs (used by broadcast, gban)RemoveServedChat(chatID)- Cleanup on bot removal
served_users
Tracks all users who have interacted with the bot in private.
{
"_id": ObjectId,
"user_id": 123456789 // int64 - Telegram user ID
}Operations:
AddServedUser(userID)- Upsert on/startin private chatGetServedUsers()- Returns all user IDs (used by broadcast)
sudoers
Global sudoer users with elevated permissions across all chats.
{
"_id": ObjectId,
"user_id": 123456789 // int64
}Operations:
AddSudoer(userID)- Owner-onlyRemoveSudoer(userID)- Owner-onlyIsSudoer(userID)- Checked on every admin commandGetSudoers()- List for/sudolist
gbans
Globally banned users. Banned across all served chats.
{
"_id": ObjectId,
"user_id": 123456789, // int64
"reason": "Banned by sudo" // string
}Operations:
AddGBan(userID, reason)- Triggers async ban across all chatsRemoveGBan(userID)- Un-gbanIsGBanned(userID)- Checked on new member join events
blocked_users
Users blocked from using the bot entirely.
{
"_id": ObjectId,
"user_id": 123456789 // int64
}blacklisted_chats
Chats where the bot is not allowed to operate.
{
"_id": ObjectId,
"chat_id": -1001234567890 // int64
}auth_users
Per-chat authorized users who can use music commands without being admins.
{
"_id": ObjectId,
"chat_id": -1001234567890, // int64
"user_id": 123456789, // int64
"added_by": 987654321 // int64 - who authorized them
}Constraints:
- Maximum 25 authorized users per chat
- Checked in the
CheckAdminSassy()permission middleware
chat_settings
Per-chat configuration and settings.
{
"_id": ObjectId,
"chat_id": -1001234567890, // int64
"language": "en", // string - i18n language code
"admin_cmd_mode": "everyone", // string - "everyone" | "admin"
"autoplay": true, // bool
"vote_skip_count": 3, // int - votes needed to skip
"welcome_enabled": true, // bool
"welcome_text": "Welcome {name} to {chat}!", // string
"rules": "Be nice!", // string
"warn_mode": "ban", // string - "ban" | "mute" | "kick"
"warn_limit": 3 // int
}Key functions:
GetAdminCmdMode(chatID)/SetAdminCmdMode(chatID, mode)GetChatLanguage(chatID)/SetChatLanguage(chatID, lang)GetAutoplay(chatID)/SetAutoplay(chatID, enabled)GetVoteSkipCount(chatID)/SetVoteSkipCount(chatID, count)
warnings
Per-user-per-chat warning records.
{
"_id": ObjectId,
"chat_id": -1001234567890, // int64
"user_id": 123456789, // int64
"count": 2, // int - current warning count
"reasons": [ // []string
"Spamming",
"Inappropriate language"
]
}afk
Users who have set themselves as AFK (Away From Keyboard).
{
"_id": ObjectId,
"user_id": 123456789, // int64
"reason": "sleeping", // string
"timestamp": 1700000000 // int64 - Unix timestamp when AFK was set
}Operations:
SetAFK(userID, reason, timestamp)GetAFK(userID)→(isAFK, reason, timestamp)RemoveAFK(userID)- Called automatically when user sends a message
locks
Per-chat lock settings for restricting specific message types.
{
"_id": ObjectId,
"chat_id": -1001234567890, // int64
"locks": { // map[string]bool
"url": true,
"media": false,
"bot": true,
"forward": false,
"sticker": false,
"gif": false,
"inline": false,
"poll": false,
"game": false
}
}approved_users
Users approved to bypass chat locks.
{
"_id": ObjectId,
"chat_id": -1001234567890, // int64
"user_id": 123456789 // int64
}youtube_cookies
Persistent storage for YouTube authentication cookies.
{
"_id": ObjectId,
"key": "youtube_cookies", // string - fixed key
"value": "# Netscape HTTP...",// string - full Netscape cookie content
"updated_at": ISODate(...) // Date - last update timestamp
}Operations:
SetYoutubeCookies(content)- Set/update cookiesGetYoutubeCookies()- Retrieve cookie contentGetYoutubeCookiesInfo()→(content, updatedAt, error)- For/checkcookies
maintenance
Global bot maintenance mode flag.
{
"_id": ObjectId,
"key": "maintenance", // string - fixed key
"enabled": true // bool
}Index Strategy
The database relies on the following query patterns:
| Collection | Primary Query | Suggested Index |
|---|---|---|
served_chats | chat_id | { chat_id: 1 } unique |
served_users | user_id | { user_id: 1 } unique |
sudoers | user_id | { user_id: 1 } unique |
gbans | user_id | { user_id: 1 } unique |
auth_users | chat_id + user_id | { chat_id: 1, user_id: 1 } compound unique |
chat_settings | chat_id | { chat_id: 1 } unique |
warnings | chat_id + user_id | { chat_id: 1, user_id: 1 } compound unique |
afk | user_id | { user_id: 1 } unique |
locks | chat_id | { chat_id: 1 } unique |
Data Flow Diagram
User Command
│
▼
┌─────────────────────────┐
│ BotHandler methods │
│ (bot.go, admins.go) │
│ │
│ ┌───────────────────┐ │
│ │ database package │ │
│ │ │ │
│ │ • IsSudoer() │ │
│ │ • IsAuthUser() │ │
│ │ • GetAutoplay() │ │
│ │ • AddWarning() │ │
│ │ • GetAFK() │ │
│ │ • ... │ │
│ └────────┬──────────┘ │
└────────────┼────────────┘
│
▼
┌─────────────────┐
│ MongoDB │
│ │
│ 13+ collections │
└─────────────────┘