Разработка системы управления проектами (Project Management)

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Разработка системы управления проектами (Project Management)
Сложная
от 2 недель до 3 месяцев
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Разработка системы управления проектами (Project Management)

Системы управления проектами делятся на два полюса: универсальные SaaS-продукты вроде Jira или Asana и самописные решения под конкретный процесс. Первые подходят большинству, но когда процесс нестандартный — отраслевая специфика, жёсткие требования к данным, интеграция с внутренними системами — разработка собственной системы становится экономически обоснованной. Задача этой страницы — показать, что именно строится и в каком порядке.

Архитектурные решения

Система управления проектами — это прежде всего сложная доменная модель. Центральные сущности: Project → Milestone → Task → Subtask, плюс поперечные: User, Team, Comment, Attachment, TimeLog, Activity. Связи между ними нетривиальны: задача может принадлежать нескольким проектам через эпики, пользователь может иметь разные роли в разных проектах, зависимости между задачами образуют граф (а не дерево).

Два принципиальных архитектурных выбора на старте:

Монолит vs микросервисы. Для проектов до 50 000 активных пользователей монолит с чёткими доменными границами — правильный выбор. Микросервисы оправданы, когда отдельные компоненты масштабируются независимо: например, движок уведомлений под нагрузкой отличается от аналитики. На практике 90% систем PM строятся как модульный монолит и остаются им навсегда.

Event-driven внутри монолита. Переходы состояний задач, назначение исполнителей, изменение дедлайнов — всё это события, которые должны тригерить побочные эффекты (уведомления, обновление дашбордов, запись в лог активности) без прямой связи между модулями. Используем внутренний event bus — в Laravel это Event::dispatch(), в Node.js — EventEmitter или библиотека eventemitter2.

Модель данных

Схема должна поддерживать иерархию задач произвольной глубины. Неочевидное решение — adjacency list с материализованным путём вместо чистого Nested Sets: проще в записи, достаточно быстро в чтении при индексации по path.

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 позволяет делать запросы вида «все подзадачи задачи 5» одним запросом: WHERE path <@ '1.5'.

Зависимости между задачами — отдельная таблица:

CREATE TABLE task_dependencies (
  task_id       BIGINT REFERENCES tasks(id),
  depends_on_id BIGINT REFERENCES tasks(id),
  type          dep_type NOT NULL,     -- 'blocks', 'required_by', 'related'
  PRIMARY KEY (task_id, depends_on_id)
);

Перед сохранением зависимости проверяем цикличность — обход графа в глубину или запрос через WITH RECURSIVE.

Статусные машины и воркфлоу

Воркфлоу — главная причина, по которой компании разрабатывают собственную PM-систему. Jira позволяет настраивать воркфлоу, но это медленно и дорого в сопровождении.

Подход: настраиваемые воркфлоу на уровне типа задачи. Каждый тип (Task, Bug, Epic, Story, CR) имеет собственную 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'],
        ],
    ],
],

Конфигурация воркфлоу хранится в базе данных (JSON-поле), редактируется через визуальный конструктор — drag-and-drop редактор состояний, аналогичный тому, что есть в Jira, но проще.

Реалтайм-обновления

PM-система без реалтайма — это система для работы в одиночку. Когда кто-то меняет статус задачи или добавляет комментарий, остальные участники должны видеть изменения без перезагрузки страницы.

Стек реалтайма:

  • WebSocket-сервер: Laravel Reverb (собственное решение Laravel), Soketi (self-hosted совместимый с Pusher) или Ably для managed-решения
  • Каналы: приватные каналы на уровне проекта (private-project.{id}) и на уровне задачи (private-task.{id})
  • Presence-каналы: показывают, кто сейчас просматривает задачу — важно для совместного редактирования
// 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]);
  });

Оптимистичные обновления на фронте: пользователь меняет статус задачи — UI обновляется мгновенно, запрос уходит в фоне. При ошибке — откат. Реализуется через React Query useMutation с onMutate / onError / onSettled.

Просмотры задач: Kanban, список, Gantt, календарь

Разные команды работают по-разному. Минимальный набор представлений:

Kanban-доска: колонки = статусы воркфлоу. Drag-and-drop через @dnd-kit/core — более производительный аналог react-beautiful-dnd. При перетаскивании между колонками вызывается transition API. Важно: виртуализация списков задач в колонках при количестве > 50 карточек (react-virtual или TanStack Virtual).

Список с вложенностью: tree-table с раскрывающимися подзадачами. Сортировка и фильтрация на сервере — не тащить всё дерево на клиент.

Диаграмма Ганта: самый сложный компонент. Строим на базе frappe-gantt или @dhtmlx/gantt (платная, но мощная). Ключевая сложность — отображение зависимостей между задачами стрелками и автоматический пересчёт дат при изменении длительности.

