Initial commit

This commit is contained in:
2026-05-17 05:22:06 +03:00
commit ca4d00c895
155 changed files with 45216 additions and 0 deletions
+170
View File
@@ -0,0 +1,170 @@
-- ============================================
-- 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`;