Skip to content

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.

  • 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 bastrel in server.cfg.

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):

Terminal window
mysql -u <user> -p <database> < resources/bastrel/sql/install.sql

The 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.

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.

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.

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.

  • 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 in config/modules.lua, under logger.redactKeys.

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 db folder, 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 the bastrel resource 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.