Skip to content

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_URL

The database name defaults to solstice and is derived from the connection URI.


Collections

served_chats

Tracks all groups where the bot has been added.

json
{
  "_id": ObjectId,
  "chat_id": -1001234567890     // int64 - Telegram chat ID
}

Operations:

  • AddServedChat(chatID) - Upsert on group join
  • GetServedChats() - 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.

json
{
  "_id": ObjectId,
  "user_id": 123456789          // int64 - Telegram user ID
}

Operations:

  • AddServedUser(userID) - Upsert on /start in private chat
  • GetServedUsers() - Returns all user IDs (used by broadcast)

sudoers

Global sudoer users with elevated permissions across all chats.

json
{
  "_id": ObjectId,
  "user_id": 123456789          // int64
}

Operations:

  • AddSudoer(userID) - Owner-only
  • RemoveSudoer(userID) - Owner-only
  • IsSudoer(userID) - Checked on every admin command
  • GetSudoers() - List for /sudolist

gbans

Globally banned users. Banned across all served chats.

json
{
  "_id": ObjectId,
  "user_id": 123456789,         // int64
  "reason": "Banned by sudo"    // string
}

Operations:

  • AddGBan(userID, reason) - Triggers async ban across all chats
  • RemoveGBan(userID) - Un-gban
  • IsGBanned(userID) - Checked on new member join events

blocked_users

Users blocked from using the bot entirely.

json
{
  "_id": ObjectId,
  "user_id": 123456789          // int64
}

blacklisted_chats

Chats where the bot is not allowed to operate.

json
{
  "_id": ObjectId,
  "chat_id": -1001234567890     // int64
}

auth_users

Per-chat authorized users who can use music commands without being admins.

json
{
  "_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.

json
{
  "_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.

json
{
  "_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).

json
{
  "_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.

json
{
  "_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.

json
{
  "_id": ObjectId,
  "chat_id": -1001234567890,    // int64
  "user_id": 123456789          // int64
}

youtube_cookies

Persistent storage for YouTube authentication cookies.

json
{
  "_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 cookies
  • GetYoutubeCookies() - Retrieve cookie content
  • GetYoutubeCookiesInfo()(content, updatedAt, error) - For /checkcookies

maintenance

Global bot maintenance mode flag.

json
{
  "_id": ObjectId,
  "key": "maintenance",         // string - fixed key
  "enabled": true               // bool
}

Index Strategy

The database relies on the following query patterns:

CollectionPrimary QuerySuggested Index
served_chatschat_id{ chat_id: 1 } unique
served_usersuser_id{ user_id: 1 } unique
sudoersuser_id{ user_id: 1 } unique
gbansuser_id{ user_id: 1 } unique
auth_userschat_id + user_id{ chat_id: 1, user_id: 1 } compound unique
chat_settingschat_id{ chat_id: 1 } unique
warningschat_id + user_id{ chat_id: 1, user_id: 1 } compound unique
afkuser_id{ user_id: 1 } unique
lockschat_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 │
    └─────────────────┘

Released under the GPL-3.0 License.