aether-framework/sql/aether_admin.sql
Jerrit Fritzsche e4b82dd685 Aether-Framework: Fachmodule, Admin-Panel und Docker-Datenbank
- aether-medical: Stationen/Belegung, Intensivstation, Blutbank, Fuhrpark,
  Nachrichten/Aushänge, Berichte und Textbausteine (server + NUI)
- aether-admin: vollständiges Server-Admin-Panel als echtes FiveM-Resource,
  an aether-core gekoppelt (Rechte über aether_users.admin_group), mit
  WebRTC-Live-Kameras (Bildschirmfreigabe) und separatem Media-Server (SFU)
- Prototypen admin/ vervollständigt
- SQL-Schema aether_admin.sql
- Docker-Compose mit MariaDB und idempotenter Auto-Migration (schema_migrations)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 18:55:32 +02:00

205 lines
9.4 KiB
SQL

-- =====================================================================
-- aether-admin — Datenbankschema
--
-- Grundsatz: Das Admin-Panel führt Buch und greift durch, aber es
-- erfindet keine Wahrheit. Rechte und Bans leben in `aether_users`
-- (aus aether-core) — dort prüft der Core sie bereits beim Connect.
-- Dieses Schema ergänzt nur, was der Core nicht kennt: Verwarnungen,
-- Reports, Notizen, das Prüfprotokoll und die verwaltbaren Datensätze
-- einzelner Panel-Bereiche.
--
-- Voraussetzung: sql/aether.sql (aether_users, aether_characters) ist
-- eingespielt. `admin_group` und die Bann-Spalten existieren dort schon.
-- =====================================================================
-- ---------------------------------------------------------------------
-- Verwarnungen
--
-- Eine Verwarnung ist eine dokumentierte Ermahnung, mehr nicht. Sie
-- sperrt nichts und läuft nicht ab — sie steht in der Akte, bis ein
-- Admin sie entfernt.
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `aether_admin_warns` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`license` VARCHAR(64) NOT NULL COMMENT 'Betroffener Benutzer',
`character` INT UNSIGNED DEFAULT NULL COMMENT 'Charakter, falls bekannt',
`name` VARCHAR(64) NOT NULL COMMENT 'Anzeigename zum Zeitpunkt',
`grund` VARCHAR(255) NOT NULL,
`admin_license` VARCHAR(64) DEFAULT NULL,
`admin_name` VARCHAR(64) NOT NULL DEFAULT 'System',
`erstellt_am` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_license` (`license`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ---------------------------------------------------------------------
-- Bann-Verlauf
--
-- Die Durchsetzung liegt in `aether_users` (is_banned/ban_reason/
-- ban_until) — der Core sperrt darüber beim Connect. Diese Tabelle ist
-- das Gedächtnis: jeder Bann und jede Entbannung bleibt nachlesbar,
-- auch für Identifier ohne Benutzerkonto (Offline-Ban).
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `aether_admin_bans` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`license` VARCHAR(64) DEFAULT NULL COMMENT 'Lizenz, falls bekannt',
`name` VARCHAR(64) NOT NULL,
`grund` VARCHAR(255) NOT NULL,
`admin_license` VARCHAR(64) DEFAULT NULL,
`admin_name` VARCHAR(64) NOT NULL DEFAULT 'System',
`bis` DATETIME DEFAULT NULL COMMENT 'NULL = dauerhaft',
`aktiv` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '0 = wieder entbannt',
`erstellt_am` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`aufgehoben_am` DATETIME DEFAULT NULL,
`aufgehoben_von` VARCHAR(64) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_license` (`license`),
KEY `idx_aktiv` (`aktiv`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ---------------------------------------------------------------------
-- Reports / Support-Tickets
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `aether_admin_reports` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`melder_license` VARCHAR(64) DEFAULT NULL,
`melder_name` VARCHAR(64) NOT NULL,
`betreff` VARCHAR(160) NOT NULL,
`nachricht` TEXT DEFAULT NULL,
`prioritaet` TINYINT NOT NULL DEFAULT 3 COMMENT '1 hoch … 3 niedrig',
`status` VARCHAR(16) NOT NULL DEFAULT 'offen'
COMMENT 'offen/bearbeitung/geschlossen',
`bearbeiter` VARCHAR(64) DEFAULT NULL COMMENT 'Admin, der übernommen hat',
`erstellt_am` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`aktualisiert_am` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Nachrichtenverlauf eines Reports (Antworten des Teams / Rückfragen)
CREATE TABLE IF NOT EXISTS `aether_admin_report_msgs` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`report` INT UNSIGNED NOT NULL,
`autor` VARCHAR(64) NOT NULL,
`ist_admin` TINYINT(1) NOT NULL DEFAULT 1,
`nachricht` TEXT NOT NULL,
`erstellt_am` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_report` (`report`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ---------------------------------------------------------------------
-- Interne Spielernotizen (nur für das Team sichtbar)
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `aether_admin_notes` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`license` VARCHAR(64) NOT NULL,
`name` VARCHAR(64) NOT NULL,
`notiz` TEXT NOT NULL,
`admin_name` VARCHAR(64) NOT NULL DEFAULT 'System',
`erstellt_am` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_license` (`license`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ---------------------------------------------------------------------
-- Prüfprotokoll (Audit-Log)
--
-- Jede eingreifende Aktion hinterlässt eine Spur: wer, was, an wem,
-- mit welchem Detail. Einträge werden nur geschrieben und gelesen.
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `aether_admin_log` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`admin_license` VARCHAR(64) DEFAULT NULL,
`admin_name` VARCHAR(64) NOT NULL DEFAULT 'System',
`aktion` VARCHAR(64) NOT NULL,
`ziel` VARCHAR(96) DEFAULT NULL,
`detail` VARCHAR(512) DEFAULT NULL,
`erstellt_am` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_admin` (`admin_license`),
KEY `idx_zeit` (`erstellt_am`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ---------------------------------------------------------------------
-- Ankündigungen (Verlauf der Rundmeldungen)
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `aether_admin_broadcasts` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`typ` VARCHAR(16) NOT NULL DEFAULT 'info',
`nachricht` VARCHAR(512) NOT NULL,
`admin_name` VARCHAR(64) NOT NULL DEFAULT 'System',
`erstellt_am` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ---------------------------------------------------------------------
-- Staatsprojekte (Abstimmungen; später koppelbar an eine Handy-App)
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `aether_admin_projects` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`titel` VARCHAR(160) NOT NULL,
`beschreibung` TEXT DEFAULT NULL,
`kosten` BIGINT NOT NULL DEFAULT 0,
`ja` INT UNSIGNED NOT NULL DEFAULT 0,
`nein` INT UNSIGNED NOT NULL DEFAULT 0,
`abstimmung_offen` TINYINT(1) NOT NULL DEFAULT 1,
`aktiviert` TINYINT(1) NOT NULL DEFAULT 0,
`erstellt_am` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ---------------------------------------------------------------------
-- Immobilien
--
-- Solange kein eigenständiges Immobilien-Resource läuft, verwaltet
-- das Panel die Objekte selbst. `HoleImmobilien` ist als Export
-- vorgesehen, damit ein späteres Modul die Hoheit übernehmen kann.
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `aether_admin_properties` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(96) NOT NULL,
`ort` VARCHAR(96) DEFAULT NULL,
`preis` BIGINT NOT NULL DEFAULT 0,
`besitzer` INT UNSIGNED DEFAULT NULL COMMENT 'Charakter aus aether_characters',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ---------------------------------------------------------------------
-- Fraktions-Metadaten
--
-- Mitgliedschaft ergibt sich aus aether_characters.faction. Hier
-- liegen nur die Zusatzangaben (Gehalt, Farbe), die der Charakter
-- nicht kennt.
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `aether_admin_factions` (
`name` VARCHAR(48) NOT NULL,
`gehalt` INT NOT NULL DEFAULT 0 COMMENT 'Payday pro Stunde',
`farbe` VARCHAR(9) NOT NULL DEFAULT '#34d39a',
`aktiv` TINYINT(1) NOT NULL DEFAULT 1,
PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ---------------------------------------------------------------------
-- Persistierte Server-Einstellungen (Schlüssel/Wert)
-- z. B. staatskasse, steuersatz, pvp, whitelist, servername …
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `aether_admin_settings` (
`schluessel` VARCHAR(48) NOT NULL,
`wert` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`schluessel`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ---------------------------------------------------------------------
-- Grundbestand (nur einmalig, wenn leer)
-- ---------------------------------------------------------------------
INSERT INTO `aether_admin_settings` (`schluessel`, `wert`) VALUES
('staatskasse', '12480000'),
('steuersatz', '8'),
('pvp', '1'),
('whitelist', '1'),
('voice', '1'),
('economy', '1')
ON DUPLICATE KEY UPDATE `schluessel` = `schluessel`;