Files
flights_web/docs/user-stories-7-errors-accessibility.md
gnezim 71d0c983fd
CI / ci (push) Failing after 28s
Deploy / build-and-deploy (push) Failing after 5s
Fix API calls: bind fetch to globalThis, fix date format for calendar
Root cause of search not working: globalThis.fetch stored as a class
field loses its Window binding, causing 'Illegal invocation'. Fixed
with fetch.bind(globalThis).

Also fix calendar days endpoint date format from yyyyMMdd to
yyyy-MM-ddT00:00:00 matching Angular's ApiFormatterService.
2026-04-15 22:32:51 +03:00

42 KiB
Raw Permalink Blame History

Пользовательские истории: Обработка ошибок, граничные случаи и доступность

US-85: Ошибка 404 — Страница не найдена

Цель: Пользователь видит понятное сообщение при переходе на несуществующий URL и может быстро вернуться к рабочему разделу.

Путь клиента:

  1. Переход по неверному URL — ввод или клик по битой ссылке — пользователь вводит /onlineboard/invalid или попадает на устаревшую ссылку.
  2. Router сопоставляет маршрут — wildcard redirect — роутер не находит соответствия и перенаправляет на /error/404.
  3. Страница ошибки загружается — ErrorPageComponent — компонент читает errorCode, title, description из route.snapshot.data.
  4. Отображение сообщения — код и текст — на экране виден код «404», заголовок PAGE404.HEADER и описание PAGE404.DESCRIPTION.
  5. Скрытие баннеров хоста — hideAflComponents() — страница скрывает .afl-component--banners на время показа ошибки.
  6. Поле поиска на странице ошибки — на странице отображается текстовое поле с кнопкой поиска; ввод запроса и клик по кнопке открывает результаты поиска на aeroflot.ru в новой вкладке.
  7. Возврат к работе — переход на главную — пользователь нажимает кнопку и возвращается на /onlineboard или в поиск.

Критерии приёмки:

  • Маршрут /error/404 отображает страницу с кодом 404.
  • Любой неизвестный URL приводит к редиректу на /error/404.
  • Заголовок и описание берутся из переводов (PAGE404.*).
  • Поле поиска позволяет выполнить поиск на aeroflot.ru из страницы ошибки (открывается в новой вкладке).
  • Кнопка «На главную» возвращает на рабочий раздел.
  • Баннеры хост-приложения скрыты на время показа ошибки и восстанавливаются при уходе со страницы (ngOnDestroy).

Примечание: URL онлайн-табло — /onlineboard (без дефиса). Компонент ошибки — общий для 404 и 500, различие задаётся через route.data.


US-86: Ошибка 500 — Внутренняя ошибка сервера

Цель: Пользователь получает понятное сообщение при серверной ошибке и возможность повторить запрос или вернуться на главную.

Путь клиента:

  1. Действие пользователя — поиск или загрузка расписания — пользователь запускает поиск рейсов.
  2. Ошибка на бэкенде — HTTP 5xx — API возвращает 500 либо приложение роутится на /error/500 как default.
  3. Показ страницы ошибки — ErrorPageComponent с errorCode=500 — читаются PAGE500.HEADER и PAGE500.DESCRIPTION.
  4. Скрытие баннеров — hideAflComponents() — сторонние компоненты хоста временно скрываются.
  5. Действия пользователя — повтор или возврат — пользователь может повторить запрос или перейти на главную.
  6. Восстановление — ngOnDestroy — при уходе со страницы баннеры возвращаются в прежнее состояние.

Критерии приёмки:

  • При неизвестной ошибке приложение показывает /error/500 (дефолтный редирект с /error).
  • На странице отображается код «500» и локализованные PAGE500.* строки.
  • Кнопка «На главную» доступна и работает.
  • Баннеры хоста скрываются и корректно восстанавливаются.
  • Страница не ломает верстку хост-приложения.

Примечание: URL онлайн-табло — /onlineboard (без дефиса). В Angular-источнике ErrorPage один компонент на оба кода; дифференциация — через route.data.


US-88: Timeout при загрузке данных

Цель: Пользователь видит корректное состояние, если ответ сервера долго не приходит, и может отменить или повторить запрос.

