Skip to content

Repository files navigation

hackaton_opt

Сервис планирования маршрутов выездных инженеров: PostgreSQL + FastAPI + Vue/Leaflet, self-hosted Valhalla для дорожной сети и R5 для общественного транспорта.

./deploy/local.sh            # поднять всё локально одной командой
./deploy/deploy.sh           # развернуть или обновить сервер (настройки — deploy/deploy.env)

Развёртывание описано в deploy/README.md: локально — deploy/LOCAL.md, на сервере с доменом и сертификатом — deploy/SERVER.md. Для разработки можно поднимать compose напрямую:

docker compose --profile transit up
Сервис Порт Что это
frontend 5173 Рабочее место диспетчера: заявки, бригады, планы и их пересчёт
mobile 5175 Приложение бригады: маршрут дня, отметки «выехали / на месте / выполнено»
backend 8000 API, GET /api/v1/health/db для проверки
postgres 5432 БД
valhalla 8002 Маршрутизация по данным OpenStreetMap
r5 8003 Общественный транспорт по OSM и локальному GTFS

Первый запуск долгий: Valhalla скачивает экстракт OSM по ЦФО (~877 МБ), после чего R5 вырезает Москву и область и строит транспортный граф. Дальнейшие старты используют данные из Docker volumes.

Вход: первый администратор — admin, пароль из переменной ADMIN_PASSWORD (cp .env.example .env, см. комментарии в файле). Не задана — будет admin, о чём бэкенд предупреждает в журнале; сменить можно и в «Справочники» -> «Пользователи». Там же администратор заводит диспетчеров: диспетчер привязан к офису и видит только его заявки, бригады и планы. Бригады офиса — в «Справочники» → «Бригады» (и администратору, и диспетчеру): там же бригаде задают логин и пароль для мобильного приложения (http://localhost:5175).

  • Схема БД, миграции (накат — db/apply_migrations.sh) и допущения при наполнении — db/README.md.
  • Структура бэкенда, расчёт расстояний и замеренные особенности — backend/README.md.
  • Фронтенд — frontend/README.md.
  • Пилотный сборщик GTFS и сервис R5 (автобус + метро) — transit/README.md.
  • Приложение бригады — mobile/README.md.

Подготовка к проверке на обезличенных данных

Шесть исходных CSV в Обезличивание/ проверяются без подключения к БД:

python scripts/audit_anonymized.py

Команда сверяет синтетические заявки с контрольными строка к строке по типу, окну, району и адресу без номера квартиры; проверяет даты, повторы номеров и наличие адреса офиса. Отчёт содержит только агрегаты и номера проблемных строк, без адресов и номеров заявок. Ненулевой код выхода означает ошибку структуры, а повторы номеров в контрольном файле показываются отдельно: контрольное распределение нельзя загружать как входной план. Оно нужно для последующего сравнения результатов.

В исходных файлах нет координат, смен, навыков и транспорта бригад. Перед проверкой на полном сценарии потребуется подготовить эти данные и отдельно зафиксировать правила геокодирования адресов. Все исходные окна относятся к 17 августа 2026 года. В текущем GTFS метро покрывает этот день; автобусные шаблоны доступны с 1 августа 2026 года, но до сентябрьских снимков они являются ретроспективной оценкой, а не точным историческим расписанием. Это ограничение учитываем при сравнении с контролем.

Как бригады ведут день

  1. Диспетчер строит и утверждает план дня. Невлезшие заявки «Новыми» без решения не остаются: при утверждении второй расчёт с раскрытыми окнами сразу предлагает их клиентам время, диспетчер отмечает ответ по каждой (согласен, перенести на другой день, отменить, не дозвонились), и день считается заново — новым черновиком со ссылкой «с решениями из №…». Его смотрят и утверждают отдельно. Перенесённая заявка войдёт в план своего дня. Пока по невлезшим нет решений, сервер черновик не утвердит.

  2. Бригада входит в приложение (mobile) и видит свой маршрут; по ходу дня отмечает «Выехали» (заявка «В пути»), «На месте» («В работе»), «Выполнено» или «Не выполнить» с причиной. Статус заявки и время отметки уходят на сервер, следующую заявку не начать, пока не закрыта прошлая.

  3. Диспетчер на карте плана в режиме «Факт» видит, где бригады, что выполнено и кто отстаёт; у плана появляется «!» — если заявки сняли, пришли новые или бригада не успевает к окну.

  4. «Пересчитать с текущего момента»: сначала пробный расчёт показывает заявки, на которые уже не успеваем, — по каждой выбирают новое окно или отмену; затем выполненное и начатое остаётся за бригадами, бригады стартуют оттуда, где они сейчас, остальное раскладывается заново. Утверждённый пересчёт заменяет план — бригады сразу видят новый маршрут; заявки, которым не нашлось места, возвращаются в «Новые»: сдвинуть окно или отменить.

    Пересчёт считается не «прямо сейчас», а на выезд через REPLAN_LEAD_MINUTES (15 минут) — запас на сам расчёт и обзвон клиентов — и в этот момент вступает в силу сам, без кнопки: в списке планов видно «вступит в силу в 12:15 · через 7 мин». Эти минуты день идёт своим чередом: бригады едут по действующему плану, а выезд открыт туда, куда ведёт и пересчёт (на остальные заявки — «Ждите нового плана»). Выехала бригада раньше по новому маршруту, доехала, закрыла заявку — всё в порядке.

    Если к этому моменту появились новые вводные — заявка, которой пересчёт не видел, отмена, бригада выбилась из плана или уехала вопреки расчёту, — пересчёт в силу не вступает: он помечается недействительным с причиной, у действующего плана загорается «!» с этим текстом, бригады продолжают ехать по нему, и день считают заново — уже с новыми вводными. Утвердить пересчёт можно и руками, раньше срока; сам расчёт система не перезапускает.

Группой: отметить галочками и изменить или удалить

В таблицах «Заявки» и «Исполнители» первая колонка — отметки: галочка в строке, Shift-клик отмечает диапазон, а галочка в строке фильтров отмечает все отобранные строки (отбор и есть отбор — поэтому она там же, где фильтры). Отмеченные строки подсвечены, над таблицей появляется панель «Отмечено: N · Изменить · Удалить».

  • Изменить — окно, где каждое поле включается своей галочкой: меняется только то, что отмечено, остальное у каждой строки остаётся своим. Заявки: статус, перенос на другой день (время окна сохраняется), окно, работа на месте, тип работ, приоритет, транспорт. Смены: перенос на день, часы смены, транспорт, навыки, выезд из офиса. Статус — не поле, а переход: он доступен и у заявки, которая уже в плане, а список переходов появляется, только когда статус у всех отмеченных один. Остальные поля правятся целиком или никак: если хоть одну заявку менять нельзя («В плане», «Выполнена») или бригада после переноса окажется в двух сменах сразу, сервер объяснит и не тронет ничего.
  • Удалить — удаляется всё, что можно, а по остальному приходит список причин: «Удалено: 18. Не удалось удалить: 2 — заявка №12 в плане…». Одна занятая строка не отменяет удаление остальных.
  • На карте отмеченные видно сразу: они в синем кольце, в легенде — «отмечено: N» (и сколько из них скрыто фильтрами). Остальные точки остаются как есть — по ним видно обстановку вокруг выбранных. При переходе на карту страница сама прокручивается к ней, сколько бы плашек ни висело сверху. Панель действий на карте та же, что над таблицей. Сами точки окрашены по статусу заявки — теми же цветами, что плашки в таблице; авария — красная обводка точки. По клику на точку открывается карточка, из неё — «Открыть в плане».
  • Сбросить в строке фильтров — одна кнопка на всё, чем сужен список: снимает и фильтры, и отметки.

Оборудование бригад

Заявке может требоваться оборудование — роутер, ТВ-приставка. Сколько бригада увезёт, зависит от транспорта: справочник «Справочники» → «Оборудование», таблица «Сколько увозит бригада» (пары «транспорт × оборудование», db/init/051).

Выдача считается по плану дня. На вкладке планов у открытого плана есть кнопка «Оборудование»: по заявкам бригады видно, сколько ей нужно (x0), и предлагается

выдать = min(сколько увезёт её транспорт, x0 + запас)

Запас — общая настройка «Запас оборудования, шт» в «Система» → «Состояние»: он нужен на брак и на заявки, которые появятся днём. Числа диспетчер правит и утверждает; больше предела транспорта сервер не примет. Утверждение записывает запас смен, и дальше пересчёты считают уже от него: то, что бригада израсходовала или везёт к заявке, зафиксированной на момент выезда T+15, из остатка вычитается.

Решатели маршрутов

План дня можно посчитать тремя способами, выбор — в окне расчёта:

  • cuOpt — оптимизация на видеокарте NVIDIA;
  • OR-Tools — та же постановка задачи (приоритеты, ярусы, окна, цена бригады, вес пробега), но поиск на процессоре: работает там, где видеокарты нет;
  • Базовый — контрольный алгоритм ТЗ: первый подходящий исполнитель, без перестановок.

У cuOpt и OR-Tools общий вход и общий выход, поэтому дальше всё одинаково: проверка расписания общественного транспорта по R5, сохранение плана и маршруты. Планы разных решателей сравниваются на вкладке «Планы» → «Сравнение планов».

Кеш времени в пути R5

Матрица общественного транспорта и проверка расписания по каждому плечу — самые долгие шаги расчёта. Ответы R5 хранятся в базе (travel_cache) по паре точек и времени суток выезда и переиспользуются: утверждение черновика, пробный пересчёт → пересчёт и повторные расчёты берут их оттуда, а числа в расчёте остаются такими же, как без кеша. Записи старше 7 дней удаляются раз в сутки, при смене расписания GTFS — все; сбросить вручную можно в «Система» → «Состояние». Подробно — docs/algoCachV1.md.

Там же, в «Система» → «Состояние», есть очистка перед показом: она удаляет всё наработанное — заявки и факты, планы с маршрутами и назначениями, журнал расчётов, отметки бригад и смены — оставляя справочники и учётки. Доступна только администратору и подтверждается словом «УДАЛИТЬ»: отменить очистку нельзя.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages