Files
enduro-trails/docs/work-items/ET-009/06-adr/ADR-013-source-activation.md
claude-bot 4be7fbf3de
Some checks failed
CI / lint (push) Failing after 4s
CI / test (push) Failing after 6s
CI / build (push) Has been skipped
feat(ET-009): architect deliverables — ADR, infra requirements, data requirements, tech risks, wikiloc parser stub
2026-06-01 19:20:15 +00:00

17 KiB
Raw Blame History

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
agent:architect
ET-009:activation
config-only

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 закрывает три гэпа:

  1. ADR-010 — proposed → accepted (EnduroRussia).
  2. ADR-012 — создан с accepted (Wikiloc).
  3. Конфиг + регионы + 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.ruendurorussia.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_run cap + ручной мониторинг первых 3 прогонов (см. tech-risks ET-009 R-2).
  • Удаление дефиса в enduro-russia.ru URL — для новых треков работает «из коробки»; для существующих треков в БД (если есть snapshot до фикса) могут остаться external_urls с дефисом. Это опциональный one-shot fix (BRD R-9), не блокирующий ET-009.
  • Размер БД вырастет с ~5 MB (только OSM) до ~1050 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 не требует архитектурной эскалации. Если на момент работы:

  1. ADR-010 или ADR-012 оказались бы в proposed/rejected → разработка останавливается (back-to:analysis).
  2. Wikiloc систематически возвращает 403 на mva154 в первые три прогона → enabled: false + новый ADR-update «Wikiloc deprecated».
  3. EnduroRussia API возвращает 5xx в первые три прогона → диагностика через pipeline_runs.errors_json; при подтверждении сторонних проблем — wait-and-see, source остаётся enabled: true.

Связанные документы

  • docs/work-items/ET-009/01-brd.md §2, §3, §5
  • docs/work-items/ET-009/02-trz.md REQ-F-01..F-20
  • docs/work-items/ET-009/03-acceptance-criteria.md AC-01..AC-20
  • docs/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 §6
  • docs/work-items/ET-008/06-adr/ADR-010-enduro-russia-licensing.md
  • docs/work-items/ET-008/06-adr/ADR-012-wikiloc-licensing.md
  • docs/architecture/README.md (обновлён в ET-009)
  • docs/architecture/adr/README.md (обновлён в ET-009)