Files
site_aegisone/max_bot/sql/bot_schema.sql
T

206 lines
15 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- Bot tables for AegisOne Engineering Max Bot "София"
-- Run against the shared aegisone database
CREATE TABLE IF NOT EXISTS bot_users (
id SERIAL PRIMARY KEY,
max_user_id BIGINT UNIQUE NOT NULL,
first_name VARCHAR(255) DEFAULT '',
last_name VARCHAR(255) DEFAULT '',
username VARCHAR(255) DEFAULT '',
phone VARCHAR(50) DEFAULT '',
email VARCHAR(255) DEFAULT '',
consent_given BOOLEAN NOT NULL DEFAULT FALSE,
consent_timestamp TIMESTAMP NULL,
consent_method VARCHAR(50) DEFAULT '',
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
last_active_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS bot_categories (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
description VARCHAR(500) DEFAULT '',
active BOOLEAN NOT NULL DEFAULT TRUE,
sort_order INTEGER DEFAULT 0,
icon_emoji VARCHAR(10) DEFAULT '📋',
keywords JSONB DEFAULT '[]'::jsonb
);
CREATE TABLE IF NOT EXISTS bot_conversations (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES bot_users(id) ON DELETE CASCADE,
status VARCHAR(20) NOT NULL DEFAULT 'open' CHECK (status IN ('open','closed','handoff','1c_sent','awaiting_rating')),
inquiry_type INTEGER REFERENCES bot_categories(id) ON DELETE SET NULL,
inquiry_text TEXT DEFAULT '',
priority VARCHAR(20) DEFAULT 'normal' CHECK (priority IN ('low','normal','high','urgent')),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
closed_at TIMESTAMP NULL,
assigned_to VARCHAR(255) DEFAULT '',
has_attachment BOOLEAN DEFAULT FALSE,
attachment_type VARCHAR(50) DEFAULT '',
attachment_path VARCHAR(500) DEFAULT ''
);
CREATE TABLE IF NOT EXISTS bot_messages (
id SERIAL PRIMARY KEY,
conversation_id INTEGER REFERENCES bot_conversations(id) ON DELETE CASCADE,
direction VARCHAR(3) NOT NULL CHECK (direction IN ('in','out')),
text TEXT DEFAULT '',
has_attachment BOOLEAN DEFAULT FALSE,
attachment_type VARCHAR(50) DEFAULT '',
attachment_path VARCHAR(500) DEFAULT '',
max_message_id BIGINT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS bot_consent_logs (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES bot_users(id) ON DELETE CASCADE,
action VARCHAR(20) NOT NULL CHECK (action IN ('given','revoked')),
timestamp TIMESTAMP NOT NULL DEFAULT NOW(),
method VARCHAR(50) DEFAULT '',
ip_address VARCHAR(45) DEFAULT ''
);
CREATE TABLE IF NOT EXISTS bot_1c_sync_log (
id SERIAL PRIMARY KEY,
conversation_id INTEGER REFERENCES bot_conversations(id) ON DELETE CASCADE,
status VARCHAR(20) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending','sent','confirmed','error')),
request_payload TEXT DEFAULT '',
response_payload TEXT DEFAULT '',
sent_at TIMESTAMP NULL,
confirmed_at TIMESTAMP NULL
);
CREATE TABLE IF NOT EXISTS bot_knowledge_base (
id SERIAL PRIMARY KEY,
question VARCHAR(500) NOT NULL,
answer TEXT NOT NULL,
category VARCHAR(100) DEFAULT '',
keywords JSONB DEFAULT '[]'::jsonb,
active BOOLEAN NOT NULL DEFAULT TRUE,
sort_order INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS bot_settings (
id SERIAL PRIMARY KEY,
key VARCHAR(100) UNIQUE NOT NULL,
value TEXT DEFAULT '',
description VARCHAR(500) DEFAULT ''
);
CREATE TABLE IF NOT EXISTS bot_features (
id SERIAL PRIMARY KEY,
feature_key VARCHAR(100) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
description VARCHAR(500) DEFAULT '',
enabled BOOLEAN NOT NULL DEFAULT FALSE,
sort_order INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS bot_response_templates (
id SERIAL PRIMARY KEY,
template_key VARCHAR(100) UNIQUE NOT NULL,
template_text TEXT NOT NULL,
description VARCHAR(500) DEFAULT '',
variables JSONB DEFAULT '[]'::jsonb
);
CREATE TABLE IF NOT EXISTS bot_broadcasts (
id SERIAL PRIMARY KEY,
text TEXT NOT NULL,
sent_at TIMESTAMP NULL,
sent_by INTEGER NULL,
recipient_count INTEGER DEFAULT 0,
status VARCHAR(20) DEFAULT 'draft' CHECK (status IN ('draft','sent','failed'))
);
-- Indexes
CREATE INDEX IF NOT EXISTS idx_bot_conv_user ON bot_conversations(user_id);
CREATE INDEX IF NOT EXISTS idx_bot_conv_status ON bot_conversations(status);
CREATE INDEX IF NOT EXISTS idx_bot_msg_conv ON bot_messages(conversation_id);
CREATE INDEX IF NOT EXISTS idx_bot_consent_user ON bot_consent_logs(user_id);
CREATE INDEX IF NOT EXISTS idx_bot_1c_conv ON bot_1c_sync_log(conversation_id);
CREATE INDEX IF NOT EXISTS idx_bot_1c_status ON bot_1c_sync_log(status);
CREATE INDEX IF NOT EXISTS idx_bot_kb_active ON bot_knowledge_base(active);
CREATE INDEX IF NOT EXISTS idx_bot_cat_active ON bot_categories(active);
-- Initial settings
INSERT INTO bot_settings (key, value, description) VALUES
('bot_token', 'id2311381465_bot', 'Токен бота Max'),
('assistant_name', 'София', 'Имя виртуального помощника'),
('phone_1', '8 (861) 203-33-30', 'Телефон 1'),
('phone_2', '8 (995) 203-33-30', 'Телефон 2'),
('support_email', 'zakaz@aegisone.ru', 'Email поддержки'),
('email_subject', 'Обращение через Виртуального помощника AegisOne Engineering', 'Тема письма при отказе от согласия'),
('work_hours_start', '9', 'Начало рабочего времени (час)'),
('work_hours_end', '18', 'Конец рабочего времени (час)'),
('work_days', '1,2,3,4,5', 'Рабочие дни (1=Пн, 7=Вс)'),
('timezone', 'Europe/Moscow', 'Часовой пояс'),
('1c_webhook_url', '', 'URL webhook 1С:УНФ'),
('consent_policy_url', 'https://aegisone.ru/politica.php', 'Ссылка на политику ПД'),
('yandex_gpt_key', '', 'Ключ YandexGPT (пусто = ключевые слова)'),
('yandex_folder_id', '', 'Folder ID YandexGPT')
ON CONFLICT (key) DO NOTHING;
-- Initial features
INSERT INTO bot_features (feature_key, name, description, enabled, sort_order) VALUES
('risk_score', 'Risk Score калькулятор', 'Расчёт оценки рисков объекта', false, 1),
('sla_status', 'Проверка SLA статуса', 'Проверка статуса SLA контракта по номеру объекта', false, 2),
('photo_report', 'Фото-отчёт', 'Отправка фото проблемы с созданием инцидента', false, 3),
('appointment', 'Запись на визит', 'Запись на визит инженера', false, 4),
('quality_rate', 'Оценка качества', 'Оценка качества после закрытия обращения', false, 5),
('commercial', 'Коммерческое предложение', 'Генерация КП по запросу', false, 6),
('reminders', 'Напоминания о ТО', 'Автоматические напоминания о плановом ТО', false, 7),
('my_objects', 'Мои объекты', 'Просмотр информации по объектам клиента', false, 8),
('notifications', 'Уведомления о статусе', 'Автоматические уведомления при изменении статуса', false, 9),
('broadcasts', 'Рассылки', 'Массовая рассылка сообщений клиентам', false, 10),
('sla_ticket', 'SLA заявки', 'Подача заявки о неисправности клиентом с активным SLA', false, 11)
ON CONFLICT (feature_key) DO NOTHING;
-- Initial categories
INSERT INTO bot_categories (name, description, icon_emoji, keywords, sort_order) VALUES
('Видеонаблюдение', 'Камеры, видеорегистраторы, хранилища', '📹', '["камер","видео","наблюден","регистратор","хранен","запись"]', 1),
('СКУД', 'Контроль доступа, турникеты, замки', '🔐', '["скуд","доступ","турникет","замок","пропуск","карт"]', 2),
('Пожарная сигнализация', 'Датчики, оповещение, пожаротушение', '🔥', '["пожар","сигнализаци","датчик","оповещен","пожаротушен","дым"]', 3),
('IT-инфраструктура', 'Серверы, сеть, компьютеры', '💻', '["сервер","сет","компьютер","ит","инфраструктур","switch","роутер"]', 4),
('Обслуживание', 'Плановое ТО, ремонт, замена', '🔧', '["обслуживан","ремонт","замен","то","планов","срок"]', 5),
('Консультация', 'Вопросы, информация, расчёт стоимости', '💬', '["консультаци","вопрос","информац","стоимост","расчёт","цен"]', 6),
('Другое', 'Прочие обращения', '📋', '[]', 7)
ON CONFLICT DO NOTHING;
-- Initial response templates
INSERT INTO bot_response_templates (template_key, template_text, description, variables) VALUES
('greeting', 'Здравствуйте! Я {name}, виртуальный помощник AegisOne Engineering. Чем могу помочь?', 'Приветствие нового пользователя', '["name"]'),
('greeting_returning', 'Здравствуйте, {first_name}! У вас открыто обращение #{conv_id}. Чем ещё могу помочь?', 'Приветствие возвращающегося пользователя', '["first_name","conv_id"]'),
('consent_request', 'Для обработки обращения нам нужны контактные данные. Даёте согласие на обработку персональных данных?\n\n[Подробнее о политике]({policy_url})', 'Запрос согласия ФЗ-152', '["policy_url"]'),
('consent_refused', 'Понимаем. Вы можете связаться с нами:\n\n📞 {phone_1}\n📞 {phone_2}\n✉️ {support_email}', 'Ответ при отказе от согласия', '["phone_1","phone_2","support_email"]'),
('name_request', 'Как к вам обращаться?', 'Запрос имени', '[]'),
('contact_request', 'Как с вами связаться?', 'Запрос контактных данных', '[]'),
('inquiry_request', 'Опишите ваш вопрос. Вы можете прикрепить фото или документ (PDF, DOCX, XLSX, TXT).', 'Запрос обращения', '[]'),
('out_of_hours', 'Спасибо за обращение! Сейчас мы не работаем.\n\nНаше рабочее время: Пн-Пт {work_hours_start}:00-{work_hours_end}:00 (МСК).\n\nНо вы можете оставить сообщение — мы ответим как можно быстрее.', 'Сообщение вне рабочего времени', '["work_hours_start","work_hours_end"]'),
('confirmation', 'Спасибо, {first_name}! Обращение #{conv_id} принято.\n\nОтветим как можно быстрее.', 'Подтверждение (рабочее время)', '["first_name","conv_id"]'),
('confirmation_ooh', 'Спасибо, {first_name}! Обращение #{conv_id} принято.\n\nСейчас нерабочее время, но мы ответим как можно быстрее.', 'Подтверждение (вне рабочего времени)', '["first_name","conv_id"]'),
('handoff', 'Передаю обращение оператору. Ожидайте.', 'Передача оператору', '[]'),
('quality_request', 'Обращение #{conv_id} выполнено. Оцените качество нашей работы:\n\n⭐ 1 — Плохо\n⭐⭐ 2\n⭐⭐⭐ 3\n⭐⭐⭐⭐ 4\n⭐⭐⭐⭐⭐ 5 — Отлично', 'Запрос оценки качества', '["conv_id"]'),
('sla_found', 'Объект: {object_name}\nSLA: {service_level}\nСтатус: {status}\nЦена/мес: {price} ₽', 'Результат проверки SLA', '["object_name","service_level","status","price"]'),
('sla_not_found', 'Объект не найден или SLA контракт не оформлен.', 'SLA не найден', '[]'),
('risk_result', 'Risk Score вашего объекта: {score}/100\nУровень: {label}\n\nРекомендуем: {recommendation}', 'Результат Risk Score', '["score","label","recommendation"]'),
('appointment_confirm', 'Запись на визит подтверждена.\n\nДата: {date}\nИнженер: {engineer}', 'Подтверждение записи на визит', '["date","engineer"]'),
('commercial_offer', 'Коммерческое предложение по вашему запросу:\n\n{offer_text}', 'Коммерческое предложение', '["offer_text"]'),
('reminder', 'Напоминаем: плановое ТО объекта {object_name} запланировано на {date}.', 'Напоминание о ТО', '["object_name","date"]'),
('status_update', 'Ваше обращение #{conv_id} — {status}.\nИнженер: {engineer}.', 'Уведомление о статусе', '["conv_id","status","engineer"]'),
('main_menu', 'Выберите действие:', 'Текст главного меню', '[]'),
('emotion_escalate', 'Я понимаю ваше беспокойство. Передаю обращение старшему специалисту. Ожидайте, пожалуйста.', 'Реакция на негативные эмоции', '[]'),
('auto_categorize_confirm', 'Я определил вашу тему как: {category}. Это верно?', 'Подтверждение авто-категоризации', '["category"]')
ON CONFLICT (template_key) DO NOTHING;
-- Sample knowledge base entries
INSERT INTO bot_knowledge_base (question, answer, category, keywords, active, sort_order) VALUES
('Какие услуги вы оказываете?', 'Мы оказываем услуги по проектированию, монтажу и обслуживанию систем видеонаблюдения, СКУД, пожарной сигнализации и IT-инфраструктуры.', 'Общее', '["услуг","оказыва","монтаж","проект","обслуживан"]', true, 1),
('Как оставить заявку?', 'Нажмите кнопку «Оставить заявку» в главном меню и опишите ваш вопрос.', 'Общее', '["заявк","оставит","как"]', true, 2),
('Какие гарантии?', 'Мы предоставляем гарантию на все выполненные работы и установленное оборудование. Подробности уточняйте у менеджера.', 'Общее', '["гарант","условия"]', true, 3),
('Режим работы?', 'Наш офис работает Пн-Пт с 9:00 до 18:00 (МСК).', 'Общее', '["режим","работ","время","график"]', true, 4),
('Как связаться?', 'Вы можете написать нам здесь, позвонить по телефону 8 (861) 203-33-30 или написать на zakaz@aegisone.ru', 'Общее', '["связат","контакт","телефон","почт"]', true, 5)
ON CONFLICT DO NOTHING;