Путь клиента:

  1. Запуск запроса — пользователь выполняет поиск — отправляется запрос на API рейсов/расписания.
  2. Отображение спиннера — loading state — UI показывает индикатор загрузки до получения ответа.
  3. Ожидание превышает лимит — длительное отсутствие ответа — сеть медленная или сервер не отвечает.
  4. Обработка таймаута — http-cancel / error handler — запрос завершается с ошибкой, приложение переходит в состояние ошибки.
  5. Сообщение пользователю — понятный текст — отображается сообщение о проблеме соединения и предложение повторить.
  6. Повтор или отмена — пользователь управляет ситуацией — можно повторить поиск либо отказаться.

Критерии приёмки:

  • Во время загрузки виден индикатор прогресса.
  • При длительном отсутствии ответа приложение не «зависает».
  • После таймаута пользователь видит понятное сообщение об ошибке.
  • Доступно действие «Повторить».
  • Отменённые запросы не обновляют UI задним числом.

Примечание: Сценарий тестовый — описывает ожидаемое поведение; в Angular-источнике явного лимита таймаута нет, обработка опирается на общий error handler и HttpCancelService.


US-89: Некорректный ввод (специальные символы)

Цель: Система безопасно обрабатывает ввод со специальными символами и не допускает XSS.

Путь клиента:

  1. Ввод спецсимволов — пользователь печатает <script>, кавычки, HTML-теги — данные попадают в поле поиска/фильтра.
  2. Санитизация — Angular/React встроенная защита — фреймворк экранирует значения при выводе.
  3. Валидация — проверка на валидные коды IATA или названия — некорректные значения не проходят в запрос к API.
  4. Безопасное отображение — текст как текст — символы показываются экранированными, без исполнения.
  5. Ответ пользователю — подсказка об ошибке — при невалидном вводе показывается сообщение.

Критерии приёмки:

  • Ввод <script>-тегов не приводит к исполнению JS.
  • HTML-теги отображаются как текст, а не как разметка.
  • Невалидные IATA/названия отклоняются до отправки на сервер.
  • Ответ сервера также экранируется при выводе.
  • Атрибуты DOM не собираются из пользовательского ввода напрямую.

Примечание: Тестовый сценарий безопасности; в кодовой базе обеспечивается framework-уровнем (автоэкранирование).


US-90: Невалидная комбинация параметров

Цель: Система валидирует комбинации параметров поиска и предотвращает бессмысленные запросы.

Путь клиента:

  1. Пользователь заполняет форму — города, даты, направление — вводятся параметры поиска.
  2. Обнаружение конфликта — валидаторы формы — пользователь выбирает одинаковый город для «Откуда» и «Куда», либо прошлую дату, либо недопустимый диапазон.
  3. Блокировка отправки — disable submit — кнопка «Найти» остаётся неактивной или поиск не запускается.
  4. Отображение ошибок — подсказки под полями — рядом с полем выводится причина ошибки.
  5. Исправление — пользователь меняет параметры — после корректного ввода ошибки очищаются и поиск становится доступен.

Критерии приёмки:

  • Совпадающие города «Откуда»/«Куда» отклоняются.
  • Даты в прошлом недопустимы для выбора.
  • Недопустимый диапазон дат показывает сообщение об ошибке.
  • Пока форма невалидна, кнопка поиска неактивна.
  • Сообщения об ошибках локализованы.

Примечание: Тестовый сценарий; в Angular-источнике правила валидации частично присутствуют в shared/services/validators.


US-91: Пустой результат поиска

Цель: Пользователь получает понятное сообщение, когда по запросу нет рейсов.

Путь клиента:

  1. Поиск — пользователь задаёт параметры — выбирает города и даты, запускает поиск.
  2. Запрос к API — корректные параметры — валидация пройдена, запрос уходит на сервер.
  3. Пустой ответ — нет рейсов — API возвращает пустой список для указанных условий.
  4. Отображение empty state — сообщение «Рейсов не найдено» — вместо списка показывается информационный блок.
  5. Подсказки пользователю — альтернативы — предлагается изменить дату/направление или сбросить фильтры.

Критерии приёмки:

  • Пустой массив результатов не показывает «сломанный» UI.
  • Отображается локализованное сообщение об отсутствии рейсов.
  • Пользователь может легко изменить параметры поиска.
  • Активные фильтры не блокируют новый поиск.
  • Состояние empty отличается визуально от состояния ошибки.

US-92: Unicode символы в вводе

Цель: Система корректно отображает и обрабатывает строки в Unicode (кириллица, CJK, арабский, emoji).

