fix(map-gateway): unlock warm layers and local station search

This commit is contained in:
Codex
2026-08-09 20:27:04 +03:00
parent 07224c6f0d
commit 49813d7839
6 changed files with 289 additions and 25 deletions
+14 -5
View File
@@ -32,7 +32,7 @@ GET /api/map/reference-sources/v1/profiles/transport-stations.v1/search?q=<exact
Reference-station route возвращает `nodedc.map-reference.snapshot/v1` и только
два онтологических типа: `map.station` и `map.terminal`. Категории v1 —
`metro`, `railway_station`, `railway_terminal`. Проекция allowlist-ит имена,
operator/network, `uic_ref`, wheelchair и геометрию; raw OSM tags, upstream
operator/network, локализованные/альтернативные имена, `uic_ref`, wheelchair и геометрию; raw OSM tags, upstream
endpoint и provider credentials в snapshot отсутствуют.
Seed проверяется на старте и покрывает Москву без сетевого запроса. Для bbox за
@@ -48,9 +48,11 @@ upstream не повреждает уже сохранённые cells; `complet
upstream endpoint или payload.
Поиск вне уже загруженного viewport вызывается только явным Enter пользователя.
Gateway сначала ищет в seed и persistent search index, затем при miss выполняет
точный OSM name lookup. Upstream selector использует глобально индексированные
`name`/`name:ru`, а найденные элементы повторно проходят fail-closed проверку
Gateway при старте восстанавливает индекс из seed, persistent search index и
всех сохранённых spatial cells. Локальное совпадение возвращается сразу и не
ждёт Overpass; только полный miss выполняет точный OSM name lookup. Upstream
selector использует глобально индексированные `name`, `name:ru`, `name:en`,
`official_name` и `alt_name`, а найденные элементы повторно проходят fail-closed проверку
`railway=station|halt`. Это не autocomplete и не глобальный regex scan.
Нормализованный результат атомарно пополняет persistent search index; после
перелёта обычный bbox-контур загружает полную spatial cell. Одинаковые запросы
@@ -68,7 +70,7 @@ search counters.
`/api/map/ion/assets/:assetId/endpoint` разрешает только `CESIUM_ION_ASSET_ALLOWLIST`. Ответ не содержит credential: Browser использует публичный provider URL вместе с Cesium `DefaultProxy`, направляющим resource requests в `/api/map/cache`. Gateway валидирует scope URL, удаляет любые credential query parameters из browser request и добавляет соответствующий server-side credential только перед обращением к provider.
Ion endpoint metadata с asset credential сохраняется только в private persistent storage с файловыми правами `0600`. Это нужно для cold start и offline: Browser по-прежнему получает только sanitised URL, а Gateway отвечает из ранее записанного cache. В metadata никогда не записывается master token; NAS backup этого каталога считается service-sensitive.
Ion endpoint metadata с asset credential сохраняется только в private persistent storage с файловыми правами `0600`. Это нужно для cold start и offline: Browser по-прежнему получает только sanitised URL, а Gateway отвечает из ранее записанного cache. Если asset credential истёк, а upstream/VPN недоступен, Gateway всё равно возвращает сохранённый публичный URL без credential: cache lookup выполняется раньше credential injection, поэтому warm `layer.json`, `tileset.json` и дочерние объекты остаются доступны, а настоящий miss по-прежнему fails closed. В metadata никогда не записывается master token; NAS backup этого каталога считается service-sensitive.
## Cache modes
@@ -80,6 +82,13 @@ Ion endpoint metadata с asset credential сохраняется только в
Первый cold miss начинает стримиться клиенту сразу после provider headers и одновременно записывается в private temp-файл. Только полностью полученный object публикуется через atomic rename и durable `index.json`; partial/error никогда не становится cache entry. Одинаковые параллельные misses делят один upstream download, а отмена одного browser request не прерывает server-owned fill для других инстансов. Warm hit не меняет index. Параллельные новые объекты объединяются в минимальное число полных index snapshots вместо одного O(N) rewrite на каждый tile.
Новые index entries получают безопасные `resourceKind`/`assetId` без URL и
credentials. `/healthz` агрегирует число и размер imagery, terrain, buildings,
metadata и legacy 3D/binary объектов. Старые hash-only entries классифицируются
только по надёжному content type; `application/octet-stream` честно остаётся
`3d-binary`, потому что ретроспективно приписать его конкретному Ion asset без
сохранённого URL невозможно.
`offline` дополнительно требует, чтобы hostname был явно указан в `MAP_GATEWAY_OFFLINE_PROVIDER_ALLOWLIST`. По умолчанию список пуст: Gateway не превращает Cesium ion или public OSM tile service в offline distribution. Это осознанная provider policy, а не техническая ошибка cache.
Range requests пока transparently проксируются и не записываются как partial cache object. Полные GET responses кэшируются. Это безопасная начальная граница для terrain/3D Tiles; отдельным следующим шагом добавляется range-aware chunk cache после замеров реальных GOS/3D Tiles assets.