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.
42 KiB
Пользовательские истории: Обработка ошибок, граничные случаи и доступность
US-85: Ошибка 404 — Страница не найдена
Цель: Пользователь видит понятное сообщение при переходе на несуществующий URL и может быстро вернуться к рабочему разделу.
Путь клиента:
- Переход по неверному URL — ввод или клик по битой ссылке — пользователь вводит
/onlineboard/invalidили попадает на устаревшую ссылку. - Router сопоставляет маршрут — wildcard redirect — роутер не находит соответствия и перенаправляет на
/error/404. - Страница ошибки загружается — ErrorPageComponent — компонент читает
errorCode,title,descriptionизroute.snapshot.data. - Отображение сообщения — код и текст — на экране виден код «404», заголовок
PAGE404.HEADERи описаниеPAGE404.DESCRIPTION. - Скрытие баннеров хоста — hideAflComponents() — страница скрывает
.afl-component--bannersна время показа ошибки. - Поле поиска на странице ошибки — на странице отображается текстовое поле с кнопкой поиска; ввод запроса и клик по кнопке открывает результаты поиска на aeroflot.ru в новой вкладке.
- Возврат к работе — переход на главную — пользователь нажимает кнопку и возвращается на
/onlineboardили в поиск.
Критерии приёмки:
- ✅ Маршрут
/error/404отображает страницу с кодом 404. - ✅ Любой неизвестный URL приводит к редиректу на
/error/404. - ✅ Заголовок и описание берутся из переводов (
PAGE404.*). - ✅ Поле поиска позволяет выполнить поиск на aeroflot.ru из страницы ошибки (открывается в новой вкладке).
- ✅ Кнопка «На главную» возвращает на рабочий раздел.
- ✅ Баннеры хост-приложения скрыты на время показа ошибки и восстанавливаются при уходе со страницы (
ngOnDestroy).
Примечание: URL онлайн-табло — /onlineboard (без дефиса). Компонент ошибки — общий для 404 и 500, различие задаётся через route.data.
US-86: Ошибка 500 — Внутренняя ошибка сервера
Цель: Пользователь получает понятное сообщение при серверной ошибке и возможность повторить запрос или вернуться на главную.
Путь клиента:
- Действие пользователя — поиск или загрузка расписания — пользователь запускает поиск рейсов.
- Ошибка на бэкенде — HTTP 5xx — API возвращает 500 либо приложение роутится на
/error/500как default. - Показ страницы ошибки — ErrorPageComponent с errorCode=500 — читаются
PAGE500.HEADERиPAGE500.DESCRIPTION. - Скрытие баннеров — hideAflComponents() — сторонние компоненты хоста временно скрываются.
- Действия пользователя — повтор или возврат — пользователь может повторить запрос или перейти на главную.
- Восстановление — ngOnDestroy — при уходе со страницы баннеры возвращаются в прежнее состояние.
Критерии приёмки:
- ✅ При неизвестной ошибке приложение показывает
/error/500(дефолтный редирект с/error). - ✅ На странице отображается код «500» и локализованные
PAGE500.*строки. - ✅ Кнопка «На главную» доступна и работает.
- ✅ Баннеры хоста скрываются и корректно восстанавливаются.
- ✅ Страница не ломает верстку хост-приложения.
Примечание: URL онлайн-табло — /onlineboard (без дефиса). В Angular-источнике ErrorPage один компонент на оба кода; дифференциация — через route.data.
US-88: Timeout при загрузке данных
Цель: Пользователь видит корректное состояние, если ответ сервера долго не приходит, и может отменить или повторить запрос.
Путь клиента:
- Запуск запроса — пользователь выполняет поиск — отправляется запрос на API рейсов/расписания.
- Отображение спиннера — loading state — UI показывает индикатор загрузки до получения ответа.
- Ожидание превышает лимит — длительное отсутствие ответа — сеть медленная или сервер не отвечает.
- Обработка таймаута — http-cancel / error handler — запрос завершается с ошибкой, приложение переходит в состояние ошибки.
- Сообщение пользователю — понятный текст — отображается сообщение о проблеме соединения и предложение повторить.
- Повтор или отмена — пользователь управляет ситуацией — можно повторить поиск либо отказаться.
Критерии приёмки:
- ✅ Во время загрузки виден индикатор прогресса.
- ✅ При длительном отсутствии ответа приложение не «зависает».
- ✅ После таймаута пользователь видит понятное сообщение об ошибке.
- ✅ Доступно действие «Повторить».
- ✅ Отменённые запросы не обновляют UI задним числом.
Примечание: Сценарий тестовый — описывает ожидаемое поведение; в Angular-источнике явного лимита таймаута нет, обработка опирается на общий error handler и HttpCancelService.
US-89: Некорректный ввод (специальные символы)
Цель: Система безопасно обрабатывает ввод со специальными символами и не допускает XSS.
Путь клиента:
- Ввод спецсимволов — пользователь печатает
<script>, кавычки, HTML-теги — данные попадают в поле поиска/фильтра. - Санитизация — Angular/React встроенная защита — фреймворк экранирует значения при выводе.
- Валидация — проверка на валидные коды IATA или названия — некорректные значения не проходят в запрос к API.
- Безопасное отображение — текст как текст — символы показываются экранированными, без исполнения.
- Ответ пользователю — подсказка об ошибке — при невалидном вводе показывается сообщение.
Критерии приёмки:
- ✅ Ввод
<script>-тегов не приводит к исполнению JS. - ✅ HTML-теги отображаются как текст, а не как разметка.
- ✅ Невалидные IATA/названия отклоняются до отправки на сервер.
- ✅ Ответ сервера также экранируется при выводе.
- ✅ Атрибуты DOM не собираются из пользовательского ввода напрямую.
Примечание: Тестовый сценарий безопасности; в кодовой базе обеспечивается framework-уровнем (автоэкранирование).
US-90: Невалидная комбинация параметров
Цель: Система валидирует комбинации параметров поиска и предотвращает бессмысленные запросы.
Путь клиента:
- Пользователь заполняет форму — города, даты, направление — вводятся параметры поиска.
- Обнаружение конфликта — валидаторы формы — пользователь выбирает одинаковый город для «Откуда» и «Куда», либо прошлую дату, либо недопустимый диапазон.
- Блокировка отправки — disable submit — кнопка «Найти» остаётся неактивной или поиск не запускается.
- Отображение ошибок — подсказки под полями — рядом с полем выводится причина ошибки.
- Исправление — пользователь меняет параметры — после корректного ввода ошибки очищаются и поиск становится доступен.
Критерии приёмки:
- ✅ Совпадающие города «Откуда»/«Куда» отклоняются.
- ✅ Даты в прошлом недопустимы для выбора.
- ✅ Недопустимый диапазон дат показывает сообщение об ошибке.
- ✅ Пока форма невалидна, кнопка поиска неактивна.
- ✅ Сообщения об ошибках локализованы.
Примечание: Тестовый сценарий; в Angular-источнике правила валидации частично присутствуют в shared/services/validators.
US-91: Пустой результат поиска
Цель: Пользователь получает понятное сообщение, когда по запросу нет рейсов.
Путь клиента:
- Поиск — пользователь задаёт параметры — выбирает города и даты, запускает поиск.
- Запрос к API — корректные параметры — валидация пройдена, запрос уходит на сервер.
- Пустой ответ — нет рейсов — API возвращает пустой список для указанных условий.
- Отображение empty state — сообщение «Рейсов не найдено» — вместо списка показывается информационный блок.
- Подсказки пользователю — альтернативы — предлагается изменить дату/направление или сбросить фильтры.
Критерии приёмки:
- ✅ Пустой массив результатов не показывает «сломанный» UI.
- ✅ Отображается локализованное сообщение об отсутствии рейсов.
- ✅ Пользователь может легко изменить параметры поиска.
- ✅ Активные фильтры не блокируют новый поиск.
- ✅ Состояние empty отличается визуально от состояния ошибки.
US-92: Unicode символы в вводе
Цель: Система корректно отображает и обрабатывает строки в Unicode (кириллица, CJK, арабский, emoji).
Путь клиента:
- Ввод Unicode — пользователь печатает нелатинские символы — в поле поиска появляется текст в разных алфавитах.
- Передача в API — UTF-8 кодирование — запрос корректно кодирует параметры.
- Ответ сервера — Unicode в названиях — города и аэропорты возвращаются с корректной кодировкой.
- Отображение — шрифты и вёрстка — названия видны без «кракозябр».
- Фильтрация и поиск — регистронезависимое сравнение — совпадения находятся вне зависимости от регистра и алфавита.
Критерии приёмки:
- ✅ Кириллица, CJK и арабский отображаются корректно.
- ✅ Emoji не ломают верстку (допустимо отклонить при валидации IATA).
- ✅ Поиск работает с Unicode-запросами.
- ✅ Параметры корректно кодируются в URL.
- ✅ Ответ API с Unicode-строками рендерится без повреждений.
US-93: Очень длинные имена городов и аэропортов
Цель: Интерфейс не ломается при очень длинных названиях городов, аэропортов и авиакомпаний.
Путь клиента:
- Загрузка данных — длинное название — API возвращает запись с длинным именем (например, полное название аэропорта).
- Отображение в списке — ограниченная ширина — карточка или строка имеет фиксированную ширину.
- Обрезка текста — CSS ellipsis — длинный текст усекается с многоточием.
- Полное имя — tooltip/title — при наведении доступно полное название.
- Адаптив — разные breakpoints — поведение сохраняется на мобильных и десктопе.
Критерии приёмки:
- ✅ Длинные названия не выходят за границы контейнера.
- ✅ Текст усекается с видимым многоточием.
- ✅ Полное название доступно через tooltip или аналогичный механизм.
- ✅ Верстка соседних элементов не сдвигается.
- ✅ Поведение работает на всех breakpoint.
Примечание: Тестовый сценарий устойчивости; в кодовой базе опирается на CSS-классы текстовых ячеек.
US-94: Быстрая последовательность поисков
Цель: Система корректно обрабатывает быстро выполняемые подряд запросы и показывает результат последнего.
Путь клиента:
- Пользователь запускает поиск — первый запрос — уходит HTTP-запрос на сервер.
- Смена параметров — новый запрос до завершения предыдущего — пользователь меняет город/дату и снова нажимает поиск.
- Отмена предыдущего — HttpCancelService — незавершённые запросы отменяются через cancel-механизм.
- Обработка последнего — применение свежего ответа — в UI показывается результат только последнего запроса.
- Защита от гонок — state не перезаписывается старым ответом — отменённые запросы не обновляют список.
Критерии приёмки:
- ✅ Отменённый запрос не обновляет UI.
- ✅ В результатах отображается ответ последнего запроса.
- ✅ Индикатор загрузки виден до завершения последнего запроса.
- ✅ Быстрые клики не приводят к миганию результатов.
- ✅ Нет утечек подписок/обработчиков.
Примечание: В Angular-источнике есть shared/services/http-cancel.service.ts, обеспечивающий отмену предыдущих запросов.
US-95: Клавиатурная навигация
Цель: Пользователь может полностью управлять приложением только с клавиатуры.
Путь клиента:
- Навигация по Tab — обход интерактивных элементов — фокус проходит по полям, кнопкам и ссылкам в логичном порядке.
- Активация — Enter/Space — кнопки и ссылки активируются клавиатурой.
- Отправка формы — Enter в поле поиска — запускает поиск без использования мыши.
- Закрытие попапов — Escape — выпадающие списки и диалоги закрываются по Esc.
- Навигация по спискам — стрелки — в dropdown и списках работает перемещение стрелками.
- Видимый фокус — focus ring — текущий элемент визуально выделен.
Критерии приёмки:
- ✅ Tab-порядок соответствует визуальному порядку элементов.
- ✅ Нет «ловушек» фокуса вне диалогов.
- ✅ Enter отправляет форму поиска.
- ✅ Escape закрывает выпадающие меню и диалоги.
- ✅ На всех интерактивных элементах виден focus-индикатор.
Примечание: Тестовый сценарий доступности; поведение собирается из встроенной семантики и ARIA.
US-96: Читатели экрана (ARIA-метки)
Цель: Приложение корректно работает со screen reader (NVDA, VoiceOver, JAWS).
Путь клиента:
- Загрузка страницы — screen reader озвучивает заголовок —
<title>иh1корректно читаются. - Формы — label и aria-label — каждое поле связано с текстовой меткой.
- Кнопки и иконки — aria-label для icon-only — иконочные кнопки имеют текстовую аннотацию.
- Динамический контент — aria-live — появление результатов поиска или ошибок объявляется.
- Списки и таблицы — корректные роли — расписание использует семантическую структуру.
- Изображения — alt — декоративные скрыты (
alt=""), смысловые имеют описание.
Критерии приёмки:
- ✅ Все поля форм имеют связанный label или aria-label.
- ✅ Icon-only кнопки озвучиваются со смысловой подписью.
- ✅ Динамические обновления (результаты, ошибки) объявляются screen reader.
- ✅ Используется семантический HTML (
button,nav,main,h1–h3). - ✅ Изображения имеют корректный alt.
Примечание: Тестовый сценарий WCAG; конкретная реализация ARIA — часть компонентного слоя.
US-98: Фокусное кольцо (focus-visible)
Цель: Пользователь, навигирующий с клавиатуры, всегда видит, какой элемент находится в фокусе.
Путь клиента:
- Навигация Tab — пользователь переходит между элементами — каждое нажатие Tab смещает фокус.
- Рендеринг focus ring — CSS
:focus-visible— обводка появляется только при клавиатурной навигации. - Скрытие при клике мышью —
:focus:not(:focus-visible)— кольцо не отображается при обычных кликах. - Контрастность — видимое кольцо — цвет и толщина заметны на фоне.
- Единообразие — стиль одинаков для всех интерактивных элементов — кнопки, ссылки, поля ввода.
Критерии приёмки:
- ✅ При Tab-навигации фокус виден на всех интерактивных элементах.
- ✅ При кликах мышью кольцо не появляется (используется
:focus-visible). - ✅ Контраст кольца соответствует WCAG AA.
- ✅ Стиль фокуса согласован между компонентами.
- ✅ Ни один интерактивный элемент не остаётся без индикатора фокуса.
Примечание: Тестовый сценарий доступности, реализуется через глобальные CSS-стили.
US-99: Масштабирование текста (zoom)
Цель: Пользователь может увеличивать текст/страницу до 200% без потери функциональности.
Путь клиента:
- Запуск zoom — Ctrl + / Cmd + — браузер увеличивает масштаб страницы.
- Адаптация текста — относительные единицы —
rem/emкорректно пересчитываются. - Адаптивный layout — reflow — сетка перестраивается под новую ширину.
- Отсутствие горизонтального скролла — контент остаётся в viewport — до 200% без обрезки.
- Интерактив доступен — все кнопки и поля видны — форма поиска и результаты пригодны к использованию.
Критерии приёмки:
- ✅ Увеличение до 200% не ломает layout.
- ✅ Нет горизонтального скролла на типовых breakpoint.
- ✅ Текст не перекрывается и не обрезается.
- ✅ Все интерактивные элементы остаются доступными.
- ✅ Relative units используются для размеров текста и отступов.
Примечание: Тестовый сценарий WCAG 1.4.4; реализация зависит от CSS.
US-100: Сенсорная навигация (touch)
Цель: Мобильные пользователи могут полностью управлять приложением пальцами.
Путь клиента:
- Touch-жесты — tap, swipe, pinch — пользователь взаимодействует с экраном.
- Размер целей — минимум 44×44px — кнопки и ссылки достаточны для попадания пальцем.
- Интервалы — достаточные отступы — соседние цели не кликаются случайно.
- Альтернативы жестам — обычные кнопки — любое действие через swipe дублируется кнопкой.
- Отсутствие hover-only — tap доступен всегда — функциональность не скрыта за hover.
Критерии приёмки:
- ✅ Touch-таргеты не меньше 44×44px.
- ✅ Расстояние между целями предотвращает случайные нажатия.
- ✅ Все функции доступны без hover.
- ✅ Жесты (где используются) имеют альтернативу обычным тапом.
- ✅ Скролл и pinch-zoom работают штатно.
Примечание: Тестовый сценарий мобильной доступности.
US-101: Персистентное состояние (StateService)
Цель: Ключевое состояние приложения сохраняется между переходами и переживает перезагрузку страницы там, где это предусмотрено.
Путь клиента:
- Сохранение — StateService.set(key, data) — страница кладёт состояние в Map по ключу.
- Переход между разделами — навигация — пользователь уходит с экрана и возвращается.
- Чтение — StateService.get(key) — экран восстанавливает данные из сервиса.
- Параметры поиска в URL — query params — часть состояния синхронизируется через URL.
- Перезагрузка страницы — refresh — параметры из URL позволяют восстановить форму и запустить поиск.
- Очистка — 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)
Цель: Кнопки браузера «Назад» и «Вперёд» корректно перемещают пользователя по состояниям приложения.
Путь клиента:
- Переход по разделам — пользователь открывает страницы — роутер добавляет записи в history.
- Обновление URL — query params отражают фильтры — параметры поиска и сортировки видны в URL.
- Нажатие Back — popstate — роутер восстанавливает предыдущее состояние.
- Нажатие Forward — возврат к следующему состоянию — аналогично, без потери данных.
- Синхронизация UI — чтение query params — фильтры и форма обновляются под URL.
Критерии приёмки:
- ✅ Каждая значимая навигация создаёт запись в history.
- ✅ Back возвращает на предыдущий URL с корректным состоянием.
- ✅ Forward работает симметрично.
- ✅ Query params читаются при навигации и обновляют UI.
- ✅ Глубокие ссылки открывают нужный раздел напрямую.
Примечание: В Angular-источнике навигация — стандартный Angular Router; синхронизация через query params.
US-103: Обработка больших объёмов данных
Цель: Приложение остаётся отзывчивым при отображении длинных списков рейсов/расписания.
Путь клиента:
- Загрузка данных — большой ответ API — приходит расписание с сотнями рейсов.
- Рендер списка — оптимизированный вывод — используется виртуализация либо разумная пагинация/ограничение.
- Скролл — плавная прокрутка — браузер не проседает по FPS.
- Фильтрация и сортировка — мгновенная реакция — действия не вызывают полной перерисовки.
- Освобождение памяти — unsubscribe при уходе — подписки и кэши корректно очищаются.
Критерии приёмки:
- ✅ Список из сотен элементов рендерится без ощутимых задержек.
- ✅ Скролл остаётся плавным на типовых устройствах.
- ✅ Фильтрация и сортировка не «замораживают» UI.
- ✅ При уходе со страницы не остаётся зомби-подписок.
- ✅ Память приложения не растёт неограниченно при повторных поисках.
Примечание: Тестовый сценарий производительности; конкретный механизм (виртуализация/пагинация) — на выбор реализации.
US-104: Кэширование ответов (CacheService 30s)
Цель: Повторные одинаковые запросы к API обслуживаются из кэша, чтобы снизить нагрузку и ускорить отклик.
Путь клиента:
- Первый запрос — CacheService.get(key, options) — кэш пуст, запрос уходит на сервер.
- Сохранение ответа — CacheService.set(key, options, result) — результат кладётся в
requestsMapпо ключу. - Таймер инвалидации — setTimeout 30s — через
INVALID_TIMEOUT = 30 * 1000запись удаляется. - Повторный запрос в пределах окна — быстрый ответ —
get()возвращает закэшированныйresult. - Истечение 30 секунд — удаление ключа — следующий запрос снова идёт на сервер.
- Ручная инвалидация — 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)
Цель: Данные онлайн-табло автоматически обновляются при поступлении серверных событий, чтобы пользователь видел актуальную информацию без ручной перезагрузки.
Путь клиента:
- Подключение к хабу — при загрузке страницы результатов или деталей рейса
RefreshBoardService/RefreshServiceинициализирует SignalR-соединение сenvironment.urlForTrackerHub. - Подписка на события — сервис подписывается на события
RefreshDate(для списка рейсов) илиRefresh(для деталей рейса по ID). - Тихое обновление — при поступлении события данные перезагружаются с флагом
silent, без показа индикатора загрузки, чтобы не отвлекать пользователя. - Оверлей устаревших данных —
FadeServiceзапускает таймер; при бездействии пользователя в течениеenvironment.refreshPauseMinминут поверх страницы появляется полупрозрачный оверлей с сообщением «Данные устарели, обновите страницу!». - Автоматический редирект — если бездействие превышает
environment.refreshStopMinминут, приложение перенаправляет пользователя на главную страницу (/). - Очистка — при уходе со страницы (
ngOnDestroy) подписки SignalR и таймерыFadeServiceочищаются.
Критерии приёмки:
- ✅ На страницах результатов онлайн-табло устанавливается SignalR-соединение для получения обновлений.
- ✅ На странице деталей рейса подписка привязана к конкретному ID рейса.
- ✅ Обновление данных происходит без видимого индикатора загрузки (silent reload).
- ✅ После
refreshPauseMinминут бездействия показывается полноэкранный оверлей (z-index 9999, полупрозрачный фон). - ✅ После
refreshStopMinминут бездействия происходит автоматический редирект на главную. - ✅ SignalR-подписки и таймеры корректно очищаются при уничтожении компонентов.
Примечание: Функция актуальна только для онлайн-табло (реальное время). Расписание и карта полётов не используют SignalR. FadeService создаёт overlay программно через DOM API (document.createElement).
US-106: Встроенный чат-бот
Цель: Пользователь может воспользоваться чат-ботом для получения справочной информации.
Путь клиента:
- Инициализация — компонент
chat-botвngAfterViewInitдинамически создаёт<script>элемент с URL изenvironment.chatBotScript. - Загрузка виджета — скрипт монтируется к
#app-chat-bot-container, загружая внешний чат-виджет. - Использование — после загрузки пользователь видит виджет чата и может задавать вопросы.
Критерии приёмки:
- ✅ Чат-бот загружается динамически через внешний скрипт из
environment.chatBotScript. - ✅ Виджет монтируется в контейнер
#app-chat-bot-container. - ✅ Ошибки загрузки скрипта не ломают остальной интерфейс.
Примечание: URL скрипта настраивается через конфигурацию окружения.
US-107: Canonical URL и SEO мета-теги по страницам
Цель: Каждая страница приложения имеет корректные canonical URL и уникальные SEO мета-теги для правильной индексации поисковыми системами.
Путь клиента:
- Установка canonical —
CanonicalServiceформирует<link rel="canonical">для текущей страницы. - Мета-теги по разделам — каждый раздел (онлайн-табло, расписание, карта полётов) имеет собственные компоненты мета-тегов с уникальными ключами
SEO.*:- Онлайн-табло: стартовая, результаты (по номеру/маршруту/отправлению/прибытию), детали рейса
- Расписание: стартовая, результаты, детали рейса
- Карта полётов: стартовая
- Динамические значения — для страниц результатов и деталей мета-теги включают названия городов, даты и номера рейсов.
- OpenGraph — для страниц деталей формируются
og:title,og:description,og:imageтеги. - noRobots — на страницах с динамическими параметрами (результаты, детали) установлен
noRobots: trueдля предотвращения индексации.
Критерии приёмки:
- ✅ Canonical URL корректен для каждой страницы.
- ✅ Мета-теги
titleиdescriptionуникальны для каждого типа страницы. - ✅ Динамические страницы включают контекст (город, дата, номер рейса) в мета-теги.
- ✅ Стартовые страницы разделов индексируются (
noRobots: false), страницы результатов — нет. - ✅ OpenGraph-теги формируются для страниц деталей.
Примечание: Компоненты мета-тегов наследуют от MetaBaseComponent и переопределяют translateTitle()/translateDescription().
US-108: Отображение версии API (debug-режим)
Цель: В debug-режиме разработчик может видеть текущую версию API для диагностики.
Путь клиента:
- Проверка флага —
AppVersionComponentпроверяетsettings.showDebugVersionизAPP_SETTINGS. - Запрос версии — если флаг включён,
NetworkService.getApiVersion()загружает номер версии. - Отображение — версия выводится компонентом
app-versionрядом с навигацией. - Скрытие баннера — при включённом debug-режиме скрывается элемент
.banner--top.
Критерии приёмки:
- ✅ В обычном режиме версия не отображается.
- ✅ При
showDebugVersion = trueпоказывается номер версии API. - ✅ Компонент
app-show-debugусловно рендерит debug-информацию.
Примечание: Предназначено для разработки и тестирования, не для конечных пользователей.