Docs: say plainly that only the bot is open source; the dashboard and API are proprietary
- README, license section and architecture no longer point to the dashboard repositories - schema.sql is the schema for contributors; database changes only need schema.sql and a note in the PR - self-hosting: settings without a dashboard (SQL for security thresholds, beta settings, opted-in servers) - beta features, deployment and troubleshooting reworded for people who don't have the dashboard Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
1 parent
1fbc38ca56
commit
02b7db1813
11 files changed
+93
-77
No files matched your search
+24
-18
@@ -4,19 +4,26 @@ The bot uses PostgreSQL through `database/sql` with the pgx driver. All SQL live
|
||||
|
||||
## Who owns the schema
|
||||
|
||||
The bot and the dashboard API share one database, so two files describe it:
|
||||
**`schema.sql`** in this repository is the schema. It describes every table the bot reads and writes, and it is enough to run the bot. It is safe to run more than once (`CREATE TABLE IF NOT EXISTS`). The bot never runs migrations itself.
|
||||
|
||||
- **`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.
|
||||
The hosted Velox also has a proprietary dashboard API that keeps its own migrations for the same tables. That is the maintainer's concern: if your change adds or alters a table, update `schema.sql` and say so in your pull request, and the maintainer ports it. You never need the API to develop or run the bot.
|
||||
|
||||
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.
|
||||
Two things are not in `schema.sql`, because only a dashboard needs them: the `NOTIFY` triggers on the three `*_commands` tables (see below), and a migration history. If you write a tool that inserts command rows, add the trigger yourself:
|
||||
|
||||
**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.
|
||||
```sql
|
||||
CREATE OR REPLACE FUNCTION notify_music_command() RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
PERFORM pg_notify('music_commands', NEW.id::text);
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
Two things only exist in the API's migrations, because the bot never inserts into those tables:
|
||||
CREATE TRIGGER music_commands_notify
|
||||
AFTER INSERT ON music_commands
|
||||
FOR EACH ROW EXECUTE FUNCTION notify_music_command();
|
||||
```
|
||||
|
||||
- the `NOTIFY` triggers on the three `*_commands` tables (see below),
|
||||
- the migration history.
|
||||
The same works for `ticket_commands` and `security_commands`. Without the trigger the bot still picks the rows up, but only the next time it starts or is notified for another reason.
|
||||
|
||||
## Tables
|
||||
|
||||
@@ -30,7 +37,7 @@ Two things only exist in the API's migrations, because the bot never inserts int
|
||||
| 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 |
|
||||
| Music | `music_settings`, `music_now_playing`, `music_queue`, `music_commands` | State a dashboard can show, plus requests to the bot |
|
||||
| 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`, `beta_guilds` | `beta_settings` is one row: the beta server and the Beta Tester role. `beta_guilds` lists servers whose owner opted in to beta features. Both are written by the dashboard and read by the bot. `beta_registered` is the bot's own note of where it registered beta commands |
|
||||
@@ -39,27 +46,26 @@ Discord IDs are `BIGINT` (snowflakes fit in 64 bits). In Go they are `int64`; Di
|
||||
|
||||
## Dashboard to bot: settings and requests
|
||||
|
||||
There are two kinds of traffic from the dashboard, and the difference matters.
|
||||
There are two kinds of traffic from a dashboard to the bot, 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.
|
||||
**Settings.** A 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).
|
||||
1. A dashboard 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.
|
||||
Every listener **validates the request again**. The dashboard should check 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.
|
||||
1. Update `schema.sql`. Use `CREATE TABLE IF NOT EXISTS`, and avoid destructive changes: a bot that is a version behind (or a tool reading the same tables) must keep working against the new schema for a moment. Add a column or table first, and remove old ones in a later release.
|
||||
2. Add or change the repo method in `internal/db/repos/<area>repo`.
|
||||
3. If something outside the bot must make it do something, add a `command_type` to the `CHECK` in the right `*_commands` table and handle it in the listener.
|
||||
4. In your pull request, say that the schema changed and whether an existing table is affected, so the maintainer can port the change to the dashboard's migrations.
|
||||
|
||||
## Connection settings
|
||||
|
||||
|
||||
Reference in new issue
Block a user