Installing the database schema
Bastrel stores its bans, detections and staff actions in your server’s own MySQL or MariaDB database, through oxmysql. Nothing leaves your server for this.
Requirements
Section titled “Requirements”- MySQL 5.7.8 or later, or MariaDB 10.2.7 or later, the database your server already uses (JSON columns; with the default DYNAMIC row format, indexes on utf8mb4 text up to 255 characters).
- oxmysql installed and started before
bastrelinserver.cfg.
Apply the schema
Section titled “Apply the schema”The schema is in bastrel/sql/install.sql. Run it once against your server database, with your usual tool (HeidiSQL, phpMyAdmin, or the command line):
mysql -u <user> -p <database> < resources/bastrel/sql/install.sqlThe file is safe to run again: every table is created only if it does not exist yet, and it never deletes or changes data. Its last two statements (re)create one trigger on bastrel_bans that keeps a lifted ban’s status and its who, when and why exactly as recorded: this needs the TRIGGER privilege (on MySQL with binary logging, also SUPER or log_bin_trust_function_creators); if your database user lacks it, that last statement fails, every table is already created, and Bastrel prints a warning at startup until you run the file again with a user that holds the privilege. Running it again after an update creates the tables that update added. It does not change existing tables: when an update changes one, its release notes give the steps.
What it creates
Section titled “What it creates”| Table | Content |
|---|---|
bastrel_detections |
One row per detection, or per burst of identical detections (the count column grows) |
bastrel_bans |
Bans: code, reason, evidence, author, dates, scope, status, and who lifted a ban, when and why |
bastrel_ban_identifiers |
Identifiers and hardware tokens seen when a ban was issued |
bastrel_players |
First and last connection of each player |
bastrel_player_identifiers |
Identifier history of each player |
bastrel_staff_actions |
Staff commands |
bastrel_transactions |
Economy journal: money and item movements (economy); delta is the signed change of a money line, empty when unknown |
bastrel_screenshots |
Encrypted screenshots (off by default; see screenshots). The data column holds encrypted text, never an image |
bastrel_outbox |
Items waiting to be sent to the Bastrel API, already turned into references (uplink); empty when the licence is off |
bastrel_meta |
Internal state of the resource, such as the date observe mode started |
bastrel_schema_version |
Schema version, for future updates |
All tables use InnoDB and utf8mb4. Every date is stored in UTC.
Updating an older database
Section titled “Updating an older database”Schema version 2 adds the column bastrel_transactions.delta. A database created by an earlier version gets it at startup: Bastrel looks for the column in information_schema, runs one ALTER TABLE ... ADD COLUMN if it is missing, then records version 2 in bastrel_schema_version. Starting again changes nothing. The economy journal writes nothing until the column is there; if the update fails (a slow database at startup, for example), a schema.failed line explains why, the journal stays off, and Bastrel tries again after economy.migrationRetryMs (30 s by default, doubled after each failure up to economy.migrationRetryMaxMs). Version 2 is recorded only once the update has succeeded.
Schema version 3 adds the table bastrel_outbox. Run install.sql again after an update: it only creates what is missing. Without the table Bastrel keeps detecting, sanctioning and banning; only the upload to the API is inert, and one console line says why.
Retention
Section titled “Retention”Bastrel deletes old rows at startup, then once a day, in small batches so that the database is never locked for long:
| Data | Kept for |
|---|---|
| Detections | 90 days |
| Economy journal | 90 days |
| Screenshots (encrypted) | 30 days (logger.retention.screenshotsDays, 1 to 365) |
| Bans | 12 months after their end (expiry or revocation), with their identifiers; active permanent bans are kept |
You can change these durations in config/modules.lua, under logger.retention.
Lifting a ban never deletes it: the ban is marked revoked, with who lifted it, when and why. Only the retention above deletes bans.
Personal data
Section titled “Personal data”- Detection evidence never contains a raw hardware token or a raw IP address, only a reference to the identifier tables.
- Before anything is printed, stored or sent to Discord, Bastrel replaces with
<redacted>: secrets, tokens, passwords, webhook URLs and raw IP addresses. The list of key names is inconfig/modules.lua, underlogger.redactKeys.
If the database is unavailable
Section titled “If the database is unavailable”Bastrel keeps running:
- oxmysql missing or not started: Bastrel keeps detecting and writes its log to the server console only, with one warning when it first tries to write.
- Bans while the database is down: a ban still applies at once and the player is dropped. Bastrel keeps it in the server’s key-value store (KVP, in the server’s
dbfolder, outside the resource folder, so a Bastrel update keeps it) and writes it to the database as soon as it is back. Until then, the console shows an error every minute. Lifting a ban works the same way. Renaming thebastrelresource loses this store. - Database down at startup: Bastrel applies the last known list of bans, saved in the same store after each successful load. Without that list, connections are accepted (fail-open), with a warning.
- Database slow or down: writes never block the server. When too many writes are waiting, new entries without a sanction are dropped first. Entries with a kick or a ban have a reserved share of the queue. The console shows the number of lost entries, at most once a minute. When a write fails with a database error, the same line also names the table, the detection code and the database’s own error message (at most five distinct causes per line, covering the period since the previous line; the counters of lost entries are cumulative since startup). Only the beginning of the database’s own message is shown, up to the first quote character (excluded), cut to 300 bytes: the query, its parameters and the evidence are never printed.
The queue settings are in config/modules.lua, under logger. An invalid value never stops Bastrel: it uses its built-in defaults and reports the error in the console.