Какие проблемы решает кастомный веб-интерфейс CRM?
Представьте: у вас 50 менеджеров по продажам, каждый ведёт клиентов в Excel или своей голове. Сделки теряются, лиды не обрабатываются, отчёты собираются неделями. Веб-интерфейс кастомной CRM решает это — но только если он спроектирован под ваши бизнес-процессы, а не под шаблон.
Наша команда за 6 лет реализовала более 15 CRM-систем для B2B-компаний, поэтому мы знаем типовые ошибки и как их избежать. Мы разрабатываем веб-интерфейсы CRM на React и Laravel с нуля: от прототипа до продакшена. В статье разберём типовую архитектуру, ключевые сущности и подводные камни.
Основная задача — не накодить кнопок, а выстроить логику: кто видит какие сделки, как движется воронка, какие уведомления критичны. Без этого даже красивый интерфейс бесполезен. Проект начинается с аудита текущих процессов — за 2-3 дня мы собираем требования и предлагаем архитектуру.
Один из наших клиентов — дистрибьютор электроники — терял до 15% лидов из-за того, что менеджеры не видели историю звонков. Решение: интерфейс с автоматическим логированием всех активностей. Через месяц после внедрения отсев снизился до 3%.
Почему кастомная CRM выгоднее готовых решений?
Готовые CRM (amoCRM, Bitrix24) предлагают стандартный набор функций, но их адаптация под специфику бизнеса часто требует дорогих доработок и ограничивает гибкость. Кастомная разработка на React и Laravel позволяет:
- Оптимизировать воронку под конкретные этапы продаж: например, для дистрибьютора — стадии "Запрос КП", "Согласование цены", "Отгрузка".
- Интегрировать любое внешнее ПО: телефонию, 1С, мессенджеры, email-рассылки.
- Масштабировать функционал без оглядки на лицензионные ограничения.
При этом стоимость владения кастомной CRM уже через год оказывается ниже, чем ежемесячная плата за коробочное решение с аналогичным набором интеграций. По нашим данным, компании экономят до 40% на лицензиях при переходе на собственную разработку.
Типовой набор сущностей и их реализация
В кастомной CRM выделяют пять основных сущностей. Для каждой мы реализуем отдельный модуль с CRUD, фильтрацией и связями.
| Сущность | Назначение | Пример полей |
|---|---|---|
| Контакты | Физические лица с историей взаимодействий | name, email, phone, source |
| Компании | Юридические лица, к которым привязаны контакты | name, inn, address |
| Сделки | Потенциальные и активные продажи со статусами | amount, stage_id, responsible_id |
| Задачи | Поручения с дедлайнами, привязанные к сделкам/контактам | title, due_date, assignee |
| Активности | Лог коммуникаций (звонки, письма, встречи) | type, body, happened_at |
Кастомная разработка на React и Laravel в 2-3 раза быстрее адаптируется к изменениям бизнеса, чем готовые CRM-системы. Например, добавление нового поля или этапа воронки занимает часы, а не дни.
Как мы проектируем CRM под ваш бизнес?
Процесс работы разбит на шесть этапов:
- Аналитика — интервью с ключевыми пользователями, выявление сценариев и болей. (2-3 дня)
- Прототипирование — интерактивные макеты в Figma с утверждением заказчиком. (3-5 дней)
- Разработка бэкенда — Laravel (PHP 8.3+) с RESTful API, PostgreSQL, Redis для кеша и очередей.
- Разработка фронтенда — React 18 + TypeScript, TanStack Table для таблиц, @dnd-kit для воронки.
- Интеграции — телефония (Asterisk, Miko), email (SMTP/API), мессенджеры (Telegram, WhatsApp).
- Тестирование и деплой — CI/CD, нагрузочное тестирование, мониторинг.
Для авторизации используем Laravel Policies — стандартный механизм, который позволяет гибко разграничивать доступ: менеджер видит только свои сделки, руководитель — все в своём отделе.
Архитектура базы данных и API
База данных строится на PostgreSQL с нормализованной схемой. Пример основных таблиц:
CREATE TABLE contacts (
id BIGSERIAL PRIMARY KEY,
company_id BIGINT REFERENCES companies(id),
name VARCHAR(255) NOT NULL,
email VARCHAR(255),
phone VARCHAR(50),
source VARCHAR(64),
responsible_id BIGINT REFERENCES users(id),
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE deals (
id BIGSERIAL PRIMARY KEY,
contact_id BIGINT REFERENCES contacts(id),
company_id BIGINT REFERENCES companies(id),
title VARCHAR(255) NOT NULL,
amount DECIMAL(14,2),
currency CHAR(3) DEFAULT 'RUB',
stage_id BIGINT REFERENCES pipeline_stages(id),
responsible_id BIGINT REFERENCES users(id),
closed_at DATE,
created_at TIMESTAMPTZ DEFAULT NOW()
);
API строится по RESTful-принципам. Пример ресурса сделок:
GET /api/deals?stage_id=2&responsible_id=5
POST /api/deals
PATCH /api/deals/{id}
DELETE /api/deals/{id}
POST /api/deals/{id}/move # смена стадии
{
"id": 1042,
"stage_id": 4,
"stage": { "id": 4, "name": "Переговоры" },
"updated_at": "2024-01-15T14:22:00Z",
"activity": {
"id": 3891,
"type": "stage_change",
"body": "Стадия изменена: Квалификация → Переговоры",
"user_id": 12
}
}
Воронка с drag-and-drop
Воронка продаж визуализируется как Kanban-доска. Используем библиотеку @dnd-kit для перетаскивания карточек между колонками. Optimistic update — ключевой приём: карточка мгновенно меняет позицию без ожидания ответа сервера. При ошибке откатываем.
import { DndContext, DragEndEvent, closestCenter } from '@dnd-kit/core';
import { SortableContext } from '@dnd-kit/sortable';
const Pipeline: React.FC<{ stages: Stage[]; deals: Deal[] }> = ({ stages, deals }) => {
const moveDeal = useMutation({
mutationFn: ({ dealId, stageId }) => api.patch(`/deals/${dealId}/move`, { stage_id: stageId }),
onMutate: async ({ dealId, stageId }) => {
await queryClient.cancelQueries({ queryKey: ['deals'] });
const prev = queryClient.getQueryData(['deals']);
queryClient.setQueryData(['deals'], (old: Deal[]) =>
old.map(d => d.id === dealId ? { ...d, stage_id: stageId } : d)
);
return { prev };
},
onError: (_, __, context) => queryClient.setQueryData(['deals'], context?.prev),
});
return (
<DndContext collisionDetection={closestCenter} onDragEnd={moveDeal.mutate}>
<div className="flex gap-4 overflow-x-auto p-4">
{stages.map(stage => (
<KanbanColumn key={stage.id} stage={stage}
deals={deals.filter(d => d.stage_id === stage.id)} />
))}
</div>
</DndContext>
);
};
Управление правами доступа
CRM требует гранулярных прав. В Laravel это реализуется через Policy-классы и глобальные скоупы модели.
class DealPolicy {
public function view(User $user, Deal $deal): bool {
if ($user->hasRole('admin')) return true;
if ($user->hasRole('team_lead')) {
return $deal->responsible->team_id === $user->team_id;
}
return $deal->responsible_id === $user->id;
}
}
class Deal extends Model {
public function scopeVisibleTo(Builder $query, User $user): Builder {
if ($user->hasRole('admin')) return $query;
if ($user->hasRole('team_lead')) {
return $query->whereHas('responsible', fn($q) =>
$q->where('team_id', $user->team_id)
);
}
return $query->where('responsible_id', $user->id);
}
}
Что входит в разработку кастомной CRM
В стоимость проекта включены:
- Техническое задание и интерактивный прототип интерфейса
- Разработка бэкенда (Laravel + PostgreSQL + Redis)
- Разработка фронтенда (React 18 + TypeScript)
- Интеграция с телефонией (Asterisk, Miko), email (SMTP/API), мессенджерами
- Документация API и пользовательская инструкция
- Обучение сотрудников (2-3 часа)
- Гарантийная поддержка 3 месяца после запуска
Дополнительно можем подключить мобильную версию (PWA или React Native) и настроить BI-аналитику.
Сроки и стоимость реализации
MVP с воронкой, карточками контактов/сделок, задачами и базовой аналитикой занимает 4–6 недель. Добавление интеграций (телефония, email), расширенных отчётов и ролей — ещё 3–4 недели. Мобильная версия — дополнительно 3–4 недели.
Стоимость рассчитывается индивидуально после анализа ваших бизнес-процессов. Свяжитесь с нами, чтобы обсудить проект и получить предварительную оценку. Закажите демо нашей CRM-архитектуры на ваших данных — это займёт не больше часа.







