Beton CRM: От идеи до production — как мы создали современную систему управления заказами
Расскажу о разработке полнофункциональной CRM-системы для управления заказами бетона с интеграцией Bitrix24.
В процессе создания проекта мы внедрили множество интересных технических решений, включая Elasticsearch для
молниеносного поиска, периодические заявки, динамические формы и многое другое.
Что мы построили
Beton CRM — это полноценная система управления заказами на бетон с веб-интерфейсом,
которая решает реальные бизнес-задачи:
- Прием и обработка заказов через динамические формы
- Интеграция с Bitrix24 для управления сделками
- Молниеносный поиск по всей базе заказов и клиентов
- Создание периодических заявок (например, ежедневные поставки на месяц)
- Адаптивный интерфейс для мобильных устройств и десктопа
Elasticsearch: Умный поиск на стероидах
Одна из самых интересных фич проекта — это система поиска на базе Elasticsearch.
Мы не просто добавили поиск, а создали интеллектуальную систему с множеством продвинутых возможностей.
Что умеет наш поиск:
1. Адаптивные стратегии поиска
Система автоматически выбирает оптимальную стратегию поиска в зависимости от длины запроса:
- Короткие запросы (<5 символов): Агрессивный fuzzy-поиск с автокомплитом и высокой толерантностью к опечаткам
- Средние запросы (5-20 символов): Сбалансированный подход с точным совпадением, wildcard-поиском и multi-match
- Длинные запросы (>20 символов): Оптимизированный поиск по длинным текстам с точным фразовым совпадением
2. Специальные анализаторы для русского языка
product_search: {
type: 'custom',
tokenizer: 'standard',
filter: [
'lowercase',
'russian_stop', // Фильтрация стоп-слов
'russian_stemmer', // Стемминг для русского
'product_synonyms', // Синонимы для товаров
'product_edge_ngram' // N-граммы для частичного совпадения
]
}
3. Умные синонимы для строительной отрасли
Система понимает отраслевую специфику и обрабатывает синонимы:
- бетон ↔ цемент ↔ смесь
- В25 ↔ В-25 ↔ бетон В25 ↔ марка В25
- М300 ↔ М-300 ↔ марка 300 ↔ бетон М300
- фундамент ↔ основание ↔ база ↔ фундаментный
4. Интеллектуальный скоринг результатов
Elasticsearch не просто находит документы, но и умно ранжирует их:
- Boost ×2.0 для точных совпадений марок бетона (В25, М300)
- Boost ×1.3 для заявок с высоким приоритетом
- Boost ×1.2 для недавно созданных документов (последние 30 дней)
- Boost ×1.15 для активных статусов (NEW, IN_PROCESS, PENDING)
- Min score 0.5 для фильтрации нерелевантных результатов
5. Встроенное кэширование поисковых запросов
// In-memory кэш с TTL 2 минуты
private searchCache = new Map<string, {
data: SearchResult[];
timestamp: number
}>()
private readonly CACHE_TTL = 2 * 60 * 1000
private readonly MAX_CACHE_SIZE = 500
6. Подсветка найденных фрагментов
Результаты поиска отображаются с подсветкой найденных фрагментов в HTML-формате:
<mark>бетон В25</mark> для фундамента с доставкой
Периодические заявки: Автоматизация рутины
Еще одна инновационная фича — система периодических заявок. Представьте: клиенту нужна
ежедневная поставка бетона на месяц. Вместо создания 30 заявок вручную, система делает это автоматически!
Как это работает:
- Выбор периода: Пользователь включает режим «Периодические заявки» и выбирает диапазон дат
- Заполнение формы: Все поля (кроме даты доставки) заполняются один раз
- Магия транзакций: Система создает по одной заявке на каждый день выбранного периода
- Синхронизация с Bitrix24: Для каждой заявки автоматически создается сделка в CRM
- Атомарность: Если хоть одна заявка не создалась — откатывается вся транзакция
Технические детали:
// Создание периодической группы с транзакцией
const queryRunner = AppDataSource.createQueryRunner()
await queryRunner.startTransaction()
try {
// Генерируем массив дат
const dates = this.generateDateRange(startDate, endDate)
// Создаем группу периода
const periodGroup = queryRunner.manager.create(SubmissionPeriodGroup, {
startDate, endDate,
totalSubmissions: dates.length,
status: PeriodGroupStatus.ACTIVE
})
// Создаем заявки для каждой даты
for (const date of dates) {
// Создаем сделку в Bitrix24
const bitrixDealId = await bitrix24Service.createDeal(dealData)
// Создаем заявку в БД
const submission = await queryRunner.manager.save(...)
}
await queryRunner.commitTransaction()
} catch (error) {
await queryRunner.rollbackTransaction()
throw error
}
Система также умеет:
- Массово обновлять все заявки периода (кроме даты)
- Отменять весь период одной кнопкой
- Отслеживать прогресс выполнения периода
- Хранить метаданные для аудита
Динамический конструктор форм
В CRM реализован мощный drag-and-drop конструктор форм с административной панелью:
Возможности конструктора:
- 15+ типов полей: текст, число, дата, время, выпадающий список, автокомплит, чекбокс, радио, файлы, заголовки, разделители
- Секционная организация: Поля группируются в разделы с аккордеонами
- Drag & Drop: Перетаскивание полей между секциями и изменение порядка
- Связанные поля: Автозаполнение данных из Bitrix24 по выбранному клиенту
- Условная логика: Поля могут показываться/скрываться в зависимости от других полей
- Валидация: Кастомные правила проверки на фронте и бэкенде
- Bitrix24 mapping: Автоматическое связывание полей формы с полями Bitrix24
Адаптивность:
Формы автоматически переключаются между десктопной и мобильной версией:
- Desktop: Аккордеоны с секциями, кнопки управления, прогресс заполнения
- Mobile: Упрощенная версия с touch-friendly элементами и оптимизацией под экраны смартфонов
Миграция с MongoDB на PostgreSQL
Проект изначально использовал MongoDB, но мы провели полную миграцию на PostgreSQL с TypeORM. Почему?
- ACID-транзакции: Критично для периодических заявок и финансовых операций
- Сложные связи: Множество отношений между сущностями (формы → поля → заявки → пользователи)
- Миграции схемы: TypeORM предоставляет удобный механизм версионирования БД
- Производительность JOIN: Эффективная работа со связанными данными
Ключевые сущности:
User ← (1:N) → Submission ← (N:1) → Form ← (1:N) → FormField
↓
(N:1) SubmissionPeriodGroup
↓
(1:N) Submission (periodic)
Интеграция с Bitrix24
Система плотно интегрирована с Bitrix24 CRM через webhook API:
Что интегрировано:
- Автоматическое создание сделок: При отправке формы создается сделка в Bitrix24
- Синхронизация статусов: Двусторонняя синхронизация статусов сделок
- Подгрузка справочников: Автокомплит клиентов, компаний, товаров из Bitrix24
- Связанные поля: При выборе клиента автоматически заполняются телефон, email, адрес
- Кэширование: Redis-кэш для API-ответов Bitrix24 (TTL: 30 минут — 2 часа)
- Обратная связь: ID заявки записывается в пользовательское поле Bitrix24
In-Memory кэширование
Для оптимизации производительности реализована многоуровневая система кэширования:
1. CacheService (базовый)
const memoryCache = new Map<string, {
data: any;
expires: number
}>()
// Паттерн get-or-set
async getOrSet<T>(
key: string,
setter: () => Promise<T>,
options?: CacheOptions
): Promise<T | null>
2. BitrixCacheService (специализированный)
- Категории сделок: TTL 2 часа
- Стадии сделок: TTL 1 час
- Динамические опции (клиенты, товары): TTL 30 минут
3. FormCacheService (для форм)
- Формы с полями: TTL 30 минут
- Список активных форм: TTL 10 минут
4. Elasticsearch SearchCache
- Результаты поиска: TTL 2 минуты
- Максимальный размер: 500 записей
- Auto-cleanup устаревших записей
Docker-инфраструктура
Весь проект упакован в Docker с продакшн-оптимизацией:
Сервисы в docker-compose:
- PostgreSQL 16 Alpine: Компактная БД с health checks
- Redis 7 Alpine: Кэш с AOF persistence
- Elasticsearch 8.11: Поисковый движок с ограниченной памятью (512MB)
- Backend: Node.js API с multi-stage build
- Frontend: Nginx + статика React с оптимизацией
Особенности конфигурации:
services:
postgres:
ports:
- '127.0.0.1:5489:5432' # Доступ только через localhost
healthcheck:
test: ['CMD-SHELL', 'pg_isready']
elasticsearch:
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- 'ES_JAVA_OPTS=-Xms512m -Xmx512m'
backend:
depends_on:
postgres: { condition: service_healthy }
redis: { condition: service_healthy }
elasticsearch: { condition: service_healthy }
E2E тестирование с Playwright
Для обеспечения качества реализованы E2E-тесты на Playwright:
- Тестирование аутентификации (вход/выход)
- Создание и отправка заявок
- Административные функции
- Тесты API endpoints
- Интеграция с Bitrix24
Производительность и оптимизации
Backend оптимизации:
- Connection pooling для PostgreSQL
- Индексы БД на часто запрашиваемые поля
- Lazy loading связанных сущностей в TypeORM
- Background jobs для тяжелых операций (синхронизация с Bitrix24)
- Elasticsearch refresh_interval: 30s для лучшей производительности индексации
Frontend оптимизации:
- React Query для кэширования серверных данных
- Code splitting на уровне роутов
- Debouncing для автокомплита и поиска
- Виртуализация длинных списков в таблицах
- Lazy loading компонентов форм
Безопасность
- JWT токены с refresh механизмом (access: 7 дней, refresh: 30 дней)
- Bcrypt хэширование паролей с солью
- Role-based access control (user/admin)
- CORS с белым списком доменов
- Input validation на фронте (Yup) и бэкенде (class-validator)
- SQL injection protection через TypeORM query builder
- Rate limiting для API endpoints
Мобильная адаптация
Система полностью адаптирована для мобильных устройств:
- Responsive breakpoints: xs, sm, md, lg, xl
- Touch-friendly: Увеличенные кнопки и поля ввода
- Упрощенные формы: Автопереключение на SimpleMobileBetoneForm
- Progressive disclosure: Секции открываются по одной
- Оптимизация трафика: Сжатие данных, ленивая загрузка
Чему я научился
Этот проект был отличным опытом работы с современным стеком технологий:
- Настройка и тонкая настройка Elasticsearch для русскоязычного контента
- Проектирование сложных транзакций с TypeORM
- Оптимизация производительности с многоуровневым кэшированием
- Интеграция с внешними API (Bitrix24 webhook)
- Создание type-safe приложений с TypeScript
- Docker-оркестрация для продакшен-окружения
- E2E тестирование с Playwright
- Работа с Material-UI и создание адаптивных интерфейсов
Что дальше?
Планы по развитию проекта:
- Внедрение WebSocket для real-time уведомлений
- Добавление аналитики и отчетов (дашборды, графики)
- Интеграция с 1C для учета
- Мобильное приложение на React Native
- Система уведомлений (email, SMS, push)
- AI-ассистент для предсказания спроса
Заключение
Beton CRM — это пример того, как современные технологии могут решать реальные бизнес-задачи.
Мы создали систему, которая не только автоматизирует процессы, но и делает работу с заказами приятной и эффективной.
Особенно горжусь реализацией Elasticsearch с умным поиском, системой периодических заявок
с транзакциями и динамическим конструктором форм. Эти фичи действительно выделяют проект среди типовых CRM.
Если у вас есть вопросы по реализации каких-то частей или хотите обсудить архитектурные решения —
пишите! Буду рад поделиться опытом.
Технологии: React 19, TypeScript, Node.js, Express, PostgreSQL, TypeORM,
Elasticsearch 8.11, Redis, Docker, Material-UI 7, React Query, Bitrix24 API, Playwright
