19 KiB
type, work_item_id, title, version, status, created_at, authors
| type | work_item_id | title | version | status | created_at | authors | |
|---|---|---|---|---|---|---|---|
| data-requirements | ET-009 | Требования к данным — ET-009: Активация EnduroRussia + Wikiloc | 1 | approved | 2026-06-01 |
|
Требования к данным — ET-009
1. Резюме
ET-009 — активация двух уже разработанных source-парсеров. Никаких изменений в схеме БД, контрактах API, формате localStorage или dedup-алгоритме.
Меняются:
- Содержимое существующей таблицы
tracks(новые записи сsource_id ∈ {enduro_russia, wikiloc}); - Содержимое существующей таблицы
pipeline_runs(новые записи сsource_id ∈ {enduro_russia, wikiloc}); - Содержимое
config/gps_sources.yaml,config/gps_regions.yaml; - Содержимое
src/web/style.json,style-dark.json(match-expressions поsource).
Не меняются:
- Schema
tracks,pipeline_runs; - API контракты
/api/gps-tracks*; - localStorage ключи и значения;
- Dedup-алгоритм (
compute_dedup_key); - ACTIVITY_TYPES enum.
2. Архитектурные границы данных
| Слой данных | Тип | Расположение | Изменения в ET-009 |
|---|---|---|---|
OSM-vector (trails, centralfederal.sqlite) |
существующий | /app/data/centralfederal.sqlite |
нет |
| Личные GPX треки (ET-006) | существующий | браузер (memory) | нет |
| Публичные GPS треки (ET-008) | существующий | /app/data/gps_tracks.sqlite |
+новые записи из новых источников |
| OSRM-граф | существующий | /app/data/enduro.osrm.* |
нет |
| User UI state | существующий | localStorage |
нет новых ключей |
3. Серверные данные — gps_tracks.sqlite
3.1 Schema
Без изменений vs ET-008. См. docs/work-items/ET-008/08-data-requirements.md
§3.1, §3.5. Никаких ALTER TABLE / DROP COLUMN / INDEX CREATE не делается.
3.2 Новые записи в tracks
| Поле | Значение для source_id='enduro_russia' |
Значение для source_id='wikiloc' |
|---|---|---|
dedup_key |
вычислено compute_dedup_key |
вычислено compute_dedup_key |
name |
из JSON meta.name |
из HTML <h1> или GPX metadata/name |
description |
nullable (ADR-010: сохраняем) | null (ADR-012: save_description: false) |
activity_type |
из MAPPING (difficulty → enduro/moto) |
из MAPPING (motorcycle → moto, enduro → enduro) |
user |
null (ADR-010: save_user_field: false) |
null (ADR-012) |
created_at |
из JSON meta.created_at (если есть) |
nullable |
length_m, points_count |
вычислено из GPX | вычислено из GPX |
min_lon..max_lat |
вычислено | вычислено |
geom |
WKB LineString | WKB LineString |
sources_json |
["enduro_russia"] или ["enduro_russia", ...] после merge |
["wikiloc"] или [..., "wikiloc"] |
external_urls_json |
["https://endurorussia.ru/tracks/<id>"] |
["https://www.wikiloc.com/trails/<slug>/<id>"] |
tags_json |
[] (источник не отдаёт tags) |
[] |
inserted_at, updated_at |
NOW() | NOW() |
3.3 Dedup-key — без изменений
Алгоритм compute_dedup_key (ADR-006) не меняется. Применяется к
трекам из всех источников.
Ожидаемое поведение для пары (osm-трек, enduro_russia-трек, wikiloc-трек) из одной поездки:
- Одинаковые
(bbox_quantized, length_bucket, date)→ одинаковыйdedup_key; - Upsert ON CONFLICT →
sources_jsonобъединяется["osm", "enduro_russia", "wikiloc"](порядок поsource_prioritydescending); external_urls_jsonсинхронно объединяется.
См. ET-008 ADR-006 для деталей.
3.4 ACTIVITY_TYPES — без изменений
Enum остаётся прежним. MAPPING каждого source-парсера независимо переводит свои категории в этот enum.
| Source-категория | → ACTIVITY_TYPES |
|---|---|
EnduroRussia: enduro, hard, soft |
enduro |
EnduroRussia: мото, тур |
moto |
EnduroRussia: motorcycle |
moto |
EnduroRussia: offroad |
offroad |
| EnduroRussia: остальное | enduro (fallback в коде) |
Wikiloc (act=19): motorcycle, enduro |
moto (default из MAPPING['motorcycle']) |
Wikiloc (act=3): mtb, mountain biking |
bicycle |
Wikiloc: hiking, running, trail running |
hike |
Wikiloc: offroad |
offroad |
| Wikiloc: неизвестное | moto (parser fallback) |
3.5 Новые записи в pipeline_runs
После первого прогона:
SELECT id, source_id, status, tracks_new, finished_at - started_at
FROM pipeline_runs
ORDER BY id DESC LIMIT 5;
Ожидаемо ≥ 2 новые строки:
source_id='enduro_russia',status='ok'(илиpartial),tracks_new ≥ 200;source_id='wikiloc',status ∈ {ok, partial, rate_limited},tracks_new ≥ 1.
errors_json — null или JSON-object {HTTPError429: N, ...} если
были transient errors.
3.6 Размер БД — оценка после ET-009
| Источник | Треков | Средний размер записи | Итого |
|---|---|---|---|
| OSM (уже в БД) | ≤ 5000 | ≈ 21 КБ | ≤ 105 МБ |
| EnduroRussia (новое) | ≈ 200–305 | ≈ 50 КБ (треки длиннее) | ≈ 10–15 МБ |
| Wikiloc (новое) | ≈ 1–50 | ≈ 50 КБ | ≈ 0.5–2.5 МБ |
| Итого после ET-009 | ≤ 5400 | ≤ 130 МБ |
Запас до операционного лимита (2 ГБ) — больше 15×.
3.7 GC и retention
Без изменений vs ET-008. Месячный GC через --gc (запускается
отдельным cron'ом после двух успешных ручных прогонов).
3.8 Backup
Без изменений (см. 07-infra-requirements.md §4.2).
4. Клиентское хранилище
4.1 Существующие ключи (ET-008) — без изменений
| Ключ | Значение | Замечания для ET-009 |
|---|---|---|
gps-tracks-enabled |
"true" | "false" |
без изменений |
gps-tracks-activities |
JSON-array | без изменений |
gps-tracks-sources |
JSON-array source IDs | может содержать новые ID после первого прогона; клиент сам подхватит. Defaults обновляются автоматически: при первом открытии после ET-009 — все 3 enabled источника попадают в default-набор |
gps-tracks-color-mode |
"source" | "activity" |
без изменений |
4.2 Миграция defaults
При первом открытии страницы после ET-009 клиент видит, что
gps-tracks-sources (если есть в localStorage со старым значением
["osm"]) не содержит enduro_russia и wikiloc. Поведение
ET-008:
- Существующее значение
localStorageсохраняется (пользователь сознательно мог выключить источники); - Новые источники появляются в UI-фильтре с галкой
unchecked; - Пользователь может включить их вручную.
Это компромисс UX: автоматическое включение новых источников без согласия пользователя — нарушение принципа «без сюрпризов»; оставляем явный opt-in.
При желании оператора (нет в scope ET-009) — добавить one-shot
migration в client-side JS: «если gps-tracks-sources существует и не
содержит enduro_russia или wikiloc — добавить и пересохранить».
Не делаем в ET-009.
4.3 Не-персистентное состояние
window.gpsTracksLayer (ET-008) — без изменений.
Маппинг SOURCE_ATTRIBUTIONS в gps_tracks.js расширяется:
const SOURCE_ATTRIBUTIONS = {
osm: "© OpenStreetMap contributors (ODbL)",
enduro_russia: "EnduroRussia.ru",
wikiloc: "© Wikiloc contributors",
ttrails: "ttrails.ru", // для будущей активации
};
И маппинг SOURCE_LABELS для UI-чекбоксов:
const SOURCE_LABELS = {
osm: "OSM",
enduro_russia: "EnduroRussia",
wikiloc: "Wikiloc",
ttrails: "ttrails.ru",
};
5. Внешние входные данные
5.1 OSM Public GPS Traces (ADR-009) — без изменений
См. docs/work-items/ET-008/08-data-requirements.md §5.1.
5.2 EnduroRussia.ru (ADR-010 accepted)
| Параметр | Значение |
|---|---|
| Endpoint list | GET https://endurorussia.ru/api/tracks?page=N&limit=50 |
| Endpoint GPX | GET https://endurorussia.ru/api/tracks/{id}/gpx |
| Формат list | JSON {items: [{id, name, difficulty, created_at}, ...], total} |
| Формат GPX | XML (GPX 1.1) — <trk><trkseg><trkpt> |
| Лицензия | Public; ADR-010 §3 — обезличенно (без user) |
| Атрибуция | EnduroRussia.ru |
| Rate-limit | 5 sec / req |
| Объём для ЦФО+Чувашии (оценка) | ≥ 200 треков |
| User-Agent | enduro-trails/1.0 (+https://openclaw.mva154.duckdns.org/enduro/) |
| Authentication | Нет |
5.3 Wikiloc (ADR-012 accepted)
| Параметр | Значение |
|---|---|
| Endpoint поиска | GET https://www.wikiloc.com/wikiloc/find.do?act=<code>&sw=<lat,lon>&ne=<lat,lon>&page=<N> |
| Endpoint трека | GET https://www.wikiloc.com/trails/<slug>/<id> |
| Endpoint GPX | GET https://www.wikiloc.com/wikiloc/downloadTrail.do?id=<id> |
| Формат поиска | HTML (regex-extract <a href="/trails/…/<id>">) |
| Формат трека | HTML (regex-extract <h1> для имени + ссылка на GPX) |
| Формат GPX | XML (GPX 1.1) |
| Лицензия | Proprietary (ADR-012 §3 — обезличенно, без description) |
| Атрибуция | © Wikiloc contributors |
| Rate-limit | 10 sec / req (жёстко) |
| Graceful-stop | На 403/429 — return без raise |
| max_tracks_per_run | 50 (soft-cap первого прогона) |
| User-Agent | enduro-trails/1.0 (+https://openclaw.mva154.duckdns.org/enduro/) |
| Authentication | Нет |
5.4 ttrails.ru (ADR-011 proposed)
Не используется в ET-009. enabled: false в gps_sources.yaml,
pipeline-guard пропускает.
6. Контракт публичного API
6.1 GET /api/gps-tracks — без изменений
Endpoint остаётся как в ET-008. Новые ID источников
(enduro_russia, wikiloc) появляются в значениях:
properties.sources— массив["enduro_russia"]/["wikiloc"]/["osm", "enduro_russia"](после dedup-merge);properties.external_urls—["https://endurorussia.ru/tracks/<id>"]/["https://www.wikiloc.com/trails/<slug>/<id>"].
Никаких новых query-параметров, response-полей или error-кодов.
Query-параметр source=... (фильтр по source ID) уже существует;
теперь принимает новые значения enduro_russia, wikiloc.
6.2 GET /api/gps-tracks/tiles/{z}/{x}/{y}.mvt — без изменений
properties.source в MVT-feature может теперь принимать значения
enduro_russia / wikiloc (первый source в sources_json).
Клиент-стиль (match-expression line-color) переключается на
соответствующий цвет.
6.3 GET /api/gps-tracks/health — без изменений в схеме
Response shape без изменений. Содержимое:
tracks_by_sourceтеперь содержит ключиenduro_russiaиwikilocс числовыми значениями;last_pipeline_run.sources_ok/sources_error/sources_skipped_licenseмогут содержать новые source IDs.
Клиент-side SOURCE_ATTRIBUTIONS маппинг превращает ключи
tracks_by_source в строки атрибуции для MapLibre Attribution control
(REQ-F-14).
6.4 POST /api/gps-tracks/cache/clear — без изменений
7. Персональные данные (PII)
Без изменений vs ET-008 §7, с расширением табличного сводного:
| Канал | PII | Условия в ET-009 |
|---|---|---|
tracks.user для enduro_russia |
нет — save_user_field: false (ADR-010) |
сохраняется null |
tracks.user для wikiloc |
нет — save_user_field: false (ADR-012) |
сохраняется null |
tracks.geom, tracks.created_at, tracks.length_m |
низкий риск, публично выложено автором | сохраняется как в ET-008 |
tracks.description для enduro_russia |
возможны следы PII в свободном тексте | сохраняется в default (ADR-010 §3); может быть пере-включено save_description: false |
tracks.description для wikiloc |
возможны следы PII | null — save_description: false (ADR-012) |
tracks.name для enduro_russia / wikiloc |
название может содержать псевдонимы | сохраняется (видно в popup) |
IP mva154 становится известен endurorussia.ru, wikiloc.com |
да | стандартное поведение скрейпера; User-Agent с контактом |
7.1 Право на удаление
Без изменений. external_urls_json хранит ссылку; точечное удаление
по запросу автора возможно (ET-008 §7.1).
7.2 GDPR / РФ ФЗ-152
Без изменений. Обрабатываются только публично выложенные данные.
8. Атрибуция
Расширение vs ET-008:
| Источник | Атрибуция-строка |
|---|---|
osm |
© OpenStreetMap contributors (ODbL) |
enduro_russia |
EnduroRussia.ru |
wikiloc |
© Wikiloc contributors |
ttrails (будущее) |
ttrails.ru |
Клиент формирует список из tracks_by_source (где count > 0) через
SOURCE_ATTRIBUTIONS маппинг и подмешивает в MapLibre Attribution
control при включённом слое «Публичные треки».
В popup трека (gps_tracks.js) — ссылки external_urls (как в
ET-008 REQ-F-18); никаких дополнительных правок.
9. Backup и retention
Без изменений vs ET-008 §9. Ежедневный snapshot + 14 дней retention
для data/gps_tracks.sqlite. После ET-009 backup-размер вырастет с
~5 МБ до ~50 МБ — пренебрежимое влияние на disk budget.
10. Тестовые данные (фикстуры)
ET-009 вводит новые фикстуры в tests/fixtures/gps-tracks/:
| Файл | Содержимое | Использование |
|---|---|---|
enduro-russia-api-tracks-page1.json |
реальный snapshot GET /api/tracks?page=0&limit=50; ≥ 5 items с полями id/name/difficulty/created_at |
UT-ER-01..08, IT-ER-01 |
enduro-russia-track-1.gpx |
реальный GPX, ≥ 10 trkpt, в bbox tsfo_plus_chuvashia |
UT-ER-01, IT-ER-01 |
enduro-russia-track-2.gpx |
пустой GPX (<trkseg></trkseg>) |
UT-ER-02 (skip-логика) |
enduro-russia-track-3.gpx |
GPX с одной точкой за пределами bbox | UT-ER-03 (bbox-фильтрация) |
wikiloc-search-page1.html |
HTML страницы поиска; ≥ 5 ссылок /trails/…/<id> |
UT-WL-01, IT-WL-01 |
wikiloc-trail-page.html |
HTML страницы одного трека | UT-WL-02..04, IT-WL-01 |
wikiloc-track.gpx |
реальный GPX, координаты совпадают с одним из EnduroRussia-треков | UT-WL-05, IT-DEDUP-01 |
wikiloc-rate-limited.html |
пустой/тестовый HTML | UT-WL-07/08 (для mock 403/429) |
Снимки делаются разово, вручную оператором / разработчиком через
curl или браузер-инспектор; сохраняются в git и не зависят от
состояния сайта.
10.1 Юридический статус фикстур
Фикстуры в tests/fixtures/gps-tracks/ — публичные snapshot'ы
открытых страниц/API, размещённые исключительно для верификации
парсеров (некоммерческое тестовое использование). Не включаются в
production-БД, не отдаются через API. Внутри фикстур не сохраняются
authentication-cookies, авторские контактные данные или иные PII.
При запросе администратора платформы — фикстура подменяется на синтетический минимальный пример с той же структурой.
11. Контракты, которые нельзя ломать
Без изменений vs ET-008 §10:
dedup_keyформула — не меняется в ET-009.ACTIVITY_TYPESenum — не меняется в ET-009.- GeoJSON response shape — не меняется.
- MVT layer name
gps_tracksи properties — не меняется. - localStorage keys — не меняется.
Новое: маппинги SOURCE_ATTRIBUTIONS / SOURCE_LABELS в клиенте
являются «soft contract»: добавление ключей — safe; удаление —
сломает атрибуцию для соответствующих треков.
12. Вывод
ET-009 — append-only data event:
- Заполняет существующую схему БД новыми записями;
- Использует существующие API-контракты без изменений;
- Расширяет существующие client-side маппинги (атрибуция, цвета);
- Никаких миграций, никаких ALTER, никаких новых ключей localStorage.
Юридически защищён через ADR-010 (accepted) и ADR-012 (accepted).
Pipeline-guard прозрачен — proposed ADR блокирует source автоматически.