Appearance
Гео-расширение на всю Россию (ГАР + 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 поверх
addressestable).
Проблема
Текущая геосистема ограничена ручным сидированием: только СПб (18 районов, 69 метро) + Москва (12 районов, 41 метро). Для масштабирования маркетплейса на всю Россию нужен автоматический импорт справочника и автокомплит адресов.
Решение
Источники данных
| Компонент | Источник | Тип зависимости |
|---|---|---|
| Справочник (регионы, города, районы) | ГАР XML-дамп (fias.nalog.ru) | Разовый импорт + дельта 2р/нед, нет runtime-зависимости |
| Координаты (lat/lon) | DaData geocode API | Разовое обогащение при импорте, нет runtime-зависимости |
| Станции метро | DaData Suggestions API | Разовый импорт по 7 городам с метро, нет runtime-зависимости |
| Автокомплит адреса | DaData Suggestions API | Runtime с 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 | Наша таблица | Пример |
|---|---|---|
| 1 | regions | Ленинградская обл., г. Санкт-Петербург |
| 4 | cities | Выборг, Гатчина |
| 5 | districts | Адмиралтейский р-н, Центральный р-н |
| 6 | cities | деревня, посёлок |
Нюанс: СПб и Москва — города федерального значения (LEVEL 1), внутри сразу LEVEL 5 (районы).
Ключевые поля AS_ADDR_OBJ
| Поле | Описание |
|---|---|
| OBJECTGUID | UUID — наш fias_id |
| NAME | Название объекта |
| TYPENAME | Тип (г, р-н, пр-кт) |
| LEVEL | Уровень иерархии |
| ISACTUAL, ISACTIVE | Фильтр актуальных записей |
Координат в ГАР нет — обогащаем через DaData geocode.
Дельта-обновления
- Частота: 2 раза в неделю (вт/пт)
- Формат: идентичен полному дампу, только изменённые записи
- Логика: upsert по OBJECTGUID; ISACTIVE=0 → soft-delete (не удалять физически из-за FK)
DaData: лимиты и стоимость
| Тир | Лимит | Цена |
|---|---|---|
| Бесплатный | 10 000 запросов/день | 0 ₽ |
| Light | 50 000/день | 14 000 ₽/год |
Расход на импорт: ~1200 запросов (85 регионов + 1100 городов) — один день. Runtime: автокомплит = 3-5 запросов на ввод адреса. 10K/день хватит для MVP.
Декомпозиция задач
Часть 1: Инфраструктура и импорт данных (DEV-379)
| # | Задача | YouTrack | Зависит от |
|---|---|---|---|
| 1 | Миграция БД: fias_id в geo-таблицах | DEV-381 | — |
| 2 | Консольная команда импорта ГАР | DEV-382 | DEV-381 |
| 3 | Обогащение координатами (DaData geocode) | DEV-383 | DEV-382 |
| 4 | Импорт станций метро (DaData) | DEV-384 | DEV-382 |
| 5 | Маппинг существующих СПб/Москва на fias_id | DEV-385 | DEV-382 |
Часть 2: API и runtime-интеграция (DEV-380)
| # | Задача | YouTrack | Зависит от |
|---|---|---|---|
| 6 | GeoProvider интерфейс + DaData реализация | DEV-386 | DEV-379 |
| 7 | Endpoint автокомплита адреса | DEV-387 | DEV-386 |
| 8 | Резолвинг DaData → внутренние geo ID | DEV-388 | DEV-386 |
| 9 | Адаптация vendor endpoints | DEV-389 | DEV-388 |
| 10 | Дельта-обновления ГАР (cron) | DEV-390 | DEV-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-панели для управления расширенной географией