Совершение обходов на предприятиях
Go to file
2026-10-22 14:37:09 +05:00
apps Update passport.client.ts 2026-10-22 14:37:09 +05:00
docker Delete Caddyfile 2026-10-22 11:09:40 +05:00
packages/shared init-commit 2026-10-22 10:53:02 +05:00
scripts init-commit 2026-10-22 10:53:02 +05:00
tiles init-commit 2026-10-22 10:53:02 +05:00
.env.example init-commit 2026-10-22 10:53:02 +05:00
.env.production.example Update .env.production.example 2026-10-22 11:09:44 +05:00
.gitignore init-commit 2026-10-22 10:53:02 +05:00
docker-compose.override.yml init-commit 2026-10-22 10:53:02 +05:00
docker-compose.prod.yml Update docker-compose.prod.yml 2026-10-22 11:09:42 +05:00
docker-compose.yml init-commit 2026-10-22 10:53:02 +05:00
package-lock.json init-commit 2026-10-22 10:53:02 +05:00
package.json init-commit 2026-10-22 10:53:02 +05:00
README.md Update README.md 2026-10-22 11:09:38 +05:00

Aspans · Обходы

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

Стек: React 18 + TypeScript + MUI (Vite, PWA), NestJS 11 + TypeORM, PostgreSQL 17 + PostGIS, SeaweedFS (S3 API) для медиа, tileserver-gl для своей карты Казахстана. Всё поднимается через docker compose.

Запуск

cp .env.example .env
./scripts/build-tiles.sh
docker compose up -d --build

Откройте http://localhost:8090 и войдите владельцем платформы — учётной записью паспорта Aspans из PLATFORM_ADMIN_USERNAMES (по умолчанию admin, с его паролем из паспорта). Компанию можно зарегистрировать там же («Организации») или самостоятельно на странице входа → «Зарегистрировать».

Перед реальным использованием смените в .env JWT_SECRET, POSTGRES_PASSWORD, S3_SECRET_KEY.

Паспорт Aspans, Aspans ID и Kafka

Люди и пароли живут в паспорте Aspans, «Обходы» — платформа patrol в нём. Организации, роли и доступ к объектам — свои, внутри «Обходов».

  1. В паспорте через интерфейс «Платформы и группы» создать платформу patrol (без домена) и её группу patrol_user; выложить метод v1/users/findUsers.
  2. В .env: PASSPORT_URL, PASSPORT_PLATFORM_TOKEN (= PLATFORM_SALT паспорта), ASPANS_ID_BASE_URL. Локально паспорт — контейнер в docker-сети aspans (см. docker-compose.override.yml), на сервере — https://passport.aspans.com.
  3. Синхронизация через Kafka (как у symfony): в проекте kafka make service NAME=platform-patrol и ./bin/service.sh grant-shared platform-patrol aspans., пароль — в KAFKA_PASSWORD, затем docker compose --profile kafka up -d users_sync.

Как это работает:

  • Вход — логином и паролем паспорта или через Aspans ID (SSO). Если человек уже вошёл в другой сервис Aspans, «Обходы» входят тихо (prompt=none). Пускают только тех, кто заведён в «Обходах» и состоит в организации с ролью; владельцы платформы — по PLATFORM_ADMIN_USERNAMES.
  • Новый сотрудник заводится в паспорте (createOrGetUserSimple, группа patrol_user). Существующий — ищется в паспорте (findUsers, контакты замаскированы) и привязывается к платформе. Один человек — одна организация в «Обходах».
  • Профиль (ФИО, email, телефон) правится в обе стороны через aspans.users.changed: правки из «Обходов» уходят событием UserProfileUpsertedEvent (очередь users_sync_pending), правки из паспорта применяются по версии (LWW). Пароль меняется сразу в паспорте.
  • Удаление: убрали с платформы в паспорте (UserRemovedFromPlatformEvent) — доступ закрывается, сессии гаснут, человек пропадает из сотрудников; запись остаётся для отчётов. «Убрать из организации» в «Обходах» отвязывает человека от платформы в паспорте.

build-tiles.sh один раз скачивает OSM-данные Казахстана и собирает tiles/kazakhstan.mbtiles (planetiler, нужно ~4 ГБ RAM, несколько минут). Без этого файла сервис работает, но карта будет пустой. Повторный запуск обновляет карту, после него — docker compose restart tiles.

Сервер

Сервис отдаётся по http на WEB_PORT (8090). HTTPS делает прокси перед сервером. Пока его нет, на телефонах охранников не работают геолокация и офлайн-режим PWA: браузеры дают их только по HTTPS.

  1. Нужен docker compose v2 (не старый docker-compose 1.x). Проверка сервера, только чтение: ssh user@IP 'bash -s' < scripts/server-check.sh.
  2. Склонировать репозиторий, cp .env.production.example .env, заполнить.
  3. Карту на сервере не собирать: скопировать готовый файл tiles/kazakhstan.mbtiles (~0,5 ГБ) в tiles/ проекта. Сборка planetiler требует ~4 ГБ RAM и качает исходные данные.
  4. docker compose up -d --build (COMPOSE_FILE из .env сам подключит docker-compose.prod.yml).
  5. В Aspans ID у клиента patrol разрешить redirect_uri ${WEBSITE_URL}/auth/sso/callback.

Наружу открыт только web на WEB_PORT. База слушает 127.0.0.1, api, tiles и s3 доступны только внутри docker.

Порты

Что Адрес
Веб и API http://localhost:8090 (/api/…, карта — /tiles/…)
PostgreSQL localhost:5470

Разработка без Docker для фронта

npm install
docker compose up -d db s3 tiles api web
npm run dev:web

Vite на http://localhost:5173 проксирует /api и /tiles на :8090.

Устройство

apps/api      NestJS: auth, organizations, users/roles, sites, routes, schedules, rounds, media, reports, webhooks
apps/web      React: панель управления и экран сотрудника /guard (PWA, офлайн-очередь в IndexedDB)
packages/shared  права, статусы, флаги отметок, события вебхуков — общие для фронта и API
docker/       Dockerfile'ы и nginx
scripts/      сборка тайлов карты
  • Обходы создаются из графиков на 7 дней вперёд (cron раз в час) для дней, где назначены дежурные. Начать обход может любой дежурный этого дня.
  • Незакрытые к концу окна обходы становятся «Пропущен» или «Не полностью». Отметки, снятые офлайн до конца окна и пришедшие позже, пересчитывают статус.
  • GPS только записывается: отметку «я тут» сотрудник ставит на карте, координаты телефона сохраняются рядом. Расхождения видны в отчёте флагами и ничего не блокируют.
  • Медиа грузятся кусками по 8 МБ через API в SeaweedFS и докачиваются после обрыва связи.
  • Вебхуки: POST с JSON, подпись X-Patrol-Signature: sha256=<HMAC тела секретом>; события round.completed, round.partial, round.missed, visit.issue.
  • Реквизиты по БИН — из pk.uchet.kz: публичный поиск без токена даёт название, адрес и руководителя. С токеном из личного кабинета pk.uchet.kz (UCHET_KZ_TOKEN в .env) добавляются телефон и email. Выключить обращения к uchet.kz: UCHET_KZ_DISABLED=true.