CREATE TABLE IF NOT EXISTS users ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, full_name VARCHAR(160) NOT NULL, email VARCHAR(190) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, platform_role ENUM('platform_admin', 'user') NOT NULL DEFAULT 'user', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS tenants ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, name VARCHAR(190) NOT NULL, slug VARCHAR(120) NOT NULL UNIQUE, plan ENUM('starter', 'team', 'business') NOT NULL DEFAULT 'starter', status ENUM('trial', 'active', 'suspended') NOT NULL DEFAULT 'trial', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS tenant_domains ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, tenant_id BIGINT UNSIGNED NOT NULL, host VARCHAR(190) NOT NULL UNIQUE, is_primary TINYINT(1) NOT NULL DEFAULT 0, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_tenant_domains_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS tenant_memberships ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, tenant_id BIGINT UNSIGNED NOT NULL, user_id BIGINT UNSIGNED NOT NULL, role ENUM('owner', 'admin', 'member', 'device') NOT NULL DEFAULT 'member', status ENUM('active', 'invited', 'disabled') NOT NULL DEFAULT 'active', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uniq_tenant_user (tenant_id, user_id), CONSTRAINT fk_memberships_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE, CONSTRAINT fk_memberships_user FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS tenant_settings ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, tenant_id BIGINT UNSIGNED NOT NULL, currency_code CHAR(3) NOT NULL DEFAULT 'EUR', default_product_price_cents INT NOT NULL DEFAULT 120, allow_self_service TINYINT(1) NOT NULL DEFAULT 1, allow_paper_lists TINYINT(1) NOT NULL DEFAULT 1, allow_rfid TINYINT(1) NOT NULL DEFAULT 0, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uniq_tenant_settings (tenant_id), CONSTRAINT fk_tenant_settings_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS members ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, tenant_id BIGINT UNSIGNED NOT NULL, user_id BIGINT UNSIGNED NULL, display_name VARCHAR(160) NOT NULL, email VARCHAR(190) NULL, access_pin VARCHAR(20) NULL, status ENUM('active', 'archived') NOT NULL DEFAULT 'active', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uniq_member_email (tenant_id, email), CONSTRAINT fk_members_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE, CONSTRAINT fk_members_user FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS products ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, tenant_id BIGINT UNSIGNED NOT NULL, name VARCHAR(120) NOT NULL, sku VARCHAR(60) NULL, is_active TINYINT(1) NOT NULL DEFAULT 1, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_products_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS product_prices ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, tenant_id BIGINT UNSIGNED NOT NULL, product_id BIGINT UNSIGNED NOT NULL, price_cents INT NOT NULL, valid_from DATETIME NOT NULL, valid_until DATETIME NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_product_prices_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE, CONSTRAINT fk_product_prices_product FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS capture_sources ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, tenant_id BIGINT UNSIGNED NOT NULL, code VARCHAR(60) NOT NULL, name VARCHAR(120) NOT NULL, channel ENUM('paper', 'digital', 'admin', 'rfid') NOT NULL, is_system TINYINT(1) NOT NULL DEFAULT 0, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uniq_capture_source_code (tenant_id, code), CONSTRAINT fk_capture_sources_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS paper_sheets ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, tenant_id BIGINT UNSIGNED NOT NULL, title VARCHAR(190) NOT NULL, period_label VARCHAR(120) NULL, period_start DATE NULL, period_end DATE NULL, status ENUM('draft', 'posted') NOT NULL DEFAULT 'draft', notes TEXT NULL, created_by_user_id BIGINT UNSIGNED NULL, posted_at DATETIME NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_paper_sheets_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE, CONSTRAINT fk_paper_sheets_user FOREIGN KEY (created_by_user_id) REFERENCES users (id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS paper_sheet_lines ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, paper_sheet_id BIGINT UNSIGNED NOT NULL, tenant_id BIGINT UNSIGNED NOT NULL, member_id BIGINT UNSIGNED NOT NULL, product_id BIGINT UNSIGNED NOT NULL, quantity DECIMAL(8,2) NOT NULL DEFAULT 1.00, effective_at DATETIME NULL, note VARCHAR(255) NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_paper_sheet_lines_sheet FOREIGN KEY (paper_sheet_id) REFERENCES paper_sheets (id) ON DELETE CASCADE, CONSTRAINT fk_paper_sheet_lines_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE, CONSTRAINT fk_paper_sheet_lines_member FOREIGN KEY (member_id) REFERENCES members (id) ON DELETE CASCADE, CONSTRAINT fk_paper_sheet_lines_product FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS consumption_events ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, tenant_id BIGINT UNSIGNED NOT NULL, member_id BIGINT UNSIGNED NOT NULL, product_id BIGINT UNSIGNED NOT NULL, source_id BIGINT UNSIGNED NOT NULL, paper_sheet_line_id BIGINT UNSIGNED NULL, quantity DECIMAL(8,2) NOT NULL DEFAULT 1.00, unit_price_cents INT NOT NULL, total_cents INT NOT NULL, effective_at DATETIME NOT NULL, recorded_at DATETIME NOT NULL, recorded_by_user_id BIGINT UNSIGNED NULL, source_reference VARCHAR(120) NULL, notes TEXT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_consumption_events_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE, CONSTRAINT fk_consumption_events_member FOREIGN KEY (member_id) REFERENCES members (id) ON DELETE CASCADE, CONSTRAINT fk_consumption_events_product FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE CASCADE, CONSTRAINT fk_consumption_events_source FOREIGN KEY (source_id) REFERENCES capture_sources (id) ON DELETE CASCADE, CONSTRAINT fk_consumption_events_sheet_line FOREIGN KEY (paper_sheet_line_id) REFERENCES paper_sheet_lines (id) ON DELETE SET NULL, CONSTRAINT fk_consumption_events_recorded_by FOREIGN KEY (recorded_by_user_id) REFERENCES users (id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS ledger_entries ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, tenant_id BIGINT UNSIGNED NOT NULL, member_id BIGINT UNSIGNED NULL, source_id BIGINT UNSIGNED NULL, type ENUM('consumption', 'payment', 'correction', 'credit', 'opening_balance') NOT NULL, reference_type VARCHAR(60) NULL, reference_id BIGINT UNSIGNED NULL, description VARCHAR(255) NOT NULL, occurred_at DATETIME NOT NULL, created_by_user_id BIGINT UNSIGNED NULL, reversal_of_entry_id BIGINT UNSIGNED NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_ledger_entries_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE, CONSTRAINT fk_ledger_entries_member FOREIGN KEY (member_id) REFERENCES members (id) ON DELETE SET NULL, CONSTRAINT fk_ledger_entries_source FOREIGN KEY (source_id) REFERENCES capture_sources (id) ON DELETE SET NULL, CONSTRAINT fk_ledger_entries_user FOREIGN KEY (created_by_user_id) REFERENCES users (id) ON DELETE SET NULL, CONSTRAINT fk_ledger_entries_reversal FOREIGN KEY (reversal_of_entry_id) REFERENCES ledger_entries (id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS ledger_lines ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, ledger_entry_id BIGINT UNSIGNED NOT NULL, tenant_id BIGINT UNSIGNED NOT NULL, member_id BIGINT UNSIGNED NULL, account_code ENUM('member_balance', 'cashbox', 'coffee_revenue') NOT NULL, amount_cents INT NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_ledger_lines_entry FOREIGN KEY (ledger_entry_id) REFERENCES ledger_entries (id) ON DELETE CASCADE, CONSTRAINT fk_ledger_lines_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE, CONSTRAINT fk_ledger_lines_member FOREIGN KEY (member_id) REFERENCES members (id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS rfid_devices ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, tenant_id BIGINT UNSIGNED NOT NULL, name VARCHAR(120) NOT NULL, location_label VARCHAR(160) NULL, device_token VARCHAR(80) NOT NULL UNIQUE, status ENUM('planned', 'active', 'disabled') NOT NULL DEFAULT 'planned', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_rfid_devices_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS rfid_tags ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, tenant_id BIGINT UNSIGNED NOT NULL, member_id BIGINT UNSIGNED NULL, uid_hash CHAR(64) NOT NULL, label VARCHAR(120) NULL, status ENUM('active', 'lost', 'retired') NOT NULL DEFAULT 'active', last_seen_at DATETIME NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uniq_rfid_tag (tenant_id, uid_hash), CONSTRAINT fk_rfid_tags_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE, CONSTRAINT fk_rfid_tags_member FOREIGN KEY (member_id) REFERENCES members (id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS rfid_events ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, tenant_id BIGINT UNSIGNED NOT NULL, device_id BIGINT UNSIGNED NULL, external_event_id VARCHAR(120) NULL, uid_hash CHAR(64) NOT NULL, payload_json JSON NULL, status ENUM('received', 'linked', 'ignored', 'error') NOT NULL DEFAULT 'received', received_at DATETIME NOT NULL, processed_at DATETIME NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uniq_rfid_external_event (tenant_id, external_event_id), CONSTRAINT fk_rfid_events_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE, CONSTRAINT fk_rfid_events_device FOREIGN KEY (device_id) REFERENCES rfid_devices (id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS audit_events ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, tenant_id BIGINT UNSIGNED NULL, actor_user_id BIGINT UNSIGNED NULL, action VARCHAR(120) NOT NULL, target_type VARCHAR(80) NOT NULL, target_id BIGINT UNSIGNED NULL, result ENUM('success', 'failure') NOT NULL, request_id CHAR(36) NOT NULL, ip_hash CHAR(64) NULL, user_agent_hash CHAR(64) NULL, meta_json JSON NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, INDEX idx_audit_tenant_created (tenant_id, created_at), CONSTRAINT fk_audit_events_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE SET NULL, CONSTRAINT fk_audit_events_user FOREIGN KEY (actor_user_id) REFERENCES users (id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;