Путь клиента:

  1. Ввод Unicode — пользователь печатает нелатинские символы — в поле поиска появляется текст в разных алфавитах.
  2. Передача в API — UTF-8 кодирование — запрос корректно кодирует параметры.
  3. Ответ сервера — Unicode в названиях — города и аэропорты возвращаются с корректной кодировкой.
  4. Отображение — шрифты и вёрстка — названия видны без «кракозябр».
  5. Фильтрация и поиск — регистронезависимое сравнение — совпадения находятся вне зависимости от регистра и алфавита.

Критерии приёмки:

  • Кириллица, CJK и арабский отображаются корректно.
  • Emoji не ломают верстку (допустимо отклонить при валидации IATA).
  • Поиск работает с Unicode-запросами.
  • Параметры корректно кодируются в URL.
  • Ответ API с Unicode-строками рендерится без повреждений.

US-93: Очень длинные имена городов и аэропортов

Цель: Интерфейс не ломается при очень длинных названиях городов, аэропортов и авиакомпаний.

Путь клиента:

  1. Загрузка данных — длинное название — API возвращает запись с длинным именем (например, полное название аэропорта).
  2. Отображение в списке — ограниченная ширина — карточка или строка имеет фиксированную ширину.
  3. Обрезка текста — CSS ellipsis — длинный текст усекается с многоточием.
  4. Полное имя — tooltip/title — при наведении доступно полное название.
  5. Адаптив — разные breakpoints — поведение сохраняется на мобильных и десктопе.

Критерии приёмки:

  • Длинные названия не выходят за границы контейнера.
  • Текст усекается с видимым многоточием.
  • Полное название доступно через tooltip или аналогичный механизм.
  • Верстка соседних элементов не сдвигается.
  • Поведение работает на всех breakpoint.

Примечание: Тестовый сценарий устойчивости; в кодовой базе опирается на CSS-классы текстовых ячеек.


US-94: Быстрая последовательность поисков

Цель: Система корректно обрабатывает быстро выполняемые подряд запросы и показывает результат последнего.

Путь клиента:

  1. Пользователь запускает поиск — первый запрос — уходит HTTP-запрос на сервер.
  2. Смена параметров — новый запрос до завершения предыдущего — пользователь меняет город/дату и снова нажимает поиск.
  3. Отмена предыдущего — HttpCancelService — незавершённые запросы отменяются через cancel-механизм.
  4. Обработка последнего — применение свежего ответа — в UI показывается результат только последнего запроса.
  5. Защита от гонок — state не перезаписывается старым ответом — отменённые запросы не обновляют список.

Критерии приёмки:

  • Отменённый запрос не обновляет UI.
  • В результатах отображается ответ последнего запроса.
  • Индикатор загрузки виден до завершения последнего запроса.
  • Быстрые клики не приводят к миганию результатов.
  • Нет утечек подписок/обработчиков.

Примечание: В Angular-источнике есть shared/services/http-cancel.service.ts, обеспечивающий отмену предыдущих запросов.


US-95: Клавиатурная навигация

Цель: Пользователь может полностью управлять приложением только с клавиатуры.

Путь клиента:

  1. Навигация по Tab — обход интерактивных элементов — фокус проходит по полям, кнопкам и ссылкам в логичном порядке.
  2. Активация — Enter/Space — кнопки и ссылки активируются клавиатурой.
  3. Отправка формы — Enter в поле поиска — запускает поиск без использования мыши.
  4. Закрытие попапов — Escape — выпадающие списки и диалоги закрываются по Esc.
  5. Навигация по спискам — стрелки — в dropdown и списках работает перемещение стрелками.
  6. Видимый фокус — focus ring — текущий элемент визуально выделен.

Критерии приёмки:

  • Tab-порядок соответствует визуальному порядку элементов.
  • Нет «ловушек» фокуса вне диалогов.
  • Enter отправляет форму поиска.
  • Escape закрывает выпадающие меню и диалоги.
  • На всех интерактивных элементах виден focus-индикатор.

Примечание: Тестовый сценарий доступности; поведение собирается из встроенной семантики и ARIA.


US-96: Читатели экрана (ARIA-метки)

Цель: Приложение корректно работает со screen reader (NVDA, VoiceOver, JAWS).

Путь клиента:

  1. Загрузка страницы — screen reader озвучивает заголовок<title> и h1 корректно читаются.
  2. Формы — label и aria-label — каждое поле связано с текстовой меткой.
  3. Кнопки и иконки — aria-label для icon-only — иконочные кнопки имеют текстовую аннотацию.
  4. Динамический контент — aria-live — появление результатов поиска или ошибок объявляется.
  5. Списки и таблицы — корректные роли — расписание использует семантическую структуру.
  6. Изображения — alt — декоративные скрыты (alt=""), смысловые имеют описание.

