import pool from '../db.js'; // ============================================================================== // Void-Genesis - Datenbank Initialisierungs-Skript // Führt alle nötigen CREATE TABLE Befehle aus, falls die Tabellen nicht existieren. // ============================================================================== const createTablesQuery = ` -- ------------------------------------------------------------------------------ -- DROP TABLES -- WICHTIG: Die Reihenfolge beim Löschen ist entscheidend! -- Tabellen mit Fremdschlüsseln (Foreign Keys) müssen zuerst gelöscht werden. -- ------------------------------------------------------------------------------ DROP TABLE IF EXISTS refresh_tokens; DROP TABLE IF EXISTS auth_otps; DROP TABLE IF EXISTS lobby_accounts_sectors; -- Zuerst die Brückentabelle löschen DROP TABLE IF EXISTS sectors; -- Dann die Sektoren-Tabelle DROP TABLE IF EXISTS lobby_accounts; -- Zuletzt die Haupt-Nutzer-Tabelle -- ------------------------------------------------------------------------------ -- TABLE: lobby_accounts -- Basis-Nutzerdaten für das gesamte Void-Genesis Universum. -- ------------------------------------------------------------------------------ CREATE TABLE IF NOT EXISTS lobby_accounts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), username VARCHAR(50) UNIQUE NOT NULL, email VARCHAR(255) UNIQUE NOT NULL, password_hash VARCHAR(255) NOT NULL, is_email_verified BOOLEAN DEFAULT false, res_premium INT DEFAULT 0, is_admin BOOLEAN DEFAULT false, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- ------------------------------------------------------------------------------ -- TABLE: sectors -- Beinhaltet die globalen Metadaten zu allen verfügbaren Spiel-Sektoren. -- Hier definieren wir, welche Server existieren und welche Eigenschaften sie haben. -- ------------------------------------------------------------------------------ CREATE TABLE IF NOT EXISTS sectors ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(50) UNIQUE NOT NULL, status VARCHAR(20) DEFAULT 'offline', speed_fleet INT DEFAULT 1, speed_economy INT DEFAULT 1, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- ------------------------------------------------------------------------------ -- TABLE: lobby_accounts_sectors (Brückentabelle) -- Verknüpft einen Lobby-Account mit einem Sektor. -- Existiert hier ein Eintrag, bedeutet das: Der Nutzer hat in diesem Sektor einen Spielstand. -- ------------------------------------------------------------------------------ CREATE TABLE IF NOT EXISTS lobby_accounts_sectors ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), lobby_account_id UUID REFERENCES lobby_accounts(id) ON DELETE CASCADE, sector_id UUID REFERENCES sectors(id) ON DELETE CASCADE, local_username VARCHAR(50) NOT NULL, gender VARCHAR(20) NOT NULL, res_premium INT DEFAULT 0, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(lobby_account_id, sector_id), UNIQUE(sector_id, local_username) ); -- ------------------------------------------------------------------------------ -- TABLE: auth_otps -- Speichert temporäre 6-stellige Codes für Registrierung oder Passwort-Reset. -- ------------------------------------------------------------------------------ CREATE TABLE IF NOT EXISTS auth_otps ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), account_id UUID REFERENCES lobby_accounts(id) ON DELETE CASCADE, otp_code VARCHAR(6) NOT NULL, type VARCHAR(20) NOT NULL, expires_at TIMESTAMPTZ NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW() ); -- ------------------------------------------------------------------------------ -- TABLE: refresh_tokens -- Speichert langlebige Tokens für die "Angemeldet bleiben"-Funktion. -- ------------------------------------------------------------------------------ CREATE TABLE IF NOT EXISTS refresh_tokens ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), account_id UUID REFERENCES lobby_accounts(id) ON DELETE CASCADE, token VARCHAR(500) UNIQUE NOT NULL, expires_at TIMESTAMPTZ NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW() ); -- ------------------------------------------------------------------------------ -- TRIGGER: Auto-update 'updated_at' timestamp -- Diese Funktion setzt das 'updated_at' Feld bei jeder Änderung auf die aktuelle Zeit. -- ------------------------------------------------------------------------------ CREATE OR REPLACE FUNCTION update_modified_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ language 'plpgsql'; -- Wir wenden den Trigger nur an, wenn er noch nicht existiert. DO $$ BEGIN -- Trigger für lobby_accounts IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_lobby_accounts_modtime') THEN CREATE TRIGGER update_lobby_accounts_modtime BEFORE UPDATE ON lobby_accounts FOR EACH ROW EXECUTE FUNCTION update_modified_column(); END IF; -- Trigger für sectors IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_sectors_modtime') THEN CREATE TRIGGER update_sectors_modtime BEFORE UPDATE ON sectors FOR EACH ROW EXECUTE FUNCTION update_modified_column(); END IF; -- Trigger für lobby_accounts_sectors (WICHTIG für unsere "Zuletzt gespielt" Funktion) IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_lobby_accounts_sectors_modtime') THEN CREATE TRIGGER update_lobby_accounts_sectors_modtime BEFORE UPDATE ON lobby_accounts_sectors FOR EACH ROW EXECUTE FUNCTION update_modified_column(); END IF; END $$; `; // ============================================================================== // Ausführungs-Logik // ============================================================================== async function initDatabase() { console.log('⏳ Starte Datenbank-Initialisierung...'); // Wir holen uns eine Verbindung aus dem Pool const client = await pool.connect(); try { // Wir senden den kompletten SQL-String an die Datenbank await client.query(createTablesQuery); console.log('✅ Tabellen wurden erfolgreich erstellt (oder existierten bereits).'); const sectorCheck = await client.query('SELECT count(*) FROM sectors'); if (parseInt(sectorCheck.rows[0].count) === 0) { console.log('🌱 Füge 24 Test-Sektoren ein...'); const greekAlphabet = [ 'Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon', 'Zeta', 'Eta', 'Theta', 'Iota', 'Kappa', 'Lambda', 'Mu', 'Nu', 'Xi', 'Omicron', 'Pi', 'Rho', 'Sigma', 'Tau', 'Upsilon', 'Phi', 'Chi', 'Psi', 'Omega' ]; // Wir generieren für jeden Namen ein dynamisches INSERT const insertPromises = greekAlphabet.map((name, index) => { // Wir variieren die Geschwindigkeiten leicht für optische Vielfalt const speed = (index % 4) + 1; return client.query(` INSERT INTO sectors (name, status, speed_fleet, speed_economy) VALUES ($1, 'online', $2, $2) `, [name, speed]); }); await Promise.all(insertPromises); console.log('✅ 24 Test-Sektoren erfolgreich eingefügt.'); } } catch (error) { console.error('❌ Fehler beim Erstellen der Tabellen:', error); } finally { // Ganz wichtig: Verbindung wieder freigeben client.release(); // Den Node-Prozess beenden, damit das Skript nicht in der Konsole hängen bleibt process.exit(); } } // Skript direkt aufrufen initDatabase();