Календарный вид: FullCalendar с кастомным рендером событий. Задачи с дедлайном — точка, задачи с диапазоном дат — полоса.

Тайм-трекинг

Встроенный тайм-трекинг нужен не всем, но когда нужен — реализуется как отдельный модуль:

CREATE TABLE time_logs (
  id          BIGSERIAL PRIMARY KEY,
  task_id     BIGINT NOT NULL REFERENCES tasks(id),
  user_id     BIGINT NOT NULL REFERENCES users(id),
  started_at  TIMESTAMPTZ NOT NULL,
  stopped_at  TIMESTAMPTZ,
  duration    INTEGER GENERATED ALWAYS AS (
                EXTRACT(EPOCH FROM (stopped_at - started_at))::INTEGER
              ) STORED,
  description TEXT
);

Таймер — глобальный элемент UI, не привязанный к конкретной странице. Хранит состояние {taskId, startedAt} в localStorage + синхронизирует с сервером. При закрытии вкладки — beforeunload сохраняет текущий интервал.

Права доступа и роли

Гранулярные права — сложная часть. Модель: RBAC с project-scope ролями.

System roles: admin, member
Project roles: owner, manager, developer, viewer, external

Каждая проектная роль имеет набор permissions: task:create, task:assign, task:delete, project:settings, member:invite и т.д. Используем spatie/laravel-permission с кастомными scoped ролями (привязка роли к модели Project, а не глобально).

Гостевой доступ: внешние пользователи (клиенты, подрядчики) видят только выбранные задачи или только читают. Реализуется через отдельный тип токена с ограниченным набором permissions.

Уведомления

Многоканальные уведомления с настройкой подписок:

Событие Email Push In-app Slack
Задача назначена мне опционально
Дедлайн через 24ч
Комментарий с упоминанием опционально
Смена статуса опционально
Изменение дедлайна

Пользователь управляет подписками в настройках профиля. Технически: очередь уведомлений через Laravel Queues / BullMQ, батчинг email-уведомлений (не отправлять 50 писем, если за 5 минут произошло 50 событий — группируем в одно дайджест-письмо).

Поиск

Глобальный поиск по задачам, проектам, комментариям, файлам. Требования: мгновенный отклик, морфология, поиск по содержимому комментариев.

PostgreSQL FTS через tsvector достаточен до ~200 000 задач:

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);

При большем объёме или необходимости поиска по вложениям (PDF, DOCX) — OpenSearch с Apache Tika для извлечения текста из файлов.

Аналитика и отчёты

Velocity: средняя скорость закрытия задач по спринтам. График в виде burndown chart.

Bottleneck analysis: задачи, которые дольше всего висят в конкретном статусе. SQL-запрос через оконные функции или предварительно агрегированные данные в отдельной таблице task_status_durations.

Отчёт по времени: кто сколько залогировал, по каким проектам. Экспорт в CSV/XLSX через maatwebsite/excel или xlsxwriter.

Кастомные дашборды: виджеты с drag-and-drop расстановкой, сохранение конфигурации в профиле пользователя. Каждый виджет — независимый запрос с кешированием (Redis, TTL 5 минут).

Интеграции

Стандартный набор интеграций для корпоративного PM:

  • Git-репозитории (GitHub, GitLab, Bitbucket): автосмена статуса задачи при упоминании в commit message (closes #123), linkback из PR в задачу
  • CI/CD (GitHub Actions, GitLab CI): статус деплоя в карточке задачи
  • Slack / Teams: уведомления, создание задач из сообщений через slash-команды
  • Confluence / Notion: двусторонняя ссылка задача ↔ документация
  • Calendars: синхронизация дедлайнов с Google Calendar / Outlook через CalDAV

Интеграции строятся через OAuth 2.0 (авторизация) + webhooks (входящие события) + REST/GraphQL API (исходящие запросы). Храним токены зашифрованными (encrypt() в Laravel, AES-256-CBC).

Производительность

Узкие места, которые появляются при росте:

N+1 на списке задач: у каждой задачи — assignee, метки, последний комментарий. Решение: eager loading с with() в Eloquent, DataLoader-паттерн в GraphQL.

Пересчёт прогресса проекта: если считать COUNT(completed) / COUNT(*) при каждом запросе — медленно. Денормализуем: поле completed_tasks_count в таблице projects, обновляется через DB-триггер или application-level событие.

Большие списки задач: пагинация cursor-based вместо offset-based. Cursor по (created_at, id) даёт стабильное поведение при одновременном добавлении новых задач.

Сроки

Этап Содержание Длительность
Проектирование Воркфлоу, роли, интеграции, 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 и интеграций. Системы, которые строятся одним большим релизом, как правило, не доходят до продакшена.