Files
topsysops-app/backend/src/seed.js
T
ogrechkoandClaude Sonnet 5 130c5382cd Initial commit: TopSysOps site + admin panel
Multi-page public site (Next.js), Node/Express backend with Postgres,
and Vite admin/account app, restructured from a single-page layout
into dedicated service, promotions, cases, about, FAQ, and blog pages
for SEO.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013otXCiTZsxdZ4SJKZ9wUky
2026-08-25 23:12:16 +03:00

168 lines
13 KiB
JavaScript

const bcrypt = require('bcryptjs');
const pool = require('./db');
async function ensureAdmin() {
const { rows } = await pool.query('SELECT COUNT(*)::int AS c FROM admin_users');
if (rows[0].c > 0) return;
const username = process.env.ADMIN_USERNAME || 'admin';
const password = process.env.ADMIN_PASSWORD;
if (!password) {
console.warn('[seed] ADMIN_PASSWORD is not set in .env - no admin user was created. Set it and restart the backend.');
return;
}
const hash = await bcrypt.hash(password, 12);
await pool.query('INSERT INTO admin_users (username, password_hash) VALUES ($1, $2)', [username, hash]);
console.log(`[seed] created admin user "${username}" - please log in and change the password from the admin panel`);
}
async function ensureContent() {
const { rows } = await pool.query('SELECT COUNT(*)::int AS c FROM service_categories');
if (rows[0].c > 0) return;
const categories = [
{ slug: 'ai', title: 'ИИ и автоматизация', description: 'Внедрение ИИ, боты и ассистенты, автоматизация процессов', icon: 'Bot', items: [
['Бот / ИИ-ассистент', 'от 20 000 ₽', '/проект', 'Автоматизация бизнес-процессов'],
['Интеграция с сервисами', 'от 25 000 ₽', '/проект', 'Подключение CRM, мессенджеров, API'],
] },
{ slug: 'support', title: 'IT-поддержка', description: 'Удалённое и выездное сопровождение инфраструктуры', icon: 'Headphones', items: [
['Базовый тариф', 'от 30 000 ₽', '/мес', 'Удалённая поддержка, график 5/2'],
['Премиум тариф', 'от 100 000 ₽', '/мес', 'Полное сопровождение, выезды, 24/7'],
] },
{ slug: 'security', title: 'Кибербезопасность', description: 'Аудит, мониторинг и защита от угроз', icon: 'ShieldCheck', items: [
['Аудит и мониторинг', 'от 50 000 ₽', '/мес', 'Комплексная защита данных и систем'],
['Внедрение IDS/IPS', 'от 30 000 ₽', '/проект', 'Обнаружение и предотвращение вторжений'],
] },
{ slug: 'db', title: 'Администрирование БД', description: 'Настройка, оптимизация, резервное копирование', icon: 'Database', items: [
['Настройка и оптимизация', 'от 3 000 ₽', '/час', 'MySQL, PostgreSQL и другие СУБД'],
['Резервное копирование', 'от 4 000 ₽', '/день', 'Бэкапы и восстановление данных'],
] },
{ slug: 'network', title: 'Сетевая инфраструктура', description: 'Проектирование и поддержка корпоративных сетей', icon: 'Network', items: [
['Настройка сервера', 'от 25 000 ₽', '', 'Подбор и настройка оборудования'],
['Почтовый сервер (ваше оборудование)', 'от 20 000 ₽', '', 'Развёртывание с нуля'],
['Почтовый сервер (наше оборудование)', 'от 30 000 ₽', '/мес', 'Аренда и обслуживание'],
['Проектирование сети', 'от 20 000 ₽', '/проект', 'Монтаж и настройка'],
['Управление оборудованием', 'от 6 000 ₽', '/мес', 'Роутеры и коммутаторы'],
] },
{ slug: 'cloud', title: 'Облачные решения', description: 'Миграция и оптимизация затрат на облако', icon: 'Cloud', items: [
['Миграция в облако', 'от 25 000 ₽', '/проект', 'Перенос и настройка сервисов'],
] },
{ slug: 'development', title: 'Разработка под ключ', description: 'От быстрого MVP до продакшн-разработки и сопровождения', icon: 'Rocket', items: [
['Лендинг', 'от 20 000 ₽', '', 'Простая посадочная страница под продукт или услугу - без формы-бота и админки, 1 неделя'],
['MVP «Быстрый старт»', 'от 120 000 ₽', '', 'Посадочная страница, форма/бот для заявок, простая админка - 2-3 недели'],
['MVP Pro', 'от 450 000 ₽', '', 'Личный кабинет с авторизацией, оплата, ИИ-ассистент - 4-6 недель'],
['Продакшн-разработка', 'от 1 200 000 ₽', '', 'Архитектура, тесты, DevOps, масштабирование - от 2 месяцев, точная смета после дискавери'],
['Discovery-воркшоп', 'от 30 000 ₽', '', 'Фиксация ТЗ и оценки перед стартом проекта - 1-2 дня'],
['Сопровождение проекта', 'от 40 000 ₽', '/мес', 'Ежемесячные доработки уже готовых продуктов'],
] },
{ slug: 'partners', title: 'White-label и партнёрство', description: 'Готовые решения для других компаний и программы сотрудничества', icon: 'Handshake', items: [
['White-label «Кабинет + ИИ-ассистент»', 'от 500 000 ₽', '', 'Личный кабинет с авторизацией и ИИ-чатом под брендом вашей компании'],
['IT-мониторинг сайта', 'от 10 000 ₽', '/мес', 'Аптайм, скорость загрузки, уведомления об инцидентах'],
['Реферальная программа', '10%', 'от суммы контракта', 'Бонус вам за рекомендацию нас новому клиенту'],
['Партнёрская программа', 'по договорённости', '', 'Комиссия для хостинг-провайдеров и поставщиков оборудования за рекомендации'],
] },
{ slug: 'extra', title: 'Дополнительные услуги', description: 'Разовые и почасовые работы вне основных тарифов', icon: 'Server', items: [
['Экстренный выезд специалиста', '10 000 ₽', '', 'В течение 2 часов, по Санкт-Петербургу'],
['Выезд специалиста', '5 000 ₽', '', 'В течение дня, по Санкт-Петербургу'],
['Почасовые работы', 'от 3 000 ₽', '/час', 'Иные работы по IT-инфраструктуре'],
['Удалённая работа', 'от 15 000 ₽', '/мес', 'Аренда мощностей для 1-5 сотрудников'],
] },
];
for (let i = 0; i < categories.length; i++) {
const cat = categories[i];
const { rows: catRows } = await pool.query(
'INSERT INTO service_categories (slug, title, description, icon, sort_order) VALUES ($1,$2,$3,$4,$5) RETURNING id',
[cat.slug, cat.title, cat.description, cat.icon, i]
);
const categoryId = catRows[0].id;
for (let j = 0; j < cat.items.length; j++) {
const [name, price, period, note] = cat.items[j];
await pool.query(
'INSERT INTO service_items (category_id, name, price_text, period, note, sort_order) VALUES ($1,$2,$3,$4,$5,$6)',
[categoryId, name, price, period, note, j]
);
}
}
const promotions = [
['Бонус для новых клиентов', '15 000 ₽', null, 'Бонус на любые услуги при заключении договора на IT-аутсорсинг, от 10 рабочих мест.'],
['Год без забот', 'от 20 000 ₽/мес', 'от 30 000 ₽', 'IT-аутсорсинг базовый 5/2 при оплате за 12 месяцев - скидка 30%.'],
['Премиум 24/7', 'от 80 000 ₽/мес', 'от 100 000 ₽', 'Полное сопровождение при договоре от 6 месяцев - скидка 20%.'],
['Почтовый сервер под ключ', '35 000 ₽', 'от 50 000 ₽', 'SPF/DKIM/DMARC, антиспам, веб-почта, 3 месяца сопровождения.'],
['Бот + ИИ-ассистент', '35 000 ₽', 'от 45 000 ₽', 'Telegram-бот с обучением на ваших данных (RAG).'],
];
for (let i = 0; i < promotions.length; i++) {
const [title, price, oldPrice, desc] = promotions[i];
await pool.query(
'INSERT INTO promotions (title, price_text, old_price_text, description, sort_order) VALUES ($1,$2,$3,$4,$5)',
[title, price, oldPrice, desc, i]
);
}
console.log('[seed] inserted starter services and promotions - edit or delete them from the admin panel any time');
}
async function ensureCasesAndFaqs() {
const { rows } = await pool.query('SELECT COUNT(*)::int AS c FROM cases');
if (rows[0].c === 0) {
const cases = [
['Миграция инфраструктуры розничной сети', 'Сетевая инфраструктура', 'завершён', 'ok', 'Перенесли серверы 12 магазинов на новое оборудование без остановки продаж, снизили время отклика сети.'],
['ИИ-ассистент для отдела поддержки', 'ИИ и автоматизация', 'завершён', 'ok', 'Внедрили Telegram-бота с RAG на базе базы знаний компании - снизили нагрузку на операторов.'],
['Аудит кибербезопасности финтех-проекта', 'Кибербезопасность', 'в работе', 'warn', 'Проводим комплексный аудит защищённости и внедряем систему мониторинга угроз 24/7.'],
];
for (let i = 0; i < cases.length; i++) {
const [title, tag, status, tone, description] = cases[i];
await pool.query(
'INSERT INTO cases (title, tag, status, tone, description, sort_order) VALUES ($1,$2,$3,$4,$5,$6)',
[title, tag, status, tone, description, i]
);
}
}
const { rows: faqRows } = await pool.query('SELECT COUNT(*)::int AS c FROM faqs');
if (faqRows[0].c === 0) {
const faqs = [
['Как быстро вы реагируете на заявки?', 'Для клиентов на поддержке 24/7 среднее время реакции - около 15 минут. Для разовых заявок мы связываемся в течение рабочего дня.'],
['Работаете ли вы полностью удалённо?', 'Да, большинство работ выполняется удалённо. Выезд специалиста доступен по Санкт-Петербургу.'],
['Что входит в базовый тариф IT-аутсорсинга?', 'Удалённая поддержка инфраструктуры по графику 5/2: мониторинг, устранение инцидентов, консультации.'],
['Как происходит оплата услуг?', 'По разовым работам - по факту выполнения или по предоплате для крупных проектов. По абонентскому обслуживанию - ежемесячно.'],
['Можно ли заказать разовую услугу без абонемента?', 'Да, доступны разовые работы: настройка сервера, аудит безопасности, разработка бота и другие услуги из прайс-листа.'],
['Как обеспечивается конфиденциальность данных?', 'Мы подписываем NDA перед началом работ и используем защищённые каналы доступа к вашей инфраструктуре.'],
];
for (let i = 0; i < faqs.length; i++) {
const [question, answer] = faqs[i];
await pool.query('INSERT INTO faqs (question, answer, sort_order) VALUES ($1,$2,$3)', [question, answer, i]);
}
}
}
async function ensureContactInfo() {
const { rows } = await pool.query('SELECT COUNT(*)::int AS c FROM contact_info');
if (rows[0].c > 0) return;
await pool.query(
'INSERT INTO contact_info (id, address, phone, email, hours, map_embed) VALUES (1, $1, $2, $3, $4, $5)',
[
'г. Санкт-Петербург, ул. Вавиловых, д. 10, к1',
'+7 (988) 845-47-65',
'info@top-sysops.ru',
'Пн-Пт: 8:00-18:00',
'https://yandex.ru/map-widget/v1/?um=constructor%3Aefc560cea4e680eb7a1e2826c633bc8b25312218ff4c0e69e571089cbb4372a5&source=constructor',
]
);
}
async function seed() {
await ensureAdmin();
await ensureContent();
await ensureCasesAndFaqs();
await ensureContactInfo();
}
module.exports = seed;