8.2 KiB
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 в нём. Организации, роли и доступ к объектам — свои, внутри «Обходов».
- В паспорте через интерфейс «Платформы и группы» создать платформу
patrol(без домена) и её группуpatrol_user; выложить методv1/users/findUsers. - В
.env:PASSPORT_URL,PASSPORT_PLATFORM_TOKEN(= PLATFORM_SALT паспорта),ASPANS_ID_BASE_URL. Локально паспорт — контейнер в docker-сетиaspans(см.docker-compose.override.yml), на сервере —https://passport.aspans.com. - Синхронизация через 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.
- Нужен
docker composev2 (не старыйdocker-compose1.x). Проверка сервера, только чтение:ssh user@IP 'bash -s' < scripts/server-check.sh. - Склонировать репозиторий,
cp .env.production.example .env, заполнить. - Карту на сервере не собирать: скопировать готовый файл
tiles/kazakhstan.mbtiles(~0,5 ГБ) вtiles/проекта. Сборка planetiler требует ~4 ГБ RAM и качает исходные данные. docker compose up -d --build(COMPOSE_FILEиз.envсам подключитdocker-compose.prod.yml).- В 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.