-- Papa-Kind-Treff – Basis-Schema (MySQL 8) -- Hinweise: -- - Passwörter mit Argon2id hashen. -- - Sensible Felder werden app-seitig mit libsodium (XChaCha20-Poly1305) verschlüsselt -- und als base64 in VARBINARY-Spalten abgelegt (nonce + cipher). -- - share_level steuert Papa-Infos (basic, papa, papa_contact). -- - children_visibility steuert Kinder-Infos separat (hidden, age_only, details). CREATE TABLE users ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, email VARCHAR(255) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, status ENUM('active','pending','blocked') DEFAULT 'pending', email_verified_at DATETIME NULL, last_login_at DATETIME NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE user_profiles ( user_id BIGINT UNSIGNED PRIMARY KEY, display_name VARCHAR(120) NOT NULL, first_name VARCHAR(120) NULL, last_name VARCHAR(120) NULL, share_level ENUM('basic','papa','papa_contact') NOT NULL DEFAULT 'basic', children_visibility ENUM('hidden','age_only','details') NOT NULL DEFAULT 'hidden', zip CHAR(5) NULL, city VARCHAR(120) NULL, region VARCHAR(120) NULL, lat DECIMAL(10,7) NULL, lng DECIMAL(10,7) NULL, contact_phone VARBINARY(512) NULL, contact_email VARBINARY(512) NULL, profession VARBINARY(512) NULL, languages VARBINARY(1024) NULL, -- JSON verschlüsselt about VARBINARY(2048) NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_profile_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, INDEX idx_profile_city (city), INDEX idx_profile_region (region), INDEX idx_profile_latlng (lat,lng) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE children ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, user_id BIGINT UNSIGNED NOT NULL, gender ENUM('male','female','diverse','unknown') NOT NULL DEFAULT 'unknown', birthdate DATE NULL, age_years TINYINT UNSIGNED NULL, encrypted_first_name VARBINARY(512) NOT NULL, note VARBINARY(1024) NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_child_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, INDEX idx_child_user (user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE events ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, created_by BIGINT UNSIGNED NOT NULL, title VARCHAR(200) NOT NULL, teaser_public VARCHAR(280) NOT NULL, description TEXT NOT NULL, location_label VARCHAR(180) NULL, street VARCHAR(180) NULL, zip CHAR(5) NULL, city VARCHAR(120) NULL, region VARCHAR(120) NULL, lat DECIMAL(10,7) NULL, lng DECIMAL(10,7) NULL, starts_at DATETIME NOT NULL, ends_at DATETIME NULL, max_participants SMALLINT UNSIGNED NULL, allow_kids TINYINT(1) NOT NULL DEFAULT 1, min_child_age TINYINT UNSIGNED NULL, max_child_age TINYINT UNSIGNED NULL, visibility ENUM('public','members') NOT NULL DEFAULT 'public', status ENUM('draft','published','cancelled') NOT NULL DEFAULT 'published', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_event_user FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE CASCADE, INDEX idx_event_city (city), INDEX idx_event_region (region), INDEX idx_event_time (starts_at), INDEX idx_event_latlng (lat,lng) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE event_participants ( event_id BIGINT UNSIGNED NOT NULL, user_id BIGINT UNSIGNED NOT NULL, status ENUM('going','interested','waitlist','cancelled') NOT NULL DEFAULT 'going', child_count TINYINT UNSIGNED NULL, note VARBINARY(1024) NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (event_id, user_id), CONSTRAINT fk_ep_event FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE, CONSTRAINT fk_ep_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Community / Forum CREATE TABLE forum_threads ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, user_id BIGINT UNSIGNED NOT NULL, title VARCHAR(200) NOT NULL, body TEXT NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_ft_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, INDEX idx_ft_created (created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE forum_posts ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, thread_id BIGINT UNSIGNED NOT NULL, user_id BIGINT UNSIGNED NOT NULL, body TEXT NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_fp_thread FOREIGN KEY (thread_id) REFERENCES forum_threads(id) ON DELETE CASCADE, CONSTRAINT fk_fp_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, INDEX idx_fp_thread (thread_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Session-Handling (neutral, keine sensiblen Inhalte) CREATE TABLE sessions ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, user_id BIGINT UNSIGNED NOT NULL, token_hash CHAR(64) NOT NULL UNIQUE, -- SHA-256 Hash des Session-Tokens ip VARCHAR(45) NULL, user_agent VARCHAR(255) NULL, expires_at DATETIME NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_session_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, INDEX idx_session_expires (expires_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Kurzlebige Tokens (Passwort-Reset, Magic-Login, E-Mail-Verify) CREATE TABLE user_tokens ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, user_id BIGINT UNSIGNED NOT NULL, type ENUM('reset','verify','magic_login') NOT NULL, code CHAR(12) NULL, -- z. B. 6-stelliger Code (optional Klartext) token_hash CHAR(64) NOT NULL UNIQUE, expires_at DATETIME NOT NULL, used_at DATETIME NULL, ip VARCHAR(45) NULL, user_agent VARCHAR(255) NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_ut_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, INDEX idx_ut_expires (expires_at), INDEX idx_ut_type (type) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Audit-Log für wichtige Aktionen CREATE TABLE audit_log ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, user_id BIGINT UNSIGNED NULL, -- NULL bei Gast-Ereignissen action VARCHAR(100) NOT NULL, -- z.B. login, profile.update, event.create target_type VARCHAR(50) NULL, -- z.B. user, event, child target_id BIGINT UNSIGNED NULL, metadata JSON NULL, -- nicht sensible Zusatzinfos ip VARCHAR(45) NULL, user_agent VARCHAR(255) NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, INDEX idx_audit_user (user_id), INDEX idx_audit_action (action), INDEX idx_audit_target (target_type, target_id), INDEX idx_audit_created (created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;