CREATE TABLE IF NOT EXISTS h5_users ( id CHAR(36) PRIMARY KEY, username VARCHAR(64) NOT NULL UNIQUE, slug VARCHAR(64) NULL, email VARCHAR(255) NULL, display_name VARCHAR(128) NOT NULL, salt VARCHAR(64) NOT NULL, password_hash VARCHAR(128) NOT NULL, password_algorithm VARCHAR(32) NOT NULL DEFAULT 'pbkdf2-sha512', role ENUM('user', 'admin') NOT NULL DEFAULT 'user', status ENUM('active', 'suspended', 'disabled') NOT NULL DEFAULT 'active', plan_type VARCHAR(32) NOT NULL DEFAULT 'free', workspace_root VARCHAR(512) NOT NULL, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, UNIQUE KEY uq_h5_users_slug (slug), UNIQUE KEY uq_h5_users_email (email) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_user_spaces ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, space_name VARCHAR(128) NOT NULL DEFAULT '我的空间', quota_bytes BIGINT NOT NULL DEFAULT 5242880, used_bytes BIGINT NOT NULL DEFAULT 0, reserved_bytes BIGINT NOT NULL DEFAULT 0, status ENUM('active', 'locked', 'deleted') NOT NULL DEFAULT 'active', created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, UNIQUE KEY uq_h5_user_space_user (user_id), CONSTRAINT fk_h5_space_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE, CONSTRAINT chk_h5_space_quota CHECK ( quota_bytes >= 0 AND used_bytes >= 0 AND reserved_bytes >= 0 ) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS mindspace_config ( `key` VARCHAR(64) PRIMARY KEY, value TEXT NOT NULL, description VARCHAR(255) NULL, updated_at BIGINT NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_space_categories ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, space_id CHAR(36) NOT NULL, category_code VARCHAR(32) NOT NULL, category_name VARCHAR(128) NOT NULL, visibility_policy VARCHAR(64) NOT NULL, ai_access_policy VARCHAR(64) NOT NULL, publish_policy VARCHAR(64) NOT NULL, is_system TINYINT(1) NOT NULL DEFAULT 0, sort_order INT NOT NULL DEFAULT 0, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, UNIQUE KEY uq_h5_space_category_code (space_id, category_code), KEY idx_h5_space_category_user (user_id, sort_order), CONSTRAINT fk_h5_category_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE, CONSTRAINT fk_h5_category_space FOREIGN KEY (space_id) REFERENCES h5_user_spaces(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_assets ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, space_id CHAR(36) NOT NULL, category_id CHAR(36) NOT NULL, parent_id CHAR(36) NULL, asset_type VARCHAR(32) NOT NULL, mime_type VARCHAR(128) NOT NULL, original_filename VARCHAR(255) NOT NULL, display_name VARCHAR(255) NOT NULL, current_version_id CHAR(36) NULL, size_bytes BIGINT NOT NULL DEFAULT 0, checksum CHAR(64) NOT NULL, risk_level ENUM('none', 'low', 'medium', 'high', 'critical') NOT NULL DEFAULT 'none', visibility ENUM('private', 'internal', 'public_candidate') NOT NULL DEFAULT 'private', status ENUM('uploaded', 'processing', 'ready', 'quarantined', 'archived', 'deleted') NOT NULL DEFAULT 'ready', source_type ENUM('upload', 'chat', 'agent', 'template', 'generated', 'workspace') NOT NULL DEFAULT 'upload', created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, deleted_at BIGINT NULL, KEY idx_h5_assets_category (user_id, category_id, updated_at), KEY idx_h5_assets_parent (user_id, parent_id), KEY idx_h5_assets_checksum (user_id, checksum), CONSTRAINT fk_h5_asset_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE, CONSTRAINT fk_h5_asset_space FOREIGN KEY (space_id) REFERENCES h5_user_spaces(id) ON DELETE CASCADE, CONSTRAINT fk_h5_asset_category FOREIGN KEY (category_id) REFERENCES h5_space_categories(id) ON DELETE CASCADE, CONSTRAINT fk_h5_asset_parent FOREIGN KEY (parent_id) REFERENCES h5_assets(id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_asset_versions ( id CHAR(36) PRIMARY KEY, asset_id CHAR(36) NOT NULL, version_no INT NOT NULL, storage_key VARCHAR(512) NOT NULL, size_bytes BIGINT NOT NULL, checksum CHAR(64) NOT NULL, mime_type VARCHAR(128) NOT NULL, created_by CHAR(36) NOT NULL, change_note VARCHAR(512) NULL, scan_status ENUM('pending', 'passed', 'warned', 'blocked') NOT NULL DEFAULT 'pending', created_at BIGINT NOT NULL, UNIQUE KEY uq_h5_asset_version (asset_id, version_no), UNIQUE KEY uq_h5_asset_storage_key (storage_key), CONSTRAINT fk_h5_asset_version_asset FOREIGN KEY (asset_id) REFERENCES h5_assets(id) ON DELETE CASCADE, CONSTRAINT fk_h5_asset_version_user FOREIGN KEY (created_by) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_upload_sessions ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, space_id CHAR(36) NOT NULL, category_id CHAR(36) NOT NULL, filename VARCHAR(255) NOT NULL, expected_size BIGINT NOT NULL, actual_size BIGINT NULL, declared_mime_type VARCHAR(128) NULL, detected_mime_type VARCHAR(128) NULL, reserved_bytes BIGINT NOT NULL, temporary_storage_key VARCHAR(512) NOT NULL, checksum CHAR(64) NULL, completed_asset_id CHAR(36) NULL, status ENUM('reserved', 'uploaded', 'completed', 'cancelled', 'expired', 'failed') NOT NULL DEFAULT 'reserved', expires_at BIGINT NOT NULL, created_at BIGINT NOT NULL, completed_at BIGINT NULL, KEY idx_h5_upload_user_status (user_id, status, expires_at), CONSTRAINT fk_h5_upload_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE, CONSTRAINT fk_h5_upload_space FOREIGN KEY (space_id) REFERENCES h5_user_spaces(id) ON DELETE CASCADE, CONSTRAINT fk_h5_upload_category FOREIGN KEY (category_id) REFERENCES h5_space_categories(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_page_records ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, space_id CHAR(36) NOT NULL, category_id CHAR(36) NOT NULL, source_session_id VARCHAR(128) NULL, source_message_id VARCHAR(128) NULL, source_asset_id CHAR(36) NULL, title VARCHAR(255) NOT NULL, summary VARCHAR(1000) NULL, cover_image_asset_id CHAR(36) NULL, page_type VARCHAR(32) NOT NULL DEFAULT 'article', template_id VARCHAR(64) NOT NULL DEFAULT 'editorial', draft_content_ref VARCHAR(512) NULL, current_version_id CHAR(36) NULL, current_publish_id CHAR(36) NULL, status ENUM('draft', 'reviewing', 'risk_found', 'ready', 'published', 'protected', 'expired', 'offline', 'deleted') NOT NULL DEFAULT 'draft', visibility ENUM('private', 'internal', 'public') NOT NULL DEFAULT 'private', created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, deleted_at BIGINT NULL, KEY idx_h5_pages_user_status (user_id, status, updated_at), KEY idx_h5_pages_category (user_id, category_id, updated_at), KEY idx_h5_pages_source_session (user_id, source_session_id), CONSTRAINT fk_h5_page_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE, CONSTRAINT fk_h5_page_space FOREIGN KEY (space_id) REFERENCES h5_user_spaces(id) ON DELETE CASCADE, CONSTRAINT fk_h5_page_category FOREIGN KEY (category_id) REFERENCES h5_space_categories(id) ON DELETE CASCADE, CONSTRAINT fk_h5_page_source_asset FOREIGN KEY (source_asset_id) REFERENCES h5_assets(id) ON DELETE SET NULL, CONSTRAINT fk_h5_page_cover_asset FOREIGN KEY (cover_image_asset_id) REFERENCES h5_assets(id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_page_versions ( id CHAR(36) PRIMARY KEY, page_id CHAR(36) NOT NULL, version_no INT NOT NULL, content_asset_id CHAR(36) NOT NULL, bundle_asset_id CHAR(36) NULL, source_snapshot_json JSON NULL, security_scan_id CHAR(36) NULL, created_by CHAR(36) NOT NULL, change_note VARCHAR(512) NULL, immutable TINYINT(1) NOT NULL DEFAULT 0, created_at BIGINT NOT NULL, UNIQUE KEY uq_h5_page_version (page_id, version_no), CONSTRAINT fk_h5_page_version_page FOREIGN KEY (page_id) REFERENCES h5_page_records(id) ON DELETE CASCADE, CONSTRAINT fk_h5_page_version_content FOREIGN KEY (content_asset_id) REFERENCES h5_assets(id) ON DELETE CASCADE, CONSTRAINT fk_h5_page_version_bundle FOREIGN KEY (bundle_asset_id) REFERENCES h5_assets(id) ON DELETE SET NULL, CONSTRAINT fk_h5_page_version_user FOREIGN KEY (created_by) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_security_scans ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, target_type ENUM('asset', 'page_version', 'publication_bundle') NOT NULL, target_id CHAR(36) NOT NULL, scanner_version VARCHAR(64) NOT NULL, status ENUM('queued', 'running', 'passed', 'warned', 'blocked', 'failed') NOT NULL, risk_level ENUM('none', 'low', 'medium', 'high', 'critical') NOT NULL DEFAULT 'none', findings_count INT NOT NULL DEFAULT 0, summary_json JSON NULL, started_at BIGINT NOT NULL, completed_at BIGINT NULL, KEY idx_h5_security_scan_target (user_id, target_type, target_id, completed_at), CONSTRAINT fk_h5_security_scan_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_security_findings ( id CHAR(36) PRIMARY KEY, scan_id CHAR(36) NOT NULL, finding_type VARCHAR(64) NOT NULL, risk_level ENUM('low', 'medium', 'high', 'critical') NOT NULL, occurrence_count INT NOT NULL DEFAULT 1, sample_masked VARCHAR(255) NULL, blocking TINYINT(1) NOT NULL DEFAULT 0, created_at BIGINT NOT NULL, KEY idx_h5_security_finding_scan (scan_id, risk_level), CONSTRAINT fk_h5_security_finding_scan FOREIGN KEY (scan_id) REFERENCES h5_security_scans(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_publish_records ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, page_id CHAR(36) NOT NULL, page_version_id CHAR(36) NOT NULL, publish_type ENUM('page', 'share') NOT NULL DEFAULT 'page', url_slug VARCHAR(64) NOT NULL, public_url VARCHAR(512) NOT NULL, access_mode ENUM('public', 'password', 'private_link', 'time_limited', 'login_required', 'owner_only') NOT NULL, password_hash VARCHAR(255) NULL, token_hash CHAR(64) NULL, token_prefix VARCHAR(16) NULL, expires_at BIGINT NULL, user_confirmed_at BIGINT NULL, published_at BIGINT NOT NULL, offline_at BIGINT NULL, status ENUM('draft', 'online', 'expired', 'offline', 'blocked') NOT NULL DEFAULT 'online', view_count BIGINT NOT NULL DEFAULT 0, security_scan_id CHAR(36) NOT NULL, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, KEY idx_h5_publish_route (url_slug, status, published_at), KEY idx_h5_publish_page (user_id, page_id, published_at), KEY idx_h5_publish_auto_private (expires_at, user_confirmed_at), UNIQUE KEY uq_h5_publish_token_hash (token_hash), CONSTRAINT fk_h5_publish_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE, CONSTRAINT fk_h5_publish_page FOREIGN KEY (page_id) REFERENCES h5_page_records(id) ON DELETE CASCADE, CONSTRAINT fk_h5_publish_page_version FOREIGN KEY (page_version_id) REFERENCES h5_page_versions(id) ON DELETE CASCADE, CONSTRAINT fk_h5_publish_scan FOREIGN KEY (security_scan_id) REFERENCES h5_security_scans(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_publication_asset_refs ( publication_id CHAR(36) NOT NULL, asset_id CHAR(36) NOT NULL, created_at BIGINT NOT NULL, PRIMARY KEY (publication_id, asset_id), KEY idx_asset_id (asset_id), KEY idx_created_at (created_at), CONSTRAINT fk_h5_pub_asset_ref_pub FOREIGN KEY (publication_id) REFERENCES h5_publish_records(id) ON DELETE CASCADE, CONSTRAINT fk_h5_pub_asset_ref_asset FOREIGN KEY (asset_id) REFERENCES h5_assets(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_publication_events ( id CHAR(36) PRIMARY KEY, publish_id CHAR(36) NOT NULL, event_type ENUM('published', 'republished', 'settings_changed', 'expired', 'offlined', 'blocked') NOT NULL, actor_id CHAR(36) NOT NULL, old_page_version_id CHAR(36) NULL, new_page_version_id CHAR(36) NULL, access_mode VARCHAR(32) NOT NULL, detail_json JSON NULL, created_at BIGINT NOT NULL, KEY idx_h5_publication_event (publish_id, created_at), CONSTRAINT fk_h5_publication_event_publish FOREIGN KEY (publish_id) REFERENCES h5_publish_records(id) ON DELETE CASCADE, CONSTRAINT fk_h5_publication_event_actor FOREIGN KEY (actor_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_publication_views ( id CHAR(36) PRIMARY KEY, publish_id CHAR(36) NOT NULL, viewer_user_id CHAR(36) NULL, referrer_host VARCHAR(255) NULL, device_type ENUM('desktop', 'mobile', 'tablet', 'bot', 'unknown') NOT NULL, viewed_at BIGINT NOT NULL, KEY idx_h5_publication_view_time (publish_id, viewed_at), KEY idx_h5_publication_viewer (viewer_user_id, viewed_at), CONSTRAINT fk_h5_publication_view_publish FOREIGN KEY (publish_id) REFERENCES h5_publish_records(id) ON DELETE CASCADE, CONSTRAINT fk_h5_publication_view_user FOREIGN KEY (viewer_user_id) REFERENCES h5_users(id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_agent_jobs ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, session_id VARCHAR(128) NULL, job_type VARCHAR(64) NOT NULL, instruction TEXT NOT NULL, permission_scope JSON NULL, user_context_json JSON NULL, output_category_id CHAR(36) NOT NULL, output_type VARCHAR(32) NOT NULL, max_output_bytes BIGINT NOT NULL DEFAULT 2097152, status ENUM('queued', 'running', 'completed', 'failed', 'cancelled', 'timed_out') NOT NULL DEFAULT 'queued', idempotency_key VARCHAR(128) NULL, progress_json JSON NULL, job_token_hash CHAR(64) NULL, result_page_id CHAR(36) NULL, result_asset_id CHAR(36) NULL, error_code VARCHAR(64) NULL, error_message VARCHAR(1000) NULL, queued_at BIGINT NOT NULL, started_at BIGINT NULL, heartbeat_at BIGINT NULL, completed_at BIGINT NULL, expires_at BIGINT NULL, updated_at BIGINT NOT NULL, UNIQUE KEY uq_h5_agent_job_idempotency (user_id, idempotency_key), KEY idx_h5_agent_job_user_status (user_id, status, queued_at), KEY idx_h5_agent_job_token (job_token_hash), CONSTRAINT fk_h5_agent_job_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE, CONSTRAINT fk_h5_agent_job_output_category FOREIGN KEY (output_category_id) REFERENCES h5_space_categories(id) ON DELETE CASCADE, CONSTRAINT fk_h5_agent_job_result_page FOREIGN KEY (result_page_id) REFERENCES h5_page_records(id) ON DELETE SET NULL, CONSTRAINT fk_h5_agent_job_result_asset FOREIGN KEY (result_asset_id) REFERENCES h5_assets(id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_agent_job_assets ( id CHAR(36) PRIMARY KEY, job_id CHAR(36) NOT NULL, asset_id CHAR(36) NOT NULL, asset_version_id CHAR(36) NOT NULL, permission ENUM('read', 'write', 'create_derivative') NOT NULL DEFAULT 'read', created_at BIGINT NOT NULL, UNIQUE KEY uq_h5_agent_job_asset (job_id, asset_id, asset_version_id), KEY idx_h5_agent_job_asset_job (job_id, created_at), CONSTRAINT fk_h5_agent_job_asset_job FOREIGN KEY (job_id) REFERENCES h5_agent_jobs(id) ON DELETE CASCADE, CONSTRAINT fk_h5_agent_job_asset_asset FOREIGN KEY (asset_id) REFERENCES h5_assets(id) ON DELETE CASCADE, CONSTRAINT fk_h5_agent_job_asset_version FOREIGN KEY (asset_version_id) REFERENCES h5_asset_versions(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_user_wallets ( user_id CHAR(36) PRIMARY KEY, balance_cents BIGINT NOT NULL DEFAULT 0, tokens_used BIGINT NOT NULL DEFAULT 0, updated_at BIGINT NOT NULL, CONSTRAINT fk_h5_wallet_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_user_path_grants ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id CHAR(36) NOT NULL, path VARCHAR(512) NOT NULL, mode ENUM('read', 'readwrite') NOT NULL DEFAULT 'readwrite', UNIQUE KEY uq_h5_user_path (user_id, path), CONSTRAINT fk_h5_path_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_user_sessions ( agent_session_id VARCHAR(128) NOT NULL PRIMARY KEY, user_id CHAR(36) NOT NULL, created_at BIGINT NOT NULL, KEY idx_h5_user_sessions_user (user_id), CONSTRAINT fk_h5_session_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_session_billing_state ( agent_session_id VARCHAR(128) NOT NULL PRIMARY KEY, user_id CHAR(36) NOT NULL, last_accumulated_cost DOUBLE NULL, last_input_tokens BIGINT NOT NULL DEFAULT 0, last_output_tokens BIGINT NOT NULL DEFAULT 0, updated_at BIGINT NOT NULL, CONSTRAINT fk_h5_billing_state_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_usage_records ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id CHAR(36) NOT NULL, agent_session_id VARCHAR(128) NOT NULL, request_id VARCHAR(128) NULL, input_tokens INT NOT NULL DEFAULT 0, output_tokens INT NOT NULL DEFAULT 0, cost_cents BIGINT NOT NULL, balance_after_cents BIGINT NOT NULL, created_at BIGINT NOT NULL, KEY idx_h5_usage_user_time (user_id, created_at), CONSTRAINT fk_h5_usage_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_user_policies ( id BIGINT AUTO_INCREMENT PRIMARY KEY, subject_type ENUM('role', 'user') NOT NULL, subject_id VARCHAR(64) NOT NULL, policy_key VARCHAR(64) NOT NULL, policy_value VARCHAR(512) NOT NULL, updated_at BIGINT NOT NULL, UNIQUE KEY uq_h5_user_policy (subject_type, subject_id, policy_key), KEY idx_h5_policy_subject (subject_type, subject_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_user_skill_grants ( id BIGINT AUTO_INCREMENT PRIMARY KEY, subject_type ENUM('role', 'user') NOT NULL, subject_id VARCHAR(64) NOT NULL, skill_name VARCHAR(64) NOT NULL, enabled TINYINT(1) NOT NULL DEFAULT 0, updated_at BIGINT NOT NULL, UNIQUE KEY uq_h5_user_skill_grant (subject_type, subject_id, skill_name), KEY idx_h5_skill_subject (subject_type, subject_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_capability_grants ( id BIGINT AUTO_INCREMENT PRIMARY KEY, subject_type ENUM('role', 'user') NOT NULL, subject_id VARCHAR(64) NOT NULL, capability_key VARCHAR(64) NOT NULL, allowed TINYINT(1) NOT NULL DEFAULT 0, updated_at BIGINT NOT NULL, UNIQUE KEY uq_h5_capability_grant (subject_type, subject_id, capability_key), KEY idx_h5_capability_subject (subject_type, subject_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_login_sessions ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, token_hash CHAR(64) NOT NULL, expires_at BIGINT NOT NULL, created_at BIGINT NOT NULL, revoked_at BIGINT NULL, UNIQUE KEY uq_h5_login_token_hash (token_hash), KEY idx_h5_login_session_user (user_id), KEY idx_h5_login_session_expires (expires_at), CONSTRAINT fk_h5_login_session_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_mindspace_audit_logs ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id CHAR(36) NOT NULL, action VARCHAR(64) NOT NULL, object_type VARCHAR(32) NOT NULL, object_id CHAR(36) NOT NULL, ip VARCHAR(64) NULL, result VARCHAR(32) NOT NULL, risk_level VARCHAR(16) NULL, created_at BIGINT NOT NULL, KEY idx_h5_mindspace_audit_user_time (user_id, created_at), CONSTRAINT fk_h5_mindspace_audit_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_billing_ledger ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id CHAR(36) NOT NULL, type ENUM('recharge', 'deduct', 'refund', 'adjust') NOT NULL, amount_cents BIGINT NOT NULL, tokens BIGINT NOT NULL DEFAULT 0, session_id VARCHAR(128) NULL, note VARCHAR(512) NULL, operator_id CHAR(36) NULL, created_at BIGINT NOT NULL, KEY idx_h5_ledger_user (user_id, created_at), CONSTRAINT fk_h5_ledger_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_llm_provider_keys ( id CHAR(36) PRIMARY KEY, provider_id VARCHAR(64) NOT NULL, provider_kind ENUM('builtin', 'custom') NOT NULL DEFAULT 'builtin', api_url VARCHAR(512) NULL, base_path VARCHAR(256) NULL, models_json TEXT NULL, goosed_provider_id VARCHAR(64) NULL, engine VARCHAR(32) NOT NULL DEFAULT 'openai', relay_provider VARCHAR(64) NULL, name VARCHAR(128) NOT NULL, api_key_ciphertext TEXT NOT NULL, api_key_iv VARCHAR(24) NOT NULL, api_key_tag VARCHAR(24) NOT NULL, default_model VARCHAR(128) NOT NULL, status ENUM('active', 'disabled') NOT NULL DEFAULT 'active', is_selected TINYINT(1) NOT NULL DEFAULT 0, is_vision_selected TINYINT(1) NOT NULL DEFAULT 0, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, UNIQUE KEY uq_h5_llm_key_name (name), KEY idx_h5_llm_key_provider (provider_id), KEY idx_h5_llm_key_selected (is_selected), KEY idx_h5_llm_key_vision (is_vision_selected) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_llm_executor_bindings ( id CHAR(36) PRIMARY KEY, executor ENUM('goose', 'aider', 'openhands') NOT NULL, purpose VARCHAR(32) NOT NULL DEFAULT 'default', provider_key_id CHAR(36) NULL, model VARCHAR(128) NOT NULL, enabled TINYINT(1) NOT NULL DEFAULT 1, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, UNIQUE KEY uq_h5_llm_executor_binding (executor, purpose), KEY idx_h5_llm_executor_provider (provider_key_id), CONSTRAINT fk_h5_llm_executor_provider FOREIGN KEY (provider_key_id) REFERENCES h5_llm_provider_keys(id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_payment_orders ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, amount_cents BIGINT NOT NULL, channel ENUM('wechat') NOT NULL DEFAULT 'wechat', status ENUM('pending', 'paid', 'failed', 'expired', 'refunded') NOT NULL DEFAULT 'pending', pay_mode ENUM('native', 'h5', 'jsapi') NOT NULL DEFAULT 'native', out_trade_no VARCHAR(64) NOT NULL, provider_txn VARCHAR(128) NULL, code_url VARCHAR(512) NULL, h5_url VARCHAR(1024) NULL, client_ip VARCHAR(64) NULL, expire_at BIGINT NOT NULL, paid_at BIGINT NULL, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, UNIQUE KEY uq_h5_payment_out_trade_no (out_trade_no), KEY idx_h5_payment_user_time (user_id, created_at), KEY idx_h5_payment_status_expire (status, expire_at), CONSTRAINT fk_h5_payment_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS plaza_categories ( id CHAR(36) PRIMARY KEY, name VARCHAR(50) NOT NULL, slug VARCHAR(50) NOT NULL, icon VARCHAR(10) NOT NULL DEFAULT '', description VARCHAR(200) NOT NULL DEFAULT '', sort_order INT NOT NULL DEFAULT 0, is_active TINYINT(1) NOT NULL DEFAULT 1, created_at BIGINT NOT NULL, UNIQUE KEY uq_plaza_category_slug (slug), KEY idx_plaza_category_sort (is_active, sort_order) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS plaza_posts ( id CHAR(36) PRIMARY KEY, publication_id CHAR(36) NOT NULL, user_id CHAR(36) NOT NULL, title VARCHAR(200) NOT NULL, summary VARCHAR(500) NOT NULL DEFAULT '', cover_url VARCHAR(500) NOT NULL DEFAULT '', user_slug VARCHAR(100) NOT NULL, user_display_name VARCHAR(100) NOT NULL, user_avatar_url VARCHAR(500) NOT NULL DEFAULT '', category_id CHAR(36) NOT NULL, tags JSON NOT NULL, status ENUM('pending_review', 'published', 'hidden', 'rejected') NOT NULL DEFAULT 'pending_review', view_count INT UNSIGNED NOT NULL DEFAULT 0, like_count INT UNSIGNED NOT NULL DEFAULT 0, collect_count INT UNSIGNED NOT NULL DEFAULT 0, comment_count INT UNSIGNED NOT NULL DEFAULT 0, share_count INT UNSIGNED NOT NULL DEFAULT 0, hot_score DOUBLE NOT NULL DEFAULT 0, hot_updated_at BIGINT NULL, allow_comment TINYINT(1) NOT NULL DEFAULT 1, published_at BIGINT NOT NULL, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, UNIQUE KEY uq_plaza_post_publication (publication_id), KEY idx_plaza_post_user_status (user_id, status), KEY idx_plaza_post_category_hot (category_id, status, hot_score), KEY idx_plaza_post_published_at (published_at), KEY idx_plaza_post_status_hot (status, hot_score), CONSTRAINT fk_plaza_post_publication FOREIGN KEY (publication_id) REFERENCES h5_publish_records(id) ON DELETE CASCADE, CONSTRAINT fk_plaza_post_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE, CONSTRAINT fk_plaza_post_category FOREIGN KEY (category_id) REFERENCES plaza_categories(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS plaza_reactions ( id CHAR(36) PRIMARY KEY, post_id CHAR(36) NOT NULL, user_id CHAR(36) NOT NULL, type ENUM('like', 'collect', 'share') NOT NULL, created_at BIGINT NOT NULL, UNIQUE KEY uq_plaza_reaction (post_id, user_id, type), KEY idx_plaza_reaction_post (post_id, type), KEY idx_plaza_reaction_user (user_id, type), CONSTRAINT fk_plaza_reaction_post FOREIGN KEY (post_id) REFERENCES plaza_posts(id) ON DELETE CASCADE, CONSTRAINT fk_plaza_reaction_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS plaza_comments ( id CHAR(36) PRIMARY KEY, post_id CHAR(36) NOT NULL, user_id CHAR(36) NOT NULL, parent_id CHAR(36) NULL, content VARCHAR(500) NOT NULL, status ENUM('visible', 'deleted', 'flagged', 'hidden') NOT NULL DEFAULT 'visible', like_count INT UNSIGNED NOT NULL DEFAULT 0, reply_count INT UNSIGNED NOT NULL DEFAULT 0, deleted_by ENUM('user', 'ops') NULL, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, KEY idx_plaza_comment_post (post_id, status, created_at), KEY idx_plaza_comment_parent (parent_id), KEY idx_plaza_comment_user (user_id, created_at), CONSTRAINT fk_plaza_comment_post FOREIGN KEY (post_id) REFERENCES plaza_posts(id) ON DELETE CASCADE, CONSTRAINT fk_plaza_comment_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS plaza_comment_reactions ( id CHAR(36) PRIMARY KEY, comment_id CHAR(36) NOT NULL, user_id CHAR(36) NOT NULL, created_at BIGINT NOT NULL, UNIQUE KEY uq_plaza_comment_reaction (comment_id, user_id), KEY idx_plaza_comment_reaction_comment (comment_id), CONSTRAINT fk_plaza_comment_reaction_comment FOREIGN KEY (comment_id) REFERENCES plaza_comments(id) ON DELETE CASCADE, CONSTRAINT fk_plaza_comment_reaction_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS plaza_follows ( follower_id CHAR(36) NOT NULL, followee_id CHAR(36) NOT NULL, created_at BIGINT NOT NULL, PRIMARY KEY (follower_id, followee_id), KEY idx_plaza_follow_followee (followee_id, created_at), CONSTRAINT fk_plaza_follow_follower FOREIGN KEY (follower_id) REFERENCES h5_users(id) ON DELETE CASCADE, CONSTRAINT fk_plaza_follow_followee FOREIGN KEY (followee_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS plaza_algorithm_config ( `key` VARCHAR(100) NOT NULL, value DOUBLE NOT NULL, description VARCHAR(200) NOT NULL DEFAULT '', updated_at BIGINT NOT NULL, PRIMARY KEY (`key`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS plaza_attribution_events ( id CHAR(36) PRIMARY KEY, event_type ENUM('landing', 'signup') NOT NULL, utm_source VARCHAR(100) NOT NULL, utm_medium VARCHAR(100) NOT NULL DEFAULT '', utm_campaign VARCHAR(100) NOT NULL DEFAULT '', ref_id VARCHAR(200) NOT NULL DEFAULT '', user_id CHAR(36) NULL, ip_hash VARCHAR(64) NOT NULL DEFAULT '', created_at BIGINT NOT NULL, KEY idx_plaza_attr_created (created_at), KEY idx_plaza_attr_campaign (utm_source, utm_campaign, created_at), CONSTRAINT fk_plaza_attr_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS plaza_reports ( id CHAR(36) PRIMARY KEY, target_type ENUM('post', 'comment') NOT NULL, target_id CHAR(36) NOT NULL, reporter_id CHAR(36) NOT NULL, reason ENUM('spam', 'violence', 'porn', 'political', 'privacy', 'other') NOT NULL, detail VARCHAR(500) NOT NULL DEFAULT '', status ENUM('pending', 'processed', 'dismissed') NOT NULL DEFAULT 'pending', processed_by CHAR(36) NULL, processed_at BIGINT NULL, action_taken VARCHAR(200) NOT NULL DEFAULT '', created_at BIGINT NOT NULL, KEY idx_plaza_report_status (status, target_type, created_at), KEY idx_plaza_report_target (target_type, target_id), CONSTRAINT fk_plaza_report_reporter FOREIGN KEY (reporter_id) REFERENCES h5_users(id) ON DELETE CASCADE, CONSTRAINT fk_plaza_report_processor FOREIGN KEY (processed_by) REFERENCES h5_users(id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Session snapshot cache: stores userVisible messages for fast history reload. -- Rollback: DROP TABLE h5_session_snapshots (data-only, no dependants). CREATE TABLE IF NOT EXISTS h5_session_snapshots ( agent_session_id VARCHAR(128) NOT NULL PRIMARY KEY, user_id CHAR(36) NOT NULL, name VARCHAR(512) NOT NULL DEFAULT '', working_dir VARCHAR(1024) NOT NULL DEFAULT '', created_at_str VARCHAR(64) NOT NULL DEFAULT '', updated_at_str VARCHAR(64) NOT NULL DEFAULT '', user_set_name TINYINT(1) NOT NULL DEFAULT 0, recipe_json TEXT NULL, synced_msg_count INT NOT NULL DEFAULT 0, source_updated_at VARCHAR(64) NOT NULL DEFAULT '', messages_json LONGTEXT NOT NULL, synced_at BIGINT NOT NULL, KEY idx_h5_snapshots_user (user_id), KEY idx_h5_snapshots_synced (synced_at), CONSTRAINT fk_h5_snapshot_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS plaza_featured ( id CHAR(36) PRIMARY KEY, post_id CHAR(36) NOT NULL, position VARCHAR(50) NOT NULL, sort_order INT NOT NULL DEFAULT 0, starts_at BIGINT NOT NULL, expires_at BIGINT NULL, created_by CHAR(36) NOT NULL, created_at BIGINT NOT NULL, KEY idx_plaza_featured_position (position, starts_at, expires_at), CONSTRAINT fk_plaza_featured_post FOREIGN KEY (post_id) REFERENCES plaza_posts(id) ON DELETE CASCADE, CONSTRAINT fk_plaza_featured_creator FOREIGN KEY (created_by) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS plaza_user_events ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NULL, session_id VARCHAR(64) NOT NULL, post_id CHAR(36) NOT NULL, event_type ENUM( 'impression', 'click', 'view', 'dwell', 'like', 'collect', 'comment', 'share', 'dislike', 'hide' ) NOT NULL, dwell_ms INT UNSIGNED NULL, feed_sort VARCHAR(32) NOT NULL DEFAULT '', feed_category VARCHAR(64) NOT NULL DEFAULT '', position INT UNSIGNED NULL, created_at BIGINT NOT NULL, KEY idx_plaza_event_user_time (user_id, created_at), KEY idx_plaza_event_session_time (session_id, created_at), KEY idx_plaza_event_post (post_id, event_type, created_at), CONSTRAINT fk_plaza_event_post FOREIGN KEY (post_id) REFERENCES plaza_posts(id) ON DELETE CASCADE, CONSTRAINT fk_plaza_event_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS ops_audit_log ( id CHAR(36) PRIMARY KEY, operator_id CHAR(36) NOT NULL, action VARCHAR(100) NOT NULL, target_type VARCHAR(50) NOT NULL, target_id CHAR(36) NOT NULL, detail JSON NOT NULL, created_at BIGINT NOT NULL, KEY idx_ops_audit_operator (operator_id, created_at), KEY idx_ops_audit_target (target_type, target_id, created_at), CONSTRAINT fk_ops_audit_operator FOREIGN KEY (operator_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_user_wechat_identities ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, app_id VARCHAR(32) NOT NULL, openid VARCHAR(64) NOT NULL, unionid VARCHAR(64) NULL, nickname VARCHAR(128) NULL, avatar_url VARCHAR(512) NULL, last_login_at BIGINT NOT NULL, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, UNIQUE KEY uq_wechat_openid (app_id, openid), UNIQUE KEY uq_wechat_user (user_id, app_id), KEY idx_wechat_unionid (unionid), CONSTRAINT fk_wechat_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_wechat_oauth_states ( state VARCHAR(64) PRIMARY KEY, return_to VARCHAR(512) NULL, utm_source VARCHAR(64) NULL, utm_medium VARCHAR(64) NULL, utm_campaign VARCHAR(64) NULL, intent VARCHAR(16) NOT NULL DEFAULT 'login', bind_user_id CHAR(36) NULL, auth_mode VARCHAR(8) NOT NULL DEFAULT 'mp', status VARCHAR(16) NOT NULL DEFAULT 'pending', result_kind VARCHAR(32) NULL, result_token VARCHAR(512) NULL, result_message VARCHAR(255) NULL, expires_at BIGINT NOT NULL, created_at BIGINT NOT NULL, KEY idx_wechat_oauth_state_expires (expires_at), KEY idx_wechat_oauth_state_status (status, expires_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_wechat_pending_binds ( token VARCHAR(64) PRIMARY KEY, app_id VARCHAR(32) NOT NULL, openid VARCHAR(64) NOT NULL, unionid VARCHAR(64) NULL, nickname VARCHAR(128) NULL, avatar_url VARCHAR(512) NULL, return_to VARCHAR(512) NULL, utm_source VARCHAR(64) NULL, utm_medium VARCHAR(64) NULL, utm_campaign VARCHAR(64) NULL, expires_at BIGINT NOT NULL, created_at BIGINT NOT NULL, KEY idx_wechat_pending_expires (expires_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_wechat_agent_routes ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, app_id VARCHAR(32) NOT NULL, openid VARCHAR(64) NOT NULL, agent_session_id VARCHAR(128) NOT NULL, status ENUM('active', 'disabled') NOT NULL DEFAULT 'active', created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, UNIQUE KEY uq_wechat_agent_route (app_id, openid), KEY idx_wechat_agent_route_user (user_id, updated_at), CONSTRAINT fk_wechat_agent_route_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_wechat_mp_messages ( app_id VARCHAR(32) NOT NULL, openid VARCHAR(64) NOT NULL, msg_id VARCHAR(128) NOT NULL, status ENUM('processing', 'done', 'failed') NOT NULL DEFAULT 'processing', agent_session_id VARCHAR(128) NULL, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, PRIMARY KEY (app_id, openid, msg_id), KEY idx_wechat_mp_messages_updated (updated_at), KEY idx_wechat_mp_messages_session (agent_session_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_wechat_mp_message_details ( id CHAR(36) PRIMARY KEY, app_id VARCHAR(32) NOT NULL, openid VARCHAR(64) NOT NULL, user_id CHAR(36) NULL, msg_id VARCHAR(128) NULL, msg_type VARCHAR(32) NOT NULL, display_text TEXT NULL, agent_text TEXT NULL, media_id VARCHAR(256) NULL, media_url TEXT NULL, media_public_url TEXT NULL, media_format VARCHAR(64) NULL, location_lat DECIMAL(10,7) NULL, location_lng DECIMAL(10,7) NULL, location_label VARCHAR(255) NULL, link_url TEXT NULL, link_title VARCHAR(255) NULL, raw_xml_hash CHAR(40) NULL, raw_json JSON NULL, created_at BIGINT NOT NULL, KEY idx_wechat_mp_message_details_user (app_id, openid, created_at), KEY idx_wechat_mp_message_details_msg (msg_id), KEY idx_wechat_mp_message_details_type (msg_type, created_at), CONSTRAINT fk_wechat_mp_message_details_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_schedule_items ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, kind ENUM('task', 'event') NOT NULL, title VARCHAR(255) NOT NULL, description TEXT NULL, status ENUM('active', 'completed', 'cancelled', 'deleted') NOT NULL DEFAULT 'active', start_at BIGINT NULL, end_at BIGINT NULL, due_at BIGINT NULL, all_day TINYINT(1) NOT NULL DEFAULT 0, timezone VARCHAR(64) NOT NULL DEFAULT 'Asia/Shanghai', location VARCHAR(255) NULL, source_channel ENUM('h5', 'wechat', 'agent', 'api') NOT NULL DEFAULT 'agent', source_session_id VARCHAR(128) NULL, source_message_id VARCHAR(128) NULL, source_text TEXT NULL, metadata_json JSON NULL, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, deleted_at BIGINT NULL, KEY idx_schedule_user_time (user_id, status, start_at, due_at), KEY idx_schedule_user_updated (user_id, updated_at), CONSTRAINT fk_schedule_item_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_schedule_reminders ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, item_id CHAR(36) NOT NULL, remind_at BIGINT NOT NULL, offset_minutes INT NULL, channel ENUM('wechat', 'in_app') NOT NULL DEFAULT 'wechat', status ENUM('pending', 'locked', 'sent', 'failed', 'cancelled') NOT NULL DEFAULT 'pending', attempts INT NOT NULL DEFAULT 0, last_error VARCHAR(500) NULL, locked_until BIGINT NULL, sent_at BIGINT NULL, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, UNIQUE KEY uq_schedule_item_remind_at (item_id, remind_at, channel), KEY idx_reminder_due (status, remind_at), KEY idx_reminder_user (user_id, status, remind_at), CONSTRAINT fk_schedule_reminder_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE, CONSTRAINT fk_schedule_reminder_item FOREIGN KEY (item_id) REFERENCES h5_schedule_items(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_schedule_digest_subscriptions ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, digest_type ENUM('todo_day') NOT NULL DEFAULT 'todo_day', hour TINYINT UNSIGNED NOT NULL, minute TINYINT UNSIGNED NOT NULL DEFAULT 0, timezone VARCHAR(64) NOT NULL DEFAULT 'Asia/Shanghai', channel ENUM('wechat', 'in_app') NOT NULL DEFAULT 'wechat', status ENUM('active', 'locked', 'failed', 'cancelled') NOT NULL DEFAULT 'active', next_run_at BIGINT NOT NULL, last_run_at BIGINT NULL, attempts INT NOT NULL DEFAULT 0, locked_until BIGINT NULL, last_error VARCHAR(500) NULL, source_channel ENUM('h5', 'wechat', 'agent', 'api') NOT NULL DEFAULT 'agent', source_session_id VARCHAR(128) NULL, source_message_id VARCHAR(128) NULL, source_text TEXT NULL, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, UNIQUE KEY uq_schedule_digest_user_type_channel (user_id, digest_type, channel), KEY idx_schedule_digest_due (status, next_run_at), CONSTRAINT fk_schedule_digest_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_balance_alert_subscriptions ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, threshold_cents BIGINT NOT NULL, channel ENUM('wechat', 'in_app') NOT NULL DEFAULT 'wechat', status ENUM('active', 'locked', 'failed', 'cancelled') NOT NULL DEFAULT 'active', next_run_at BIGINT NOT NULL, last_run_at BIGINT NULL, last_notified_balance_cents BIGINT NULL, attempts INT NOT NULL DEFAULT 0, locked_until BIGINT NULL, last_error VARCHAR(500) NULL, source_channel ENUM('h5', 'wechat', 'agent', 'api') NOT NULL DEFAULT 'agent', source_session_id VARCHAR(128) NULL, source_message_id VARCHAR(128) NULL, source_text TEXT NULL, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, UNIQUE KEY uq_balance_alert_user_channel (user_id, channel), KEY idx_balance_alert_due (status, next_run_at), KEY idx_balance_alert_user (user_id, status, next_run_at), CONSTRAINT fk_balance_alert_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_schedule_delivery_logs ( id CHAR(36) PRIMARY KEY, reminder_id CHAR(36) NULL, subscription_id CHAR(36) NULL, user_id CHAR(36) NOT NULL, channel ENUM('wechat', 'in_app') NOT NULL, status ENUM('success', 'failed') NOT NULL, provider_message_id VARCHAR(128) NULL, error_code VARCHAR(64) NULL, error_message VARCHAR(500) NULL, created_at BIGINT NOT NULL, KEY idx_delivery_reminder (reminder_id, created_at), KEY idx_delivery_subscription (subscription_id, created_at), KEY idx_delivery_user (user_id, created_at), CONSTRAINT fk_schedule_delivery_reminder FOREIGN KEY (reminder_id) REFERENCES h5_schedule_reminders(id) ON DELETE CASCADE, CONSTRAINT fk_schedule_delivery_subscription FOREIGN KEY (subscription_id) REFERENCES h5_schedule_digest_subscriptions(id) ON DELETE CASCADE, CONSTRAINT fk_schedule_delivery_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_user_notifications ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, channel ENUM('web', 'wechat') NOT NULL DEFAULT 'web', notification_type VARCHAR(64) NOT NULL, title VARCHAR(255) NOT NULL, body TEXT NOT NULL, data_json JSON NULL, status ENUM('unread', 'read') NOT NULL DEFAULT 'unread', read_at BIGINT NULL, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, KEY idx_user_notifications_user_status_created (user_id, status, created_at), KEY idx_user_notifications_user_created (user_id, created_at), CONSTRAINT fk_user_notifications_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_plan_catalog ( plan_type VARCHAR(32) PRIMARY KEY, name VARCHAR(64) NOT NULL, price_cents INT NOT NULL DEFAULT 0, period_days INT NOT NULL DEFAULT 30, period_tokens BIGINT NOT NULL DEFAULT 0, period_images INT NOT NULL DEFAULT 0, model_tier VARCHAR(32) NOT NULL DEFAULT 'basic', overage_rate DECIMAL(4,2) NOT NULL DEFAULT 1.00, sort_order INT NOT NULL DEFAULT 0, is_active TINYINT(1) NOT NULL DEFAULT 1, description VARCHAR(512) NULL, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_subscriptions ( id CHAR(36) PRIMARY KEY, user_id CHAR(36) NOT NULL, plan_type VARCHAR(32) NOT NULL DEFAULT 'free', status ENUM('active', 'expired', 'cancelled') NOT NULL DEFAULT 'active', period_tokens_limit BIGINT NOT NULL DEFAULT 0, period_tokens_used BIGINT NOT NULL DEFAULT 0, period_images_limit INT NOT NULL DEFAULT 0, period_images_used INT NOT NULL DEFAULT 0, period_start BIGINT NOT NULL, period_end BIGINT NOT NULL, expires_at BIGINT NOT NULL, overage_rate DECIMAL(4,2) NOT NULL DEFAULT 1.00, auto_renew TINYINT(1) NOT NULL DEFAULT 0, operator_id CHAR(36) NULL, note VARCHAR(512) NULL, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, KEY idx_h5_sub_user_status (user_id, status), KEY idx_h5_sub_expires (expires_at, status), CONSTRAINT fk_h5_sub_user FOREIGN KEY (user_id) REFERENCES h5_users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS h5_blocked_words ( id CHAR(36) PRIMARY KEY, word VARCHAR(200) NOT NULL, replacement VARCHAR(200) NOT NULL DEFAULT '***', note VARCHAR(500) NULL, status ENUM('active', 'disabled') NOT NULL DEFAULT 'active', created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, UNIQUE KEY uk_blocked_word (word) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Shared experience store (etat C): all goosed Worker instances read/write the -- same learned experience so capability is not siloed per instance. Built on -- MySQL first with a keyword + recency retrieval. `embedding` is reserved for a -- later move to PostgreSQL + pgvector without changing the calling contract. CREATE TABLE IF NOT EXISTS h5_experience ( id CHAR(36) PRIMARY KEY, scope VARCHAR(64) NOT NULL DEFAULT 'global', kind VARCHAR(32) NOT NULL DEFAULT 'lesson', title VARCHAR(255) NOT NULL, body MEDIUMTEXT NOT NULL, tags_json JSON NULL, source_session_id VARCHAR(128) NULL, source_user_id CHAR(36) NULL, use_count BIGINT NOT NULL DEFAULT 0, embedding JSON NULL, created_at BIGINT NOT NULL, updated_at BIGINT NOT NULL, KEY idx_h5_experience_scope_updated (scope, updated_at), FULLTEXT KEY ftx_h5_experience (title, body) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;