Docs: wiki-style documentation in docs/, README as the front page

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
FernandoJVideiraandClaude Sonnet 5.5 committed 2026-10-23 01:07:17 +01:00
1 parent 1ee6280d91
commit fefa74e045
10 files changed
+1137 -130

No files matched your search

+66
View File
@@ -0,0 +1,66 @@
# Database
The bot uses PostgreSQL through `database/sql` with the pgx driver. All SQL lives in repos under `internal/db/repos`.
## Who owns the schema
The bot and the dashboard API share one database, so two files describe it:
- **`schema.sql`** in this repository: the tables the bot reads and writes. It is safe to run more than once (`CREATE TABLE IF NOT EXISTS`). It is enough to run the bot **on its own**.
- **The API's migrations** (`velox-dashboard-api/cmd/db/migrations`): when the API is deployed, it creates and changes the tables, and runs its migrations on start. The bot never runs migrations.
Some tables are older and were created by the bot (levels, welcome, and so on). The API's migration `000005_bot_owned_tables` creates them for a fresh combined database. Newer modules (music, tickets, security, meeting lobbies, beta settings) were created by API migrations, and `schema.sql` carries a copy so the bot can run alone.
**The rule:** a table must have the same shape in `schema.sql` and in the API migrations. When you change one, change the other in the same release.
Two things only exist in the API's migrations, because the bot never inserts into those tables:
- the `NOTIFY` triggers on the three `*_commands` tables (see below),
- the migration history.
## Tables
| Area | Tables | Notes |
| --- | --- | --- |
| Leveling | `levels`, `levelsettings`, `levelrewards`, `levelup` | XP and level per member, settings, role rewards, the level-up channel |
| Welcome | `welcome`, `defaultrole` | Welcome channel, templates, GIF, default role |
| Logging | `logsettings` | Log channel and on/off |
| Twitch | `twitch`, `twitch_config` | Streamers and the notification channel |
| Fun | `rps` | Rock-paper-scissors stats |
| Meeting rooms | `meeting_lobbies`, `meeting_temp_channels`, `meeting_settings` | Lobbies (10 per server, enforced by a trigger), the temporary rooms and who created them. `meeting_settings.lobby_channel_id` is the old single lobby column and is no longer read |
| Projects | `projects`, `project_members` | |
| Scheduling | `schedules`, `schedule_messages`, `user_settings` | Sessions, the DM messages to update, and each member's timezone |
| Music | `music_settings`, `music_now_playing`, `music_queue`, `music_commands` | State for the dashboard's player, plus requests from the dashboard |
| Tickets | `ticket_settings`, `ticket_categories`, `tickets`, `ticket_commands` | |
| Security | `security_settings`, `security_trusted`, `security_quarantines`, `security_lockdowns`, `security_raids`, `security_raid_caught`, `security_snapshots`, `security_events`, `security_commands` | Settings, who is trusted, quarantines (with the roles to give back), locked channels (with the permission to restore), raids in progress, snapshots, an event history, and dashboard requests |
| Beta | `beta_settings` | One row: the beta server and the Beta Tester role. Written by the dashboard, read by the bot |
Discord IDs are `BIGINT` (snowflakes fit in 64 bits). In Go they are `int64`; Discord's own API gives them to you as strings, so convert at the edge.
## Dashboard to bot: settings and requests
There are two kinds of traffic from the dashboard, and the difference matters.
**Settings.** The dashboard writes a row, and the bot reads it when it next needs it. Nothing wakes the bot up. Hot paths cache settings for a short time. The bot's beta settings are polled every 30 seconds.
**Requests that need the bot to act.** `music_commands`, `ticket_commands` and `security_commands` work as a small queue:
1. The dashboard API inserts a row (`command_type`, a JSON `payload`, `requested_by`, `processed_at` empty).
2. A trigger in the database runs `pg_notify('<table>', id)`.
3. The bot holds one connection that ran `LISTEN <table>`. It wakes, loads **every** unprocessed row, carries each out, and sets `processed_at`.
Because the bot loads all unprocessed rows (also when it starts), nothing is lost if it was down when a request arrived. A command that fails is logged and marked processed anyway, since retrying would fail the same way.
Every listener **validates the request again**. The API checks that the requester is allowed, and the bot checks too, because it should not trust a row just because it exists. The listeners live in `internal/music/listener.go`, `internal/tickets/listener.go` and `internal/security/listener.go`, and each reconnects after 10 seconds if its connection drops.
## Changing the schema
1. Decide who owns the table (see above). New tables for the dashboard's modules are created by an API migration.
2. Write the API migration, **and** update `schema.sql` to match.
3. Add or change the repo method in `internal/db/repos/<area>repo`. Use `IF NOT EXISTS` and avoid destructive changes: the bot and the dashboard may be deployed a few minutes apart, so the old bot must keep working against the new schema for a moment. Add a column or table first, and remove old ones in a later release.
4. If the dashboard must make the bot do something, add a `command_type` to the `CHECK` in the right `*_commands` table and handle it in the listener.
5. Say in the release notes if the API, bot and dashboard have to deploy together.
## Connection settings
`internal/db/db.go` opens the pool with up to 100 open and 10 idle connections, and recycles them after an hour. The listeners use their own separate connections, because `LISTEN` needs one that stays open.