Критерии приёмки:

  • Все поля форм имеют связанный label или aria-label.
  • Icon-only кнопки озвучиваются со смысловой подписью.
  • Динамические обновления (результаты, ошибки) объявляются screen reader.
  • Используется семантический HTML (button, nav, main, h1h3).
  • Изображения имеют корректный alt.

Примечание: Тестовый сценарий WCAG; конкретная реализация ARIA — часть компонентного слоя.


US-98: Фокусное кольцо (focus-visible)

Цель: Пользователь, навигирующий с клавиатуры, всегда видит, какой элемент находится в фокусе.

Путь клиента:

  1. Навигация Tab — пользователь переходит между элементами — каждое нажатие Tab смещает фокус.
  2. Рендеринг focus ring — CSS :focus-visible — обводка появляется только при клавиатурной навигации.
  3. Скрытие при клике мышью — :focus:not(:focus-visible) — кольцо не отображается при обычных кликах.
  4. Контрастность — видимое кольцо — цвет и толщина заметны на фоне.
  5. Единообразие — стиль одинаков для всех интерактивных элементов — кнопки, ссылки, поля ввода.

Критерии приёмки:

  • При Tab-навигации фокус виден на всех интерактивных элементах.
  • При кликах мышью кольцо не появляется (используется :focus-visible).
  • Контраст кольца соответствует WCAG AA.
  • Стиль фокуса согласован между компонентами.
  • Ни один интерактивный элемент не остаётся без индикатора фокуса.

Примечание: Тестовый сценарий доступности, реализуется через глобальные CSS-стили.


US-99: Масштабирование текста (zoom)

Цель: Пользователь может увеличивать текст/страницу до 200% без потери функциональности.

Путь клиента:

  1. Запуск zoom — Ctrl + / Cmd + — браузер увеличивает масштаб страницы.
  2. Адаптация текста — относительные единицыrem/em корректно пересчитываются.
  3. Адаптивный layout — reflow — сетка перестраивается под новую ширину.
  4. Отсутствие горизонтального скролла — контент остаётся в viewport — до 200% без обрезки.
  5. Интерактив доступен — все кнопки и поля видны — форма поиска и результаты пригодны к использованию.

Критерии приёмки:

  • Увеличение до 200% не ломает layout.
  • Нет горизонтального скролла на типовых breakpoint.
  • Текст не перекрывается и не обрезается.
  • Все интерактивные элементы остаются доступными.
  • Relative units используются для размеров текста и отступов.

Примечание: Тестовый сценарий WCAG 1.4.4; реализация зависит от CSS.


US-100: Сенсорная навигация (touch)

Цель: Мобильные пользователи могут полностью управлять приложением пальцами.

Путь клиента:

  1. Touch-жесты — tap, swipe, pinch — пользователь взаимодействует с экраном.
  2. Размер целей — минимум 44×44px — кнопки и ссылки достаточны для попадания пальцем.
  3. Интервалы — достаточные отступы — соседние цели не кликаются случайно.
  4. Альтернативы жестам — обычные кнопки — любое действие через swipe дублируется кнопкой.
  5. Отсутствие hover-only — tap доступен всегда — функциональность не скрыта за hover.

Критерии приёмки:

  • Touch-таргеты не меньше 44×44px.
  • Расстояние между целями предотвращает случайные нажатия.
  • Все функции доступны без hover.
  • Жесты (где используются) имеют альтернативу обычным тапом.
  • Скролл и pinch-zoom работают штатно.

Примечание: Тестовый сценарий мобильной доступности.


US-101: Персистентное состояние (StateService)

Цель: Ключевое состояние приложения сохраняется между переходами и переживает перезагрузку страницы там, где это предусмотрено.

Путь клиента:

  1. Сохранение — StateService.set(key, data) — страница кладёт состояние в Map по ключу.
  2. Переход между разделами — навигация — пользователь уходит с экрана и возвращается.
  3. Чтение — StateService.get(key) — экран восстанавливает данные из сервиса.
  4. Параметры поиска в URL — query params — часть состояния синхронизируется через URL.
  5. Перезагрузка страницы — refresh — параметры из URL позволяют восстановить форму и запустить поиск.
  6. Очистка — StateService.delete(key) — при необходимости состояние сбрасывается.

