-- PnPaaS database schema -- Safe to run repeatedly after the database has been created. CREATE TABLE IF NOT EXISTS users ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, username VARCHAR(80) NOT NULL, email VARCHAR(254) NOT NULL, first_name VARCHAR(100) NOT NULL, last_name VARCHAR(100) NOT NULL, street_address VARCHAR(180) NOT NULL, postal_code VARCHAR(20) NOT NULL, city VARCHAR(100) NOT NULL, country_code CHAR(2) NOT NULL DEFAULT 'AT', password_hash VARCHAR(255) NOT NULL, role ENUM('admin', 'user') NOT NULL DEFAULT 'user', status ENUM('pending', 'active', 'suspended') NOT NULL DEFAULT 'pending', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uq_users_username (username), UNIQUE KEY uq_users_email (email) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS account_activation_tokens ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, user_id BIGINT UNSIGNED NOT NULL, token_hash CHAR(64) NOT NULL, expires_at DATETIME NOT NULL, used_at DATETIME NULL, requested_ip VARCHAR(45) NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uq_account_activation_token_hash (token_hash), KEY idx_account_activation_user (user_id), KEY idx_account_activation_expiry (expires_at), CONSTRAINT fk_account_activation_user FOREIGN KEY (user_id) REFERENCES users (id) ON UPDATE CASCADE ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS user_consents ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, user_id BIGINT UNSIGNED NOT NULL, consent_type ENUM('terms', 'privacy', 'withdrawal') NOT NULL, document_url VARCHAR(2048) NOT NULL, document_version VARCHAR(100) NULL, consented_at DATETIME NOT NULL, consent_ip VARCHAR(45) NULL, PRIMARY KEY (id), UNIQUE KEY uq_user_consent_type (user_id, consent_type), KEY idx_user_consents_user (user_id), CONSTRAINT fk_user_consents_user FOREIGN KEY (user_id) REFERENCES users (id) ON UPDATE CASCADE ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS password_reset_tokens ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, user_id BIGINT UNSIGNED NOT NULL, token_hash CHAR(64) NOT NULL, expires_at DATETIME NOT NULL, used_at DATETIME NULL, requested_ip VARCHAR(45) NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uq_password_reset_token_hash (token_hash), KEY idx_password_reset_user (user_id), KEY idx_password_reset_expiry (expires_at), CONSTRAINT fk_password_reset_user FOREIGN KEY (user_id) REFERENCES users (id) ON UPDATE CASCADE ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS instances ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, owner_user_id BIGINT UNSIGNED NOT NULL, name VARCHAR(120) NOT NULL, plan ENUM('s', 'm', 'l') NOT NULL DEFAULT 's', billing_period ENUM('monthly', 'yearly') NOT NULL DEFAULT 'monthly', price_gross_cents INT UNSIGNED NOT NULL DEFAULT 0, payment_status ENUM('pending', 'paid', 'rejected') NOT NULL DEFAULT 'pending', payment_method ENUM('paypal', 'bank_transfer', 'manual') NULL, requested_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, paid_at TIMESTAMP NULL, container_name VARCHAR(128) NOT NULL, port SMALLINT UNSIGNED NOT NULL, volume_size_mb INT UNSIGNED NOT NULL DEFAULT 1024, memory_limit_mb INT UNSIGNED NOT NULL DEFAULT 512, cpu_limit DECIMAL(4,2) NOT NULL DEFAULT 1.00, portainer_stack_id BIGINT UNSIGNED NULL, portainer_container_id VARCHAR(128) NULL, status ENUM('pending_payment', 'planned', 'provisioning', 'running', 'stopped', 'error', 'deleted') NOT NULL DEFAULT 'pending_payment', error_message VARCHAR(500) NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uq_instances_container_name (container_name), UNIQUE KEY uq_instances_port (port), CONSTRAINT fk_instances_owner FOREIGN KEY (owner_user_id) REFERENCES users (id) ON UPDATE CASCADE ON DELETE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS portainer_tokens ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, label VARCHAR(120) NOT NULL, token_ciphertext TEXT NOT NULL, token_nonce VARBINARY(24) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uq_portainer_tokens_label (label) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS audit_log ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, user_id BIGINT UNSIGNED NULL, action VARCHAR(120) NOT NULL, instance_id BIGINT UNSIGNED NULL, details JSON NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_audit_user (user_id), KEY idx_audit_instance (instance_id), CONSTRAINT fk_audit_user FOREIGN KEY (user_id) REFERENCES users (id) ON UPDATE CASCADE ON DELETE SET NULL, CONSTRAINT fk_audit_instance FOREIGN KEY (instance_id) REFERENCES instances (id) ON UPDATE CASCADE ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;