Skip to content

Database

DaisyFilter persists through SculkData/HikariCP. SQLite is the default; MariaDB, MySQL and PostgreSQL are supported. DaisyFilter does not add Exposed.

storage.yml selects the backend and carries the connection details:

backend: sqlite # sqlite | mysql | mariadb | postgres
file: data.db # sqlite only, relative to the plugin folder
pool-size: 10
remote: # everything below is ignored on sqlite
host: localhost
port: 3306
database: minecraft
username: root
password: ${DB_PASSWORD:-}
use-ssl: false

The password supports ${ENV_VAR} and ${ENV_VAR:-default} substitution, so the real secret need not be written into the file. Note that a file containing a placeholder is never rewritten, so it does not gain new keys automatically.

DaisyFilter’s own privacy, retention and queue settings live separately in moderation-storage.yml. Switching the backend requires a restart.

  • df_schema_meta
  • df_records — one row per logged violation (metadata; optional encrypted raw).
  • df_staff_actions — privacy-safe audit trail for external punishment commands.
  • df_rule_hits
  • df_player_stats — coalesced per-player aggregates.
  • df_warnings
  • df_staff_notes
  • df_staff_preferences

df_records is indexed by created-at, player uuid, player name, and surface for dashboard queries and keyset pagination; df_staff_actions by record, staff and created-at. Columns are named exactly as the entity properties are (playerUuid, createdAt), and indexes are declared on the entity rather than created by hand.

Writes never block the event thread:

  • a bounded append queue batches record writes off-thread;
  • player statistics use Sculk’s write-behind store, coalescing repeated updates into one row per flush;
  • queue depth, failures, retries, and dropped operations are counted and surfaced in /daisyfilter status;
  • on shutdown the queues flush within a deadline.

If the database is unavailable, filtering continues in a degraded mode — matches are still censored/blocked and players still warned — while persistence retries. Errors are rate-limited and never include raw content.

Records expire after a configurable retention period (default 30 days). A daily job purges expired rows in bounded batches. You can also purge manually with /daisyfilter purge <days> confirm.

See privacy.md for raw-content encryption and key handling.