17 KiB
type, work_item_id, adr_id, title, status, created_at, updated_at, authors, supersedes, superseded_by, labels
| type | work_item_id | adr_id | title | status | created_at | updated_at | authors | supersedes | superseded_by | labels | |||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| adr | ET-009 | ADR-013 | ADR-013: Активация двух новых GPS-источников (EnduroRussia + Wikiloc) — конфиг-only изменения поверх pipeline ET-008 | accepted | 2026-06-01 | 2026-06-01 |
|
|
ADR-013 — Активация EnduroRussia и Wikiloc в pipeline GPS-треков
Статус
Accepted. Архитектурное решение для ET-009.
Контекст
ET-008 построил pipeline сбора публичных GPS-треков:
- docker-compose service
gps-collector(profiles: [batch]); - per-source изоляция (ADR-007);
- licensing-guard
_check_license_adr(ADR-007 §6); - БД
data/gps_tracks.sqlite(ADR-005); - API
/api/gps-tracks/*(ADR-008); - парсеры
osm.py,enduro_russia.py,wikiloc.py,ttrails.py.
На момент мерджа ET-008 (2026-06-01) активирован только osm
(ADR-009 был accepted). enduro_russia и ttrails остались
enabled: false (ADR-010 и ADR-011 в proposed). Парсер wikiloc.py
был разработан в ET-008, но запись в config/gps_sources.yaml
не была добавлена и ADR-012 не был создан.
ET-009 закрывает три гэпа:
- ADR-010 —
proposed → accepted(EnduroRussia). - ADR-012 — создан с
accepted(Wikiloc). - Конфиг + регионы + UI-стили — приведены в соответствие с новой реальностью «3 активных источника».
ADR-013 фиксирует архитектурное решение об активации как самостоятельное решение работ-айтема ET-009 (отдельно от licensing-ADR ET-008, которые описывают что разрешено сохранять и при каких условиях).
Сценарий
ET-009 — «конфиг-only активация»: никакой новой инфраструктуры, никаких новых сервисов, никаких новых таблиц БД, никаких новых endpoints API. Только:
- правка
config/gps_sources.yaml(URL fix, флаги enabled, новая запись wikiloc); - правка
config/gps_regions.yaml(Wikiloc подписан на ЦФО+Чувашию); - расширение
wikiloc.pyподдержкойmax_tracks_per_run(≤ 30 строк, см. TRZ REQ-F-03); - расширение
src/web/style.json/style-dark.jsonцветами поsource(REQ-F-13); - расширение клиента атрибуцией
enduro_russia/wikiloc(REQ-F-14); - тестовые фикстуры + unit/integration-тесты;
- ручной первый продакшн-прогон.
Альтернативы и решения
Решение A — Структура licensing-ADR
Опция A1. Положить ADR-012 в docs/work-items/ET-009/06-adr/.
Опция A2 (выбрано). Положить ADR-012 в docs/work-items/ET-008/06-adr/
рядом с ADR-009/010/011, обновить ADR-010 там же.
Обоснование. Licensing-ADR — это per-source documentation, не per-work-item. ET-008 создал пакет licensing-ADR'ов (ADR-009 для OSM, ADR-010 для EnduroRussia, ADR-011 для ttrails); ADR-012 для Wikiloc логически принадлежит тому же пакету. ET-009 — активатор, не законодатель источников. Из ET-009 ADR-013 ссылается на ADR-010 и ADR-012 как на «приняли вот эти условия».
Также config/gps_sources.yaml::license_adr указывает на конкретный
файл; для Wikiloc TRZ ET-009 явно прописывает путь
docs/work-items/ET-008/06-adr/ADR-012-wikiloc-licensing.md. Хранение
в ET-008 устраняет необходимость cross-work-item ссылок в runtime
конфиге pipeline.
Решение B — Фикс URL enduro-russia.ru → endurorussia.ru
Опция B1. Считать это bug-fix'ом без отдельного ADR.
Опция B2 (выбрано). Документировать в этом ADR §3.
Обоснование. Парсер по умолчанию использует endurorussia.ru
(см. enduro_russia.py:45). YAML-конфиг же содержит
enduro-russia.ru. На момент enabled: false это работало бы
криво (парсер брал бы default URL); при enabled: true мы получили
бы баг R-4 (тогда же — баг в external_url сохранённых треков, см.
BRD R-9). Фиксация решения «правильный URL — без дефиса» в ADR
полезна как точка истории.
Решение C — max_tracks_per_run в Wikiloc
Опция C1. Жёстко зашить cap = 50 в коде парсера.
Опция C2 (выбрано). Параметр в gps_sources.yaml, парсер читает
через self.config.get("max_tracks_per_run"). Если не указан — без cap.
Обоснование. Cap в конфиге → cap легко менять без релиза кода. После первой стабильной серии прогонов оператор может поднять до 200 или снять полностью.
Реализация — 8 строк в wikiloc.py::collect():
max_tracks = self.config.get("max_tracks_per_run")
yielded = 0
# ...
if max_tracks is not None and yielded >= max_tracks:
logger.info("Wikiloc: reached max_tracks_per_run=%d, stopping", max_tracks)
return
yielded += 1
Решение D — Динамический UI-фильтр источников
Опция D1. Захардкодить список источников в HTML (#gps-source-grid).
Опция D2 (выбрано). Клиент строит фильтр из ответа
/api/gps-tracks/health.tracks_by_source (источники, у которых > 0
треков в БД). Маппинг source_id → label — JS-константа.
Обоснование. На момент первого открытия страницы (tracks_by_source
содержит только osm), UI показывает только OSM-чекбокс. После первого
прогона ET-009 — все 3 чекбокса. Активация четвёртого источника
(ttrails в будущем) не требует изменений в UI-коде.
Решение E — Source priorities
| Source | source_priority | Смысл |
|---|---|---|
osm |
100 | Самый авторитетный; первая ссылка в external_urls |
enduro_russia |
80 | Тематическая платформа эндуро в РФ |
wikiloc |
70 | Глобальная платформа, ниже из-за HTML-парсинга |
ttrails |
60 (потенциально) | Будет настроен при активации |
Применение: при dedup-merge метаданные с большим source_priority
перекрывают (ADR-006 ET-008). sources_json упорядочен по убыванию
priority.
Решение: оставить как в ET-008 (без изменений в этой части кода).
Решение
1. ADR licensing — обновить и создать
| ADR | Действие | Файл |
|---|---|---|
| ADR-010 | proposed → accepted |
docs/work-items/ET-008/06-adr/ADR-010-enduro-russia-licensing.md |
| ADR-012 | новый, accepted |
docs/work-items/ET-008/06-adr/ADR-012-wikiloc-licensing.md |
| ADR-011 | без изменений (proposed) |
docs/work-items/ET-008/06-adr/ADR-011-ttrails-licensing.md |
| ADR-009 | без изменений (accepted) |
docs/work-items/ET-008/06-adr/ADR-009-osm-licensing.md |
| ADR-013 (этот) | новый, accepted |
docs/work-items/ET-009/06-adr/ADR-013-source-activation.md |
2. Конфиг — финальное состояние config/gps_sources.yaml
sources:
- id: osm
name: "OSM Public GPS Traces"
enabled: true
license_adr: "docs/work-items/ET-008/06-adr/ADR-009-osm-licensing.md"
base_url: "https://api.openstreetmap.org/api/0.6"
rate_limit_sec: 1
user_agent: "enduro-trails/1.0 (+https://openclaw.mva154.duckdns.org/enduro/)"
attribution: "© OpenStreetMap contributors (ODbL)"
parser_module: "src.api.gps_tracks.sources.osm"
save_user_field: true
external_url_template: "https://www.openstreetmap.org/user/{user}/traces/{external_id_numeric}"
- id: enduro_russia
name: "EnduroRussia.ru"
enabled: true # FIX: было false
license_adr: "docs/work-items/ET-008/06-adr/ADR-010-enduro-russia-licensing.md"
base_url: "https://endurorussia.ru" # FIX: было https://enduro-russia.ru (с дефисом)
rate_limit_sec: 5
user_agent: "enduro-trails/1.0 (+https://openclaw.mva154.duckdns.org/enduro/)"
attribution: "EnduroRussia.ru"
parser_module: "src.api.gps_tracks.sources.enduro_russia"
save_user_field: false
source_priority: 80
- id: wikiloc # NEW
name: "Wikiloc"
enabled: true
license_adr: "docs/work-items/ET-008/06-adr/ADR-012-wikiloc-licensing.md"
base_url: "https://www.wikiloc.com"
rate_limit_sec: 10
user_agent: "enduro-trails/1.0 (+https://openclaw.mva154.duckdns.org/enduro/)"
attribution: "© Wikiloc contributors"
parser_module: "src.api.gps_tracks.sources.wikiloc"
save_user_field: false
source_priority: 70
activity_filter: [motorcycle, enduro]
max_tracks_per_run: 50
- id: ttrails
name: "Тропинки.ру"
enabled: false # NOT CHANGED in ET-009
license_adr: "docs/work-items/ET-008/06-adr/ADR-011-ttrails-licensing.md"
base_url: "https://ttrails.ru"
rate_limit_sec: 5
user_agent: "enduro-trails/1.0 (+https://openclaw.mva154.duckdns.org/enduro/)"
attribution: "ttrails.ru"
parser_module: "src.api.gps_tracks.sources.ttrails"
save_user_field: false
3. Регионы — финальное состояние config/gps_regions.yaml
regions:
- id: tsfo_plus_chuvashia
name: "ЦФО + Чувашия"
bbox: [29.0, 49.5, 47.5, 60.0]
enabled: true
sources: [osm, enduro_russia, wikiloc, ttrails] # +wikiloc
- id: north_caucasus
name: "Северный Кавказ"
bbox: [37.0, 41.5, 49.0, 47.0]
enabled: false # NOT CHANGED
sources: [osm, enduro_russia]
Замечание: ttrails остаётся в списке sources, но pipeline-guard
автоматически пропустит его (enabled: false в sources.yaml + ADR-011
в proposed).
4. Парсер Wikiloc — расширение max_tracks_per_run
В src/api/gps_tracks/sources/wikiloc.py::WikilocParser.collect()
добавляется счётчик и проверка cap. Изменение локализованное (≤ 8
строк), не затрагивает API парсера или сигнатуру методов.
5. UI-стили — цвета по источнику
В src/web/style.json и src/web/style-dark.json слой gps-tracks-layer
получает match-expression:
["match", ["get", "source"],
"osm", "#3cb44b",
"enduro_russia", "#e6194b",
"wikiloc", "#4363d8",
"#808080"]
Halo-слой gps-tracks-halo-satellite остаётся белым полупрозрачным
(unchanged).
6. UI-атрибуция
В src/web/gps_tracks.js (или клиентский модуль ET-008) маппинг
SOURCE_ATTRIBUTIONS расширяется значениями для enduro_russia и
wikiloc. MapLibre Attribution control обновляется при изменении
/api/gps-tracks/health.tracks_by_source.
7. Тесты
Полный список — TRZ ET-009 §3 (REQ-F-06..F-12). Новые файлы:
tests/unit/test_gps_tracks_enduro_russia.py(UT-ER-01..08);tests/unit/test_gps_tracks_wikiloc.py(UT-WL-01..10);tests/integration/test_pipeline_et009.py(IT-ER-01, IT-WL-01, IT-WL-02, IT-DEDUP-01, IT-LIC-01);tests/contract/test_endurorussia_api_smoke.py(CT-ER-01, CT-ER-02, маркер@pytest.mark.network);- 7 файлов фикстур в
tests/fixtures/gps-tracks/.
8. Деплой
Без изменений в docker-compose.yml, Dockerfile, nginx, cron.
После merge — стандартный docker compose up -d --no-deps app. Pipeline
запускается вручную оператором по runbook'у в 14-deploy-log.md.
Автоматический cron включается отдельным DevOps-task'ом после двух
успешных ручных прогонов подряд (out of ET-009 scope, BRD §3).
Последствия
Положительные
- Минимальная инфра-нагрузка. Никаких новых контейнеров, БД, env, секретов, портов, nginx-правил.
- Высокая обратимость. Откат активации одного источника =
enabled: falseбез редеплоя. - Источник истины для конфигов — в репозитории; деплой воспроизводим.
- Покрытие тестами новых источников + интеграционный тест
licensing-guard'а через mock-ADR с
proposed-статусом.
Отрицательные / ограничения
- Wikiloc HTML-парсер — потенциально хрупок (R-1 из ET-008 tech-risks). Митигация — фикстуры + health-эндпоинт + быстрое отключение через конфиг.
- IP mva154 банится Wikiloc'ом — средняя вероятность; митигация —
graceful-stop +
max_tracks_per_runcap + ручной мониторинг первых 3 прогонов (см. tech-risks ET-009 R-2). - Удаление дефиса в
enduro-russia.ruURL — для новых треков работает «из коробки»; для существующих треков в БД (если есть snapshot до фикса) могут остатьсяexternal_urlsс дефисом. Это опциональный one-shot fix (BRD R-9), не блокирующий ET-009. - Размер БД вырастет с ~5 MB (только OSM) до ~10–50 MB после первого прогона. Хорошо в пределах REQ-NF-03 ≤ 2 GB.
- Cron автоматизация отложена до отдельного DevOps-task'а. Это сознательное замедление — даём оператору проверить три прогона вручную перед автоматизацией.
Классификация изменения
Minor change на уровне инфраструктуры (никаких новых компонентов). Minor change на уровне ADR (status-flip + новый licensing-ADR с identical-pattern).
Лейбл arch:major-change не выставляется — изменение не вводит
новых архитектурных компонентов, только активирует существующие.
Невыполнимость / эскалация
ETC-009 не требует архитектурной эскалации. Если на момент работы:
- ADR-010 или ADR-012 оказались бы в
proposed/rejected→ разработка останавливается (back-to:analysis). - Wikiloc систематически возвращает 403 на mva154 в первые три прогона →
enabled: false+ новый ADR-update «Wikiloc deprecated». - EnduroRussia API возвращает 5xx в первые три прогона → диагностика
через
pipeline_runs.errors_json; при подтверждении сторонних проблем — wait-and-see, source остаётсяenabled: true.
Связанные документы
docs/work-items/ET-009/01-brd.md§2, §3, §5docs/work-items/ET-009/02-trz.mdREQ-F-01..F-20docs/work-items/ET-009/03-acceptance-criteria.mdAC-01..AC-20docs/work-items/ET-009/07-infra-requirements.md(этот work item)docs/work-items/ET-009/08-data-requirements.md(этот work item)docs/work-items/ET-009/10-tech-risks.md(этот work item)docs/work-items/ET-008/06-adr/ADR-007-pipeline-architecture.md§6docs/work-items/ET-008/06-adr/ADR-010-enduro-russia-licensing.mddocs/work-items/ET-008/06-adr/ADR-012-wikiloc-licensing.mddocs/architecture/README.md(обновлён в ET-009)docs/architecture/adr/README.md(обновлён в ET-009)