Из чего состоит система
> Кратко. ТГИД — это веб-сервер 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подтвердил сессию по cookietgid_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/*.
Хотите увидеть эту функцию на своих данных?Покажем ТГИД на демонстрации и ответим на вопросы инженеров.
Запросить демо