architect(ET-005): ADR, infra-requirements, data-requirements, tech-risks
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
---
|
||||
type: adr
|
||||
work_item_id: ET-005
|
||||
adr_id: adr-0001
|
||||
title: "ADR-0001: Переключение единиц измерения (км/мили) — клиентское решение с централизованным форматтером"
|
||||
status: accepted
|
||||
created_at: 2026-05-21
|
||||
authors:
|
||||
- "agent:architect"
|
||||
supersedes: []
|
||||
superseded_by: []
|
||||
labels: []
|
||||
---
|
||||
|
||||
# ADR-0001 — Переключение единиц измерения (км/мили): клиентское решение с централизованным форматтером
|
||||
|
||||
## Статус
|
||||
|
||||
Accepted
|
||||
|
||||
## Контекст
|
||||
|
||||
ET-005 добавляет переключатель единиц измерения расстояний (км/мили) в
|
||||
панель настроек карты. Выбор сохраняется в `localStorage`, по умолчанию —
|
||||
километры, при переключении все видимые расстояния пересчитываются за
|
||||
< 100 мс (см. `01-brd.md`, `02-trz.md`, `03-acceptance-criteria.md`).
|
||||
|
||||
Существующее состояние кодовой базы (`src/web/`):
|
||||
|
||||
- Фронтенд **плоский, без сборщика и без модульной системы**:
|
||||
`index.html`, `app.js`, `app.css`, `style.json`, `style-dark.json`.
|
||||
`app.js` (≈ 3036 строк) подключается как **классический скрипт**
|
||||
(`<script src="app.js"></script>`, `index.html:405`), а не ES-модуль.
|
||||
Каталога `src/web/static/js/` в репозитории **нет**.
|
||||
- Форматирование расстояний **не централизовано** — захардкоженный
|
||||
паттерн `(m / 1000).toFixed(N) + ' км'` встречается минимум в **13
|
||||
местах** `app.js`: `formatDist()` (стр. 187–189), карточки сегментов
|
||||
(638), карточки маршрута (1157, 1191, 2202, 2212, 2357, 2370, 2605),
|
||||
scale-bar (1416–1440), всплывающие подсказки (1478), линейка/ruler
|
||||
(1837, 1875, 1885, 1931). Единого форматтера нет.
|
||||
- Внутренняя каноническая единица расстояния — **метры**
|
||||
(`route.distance_m`), для линейки — километры (`rulerTotal`).
|
||||
- Сложился устойчивый паттерн персистентности UI-настроек в
|
||||
`localStorage`: ключи `enduro-theme-mode`, `terrain-hillshade`,
|
||||
`terrain-tri`, `trails-track`, `trails-path`, `poi-visible` (ET-002),
|
||||
`MARKERS_KEY`.
|
||||
- «Панель настроек карты» из BRD/ТЗ де-факто реализована как попап
|
||||
`#terrain-popup` (заголовок «Эндуро»), открываемый кнопкой «Рельеф».
|
||||
В ET-002 в этот же попап добавлен чекбокс POI. В `app.css` уже есть
|
||||
готовый компонент сегментированного переключателя `.seg-control` /
|
||||
`.seg-btn` (стр. 360–363).
|
||||
|
||||
Backend (FastAPI), БД (SQLite/Spatialite), тайл-сервер и OSRM к выбору
|
||||
единиц измерения отношения **не имеют**: расстояния приходят с backend
|
||||
в метрах, перевод — исключительно вопрос представления на клиенте.
|
||||
|
||||
## Рассматриваемые варианты
|
||||
|
||||
### Вариант A — Централизованный модуль-форматтер + единый оркестратор (выбран)
|
||||
|
||||
Новый модуль `src/web/units.js`, подключаемый как **классический скрипт
|
||||
до `app.js`**, экспортирует глобальный неймспейс `window.Units` с
|
||||
функциями состояния (`getUnit()` / `setUnit()`) и форматирования
|
||||
(`formatDistance(meters, {precision})`). Все 13 мест форматирования в
|
||||
`app.js` переводятся на вызов `Units.formatDistance(...)`. При смене
|
||||
единицы `setUnit()` пишет в `localStorage` и диспатчит `unitchange` на
|
||||
`document`; в `app.js` регистрируется **один** обработчик-оркестратор
|
||||
`onUnitChange()`, который пере-вызывает существующие функции отрисовки
|
||||
видимых поверхностей с расстояниями.
|
||||
|
||||
- **Плюсы:** единственный источник истины по форматированию убирает
|
||||
риск рассинхрона; нулевые изменения backend/БД/инфраструктуры;
|
||||
пересчёт мгновенный (нет ни сети, ни перезагрузки тайлов) — НФТ
|
||||
«< 100 мс» выполняется тривиально; согласуется с принципом «минимум
|
||||
зависимостей»; модуль покрывается unit-тестами изолированно.
|
||||
- **Минусы:** требует рефакторинга 13 мест в `app.js` (риск пропустить
|
||||
вызов — вынесен в `10-tech-risks.md`, R1); глобальный неймспейс вместо
|
||||
ES-import — но это сознательное соответствие текущему стилю `app.js`.
|
||||
|
||||
### Вариант B — Рассыпанные подписчики `unitchange` по компонентам (буквальный тех-дизайн ТЗ)
|
||||
|
||||
Каждый компонент с расстоянием самостоятельно подписывается на
|
||||
`unitchange` и сам себя перерисовывает.
|
||||
|
||||
- **Плюсы:** формально совпадает с разделом «Технический дизайн» ТЗ.
|
||||
- **Минусы:** N подписок вместо одной — высокая связность, легко
|
||||
забыть подписку у нового компонента; дублирование логики перерисовки;
|
||||
не решает корневую проблему — захардкоженное `+ ' км'` остаётся
|
||||
размазанным. Отклонён: оркестрация в одном месте надёжнее.
|
||||
|
||||
### Вариант C — Вынести `units.js` в ES-модуль `src/web/static/js/units.js`
|
||||
|
||||
Буквально следовать пути из ТЗ: создать `src/web/static/js/units.js` как
|
||||
ES-модуль.
|
||||
|
||||
- **Плюсы:** «правильная» модульность.
|
||||
- **Минусы:** в проекте нет каталога `static/js/`, нет сборщика, а
|
||||
`app.js` подключён как классический скрипт. Полноценный `import`
|
||||
потребовал бы перевода `app.js` в `type="module"` и реструктуризации
|
||||
≈ 3000 строк — несопоставимо со scope ET-005 и противоречит принципу
|
||||
«минимум зависимостей». Отклонён.
|
||||
|
||||
## Решение
|
||||
|
||||
Принимается **Вариант A**.
|
||||
|
||||
1. **Только клиент.** Backend, БД, API, тайл-сервер, OSRM, инфраструктура
|
||||
— без изменений. Расстояния продолжают приходить с backend в метрах.
|
||||
|
||||
2. **Новый модуль `src/web/units.js`** (НЕ `src/web/static/js/units.js`).
|
||||
Раздел «Технический дизайн» ТЗ носит рекомендательный характер;
|
||||
финальное размещение файлов — мандат архитектуры. Путь скорректирован
|
||||
под фактическую плоскую структуру `src/web/`. Модуль подключается в
|
||||
`index.html` как классический скрипт **строго перед `app.js`**:
|
||||
`<script src="units.js"></script>` затем `<script src="app.js">`.
|
||||
|
||||
3. **Глобальный API модуля** — неймспейс `window.Units` (соответствует
|
||||
стилю `app.js`, где функции глобальны):
|
||||
- `Units.getUnit()` → `'km' | 'mi'`;
|
||||
- `Units.setUnit(unit)` — валидирует, пишет `localStorage`, диспатчит
|
||||
`unitchange`;
|
||||
- `Units.formatDistance(meters, { precision })` — возвращает строку с
|
||||
корректной единицей в текущем режиме;
|
||||
- `Units.KM_TO_MI = 0.621371` — единственная константа коэффициента.
|
||||
|
||||
4. **Каноническая единица — метры.** Конвертация выполняется **только в
|
||||
момент форматирования**. Запрещено хранить или пересчитывать значения
|
||||
расстояний в милях во внутреннем состоянии (`route.distance_m`,
|
||||
`rulerTotal` и т.п. остаются метрическими) — это исключает накопление
|
||||
ошибок округления при многократном переключении (ФТ-3, AC-2/TP-04).
|
||||
|
||||
5. **Персистентность** — `localStorage`, ключ `distance_unit` (как в ТЗ),
|
||||
значения `'km'` / `'mi'`. При отсутствии или некорректном значении —
|
||||
дефолт `'km'` (AC-3, TP-01). Чтение — при инициализации модуля.
|
||||
|
||||
6. **Пересчёт — единый оркестратор.** `setUnit()` диспатчит `unitchange`
|
||||
на `document`. В `app.js` регистрируется ровно **один** обработчик
|
||||
`onUnitChange()`, пере-вызывающий существующие функции отрисовки
|
||||
видимых поверхностей с расстояниями (лист маршрута, список точек,
|
||||
карточки маршрутов, линейка, scale-bar). Рассыпать подписки по
|
||||
компонентам запрещено.
|
||||
|
||||
7. **Все 13 мест форматирования** `(m/1000).toFixed(N)+' км'` в `app.js`
|
||||
переводятся на `Units.formatDistance()`. Список call-sites и риск
|
||||
пропуска зафиксированы в `10-tech-risks.md` (R1). Форматтер принимает
|
||||
`precision`, чтобы сохранить текущую точность карточек (`toFixed(0)`)
|
||||
и при этом по умолчанию давать 1 знак (AC-2, R5).
|
||||
|
||||
8. **UI-элемент** — сегментированный переключатель `km | mi` на готовом
|
||||
компоненте `.seg-control` / `.seg-btn`, размещаемый в попапе
|
||||
`#terrain-popup` (та же «панель настроек», что и чекбоксы слоёв и
|
||||
POI-чекбокс из ET-002). Новый CSS-компонент не вводится.
|
||||
|
||||
9. **C4 без изменений.** Состав компонентов системы не меняется,
|
||||
обновление `docs/architecture/c4-*.mmd` не требуется (диаграммы C4 в
|
||||
репозитории отсутствуют — только `docs/architecture/README.md`).
|
||||
|
||||
## Последствия
|
||||
|
||||
### Положительные
|
||||
|
||||
- Изменение полностью клиентское: деплой без миграций и без изменения
|
||||
состава контейнеров (штатный релиз фронтенда).
|
||||
- Пересчёт < 100 мс (НФТ ТЗ) — нет ни сетевых вызовов, ни перезагрузки
|
||||
тайлов.
|
||||
- Появляется единственная точка форматирования расстояний — снижается
|
||||
будущий риск рассинхрона и упрощается поддержка (положительный
|
||||
побочный эффект рефакторинга 13 call-sites).
|
||||
- Модуль `units.js` изолирован и тестируется юнит-тестами отдельно от
|
||||
`app.js`.
|
||||
|
||||
### Отрицательные / ограничения
|
||||
|
||||
- Настройка локальна для браузера: при очистке `localStorage` или смене
|
||||
устройства сбрасывается на дефолт `km`. Принято осознанно — вне scope
|
||||
BRD (синхронизация между устройствами не требуется).
|
||||
- Требуется рефакторинг 13 мест в `app.js` — операционный риск пропуска
|
||||
call-site (митигация — `10-tech-risks.md`, R1; grep-аудит + e2e).
|
||||
- Имперский эквивалент суб-километровых значений («м») и единиц
|
||||
scale-bar требует политики — см. `10-tech-risks.md` R2, R3.
|
||||
|
||||
### Технический долг
|
||||
|
||||
- `units.js` подключается как глобальный классический скрипт. Если в
|
||||
будущих фазах появится сборщик/модульность фронтенда, модуль легко
|
||||
переводится в ES-модуль без изменения публичного контракта. На ET-005
|
||||
перевод `app.js` в модули — вне scope.
|
||||
|
||||
## Классификация изменения
|
||||
|
||||
**Minor change.** Новые сервисы, БД, API-эндпоинты и контейнеры не
|
||||
вводятся; состав компонентов C4 не меняется; backend и инфраструктура не
|
||||
затрагиваются. Лейбл `arch:major-change` **не требуется**. Обязательного
|
||||
архитектурного approve не требуется.
|
||||
|
||||
## Связанные документы
|
||||
|
||||
- `docs/work-items/ET-005/01-brd.md`
|
||||
- `docs/work-items/ET-005/02-trz.md`
|
||||
- `docs/work-items/ET-005/03-acceptance-criteria.md`
|
||||
- `docs/work-items/ET-005/04-test-plan.yaml`
|
||||
- `docs/work-items/ET-005/07-infra-requirements.md`
|
||||
- `docs/work-items/ET-005/08-data-requirements.md`
|
||||
- `docs/work-items/ET-005/10-tech-risks.md`
|
||||
- `docs/architecture/README.md`
|
||||
107
docs/work-items/ET-005/07-infra-requirements.md
Normal file
107
docs/work-items/ET-005/07-infra-requirements.md
Normal file
@@ -0,0 +1,107 @@
|
||||
---
|
||||
type: infra-requirements
|
||||
work_item_id: ET-005
|
||||
title: "Инфраструктурные требования — ET-005: Переключение единиц измерения (км/мили)"
|
||||
version: 1
|
||||
status: approved
|
||||
created_at: 2026-05-21
|
||||
authors:
|
||||
- "agent:architect"
|
||||
---
|
||||
|
||||
# Инфраструктурные требования — ET-005
|
||||
|
||||
## 1. Резюме
|
||||
|
||||
ET-005 — изменение **исключительно фронтенда** (`src/web/index.html`,
|
||||
`src/web/app.js`, `src/web/app.css` и новый файл `src/web/units.js`).
|
||||
Новой инфраструктуры не требуется. Документ зафиксирован для полноты
|
||||
work-item и явно подтверждает отсутствие инфра-воздействия (см.
|
||||
`06-adr/adr-0001-unit-toggle-client-side.md`).
|
||||
|
||||
## 2. Контейнеры и сервисы
|
||||
|
||||
| Аспект | Требование |
|
||||
|--------|------------|
|
||||
| Новые контейнеры | Нет |
|
||||
| Изменения существующих сервисов (api, osrm, nginx) | Нет |
|
||||
| Изменения `docker-compose.yml` | Нет |
|
||||
| Изменения `Dockerfile` | Нет — `units.js` это статика, попадает в образ тем же путём, что и `app.js` |
|
||||
|
||||
## 3. Сеть
|
||||
|
||||
| Аспект | Требование |
|
||||
|--------|------------|
|
||||
| Новые порты | Нет |
|
||||
| Изменения reverse proxy (nginx, `/enduro/`) | Нет |
|
||||
| Новые внешние домены / DNS | Нет |
|
||||
| Исходящие сетевые вызовы из фронтенда | Нет (конвертация и хранение — локальные) |
|
||||
|
||||
## 4. Хранилища данных
|
||||
|
||||
| Аспект | Требование |
|
||||
|--------|------------|
|
||||
| Изменения схемы SQLite/Spatialite | Нет |
|
||||
| Миграции БД (`migrations/`) | Нет |
|
||||
| Серверное хранилище состояния | Нет |
|
||||
| Клиентское хранилище | `localStorage`, ключ `distance_unit` (`'km'`/`'mi'`), ≈ 2 байта полезной нагрузки на браузер |
|
||||
|
||||
Подробности по данным — `08-data-requirements.md`.
|
||||
|
||||
## 5. Конфигурация и секреты
|
||||
|
||||
| Аспект | Требование |
|
||||
|--------|------------|
|
||||
| Новые переменные окружения | Нет |
|
||||
| Новые секреты | Нет |
|
||||
| Изменения конфигурации FastAPI / uvicorn | Нет |
|
||||
|
||||
## 6. Зависимости
|
||||
|
||||
| Аспект | Требование |
|
||||
|--------|------------|
|
||||
| Новые npm/Python пакеты | Нет |
|
||||
| Новые внешние сервисы | Нет |
|
||||
| Новые CDN-скрипты | Нет — `units.js` это локальный файл проекта, не внешний CDN |
|
||||
| Версия MapLibre GL JS | Без изменений |
|
||||
|
||||
## 7. Сборка и деплой
|
||||
|
||||
- **Pipeline:** существующий Gitea Actions без изменений (`lint`, `test`,
|
||||
`build`).
|
||||
- **Артефакт:** статические ассеты фронтенда (`src/web/`), включая новый
|
||||
`units.js`. Деплой — штатная пересборка/перевыкладка и
|
||||
`docker compose up -d` на mva154.
|
||||
- **Порядок подключения скриптов:** `units.js` должен подключаться в
|
||||
`index.html` **строго перед** `app.js` (см. ADR-0001, риск R7 в
|
||||
`10-tech-risks.md`). Контрольная точка для review.
|
||||
- **Простой (downtime):** нет — изменение только в статике фронтенда.
|
||||
- **План отката:** обратный коммит (revert) и повторный деплой;
|
||||
миграций/серверного состояния, требующих отдельного отката, нет.
|
||||
`localStorage`-ключ `distance_unit` у пользователей при откате
|
||||
безвреден (игнорируется старым кодом).
|
||||
|
||||
## 8. Ресурсы (CPU / RAM / диск)
|
||||
|
||||
Воздействие отсутствует. Конвертация расстояний — несколько
|
||||
арифметических операций в браузере клиента; тайлы и маршруты не
|
||||
перезапрашиваются. Размер `units.js` пренебрежимо мал (единицы КБ).
|
||||
|
||||
## 9. Наблюдаемость
|
||||
|
||||
Новые метрики, логи и алерты не требуются. Поведение проверяется
|
||||
unit-тестами модуля `units.js` и e2e-тестами фронтенда согласно
|
||||
`04-test-plan.yaml` (TP-01…TP-05).
|
||||
|
||||
## 10. Влияние на C4
|
||||
|
||||
Состав компонентов системы **не меняется** — добавляется лишь файл
|
||||
внутри уже существующего компонента «Frontend». Обновление
|
||||
`docs/architecture/c4-*.mmd` не требуется (диаграммы C4 в репозитории
|
||||
на данный момент отсутствуют — только `docs/architecture/README.md`).
|
||||
|
||||
## 11. Вывод
|
||||
|
||||
Инфраструктурных, сетевых, конфигурационных изменений и изменений БД
|
||||
**нет**. ET-005 безопасен для деплоя в рамках обычного релизного цикла
|
||||
фронтенда. Эскалация `arch:major-change` не требуется.
|
||||
76
docs/work-items/ET-005/08-data-requirements.md
Normal file
76
docs/work-items/ET-005/08-data-requirements.md
Normal file
@@ -0,0 +1,76 @@
|
||||
---
|
||||
type: data-requirements
|
||||
work_item_id: ET-005
|
||||
title: "Требования к данным — ET-005: Переключение единиц измерения (км/мили)"
|
||||
version: 1
|
||||
status: approved
|
||||
created_at: 2026-05-21
|
||||
authors:
|
||||
- "agent:architect"
|
||||
---
|
||||
|
||||
# Требования к данным — ET-005
|
||||
|
||||
## 1. Резюме
|
||||
|
||||
ET-005 не вводит и не изменяет ни одной серверной структуры данных.
|
||||
Единственное «данное» фичи — пользовательская UI-настройка выбранной
|
||||
единицы измерения, хранимая на клиенте.
|
||||
|
||||
## 2. Серверные данные
|
||||
|
||||
| Аспект | Требование |
|
||||
|--------|------------|
|
||||
| Изменения схемы SQLite/Spatialite | Нет |
|
||||
| Новые таблицы / колонки / индексы | Нет |
|
||||
| Миграции (`migrations/`) | Нет |
|
||||
| Изменения контракта API | Нет — расстояния и далее отдаются в **метрах** |
|
||||
|
||||
## 3. Каноническая единица расстояния
|
||||
|
||||
- Внутренняя каноническая единица системы — **метр**. Backend отдаёт
|
||||
`route.distance_m` (метры); линейка во фронтенде оперирует километрами
|
||||
(`rulerTotal`).
|
||||
- ET-005 **не меняет** ни хранимые, ни передаваемые значения. Перевод в
|
||||
мили выполняется **только в момент форматирования строки для UI**
|
||||
(`Units.formatDistance()`).
|
||||
- Запрещено хранить в рантайм-состоянии значения, конвертированные в
|
||||
мили — это исключает накопление ошибок округления при многократном
|
||||
переключении (ФТ-3 ТЗ, AC-2, тест TP-04).
|
||||
|
||||
## 4. Клиентское хранилище
|
||||
|
||||
| Параметр | Значение |
|
||||
|----------|----------|
|
||||
| Механизм | `localStorage` |
|
||||
| Ключ | `distance_unit` |
|
||||
| Допустимые значения | `'km'`, `'mi'` |
|
||||
| Значение по умолчанию | `'km'` (при отсутствии ключа или некорректном значении) |
|
||||
| Объём | ≈ 2 байта полезной нагрузки на браузер |
|
||||
| Запись | при переключении (`Units.setUnit()`) |
|
||||
| Чтение | при инициализации модуля `units.js` |
|
||||
|
||||
Ключ согласуется с уже сложившейся в проекте конвенцией UI-настроек в
|
||||
`localStorage` (`enduro-theme-mode`, `terrain-*`, `trails-*`,
|
||||
`poi-visible`).
|
||||
|
||||
## 5. Константы и точность
|
||||
|
||||
| Параметр | Значение |
|
||||
|----------|----------|
|
||||
| Коэффициент перевода | `1 km = 0.621371 mi` (`Units.KM_TO_MI`), единственное место объявления |
|
||||
| Точность по умолчанию | 1 знак после запятой (AC-2) |
|
||||
| Параметризация точности | `formatDistance()` принимает `precision`, чтобы сохранить существующую точность карточек маршрутов (`toFixed(0)`) — см. `10-tech-risks.md`, R5 |
|
||||
| Разделитель дробной части | Привести к единому виду; сейчас в `app.js` есть расхождение (`.` и `,`) — см. `10-tech-risks.md`, R4 |
|
||||
|
||||
## 6. Персональные данные
|
||||
|
||||
Персональные данные (PII) отсутствуют. `distance_unit` — обезличенная
|
||||
UI-настройка, не покидает браузер пользователя, не логируется на
|
||||
backend.
|
||||
|
||||
## 7. Вывод
|
||||
|
||||
Серверных данных, схем и миграций ET-005 **не затрагивает**. Единственная
|
||||
единица данных — клиентский флаг `localStorage:distance_unit`. Требований
|
||||
к резервному копированию, ретенции и приватности не возникает.
|
||||
128
docs/work-items/ET-005/10-tech-risks.md
Normal file
128
docs/work-items/ET-005/10-tech-risks.md
Normal file
@@ -0,0 +1,128 @@
|
||||
---
|
||||
type: tech-risks
|
||||
work_item_id: ET-005
|
||||
title: "Технические риски — ET-005: Переключение единиц измерения (км/мили)"
|
||||
version: 1
|
||||
status: approved
|
||||
created_at: 2026-05-21
|
||||
authors:
|
||||
- "agent:architect"
|
||||
---
|
||||
|
||||
# Технические риски — ET-005
|
||||
|
||||
Шкала: вероятность (Н/С/В) × влияние (Н/С/В).
|
||||
|
||||
## R1 — Пропуск одного из мест форматирования расстояний
|
||||
|
||||
- **Описание:** форматирование `(m/1000).toFixed(N)+' км'` захардкожено
|
||||
минимум в **13 местах** `src/web/app.js`. Если хотя бы одно не
|
||||
переведено на `Units.formatDistance()`, после переключения на мили это
|
||||
расстояние останется в км — нарушение AC-2 («все расстояния»).
|
||||
- **Известные call-sites** (ориентир для разработки и review):
|
||||
`formatDist()` ≈ стр. 187–189; карточка сегмента ≈ 638; карточки
|
||||
маршрута ≈ 1157, 1191, 2202/2212, 2357/2370, 2605; scale-bar
|
||||
≈ 1416–1440; всплывающая подсказка ≈ 1478; линейка/ruler ≈ 1837,
|
||||
1875, 1885, 1931. Список ориентировочный — нумерация строк может
|
||||
сдвинуться; обязателен повторный grep-аудит.
|
||||
- **Вероятность / Влияние:** С / В.
|
||||
- **Митигация:** централизация в `units.js` (ADR-0001); grep-аудит
|
||||
по `' км'` / `/ 1000` / `toFixed` на этапе разработки; e2e TP-02
|
||||
должен проверять **каждую** видимую поверхность с расстоянием, а не
|
||||
одну.
|
||||
|
||||
## R2 — Отсутствие политики для суб-километровых расстояний
|
||||
|
||||
- **Описание:** часть мест отображает расстояния < 1 км в метрах
|
||||
(«м» — напр. линейка, стр. 1837/1885). Имперский эквивалент в AC не
|
||||
определён (футы? мили с долями?). Без явной политики возможен
|
||||
показ «м» в режиме «mi».
|
||||
- **Вероятность / Влияние:** В / С.
|
||||
- **Митигация:** зафиксировать политику в реализации `units.js`.
|
||||
Рекомендация архитектуры: в режиме `mi` суб-километровые значения
|
||||
показывать в милях с увеличенной точностью (напр. 2 знака), **футы
|
||||
не вводить** — это упрощает форматтер и достаточно для эндуро-сценария.
|
||||
Финальное решение — за разработкой/ревью, но политика должна быть
|
||||
единой и явной.
|
||||
|
||||
## R3 — Scale-bar имеет собственную логику единиц
|
||||
|
||||
- **Описание:** масштабная линейка карты (`szb`, стр. 1416–1440) уже
|
||||
содержит независимую логику `km`/`m` с «красивым» округлением. Это
|
||||
отдельный код-путь, который легко не заметить при рефакторинге.
|
||||
- **Вероятность / Влияние:** С / С.
|
||||
- **Митигация:** явно включить scale-bar в список перевода на `Units`
|
||||
и в оркестратор `onUnitChange()`; добавить scale-bar в проверки e2e
|
||||
TP-02.
|
||||
|
||||
## R4 — Несогласованный разделитель дробной части
|
||||
|
||||
- **Описание:** в `app.js` есть расхождение — `formatDist()` (стр. 189)
|
||||
использует точку (`12.3 км`), карточка сегмента (стр. 638) —
|
||||
`.replace('.', ',')` (`12,3 км`). При централизации форматтер должен
|
||||
выбрать один вариант, иначе UI станет визуально неоднородным.
|
||||
- **Вероятность / Влияние:** В / Н.
|
||||
- **Митигация:** `units.js` задаёт единый разделитель для всех
|
||||
поверхностей. Так как у задачи нет требования на локаль, рекомендуется
|
||||
оставить запятую (текущий пользовательский язык интерфейса — русский),
|
||||
но решение должно быть единым и явным.
|
||||
|
||||
## R5 — Конфликт точности: AC-2 vs существующие карточки
|
||||
|
||||
- **Описание:** AC-2 требует «округление до 1 знака», но карточки
|
||||
маршрутов сейчас используют `toFixed(0)` (целые км, стр. 2202, 2357).
|
||||
Слепое применение «1 знака» изменит вид карточек; слепое сохранение
|
||||
`toFixed(0)` нарушит букву AC-2.
|
||||
- **Вероятность / Влияние:** С / Н.
|
||||
- **Митигация:** `formatDistance(meters, {precision})` параметризует
|
||||
точность; по умолчанию — 1 знак (AC-2), карточки явно запрашивают
|
||||
свою точность. Трактовка: AC-2 задаёт точность пересчёта/дефолта, а
|
||||
не запрещает целочисленный показ в карточках.
|
||||
|
||||
## R6 — Экспорт GPX и параметрические значения не должны конвертироваться
|
||||
|
||||
- **Описание:** есть риск «заодно» сконвертировать величины, которые
|
||||
обязаны остаться метрическими: экспорт GPX (стандарт GPX — метры) и
|
||||
кнопки-параметры построения маршрута (`data-km` радиусы разведки/
|
||||
scenic: «20 км», «50», «100», `index.html:130–180`). Это **входные
|
||||
параметры**, а не отображаемые расстояния.
|
||||
- **Вероятность / Влияние:** Н / С.
|
||||
- **Митигация:** scope ET-005 — **только отображаемые** расстояния.
|
||||
GPX-данные и `data-km`-параметры из перевода единиц **исключены**;
|
||||
зафиксировать в review-чеклисте.
|
||||
|
||||
## R7 — Порядок подключения скриптов
|
||||
|
||||
- **Описание:** `units.js` подключается как классический скрипт; `app.js`
|
||||
обращается к `window.Units` на старте. Если `units.js` подключён после
|
||||
`app.js`, инициализация упадёт с `Units is not defined`.
|
||||
- **Вероятность / Влияние:** Н / В.
|
||||
- **Митигация:** `<script src="units.js">` строго перед
|
||||
`<script src="app.js">` в `index.html`; контрольная точка review;
|
||||
smoke-проверка загрузки страницы.
|
||||
|
||||
## R8 — Мобильное размещение переключателя
|
||||
|
||||
- **Описание:** НФТ ТЗ и AC-4 требуют доступности кнопки на всех
|
||||
размерах экрана и неперекрытия других элементов. Попап `#terrain-popup`
|
||||
пополняется ещё одним рядом — на узких экранах (375px, TP-05) возможен
|
||||
выход за пределы/перекрытие.
|
||||
- **Вероятность / Влияние:** Н / С.
|
||||
- **Митигация:** переиспользовать готовый `.seg-control` (адаптивен по
|
||||
ширине); проверить попап на 375px; e2e TP-05.
|
||||
|
||||
## Сводка
|
||||
|
||||
| ID | Риск | Вер. | Влияние | Класс |
|
||||
|----|------|------|---------|-------|
|
||||
| R1 | Пропуск call-site форматирования | С | В | Высокий |
|
||||
| R2 | Нет политики для суб-км значений | В | С | Высокий |
|
||||
| R3 | Scale-bar — отдельная логика единиц | С | С | Средний |
|
||||
| R4 | Несогласованный десятичный разделитель | В | Н | Средний |
|
||||
| R5 | Конфликт точности AC-2 vs карточки | С | Н | Низкий |
|
||||
| R6 | GPX / параметры не конвертировать | Н | С | Низкий |
|
||||
| R7 | Порядок подключения скриптов | Н | В | Средний |
|
||||
| R8 | Мобильное размещение переключателя | Н | С | Низкий |
|
||||
|
||||
Блокирующих рисков нет. R1 и R2 требуют явного внимания на разработке и
|
||||
ревью. Эскалация `arch:major-change` или возврат в Анализ не требуются.
|
||||
Reference in New Issue
Block a user