Skip to content

Гео-расширение на всю Россию (ГАР + DaData)

Дата: 2026-04-21 YouTrack: DEV-379, DEV-380 Статус: ⚠️ Частично deprecated (2026-06-03) — см. блок ниже

⚠️ Deprecation notice (2026-06-03)

Часть про DaData Suggestions API как runtime автокомплит (UX-флоу шаг 2, декомпозиция DEV-386 / DEV-387) отменена по итогам ADR-015 batch geocoding architecture (2026-06-01) и OSM-match benchmark (2026-06-02).

Что осталось актуальным:

  • ГАР как первоисточник справочника (regions/cities/districts) — DEV-379, DEV-381 ✅, DEV-382, DEV-385
  • fias_id связующий ключ
  • Концепция GeoProviderInterface (но реализация на собственном индексе поверх ГАР, не DaData)

Что устарело:

  • DaDataGeoProvider как runtime suggestions (DEV-386 нужен переопределённый scope)
  • /store/geo/suggest как DaData proxy (DEV-387 нужен переопределённый scope)
  • Соответствующие части UX-флоу и "Почему DaData для автокомплита (MVP)"

Где DaData всё ещё используется: только batch geocode API для разовой заливки координат (Plan B/C в ADR-015), не runtime.

Следующий шаг: ждать продуктового решения по ADR-015 (Plan B/C/D/E), затем переопределить DEV-386/387 на свой suggest (Meilisearch / PostgreSQL FTS поверх addresses table).


Проблема

Текущая геосистема ограничена ручным сидированием: только СПб (18 районов, 69 метро) + Москва (12 районов, 41 метро). Для масштабирования маркетплейса на всю Россию нужен автоматический импорт справочника и автокомплит адресов.

Решение

Источники данных

КомпонентИсточникТип зависимости
Справочник (регионы, города, районы)ГАР XML-дамп (fias.nalog.ru)Разовый импорт + дельта 2р/нед, нет runtime-зависимости
Координаты (lat/lon)DaData geocode APIРазовое обогащение при импорте, нет runtime-зависимости
Станции метроDaData Suggestions APIРазовый импорт по 7 городам с метро, нет runtime-зависимости
Автокомплит адресаDaData Suggestions APIRuntime с graceful degradation на free-text

Стратегия по фазам

ФазаЧтоЗависимость
MVP (текущая)ГАР-дамп для справочника + DaData для геокодинга и автокомплитаDaData runtime — только автокомплит
РостСвой автокомплит (Meilisearch поверх ГАР)DaData отключаем полностью

Почему ГАР, а не DaData для справочника

  • Первоисточник: ГАР — госбаза ФИАС, бесплатна навсегда
  • Нет runtime-зависимости: данные в нашей БД, DaData может лежать
  • Контроль лимитов: DaData free tier 10K запросов/день — при росте станет узким местом
  • Полнота: ГАР содержит все регионы, города, районы (DaData opendata — без районов)

Почему DaData для автокомплита (MVP)

  • Быстрый старт: suggestions API из коробки
  • Нормализованные данные с fias_id для маппинга на нашу БД
  • Graceful degradation: DaData лежит → продавец вводит адрес вручную
  • Замена на Meilisearch — фаза 2, без изменения бизнес-логики (абстракция GeoProvider)

Архитектура

Связующий ключ: fias_id

fias_id (OBJECTGUID из ГАР, формат UUID) добавляется в таблицы regions, cities, districts, metro_stations. Это единый идентификатор для связи между:

  • Нашей БД (internal ID → fias_id)
  • ГАР-дампом (OBJECTGUID)
  • DaData-ответами (fias_id в suggestions)

Миграция текущих данных

  • Существующие записи СПб/Москва сохраняют свои ID — нет breaking changes по FK
  • fias_id добавляется как nullable колонка с UNIQUE constraint
  • Текущие записи обогащаются fias_id через маппинг по имени
  • Дубликаты (ручная запись + импортированная) — оставляем ручную (сохраняем FK), присваиваем fias_id, удаляем дубль

UX-флоу ввода адреса

┌─────────────────────────────────────────────────┐
│  1. Продавец выбирает регион → город             │
│     (каскадные select-ы из нашей БД)             │
│                                                   │
│  2. Вводит адрес в автокомплит-поле               │
│     (DaData Suggestions API)                      │
│                                                   │
│  3. Район определяется автоматически              │
│     (из DaData-ответа по fias_id)                 │
│                                                   │
│  4. Fallback: DaData недоступна →                 │
│     обычное текстовое поле (текущее поведение)    │
└─────────────────────────────────────────────────┘

Абстракция провайдера

