-- ============================================ -- AegisOne Engineering — Combined Migration 2026-05-16 -- ============================================ -- 1. Blog categories: English → Russian -- 2. SLA: response_time_hours, contract_number, description -- 3. Customers table + links to objects & contracts -- 4. Dynamic questionnaire items -- ============================================ -- 1. Blog ENUM update -- ============================================ ALTER TABLE `blog_posts` MODIFY `category` ENUM( 'audit', 'sla', 'incident', 'supervision', 'documentation', 'risk', 'cases' ) NOT NULL DEFAULT 'audit'; UPDATE `blog_posts` SET category = 'audit' WHERE category = 'risk-engineering'; UPDATE `blog_posts` SET category = 'sla' WHERE category = 'sla-service'; UPDATE `blog_posts` SET category = 'incident' WHERE category = 'incident-cases'; UPDATE `blog_posts` SET category = 'supervision' WHERE category = 'infrastructure-deep-dive'; UPDATE `blog_posts` SET category = 'documentation' WHERE category = 'compliance-mchs'; UPDATE `blog_posts` SET category = 'risk' WHERE category = 'economics-security'; UPDATE `blog_posts` SET category = 'cases' WHERE category = 'case-studies'; -- ============================================ -- 2. SLA fields -- ============================================ ALTER TABLE `sla_contracts` ADD COLUMN IF NOT EXISTS `response_time_hours` decimal(5,1) DEFAULT NULL AFTER `response_time_p3`, ADD COLUMN IF NOT EXISTS `contract_number` varchar(50) DEFAULT '' AFTER `id`, ADD COLUMN IF NOT EXISTS `description` text DEFAULT NULL AFTER `contract_number`; -- ============================================ -- 3. Customers table -- ============================================ CREATE TABLE IF NOT EXISTS `customers` ( `id` int UNSIGNED AUTO_INCREMENT PRIMARY KEY, `name` varchar(255) NOT NULL, `inn` varchar(12) DEFAULT '', `kpp` varchar(9) DEFAULT '', `legal_address` varchar(500) DEFAULT '', `contact_person` varchar(255) DEFAULT '', `contact_phone` varchar(50) DEFAULT '', `contact_email` varchar(255) DEFAULT '', `status` enum('active','inactive','prospect') NOT NULL DEFAULT 'active', `notes` text DEFAULT NULL, `created_by` int UNSIGNED DEFAULT NULL, `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX `idx_status` (`status`), INDEX `idx_inn` (`inn`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Add customer_id to objects (skip if column exists) SET @col_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='objects' AND COLUMN_NAME='customer_id'); SET @sql = IF(@col_exists=0, 'ALTER TABLE `objects` ADD COLUMN `customer_id` int UNSIGNED DEFAULT NULL AFTER `id`, ADD INDEX `idx_customer` (`customer_id`)', 'SELECT 1' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- Add FK objects→customers (skip if exists) SET @fk_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='objects' AND CONSTRAINT_NAME='fk_object_customer'); SET @sql = IF(@fk_exists=0, 'ALTER TABLE `objects` ADD CONSTRAINT `fk_object_customer` FOREIGN KEY (`customer_id`) REFERENCES `customers`(`id`) ON DELETE SET NULL ON UPDATE CASCADE', 'SELECT 1' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- Add customer_id to sla_contracts (skip if column exists) SET @col_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='sla_contracts' AND COLUMN_NAME='customer_id'); SET @sql = IF(@col_exists=0, 'ALTER TABLE `sla_contracts` ADD COLUMN `customer_id` int UNSIGNED DEFAULT NULL AFTER `id`, ADD INDEX `idx_customer` (`customer_id`)', 'SELECT 1' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- Add FK sla_contracts→customers (skip if exists) SET @fk_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='sla_contracts' AND CONSTRAINT_NAME='fk_sla_customer'); SET @sql = IF(@fk_exists=0, 'ALTER TABLE `sla_contracts` ADD CONSTRAINT `fk_sla_customer` FOREIGN KEY (`customer_id`) REFERENCES `customers`(`id`) ON DELETE SET NULL ON UPDATE CASCADE', 'SELECT 1' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- Migrate existing client_name from sla_contracts to customers INSERT IGNORE INTO `customers` (`name`, `status`, `created_at`) SELECT DISTINCT client_name, 'active', NOW() FROM `sla_contracts` WHERE client_name != '' AND client_name IS NOT NULL; -- Link sla_contracts to customers UPDATE `sla_contracts` sc JOIN `customers` c ON c.name = sc.client_name SET sc.customer_id = c.id WHERE sc.client_name != '' AND sc.client_name IS NOT NULL AND sc.customer_id IS NULL; -- ============================================ -- 4. Dynamic questionnaire items -- ============================================ CREATE TABLE IF NOT EXISTS `questionnaire_items` ( `id` int UNSIGNED AUTO_INCREMENT PRIMARY KEY, `step` int UNSIGNED NOT NULL DEFAULT 1, `section` varchar(100) NOT NULL DEFAULT '', `question_key` varchar(100) NOT NULL, `label` varchar(255) NOT NULL, `type` enum('text','number','select','radio','checkbox','textarea') NOT NULL DEFAULT 'text', `options` text DEFAULT NULL COMMENT 'JSON array of options for select/radio', `required` tinyint(1) NOT NULL DEFAULT 0, `sort_order` int UNSIGNED NOT NULL DEFAULT 0, `is_active` tinyint(1) NOT NULL DEFAULT 1, `help_text` varchar(500) DEFAULT '', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX `idx_step` (`step`), INDEX `idx_key` (`question_key`), INDEX `idx_sort` (`sort_order`), UNIQUE KEY `uq_key` (`question_key`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; INSERT INTO `questionnaire_items` (`step`, `section`, `question_key`, `label`, `type`, `options`, `required`, `sort_order`, `help_text`) VALUES (1, 'Коммерческий профиль объекта', 'object_name', 'Название организации / объекта', 'text', NULL, 1, 1, ''), (1, 'Коммерческий профиль объекта', 'object_type', 'Тип объекта', 'select', '["","Гостиница","Склад","Производство","ТЦ","Офис","БЦ","Медицина","Образование","Другое"]', 0, 2, ''), (1, 'Коммерческий профиль объекта', 'address', 'Адрес объекта', 'text', NULL, 0, 3, ''), (1, 'Коммерческий профиль объекта', 'area', 'Площадь (м²)', 'number', NULL, 0, 4, ''), (1, 'Коммерческий профиль объекта', 'employees', 'Количество сотрудников', 'number', NULL, 0, 5, ''), (1, 'Коммерческий профиль объекта', 'contact_person', 'Контактное лицо', 'text', NULL, 0, 6, ''), (1, 'Коммерческий профиль объекта', 'contact_phone', 'Телефон', 'text', NULL, 0, 7, ''), (1, 'Коммерческий профиль объекта', 'region_factor', 'Региональный коэффициент', 'select', '{"1.0":"Краснодар (1.0)","1.1":"Краснодарский край (1.1)","1.3":"РФ (1.3)","1.6":"РФ удалённые (1.6)","1.8":"Москва (1.8)"}', 0, 8, ''), (2, 'Видеонаблюдение', 'has_video', 'Есть система видеонаблюдения?', 'radio', '{"1":"Да","0":"Нет"}', 0, 1, ''), (2, 'Видеонаблюдение', 'camera_count', 'Количество камер', 'number', NULL, 0, 2, ''), (2, 'Видеонаблюдение', 'video_type', 'Тип системы', 'select', '["","ip","analog","mixed"]', 0, 3, ''), (2, 'Видеонаблюдение', 'archive_depth', 'Глубина архива', 'select', '{"7":"7 дней","14":"14 дней","30":"30+ дней"}', 0, 4, ''), (2, 'СКУД', 'has_acs', 'Есть система СКУД?', 'radio', '{"1":"Да","0":"Нет"}', 0, 5, ''), (2, 'СКУД', 'access_points', 'Точек доступа', 'number', NULL, 0, 6, ''), (2, 'СКУД', 'acs_vendor', 'Производитель СКУД', 'text', NULL, 0, 7, ''), (2, 'Пожарная сигнализация', 'has_fire', 'Есть пожарная сигнализация?', 'radio', '{"1":"Да","0":"Нет"}', 0, 8, ''), (2, 'Пожарная сигнализация', 'fire_type', 'Сложность системы', 'select', '{"simple":"Простая","medium":"Средняя","complex":"Сложная (>5000 м²)"}', 0, 9, ''), (2, 'Инфраструктура', 'server_state', 'Состояние сервера', 'select', '{"ok":"Нормальный","weak":"Слабый","none":"Нет"}', 0, 10, ''), (2, 'Инфраструктура', 'network_state', 'Состояние сети', 'select', '{"stable":"Стабильная","partial":"Частично","unstable":"Нестабильная"}', 0, 11, ''), (2, 'Инфраструктура', 'power_state', 'Электропитание (UPS)', 'select', '{"ok":"Нормальное","weak":"Слабый UPS","none":"Нет UPS"}', 0, 12, ''), (3, 'Эксплуатационная модель', 'service_state', 'Как обслуживается объект сейчас?', 'select', '{"none":"Не обслуживается","irregular":"Нерегулярно","formal":"Формальный подрядчик","sla":"Есть SLA"}', 0, 1, ''), (3, 'Эксплуатационная модель', 'has_regulations', 'Есть ли регламент?', 'checkbox', NULL, 0, 2, ''), (3, 'Эксплуатационная модель', 'problems', 'Отметьте частые проблемы', 'checkbox', '["Не работают камеры","Пропадает архив","Зависает СКУД","Ошибки пожарки","Нет реакции подрядчика","Нет понимания состояния систем"]', 0, 3, ''), (3, 'Эксплуатационная модель', 'resolution_time', 'Среднее время устранения', 'select', '{"2h":"До 2 часов","24h":"До суток","days":"Несколько дней"}', 0, 4, ''), (3, 'Эксплуатационная модель', 'controller', 'Кто контролирует систему?', 'select', '{"engineer":"Штатный инженер","contractor":"Подрядчик","nobody":"Никто"}', 0, 5, ''), (4, 'Risk Assessment', 'no_archive', 'Нет архива видеонаблюдения (+25)', 'checkbox', NULL, 0, 1, ''), (4, 'Risk Assessment', 'no_power', 'Нет резервного питания (+20)', 'checkbox', NULL, 0, 2, ''), (4, 'Risk Assessment', 'no_regulations', 'Нет регламента обслуживания (+15)', 'checkbox', NULL, 0, 3, ''), (4, 'Risk Assessment', 'frequent_failures', 'Частые сбои систем (+20)', 'checkbox', NULL, 0, 4, ''), (4, 'Risk Assessment', 'no_documentation', 'Нет документации (+10)', 'checkbox', NULL, 0, 5, ''), (4, 'Risk Assessment', 'consequences', 'Потенциальные последствия', 'checkbox', '["loss_of_evidence","shutdown","fines","no_investigation","access_fail"]', 0, 6, ''), (4, 'Risk Assessment', 'confidence', 'Уровень уверенности в системе', 'select', '{"high":"Высокая","medium":"Средняя","low":"Низкая"}', 0, 7, ''), (5, 'Расчёт SLA', 'sla_level', 'Предпочтительный уровень обслуживания', 'select', '{"start":"Базовый (Start SLA)","business":"Стандарт (Business SLA)","enterprise":"Расширенный (Enterprise SLA)"}', 0, 1, ''), (5, 'Расчёт SLA', 'visit_frequency', 'Интенсивность обслуживания', 'select', '{"1":"1 выезд / мес","2":"2 выезда / мес","incident":"По инцидентам"}', 0, 2, ''), (5, 'Расчёт SLA', 'reaction_time', 'Требуемое время реакции', 'select', '{"24":"24 часа","4":"4 часа","2":"2 часа"}', 0, 3, ''), (5, 'Расчёт SLA', 'extra_247', '24/7 поддержка', 'checkbox', NULL, 0, 4, ''), (5, 'Расчёт SLA', 'extra_emergency', 'Аварийные выезды', 'checkbox', NULL, 0, 5, ''), (5, 'Расчёт SLA', 'extra_audit', 'Аудит', 'checkbox', NULL, 0, 6, ''), (5, 'Расчёт SLA', 'extra_docs', 'Документация', 'checkbox', NULL, 0, 7, ''), (5, 'Расчёт SLA', 'extra_contractors', 'Контроль подрядчиков', 'checkbox', NULL, 0, 8, '') ON DUPLICATE KEY UPDATE `id`=`id`;