Почему стоит разработать собственную PM-систему?
Мы разрабатываем системы управления проектами под ключ, когда готовые SaaS-продукты не подходят: отраслевая специфика, жёсткие требования к данным, интеграция с внутренними системами. Вместо Jira или Asana вы получаете инструмент, заточенный под ваш бизнес-процесс. Ниже — архитектура, кодовая база и сроки. Закажите оценку проекта, чтобы понять детали. За 10+ лет мы реализовали более 50 проектов — от модульных монолитов до распределённых систем.
Собственная PM-система решает три главные проблемы: нестандартные воркфлоу, которые нельзя перенастроить в готовом продукте; высокая стоимость лицензий при масштабировании; необходимость глубокой интеграции с корпоративным стеком. По нашим данным, экономия на лицензиях при 500+ пользователях достигает 60%, а сокращение времени на воркфлоу — 40%. Кастомная PM-система окупается в среднем за 12-18 месяцев. Свяжитесь с нами, чтобы получить консультацию.
Сравнение: кастомная PM-система vs Jira
| Параметр | Кастомная PM-система | Jira (SaaS) |
|---|---|---|
| Стоимость при 500+ пользователях | До 60% дешевле | Высокая годовая подписка |
| Гибкость воркфлоу | Любые переходы, guards, визуальный редактор | Только стандартные схемы, сложные кастомы дороги |
| Интеграции | Любые системы через API, OAuth, webhooks | Ограниченный набор, дополнительные плагины |
| Данные | Полный контроль, хранение у вас | На серверах вендора, экспорт ограничен |
| Производительность | Настраиваемая, до 10 000 одновременных пользователей | Зависит от тарифа, возможны лимиты |
Архитектура и модель данных
Центральные сущности: Project → Milestone → Task → Subtask. Поперечные: User, Team, Comment, Attachment, TimeLog, Activity. Связи: задача может принадлежать нескольким проектам через эпики, пользователь — разные роли, зависимости между задачами образуют граф.
Модульный монолит — правильный выбор для проектов до 50 000 активных пользователей. Микросервисы оправданы, когда отдельные компоненты масштабируются независимо. 90% систем PM строятся как модульный монолит и остаются им навсегда.
Event-driven внутри монолита. Переходы состояний, назначения, изменения дедлайнов — всё это события, триггерящие побочные эффекты (уведомления, дашборды, логи). Используем внутренний event bus: в Laravel Event::dispatch(), в Node.js — EventEmitter.
CREATE TABLE tasks (
id BIGSERIAL PRIMARY KEY,
project_id BIGINT NOT NULL REFERENCES projects(id),
parent_id BIGINT REFERENCES tasks(id),
path LTREE NOT NULL, -- PostgreSQL ltree: '1.5.23'
title VARCHAR(500) NOT NULL,
status task_status NOT NULL DEFAULT 'todo',
priority SMALLINT NOT NULL DEFAULT 2,
assignee_id BIGINT REFERENCES users(id),
due_date DATE,
estimate INTEGER, -- в минутах
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX tasks_path_gist ON tasks USING GIST (path);
CREATE INDEX tasks_project_status ON tasks (project_id, status);
Этот подход с ltree описан в документации PostgreSQL.
Зависимости между задачами:
CREATE TABLE task_dependencies (
task_id BIGINT REFERENCES tasks(id),
depends_on_id BIGINT REFERENCES tasks(id),
type dep_type NOT NULL,
PRIMARY KEY (task_id, depends_on_id)
);
Перед сохранением зависимости проверяем цикличность — обход графа в глубину или рекурсивный CTE.
Как реализовать воркфлоу и реалтайм?
Воркфлоу — главная причина разработки собственной системы. Подход: настраиваемые воркфлоу на уровне типа задачи. Каждый тип (Task, Bug, Epic) имеет собственную state machine с разными переходами и guards.
// Laravel + winzou/state-machine
'bug' => [
'graph' => 'bug_workflow',
'property_path' => 'status',
'states' => ['new', 'triaged', 'in_progress', 'in_review', 'resolved', 'closed', 'reopened'],
'transitions' => [
'triage' => ['from' => ['new'], 'to' => 'triaged'],
'start' => ['from' => ['triaged'], 'to' => 'in_progress'],
'review' => ['from' => ['in_progress'], 'to' => 'in_review'],
'resolve' => ['from' => ['in_review'], 'to' => 'resolved'],
'close' => ['from' => ['resolved'], 'to' => 'closed'],
'reopen' => ['from' => ['resolved', 'closed'], 'to' => 'reopened'],
],
'callbacks' => [
'after' => [
'notify_assignee' => ['on' => ['start', 'review'], 'do' => 'NotifyAssigneeCallback'],
],
],
],
Конфигурация воркфлоу хранится в базе, редактируется через визуальный конструктор.
Пошаговая настройка state machine
- Определите состояния и переходы для каждого типа задачи.
- Создайте guards для проверки прав и условий.
- Зарегистрируйте callbacks для уведомлений и аудита.
- Протестируйте все переходы через unit-тесты.
Реалтайм-обновления. Стек: Laravel Reverb, Soketi или Ably. Приватные каналы на уровне проекта и задачи. Presence-каналы показывают, кто просматривает задачу. Оптимистичные обновления на фронте через React Query.
// Frontend: Laravel Echo + React
const channel = window.Echo.private(`project.${projectId}`);
channel
.listen('.task.updated', (e) => {
queryClient.invalidateQueries(['tasks', e.task.id]);
})
.listen('.comment.created', (e) => {
setComments(prev => [...prev, e.comment]);
});
Какие представления и тайм-трекинг нужны?
Минимальный набор: Kanban-доска (drag-and-drop через @dnd-kit/core, виртуализация при 50+ карточках), список с вложенностью (tree-table, серверная сортировка), диаграмма Ганта (frappe-gantt или @dhtmlx/gantt, отображение зависимостей), календарный вид (FullCalendar).
Тайм-трекинг. Глобальный таймер в UI, хранит состояние в localStorage, синхронизирует с сервером. Данные логов хранятся в таблице с автоматически вычисляемым duration. При закрытии вкладки — beforeunload сохраняет текущий интервал.
Как реализовать роли, уведомления и поиск?
RBAC с project-scope ролями. System roles (admin, member) и project roles (owner, manager, developer, viewer, external). Используем spatie/laravel-permission с привязкой к модели Project. Гостевой доступ через отдельные токены.
Уведомления — многоканальные: email, push, in-app, Slack. Пользователь настраивает подписки в профиле. Технически: очередь через Laravel Queues / BullMQ, батчинг email-писем.
Поиск. PostgreSQL FTS через tsvector достаточен до 200 000 задач. Для большего объёма — OpenSearch.
ALTER TABLE tasks ADD COLUMN search_vector TSVECTOR;
UPDATE tasks SET search_vector =
to_tsvector('russian', coalesce(title, '') || ' ' || coalesce(description, ''));
CREATE INDEX tasks_search ON tasks USING GIN(search_vector);
Как обеспечить производительность PM-системы?
Проблема N+1 и её решение
N+1 query на списке задач решается eager loading. Денормализация счётчиков прогресса. Cursor-based пагинация для больших списков.
Интеграции с Git-репозиториями, CI/CD, Slack/Teams, Confluence/Notion, Google Calendar строятся на OAuth 2.0, webhooks и REST API. Токены шифруются.
Что входит в работу
После завершения проекта вы получаете:
- Полный исходный код системы с комментариями
- Документацию по архитектуре, модели данных, API
- Docker-конфигурации для развёртывания
- Инструкции по эксплуатации и резервному копированию
- Обучение команды (до 3 сессий)
- Гарантийная поддержка 3 месяца
Ориентировочные сроки
| Этап | Содержание | Длительность |
|---|---|---|
| Проектирование | Воркфлоу, роли, интеграции, wireframes | 3–4 нед. |
| Ядро системы | Проекты, задачи, воркфлоу, права | 6–8 нед. |
| UI: список + Kanban | Базовые представления | 4–5 нед. |
| Реалтайм + уведомления | WebSocket, email, push | 2–3 нед. |
| Gantt + календарь | Сложные представления | 3–4 нед. |
| Тайм-трекинг | Таймер, логи, отчёты | 2 нед. |
| Интеграции (2–3 шт.) | Git + Slack + Calendar | 3–4 нед. |
| Тестирование, запуск | E2E, нагрузочное | 2–3 нед. |
Полный проект: 22–32 недели. Итерационный запуск через 10–12 недель — core-функционал без Gantt и интеграций. Закажите оценку проекта и получите оптимальный план.
Как мы гарантируем качество
Наш опыт — 10+ лет в разработке корпоративных систем. Каждый проект проходит ревью архитектуры, нагрузочное тестирование и аудит безопасности перед запуском. Гарантируем стабильную работу под нагрузкой до 10 000 одновременных пользователей. Свяжитесь с нами для получения консультации. Получите расчет стоимости вашего проекта.