Критерии приёмки:

  • StateService.set/get/delete работают как in-memory Map хранилище.
  • При возврате на страницу её состояние восстанавливается из сервиса.
  • Параметры поиска присутствуют в URL и читаются при старте.
  • После refresh форма заполняется из URL-параметров.
  • Данные не «текут» между независимыми ключами.

Примечание: В Angular-источнике StateService — простой in-memory Map (shared/services/state.service.ts), он не использует localStorage; персистенция между перезагрузками достигается через URL.


US-102: История браузера (back/forward)

Цель: Кнопки браузера «Назад» и «Вперёд» корректно перемещают пользователя по состояниям приложения.

Путь клиента:

  1. Переход по разделам — пользователь открывает страницы — роутер добавляет записи в history.
  2. Обновление URL — query params отражают фильтры — параметры поиска и сортировки видны в URL.
  3. Нажатие Back — popstate — роутер восстанавливает предыдущее состояние.
  4. Нажатие Forward — возврат к следующему состоянию — аналогично, без потери данных.
  5. Синхронизация UI — чтение query params — фильтры и форма обновляются под URL.

Критерии приёмки:

  • Каждая значимая навигация создаёт запись в history.
  • Back возвращает на предыдущий URL с корректным состоянием.
  • Forward работает симметрично.
  • Query params читаются при навигации и обновляют UI.
  • Глубокие ссылки открывают нужный раздел напрямую.

Примечание: В Angular-источнике навигация — стандартный Angular Router; синхронизация через query params.


US-103: Обработка больших объёмов данных

Цель: Приложение остаётся отзывчивым при отображении длинных списков рейсов/расписания.

Путь клиента:

  1. Загрузка данных — большой ответ API — приходит расписание с сотнями рейсов.
  2. Рендер списка — оптимизированный вывод — используется виртуализация либо разумная пагинация/ограничение.
  3. Скролл — плавная прокрутка — браузер не проседает по FPS.
  4. Фильтрация и сортировка — мгновенная реакция — действия не вызывают полной перерисовки.
  5. Освобождение памяти — unsubscribe при уходе — подписки и кэши корректно очищаются.

Критерии приёмки:

  • Список из сотен элементов рендерится без ощутимых задержек.
  • Скролл остаётся плавным на типовых устройствах.
  • Фильтрация и сортировка не «замораживают» UI.
  • При уходе со страницы не остаётся зомби-подписок.
  • Память приложения не растёт неограниченно при повторных поисках.

Примечание: Тестовый сценарий производительности; конкретный механизм (виртуализация/пагинация) — на выбор реализации.


US-104: Кэширование ответов (CacheService 30s)

Цель: Повторные одинаковые запросы к API обслуживаются из кэша, чтобы снизить нагрузку и ускорить отклик.

Путь клиента:

  1. Первый запрос — CacheService.get(key, options) — кэш пуст, запрос уходит на сервер.
  2. Сохранение ответа — CacheService.set(key, options, result) — результат кладётся в requestsMap по ключу.
  3. Таймер инвалидации — setTimeout 30s — через INVALID_TIMEOUT = 30 * 1000 запись удаляется.
  4. Повторный запрос в пределах окна — быстрый ответget() возвращает закэшированный result.
  5. Истечение 30 секунд — удаление ключа — следующий запрос снова идёт на сервер.
  6. Ручная инвалидация — CacheService.delete(key) — позволяет сбросить запись принудительно.

Критерии приёмки:

  • CacheService.set/get/delete работают по in-memory Map.
  • Таймаут инвалидации — 30 секунд (INVALID_TIMEOUT = 30 * 1000).
  • Повторный запрос в пределах окна не порождает сетевой вызов.
  • После таймаута запись удаляется и следующий запрос уходит на сервер.
  • delete(key) очищает указанную запись вручную.

Примечание: Источник истины — shared/services/cache.service.ts. Таймер на каждую set() перезапускается (clearTimeout), поэтому окно отсчитывается от последнего обновления записи.


US-105: Обновление данных в реальном времени (SignalR)

Цель: Данные онлайн-табло автоматически обновляются при поступлении серверных событий, чтобы пользователь видел актуальную информацию без ручной перезагрузки.

