---
type: adr
work_item_id: ET-008
adr_id: ADR-009
title: "ADR-009: Источник OSM Public GPS Traces — лицензия ODbL, документированный API, акцептовано для MVP"
status: accepted
created_at: 2026-06-01
authors:
  - "agent:architect"
supersedes: []
superseded_by: []
labels:
  - "ET-008:source-licensing"
---

# ADR-009 — OSM Public GPS Traces: licensing review

## Статус

Accepted

## Контекст

BRD §4 ET-008 требует обязательный ADR licensing-review для каждого внешнего источника **до** активации его в pipeline. Без `status: accepted` в этом ADR — pipeline отказывается загружать source-parser (см. ADR-007 §6).

Источник: **OpenStreetMap Public GPS Traces**.

- Endpoint: `GET https://api.openstreetmap.org/api/0.6/trackpoints?bbox=W,S,E,N&page=P`.
- Endpoint метаданных: `GET https://api.openstreetmap.org/api/0.6/gpx/{id}`.
- Документирован: <https://wiki.openstreetmap.org/wiki/API_v0.6#GPS_traces>.
- Лицензия данных: **ODbL 1.0** — Open Database License (<https://opendatacommons.org/licenses/odbl/1-0/>).
- Атрибуция: «© OpenStreetMap contributors (ODbL)».

## Чеклист по BRD §4

### 1. ToS источника по поводу скрейпинга / массовой загрузки GPX

OSM API имеет **документированный публичный contract**. Использование `bbox + page` пагинации — штатный сценарий, не «скрейпинг» (это публичный API).

Operational limit, опубликованный OSM:
- bbox area ≤ 0.25 deg² на запрос (жёсткий серверный лимит).
- Public usage policy (<https://operations.osmfoundation.org/policies/api/>): «Heavy use must be at least 1 sec between requests, no faster». Рекомендация — `1 req/sec`, что и зафиксировано в `gps_sources.yaml::osm.rate_limit_sec = 1`.
- При злоупотреблении OSM Operations Team вправе временно блокировать IP. Митигация в `10-tech-risks.md` R-5.

**Вывод:** массовая выгрузка по bbox разрешена при соблюдении rate-limit.

### 2. robots.txt

`https://api.openstreetmap.org/robots.txt`:
```
User-agent: *
Disallow:
```

Все эндпоинты API доступны без ограничений robots.

### 3. Условия публикации чужих треков

ODbL даёт «свободу копировать, изменять, использовать и предоставлять третьим лицам» при условии:
- **Attribution.** Атрибуция OSM contributors с указанием ODbL.
- **Share-alike.** Производное произведение должно распространяться на условиях, совместимых с ODbL.
- **Keep open.** Если производное произведение публикуется, source-data не должна закрываться.

Применительно к ET-008:
- Атрибуция OSM выводится MapLibre автоматически при наличии source с правильным `attribution` (уже работает для базового слоя «Схема»).
- В `gps_sources.yaml::osm.attribution = "© OpenStreetMap contributors (ODbL)"` дополнительно выставляется на ВСЕ агрегированные данные.
- В popup трека (REQ-F-18) выводится ссылка на оригинал `https://www.openstreetmap.org/user/{user}/traces/{id}`.
- Share-alike относится к опубликованной нами производной БД. `data/gps_tracks.sqlite` **не публикуется наружу** — отдаётся только через FastAPI как агрегированный сервисный слой. Это попадает под «Produced Work» определение ODbL и атрибуция здесь обязательна, share-alike — нет.

**Имя автора** (`user`) — публичное поле OSM-трека (видно на странице трека); сохранение `user` не нарушает ToS, при этом — см. §5 ниже.

### 4. Rate-limit

- Конфигурация `gps_sources.yaml::osm.rate_limit_sec = 1` (1 запрос в секунду).
- User-Agent: `enduro-trails/1.0 (+https://openclaw.mva154.duckdns.org/enduro/)` — соответствует требованию OSM API «provide a clear user agent with contact information».
- Backoff на 429/503 — экспоненциальный 2^n до 3 попыток (TRZ §6.3).
- Per-source максимальное число запросов на прогон — не ограничено явно; ЦФО+Чувашия ≈ 700 cells × 5 pages × 1 сек ≈ 1 час реального времени (REQ-NF-02). Это < 6-часового cron-окна и существенно меньше «heavy use» порога OSM.

### 5. Метаданные, запрещённые к сохранению

ODbL не накладывает ограничений на сохранение публично доступных полей. Однако:

- **`user` (имя автора)** — публикуется OSM на странице трека; сохранение разрешено. **Решение ET-008: сохраняем**, потому что это даёт пользователю credit в popup; это семантика самой OSM.
- **`description`, `tags`** — публичные, сохраняем.
- **GPS-точки** — публичные (трек загружен автором как public; private/trackable треки не отдаются в `trackpoints` API). Сохраняем как геометрию.
- **`email`, `display_name` отдельно от `user`** — OSM API таких полей в `gpx`-эндпоинте не отдаёт; сохранять нечего.

### 6. Удаление по требованию автора

Если автор удалит трек на OSM (PUT visibility=private или DELETE):
- Следующий полный прогон pipeline по тому же bbox не найдёт этот `gpx_id` → запись в нашей БД останется (stale).
- Митигация: per-source GC-проход (отдельная команда `gps_collect.py --gc-stale`) сравнивает наши `external_id` со списком актуальных id OSM и удаляет stale.
- На MVP **только реактивно**: при ручном запросе автора через issue tracker оператор может удалить запись по `external_id = "osm-<gpx_id>"`. Автоматический GC-проход — отдельный work item.

### 7. Полученное юридическое заключение

OSM Public GPS Traces — **самый изученный** open-data источник; используется тысячами open-source проектов (OsmAnd, JOSM, Strava Routes, и т.д.) для аналогичных целей. ODbL — стандартизованная лицензия фондом Open Knowledge. Внешнего юридического review не требуется для MVP.

## Решение

**Источник OSM Public GPS Traces включается в pipeline как `enabled: true` в `gps_sources.yaml`** со следующими параметрами:

```yaml
- 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            # ADR-009 §5 разрешает
  external_url_template: "https://www.openstreetmap.org/user/{user}/traces/{external_id_numeric}"
```

Атрибуция автоматически выводится MapLibre в правом нижнем углу карты при включённом source (REQ-NF-06).

## Последствия

### Положительные

- Самый стабильный источник: документированный API, ODbL — общепринятая open-data лицензия, нет коммерческих условий, нет API-ключей.
- BRD-метрика «≥ 3 источника, отдающих данные» закрывается через OSM + 2 других после ADR-010/011.
- OSM-треки — единственный гарантированно доступный источник; даже если ADR-010/011 будут отклонены, OSM в одиночку покрывает BRD-минимум.

### Отрицательные / ограничения

- OSM-treki не имеют `activity_type` — у нас по умолчанию `other`. Уточнение возможно через `tags` (если автор пометил «moto/enduro/mtb»). Mapping в `osm.py::MAPPING` (TRZ REQ-F-07). Часть треков останется `other` — это ожидаемо.
- IP-сервера mva154 будет «известен» OSM как scraper. Это допустимо при честном User-Agent + соблюдении rate-limit.
- Stale-tracks (удалённые автором, оставшиеся у нас) — GC задача для post-MVP.

## Классификация изменения

**Minor change.** Источник со стандартной open-лицензией, без скрейпинга HTML, без коммерческих условий. `arch:major-change` не требуется на уровне отдельного licensing-ADR (общая major-классификация — на ADR-005 и ADR-007).

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

- `docs/work-items/ET-008/01-brd.md` §4 «Источники», «Юридический минимум»
- `docs/work-items/ET-008/02-trz.md` REQ-F-04
- `docs/work-items/ET-008/06-adr/ADR-007-pipeline-architecture.md` §6 (licensing guard)
- `docs/work-items/ET-008/08-data-requirements.md` §5 (персональные данные)
- `docs/work-items/ET-008/10-tech-risks.md` R-5 (rate-limit), R-9 (licensing enforcement)
- <https://wiki.openstreetmap.org/wiki/API_v0.6#GPS_traces>
- <https://operations.osmfoundation.org/policies/api/>
- <https://opendatacommons.org/licenses/odbl/1-0/>
