-- Additive, re-runnable MySQL/InnoDB migration. Default feature gates remain OFF in configuration. -- Back up before an authorized release. This file does not enable the feature or grant new privileges. CREATE TABLE IF NOT EXISTS `zyt_followup_audio_upload` ( `id` varchar(64) NOT NULL, `diagnosis_id` bigint unsigned NOT NULL, `actor_id` bigint unsigned NOT NULL, `file_name` varchar(255) NOT NULL, `total_bytes` bigint unsigned NOT NULL, `received_bytes` bigint unsigned NOT NULL DEFAULT 0, `sha256` varchar(64) NOT NULL DEFAULT '', `duration_seconds` decimal(12,3) NOT NULL DEFAULT 0, `status` varchar(32) NOT NULL, `extension` varchar(10) NOT NULL, `created_at` bigint unsigned NOT NULL, `expires_at` bigint unsigned NOT NULL, PRIMARY KEY (`id`), KEY `idx_expiry` (`expires_at`,`status`), KEY `idx_diagnosis` (`diagnosis_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE IF NOT EXISTS `zyt_followup_audio_task` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT, `diagnosis_id` bigint unsigned NOT NULL, `patient_id` bigint unsigned NOT NULL, `actor_id` bigint unsigned NOT NULL, `upload_id` varchar(64) NOT NULL, `file_name` varchar(255) NOT NULL, `sha256` varchar(64) NOT NULL, `duration_seconds` decimal(12,3) NOT NULL, `recorded_at` varchar(19) NOT NULL, `model_key` varchar(16) NOT NULL, `status` varchar(32) NOT NULL, `stage` varchar(32) NOT NULL, `version` int unsigned NOT NULL DEFAULT 1, `attempts` int unsigned NOT NULL DEFAULT 0, `lease_token` varchar(64) NOT NULL DEFAULT '', `lease_until` bigint unsigned NOT NULL DEFAULT 0, `upstream_started_at` bigint unsigned NOT NULL DEFAULT 0, `upstream_run_id` varchar(191) NOT NULL DEFAULT '', `upstream_file_id` varchar(191) NOT NULL DEFAULT '', `upstream_ids_json` text NOT NULL, `error_code` varchar(96) NOT NULL DEFAULT '', `error_message` varchar(255) NOT NULL DEFAULT '', `extraction_cipher` longtext NOT NULL, `review_cipher` longtext NOT NULL, `applied_cipher` longtext NOT NULL, `created_at` bigint unsigned NOT NULL, `updated_at` bigint unsigned NOT NULL, `expires_at` bigint unsigned NOT NULL, `applied_at` bigint unsigned NOT NULL DEFAULT 0, `purged_at` bigint unsigned NOT NULL DEFAULT 0, PRIMARY KEY (`id`), UNIQUE KEY `uk_upload` (`upload_id`), UNIQUE KEY `uk_content_profile` (`diagnosis_id`,`sha256`,`model_key`), KEY `idx_queue` (`status`,`lease_until`,`expires_at`), KEY `idx_diagnosis` (`diagnosis_id`,`id`), KEY `idx_expiry` (`expires_at`,`purged_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE IF NOT EXISTS `zyt_followup_audio_audit` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT, `task_id` bigint unsigned NOT NULL, `item_id` varchar(64) NOT NULL, `diagnosis_id` bigint unsigned NOT NULL, `actor_id` bigint unsigned NOT NULL, `kind` varchar(24) NOT NULL, `table_name` varchar(64) NOT NULL, `record_id` bigint unsigned NOT NULL, `action` varchar(16) NOT NULL, `source_cipher` longtext NOT NULL, `before_cipher` longtext NOT NULL, `after_cipher` longtext NOT NULL, `created_at` bigint unsigned NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uk_task_item` (`task_id`,`item_id`), KEY `idx_record` (`table_name`,`record_id`), KEY `idx_diagnosis` (`diagnosis_id`,`created_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE IF NOT EXISTS `zyt_followup_audio_mutex` (`id` int NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB; INSERT IGNORE INTO `zyt_followup_audio_mutex` (`id`) VALUES (1),(2); -- MySQL versions without ADD COLUMN IF NOT EXISTS use information_schema guards. SET @fa_sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='zyt_tcm_blood_record' AND COLUMN_NAME='record_time_estimated')=0, 'ALTER TABLE `zyt_tcm_blood_record` ADD COLUMN `record_time_estimated` tinyint NOT NULL DEFAULT 0', 'SELECT 1'); PREPARE fa_stmt FROM @fa_sql; EXECUTE fa_stmt; DEALLOCATE PREPARE fa_stmt; SET @fa_sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='zyt_tcm_blood_record' AND COLUMN_NAME='record_time_period')=0, 'ALTER TABLE `zyt_tcm_blood_record` ADD COLUMN `record_time_period` varchar(20) NOT NULL DEFAULT \'\'', 'SELECT 1'); PREPARE fa_stmt FROM @fa_sql; EXECUTE fa_stmt; DEALLOCATE PREPARE fa_stmt; SET @fa_sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='zyt_tcm_blood_record' AND COLUMN_NAME='record_time_text')=0, 'ALTER TABLE `zyt_tcm_blood_record` ADD COLUMN `record_time_text` varchar(255) NOT NULL DEFAULT \'\'', 'SELECT 1'); PREPARE fa_stmt FROM @fa_sql; EXECUTE fa_stmt; DEALLOCATE PREPARE fa_stmt; SET @fa_sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='zyt_tcm_blood_record' AND COLUMN_NAME='followup_audio_task_id')=0, 'ALTER TABLE `zyt_tcm_blood_record` ADD COLUMN `followup_audio_task_id` bigint unsigned NULL', 'SELECT 1'); PREPARE fa_stmt FROM @fa_sql; EXECUTE fa_stmt; DEALLOCATE PREPARE fa_stmt; -- Content idempotency must not be bypassed by a different upload id/name/recorded time. SET @fa_sql = IF((SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='zyt_followup_audio_task' AND INDEX_NAME='uk_content_profile')=0, 'ALTER TABLE `zyt_followup_audio_task` ADD UNIQUE KEY `uk_content_profile` (`diagnosis_id`,`sha256`,`model_key`)', 'SELECT 1'); PREPARE fa_stmt FROM @fa_sql; EXECUTE fa_stmt; DEALLOCATE PREPARE fa_stmt; -- Additive encrypted per-stage checkpoint; re-runnable on supported MySQL versions. SET @fa_sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='zyt_followup_audio_task' AND COLUMN_NAME='pipeline_cipher')=0, 'ALTER TABLE `zyt_followup_audio_task` ADD COLUMN `pipeline_cipher` longtext NULL', 'SELECT 1'); PREPARE fa_stmt FROM @fa_sql; EXECUTE fa_stmt; DEALLOCATE PREPARE fa_stmt;