Путь клиента:

  1. Подключение к хабу — при загрузке страницы результатов или деталей рейса RefreshBoardService / RefreshService инициализирует SignalR-соединение с environment.urlForTrackerHub.
  2. Подписка на события — сервис подписывается на события RefreshDate (для списка рейсов) или Refresh (для деталей рейса по ID).
  3. Тихое обновление — при поступлении события данные перезагружаются с флагом silent, без показа индикатора загрузки, чтобы не отвлекать пользователя.
  4. Оверлей устаревших данныхFadeService запускает таймер; при бездействии пользователя в течение environment.refreshPauseMin минут поверх страницы появляется полупрозрачный оверлей с сообщением «Данные устарели, обновите страницу!».
  5. Автоматический редирект — если бездействие превышает environment.refreshStopMin минут, приложение перенаправляет пользователя на главную страницу (/).
  6. Очистка — при уходе со страницы (ngOnDestroy) подписки SignalR и таймеры FadeService очищаются.

Критерии приёмки:

  • На страницах результатов онлайн-табло устанавливается SignalR-соединение для получения обновлений.
  • На странице деталей рейса подписка привязана к конкретному ID рейса.
  • Обновление данных происходит без видимого индикатора загрузки (silent reload).
  • После refreshPauseMin минут бездействия показывается полноэкранный оверлей (z-index 9999, полупрозрачный фон).
  • После refreshStopMin минут бездействия происходит автоматический редирект на главную.
  • SignalR-подписки и таймеры корректно очищаются при уничтожении компонентов.

Примечание: Функция актуальна только для онлайн-табло (реальное время). Расписание и карта полётов не используют SignalR. FadeService создаёт overlay программно через DOM API (document.createElement).


US-106: Встроенный чат-бот

Цель: Пользователь может воспользоваться чат-ботом для получения справочной информации.

Путь клиента:

  1. Инициализация — компонент chat-bot в ngAfterViewInit динамически создаёт <script> элемент с URL из environment.chatBotScript.
  2. Загрузка виджета — скрипт монтируется к #app-chat-bot-container, загружая внешний чат-виджет.
  3. Использование — после загрузки пользователь видит виджет чата и может задавать вопросы.

Критерии приёмки:

  • Чат-бот загружается динамически через внешний скрипт из environment.chatBotScript.
  • Виджет монтируется в контейнер #app-chat-bot-container.
  • Ошибки загрузки скрипта не ломают остальной интерфейс.

Примечание: URL скрипта настраивается через конфигурацию окружения.


US-107: Canonical URL и SEO мета-теги по страницам

Цель: Каждая страница приложения имеет корректные canonical URL и уникальные SEO мета-теги для правильной индексации поисковыми системами.

Путь клиента:

  1. Установка canonicalCanonicalService формирует <link rel="canonical"> для текущей страницы.
  2. Мета-теги по разделам — каждый раздел (онлайн-табло, расписание, карта полётов) имеет собственные компоненты мета-тегов с уникальными ключами SEO.*:
    • Онлайн-табло: стартовая, результаты (по номеру/маршруту/отправлению/прибытию), детали рейса
    • Расписание: стартовая, результаты, детали рейса
    • Карта полётов: стартовая
  3. Динамические значения — для страниц результатов и деталей мета-теги включают названия городов, даты и номера рейсов.
  4. OpenGraph — для страниц деталей формируются og:title, og:description, og:image теги.
  5. noRobots — на страницах с динамическими параметрами (результаты, детали) установлен noRobots: true для предотвращения индексации.

Критерии приёмки:

  • Canonical URL корректен для каждой страницы.
  • Мета-теги title и description уникальны для каждого типа страницы.
  • Динамические страницы включают контекст (город, дата, номер рейса) в мета-теги.
  • Стартовые страницы разделов индексируются (noRobots: false), страницы результатов — нет.
  • OpenGraph-теги формируются для страниц деталей.

Примечание: Компоненты мета-тегов наследуют от MetaBaseComponent и переопределяют translateTitle()/translateDescription().


US-108: Отображение версии API (debug-режим)

Цель: В debug-режиме разработчик может видеть текущую версию API для диагностики.

Путь клиента:

  1. Проверка флагаAppVersionComponent проверяет settings.showDebugVersion из APP_SETTINGS.
  2. Запрос версии — если флаг включён, NetworkService.getApiVersion() загружает номер версии.
  3. Отображение — версия выводится компонентом app-version рядом с навигацией.
  4. Скрытие баннера — при включённом debug-режиме скрывается элемент .banner--top.

Критерии приёмки:

  • В обычном режиме версия не отображается.
  • При showDebugVersion = true показывается номер версии API.
  • Компонент app-show-debug условно рендерит debug-информацию.

Примечание: Предназначено для разработки и тестирования, не для конечных пользователей.