GeoProviderInterface
├── suggest(query, cityId, limit) → GeoSuggestion[]
└── resolve(fiasId) → GeoResolvedAddress

Реализации:
├── DaDataGeoProvider (MVP)
└── MeilisearchGeoProvider (фаза 2)

Замена провайдера — одна строка в DI-контейнере.

Резолвинг DaData → внутренние ID

DaData suggestion → fias_id

GeoResolver.resolve()

Lookup fias_id в regions/cities/districts

Район не найден? → Lazy creation (name + city_id + fias_id из DaData)

ResolvedGeoIds { region_id, city_id, district_id }

Метро

Метро только для городов с метрополитеном (7 городов РФ): Москва, Санкт-Петербург, Нижний Новгород, Новосибирск, Самара, Екатеринбург, Казань. Для остальных городов — поле скрыто.


ГАР: технические детали

Дамп

  • URL: https://fias.nalog.ru/DataArchive
  • Формат: только XML (DBF заморожен с 2021)
  • Размер: ~37 ГБ архив, но нужны только AS_ADDR_OBJ + AS_ADM_HIERARCHY с LEVEL ≤ 6
  • Дома/помещения (LEVEL 7-10) = 95% веса — не нужны
  • Структура: 92 папки по регионам (01-99), можно распаковывать выборочно

Уровни иерархии (LEVEL)

LEVELНаша таблицаПример
1regionsЛенинградская обл., г. Санкт-Петербург
4citiesВыборг, Гатчина
5districtsАдмиралтейский р-н, Центральный р-н
6citiesдеревня, посёлок

Нюанс: СПб и Москва — города федерального значения (LEVEL 1), внутри сразу LEVEL 5 (районы).

Ключевые поля AS_ADDR_OBJ

ПолеОписание
OBJECTGUIDUUID — наш fias_id
NAMEНазвание объекта
TYPENAMEТип (г, р-н, пр-кт)
LEVELУровень иерархии
ISACTUAL, ISACTIVEФильтр актуальных записей

Координат в ГАР нет — обогащаем через DaData geocode.

Дельта-обновления

  • Частота: 2 раза в неделю (вт/пт)
  • Формат: идентичен полному дампу, только изменённые записи
  • Логика: upsert по OBJECTGUID; ISACTIVE=0 → soft-delete (не удалять физически из-за FK)

DaData: лимиты и стоимость

ТирЛимитЦена
Бесплатный10 000 запросов/день0 ₽
Light50 000/день14 000 ₽/год

Расход на импорт: ~1200 запросов (85 регионов + 1100 городов) — один день. Runtime: автокомплит = 3-5 запросов на ввод адреса. 10K/день хватит для MVP.


Декомпозиция задач

Часть 1: Инфраструктура и импорт данных (DEV-379)

#ЗадачаYouTrackЗависит от
1Миграция БД: fias_id в geo-таблицахDEV-381
2Консольная команда импорта ГАРDEV-382DEV-381
3Обогащение координатами (DaData geocode)DEV-383DEV-382
4Импорт станций метро (DaData)DEV-384DEV-382
5Маппинг существующих СПб/Москва на fias_idDEV-385DEV-382

Часть 2: API и runtime-интеграция (DEV-380)

#ЗадачаYouTrackЗависит от
6GeoProvider интерфейс + DaData реализацияDEV-386DEV-379
7Endpoint автокомплита адресаDEV-387DEV-386
8Резолвинг DaData → внутренние geo IDDEV-388DEV-386
9Адаптация vendor endpointsDEV-389DEV-388
10Дельта-обновления ГАР (cron)DEV-390DEV-382

Граф зависимостей

DEV-381 (миграция)
    └── DEV-382 (импорт ГАР)
            ├── DEV-383 (координаты)
            ├── DEV-384 (метро)
            ├── DEV-385 (маппинг СПб/Мск)
            └── DEV-390 (дельта-обновления)

DEV-386 (GeoProvider)
    ├── DEV-387 (endpoint автокомплита)
    └── DEV-388 (GeoResolver)
            └── DEV-389 (vendor endpoints)

Обратная совместимость

  • Существующие ID не меняются → FK не ломаются
  • Vendor endpoints принимают как address_fias_id (новый), так и city_id (текущий) — взаимоисключающие
  • Старые клиенты без address_fias_id работают как раньше
  • Триггер sync_product_region продолжает работать для city_id

Что НЕ входит в scope

  • PostGIS / geo-radius поиск (ADR-004, Phase 3)
  • Elasticsearch/Meilisearch для автокомплита (фаза 2)
  • Полный адрес до квартиры (только до дома)
  • Frontend-изменения (отдельные таски)
  • Изменения admin-панели для управления расширенной географией