Из чего состоит система

> Кратко. ТГИД — это веб-сервер Nuxt, API на FastAPI, воркеры Celery с очередью в Redis, базы PostgreSQL/PostGIS (база каждого города, общая база пользователей и справочник sprav), GeoServer и martin для тайлов карты. Снаружи всё закрывает nginx. Ниже — кто к кому обращается и какие порты заданы в коде по умолчанию.

Читаю как

Схема

Браузер ──https──► nginx ─┬─► веб Nuxt (SSR, служба на город) ──► GeoServer (слои, стили; сервер веба)
                          ├─► API FastAPI  /city/<код>/…  ──┬─► PostgreSQL: база города, UsersDB, sprav
                          │                                 ├─► Redis (очереди, статусы задач, файлы выгрузок)
                          │                                 ├─► движок водопровода (HTTP)
                          │                                 └─► Claude API, Open-Meteo, Overpass (по флагам)
                          ├─► GeoServer /geoserver/…  (проверка входа: auth_request → API /auth/check)
                          └─► martin  /geoserver/tiles/… (тайлы сети из функций PostGIS, та же проверка)

Redis ◄── воркеры Celery (очереди tgid.<город>) ──► база города; расчёт — отдельный процесс heatnet / sety
Шлюз телеметрии (OPC UA) ──► API /api/v2/telemetry/readings (ключ API v2)

Компоненты

Компонент Что делает Где в коде Порт по умолчанию в коде
Веб (Nuxt, SSR) Страница карты, окна, справка. Сервер веба ещё собирает каталог слоёв GeoServer (/api/geoserver-layers) и отдаёт заголовки защиты от чужих фреймов репозиторий веба: pages/, components/, server/ 3000 (Nitro, переменная PORT)
API (FastAPI, uvicorn) Все данные сети, права, журналы, выгрузки, постановка задач в очередь itwin-api: main.py, routers/, database/ 8011 при запуске python main.py; у служб порт задаёт команда uvicorn
Воркеры Celery Расчёты сети, теплопотери, износ, фоновые выгрузки, запекание статичных тайлов worker.py —
Redis Брокер и результаты Celery, статусы задач, по умолчанию — и файлы выгрузок REDIS_ADDR 6379
PostgreSQL/PostGIS — база города Сеть, расчёты (us_out, ut_out…), журналы, таблицы веба (tgid_*), фото нарядов database/connect.py 5432
PostgreSQL — UsersDB Пользователи (users), права (user_permissions), журнал действий (activity_log); одна на все города database/models.py, миграции migrations/ (alembic) 5432
PostgreSQL — sprav Справочники расчёта (нормы, трубы). Нет базы — движок берёт CSV из sety/sprav heatnet/io/reader.py, database/heat_losses_norm.py 5432
GeoServer Слои карты (WMS/WMTS/MVT), стили, карточки по клику (WFS) вне репозиториев; доступ — nginx, server/utils/geoserverInternal.ts 8085 в конфигурации nginx (scripts/nginx/tgid-geoserver-auth.conf)
martin Векторные тайлы участков, узлов и зданий из функций tgid_mvt_* базы города scripts/martin/ в API 3005 (install-martin.ps1)
Движок heatnet Гидравлический и тепловой расчёт; ядро на Rust для тяжёлых частей heatnet/, native/heatnet_core — (процесс на расчёт)
Движок водопровода Расчёт EPANET (WNTR) в отдельном процессе со своей средой Python water_engine/service.py 8070
Шлюз телеметрии Читает теги OPC UA и шлёт показания в API scripts/telemetry/opcua_gateway.py —
nginx HTTPS, пути городов, проверка входа для GeoServer и martin, кеш тайлов конфигурация сервера; образцы — scripts/nginx/ в вебе 443

Кто к кому обращается

  • Браузер → веб. Страница и скрипты. Адрес API браузер берёт из NUXT_PUBLIC_MAP_API_BASE_URL и ходит в API напрямую через nginx, а не через сервер веба.
  • Браузер → API. Каждый запрос с токеном Authorization: Bearer. Живая карта получает изменения потоком SSE (/api/v1/live/stream).
  • Браузер → GeoServer и martin. Тайлы и карточки слоёв. nginx пропускает запрос, только если API на /auth/check подтвердил сессию по cookie tgid_gs. Её ставит API в ответ на /auth/me, который веб запрашивает после входа.
  • Сервер веба → GeoServer. Каталог слоёв, стили, атрибуты. Публичный /geoserver закрыт входом, поэтому сервер веба идёт по внутреннему адресу GEOSERVER_INTERNAL_URL.
  • API → Redis → воркер. API кладёт задачу в очередь своего города tgid.<код>. Воркер берёт её, открывает базу города и запускает расчёт отдельным процессом: python -m heatnet.cli или старый sety/ww.py.
  • API → движок водопровода. HTTP на WATER_ENGINE_URL с секретом WATER_ENGINE_TOKEN. Движок ничего не хранит: модель приходит в запросе.
  • API → внешние службы. Claude API — только при AI_ENABLED и ключе. Open-Meteo — прогноз погоды (WEATHER_PROVIDER). Overpass — социальные объекты из OSM (OVERPASS_URL). Вебхуки — на адреса подписчиков.
  • Шлюз телеметрии → API. POST /api/v2/telemetry/readings с ключом API v2. Если связи нет, пачки копятся в буфере шлюза.

Что работает в фоне внутри API

При запуске и затем по таймеру каждый процесс API делает следующее:

  • доводит схему базы каждого своего города — Несколько городов на одном API;
  • собирает события для вебхуков и API v2, рассылает вебхуки, проверяет тревоги телеметрии (раз в WEBHOOK_POLL_S секунд, по умолчанию 10);
  • раз в сутки удаляет старые записи журнала действий (ACTIVITY_LOG_DAYS);
  • следит за циклом событий (LOOP_STALL_S): если процесс не отвечает дольше порога, в журнал пишется стек.

Для разработчика

  • Слои ASGI снаружи внутрь (main.py): язык ошибок (api_i18n.py) → город по префиксу пути (city_context.py) → метрики (observability.py) → журнал действий (activity.py) → маскирование ПДн (pii_middleware.py) → роль PostgreSQL (DbRoleMiddleware) → обязательный вход (AuthRequiredGetMiddleware) → CORS → маршруты routers/.
  • Число маршрутов процесса видно в ответе /health (поле routes).
  • Веб — одна страница pages/index.vue; клиент API собран из разделов services/api/*.
Хотите увидеть эту функцию на своих данных?Покажем ТГИД на демонстрации и ответим на вопросы инженеров.
Запросить демо