diff --git a/docs/USER_STORIES_INDEX.md b/docs/USER_STORIES_INDEX.md new file mode 100644 index 00000000..0ddbd66c --- /dev/null +++ b/docs/USER_STORIES_INDEX.md @@ -0,0 +1,263 @@ +# Пользовательские истории: Индекс и обзор + +## ✅ ВЕРИФИЦИРОВАНО: Только реально реализованные функции Angular + +**Дата последнего обновления:** 9 апреля 2026 GMT+3 +**Статус:** Очищено - удалены все нереализованные/гипотетические функции +**Источник верификации:** `/Users/gnezim/_projects/tims/flights_web/Aeroflot.Flights.Web/ClientApp` (Angular 12.2.13) + +**Итоги аудита (Версия 4.0):** + +- 175 → **85 историй** (удалено 90, или ~51%) +- 14 → **7 документов** (удалено 4 документа полностью + 1 устаревший индекс) +- 100% оставшихся историй имеют подтверждение в исходном коде Angular + +--- + +## 📌 Изменения в версии 4.0 + +### Удалены документы (нереализованные функции) + +- ❌ **Документ 8: Многолётные рейсы** (US-106-120) — кроме базового отображения, всё гипотетика (трансфер услуги, переадресация багажа, риски пересадок). Базовый показ stay в Doc 4 (US-42). +- ❌ **Документ 10: Производительность** (US-136-150) — Service Worker, A/B тесты, Web Workers, виртуализация — ничего нет в коде. Только базовый CacheService 30s. +- ❌ **Документ 11: Продвинутые функции** (US-151-165) — конвертация валют, RTL, лояльность, IATA-поиск — не реализовано. Многоязычность уже описана в Doc 1 US-2. +- ❌ **Документ 12: Граничные случаи целостности** (US-166-175) — кросс-таб синхронизация, восстановление сессии, rollback — ничего нет. + +### Удалённые истории внутри сохранённых документов + +- **Doc 2:** US-21 (обработка ошибок сети) — нет UI обработки ошибок API +- **Doc 3:** US-34 (кнопка "Очистить") — нет такой кнопки в форме +- **Doc 4:** US-40, US-41 (перенесены в Doc 5), US-43 (фильтр по авиакомпании), US-44 (кнопка "Купить билет"), US-45 (живые обновления статусов в расписании) +- **Doc 5:** US-57 (ограничения полёта), US-58 (рецензии), US-59 (исторические данные), US-60 (сравнение рейсов), US-61 (Print version) +- **Doc 6:** US-77 (кластеризация), US-78 (выделение результатов), US-80 (топ маршруты), US-81 (легенда), US-82 (центральный офис), US-83 (ночной режим), US-84 (мобильная карта) +- **Doc 7:** US-87 (Service Worker offline), US-97 (WCAG проверка контраста), US-105 (session timeout) + +### Удалён устаревший файл + +- ❌ `USER_STORIES_VERIFIED_INDEX.md` — содержал устаревшие данные о 175 историях + +--- + +## Обзор проекта + +Это набор пользовательских историй для **UI Dashboard** — React-версии онлайн доски полётов Аэрофлота. Документы организованы по функциональным областям и содержат описание целей, путей клиента и критериев приёмки. + +**Всего историй:** 85 пользовательских историй ✅ +**Документов:** 7 +**Источник:** Angular 12.2.13 (Aeroflot.Flights.Web/ClientApp) +**Языки:** 9 (ru-ru, en-us, zh-cn, ko-kr, ja-jp, de-de, fr-fr, es-es, it-it) + +--- + +## Структура документов + +### 📄 [Документ 1: Навигация и элементы интерфейса](user-stories-1-navigation-ui.md) + +**US-1 до US-11** (11 историй) + +- US-1: Переключение между вкладками (Онлайн-Табло, Расписание, Карта полётов) +- US-2: Переключение языка интерфейса (9 языков) +- US-3: Хлебные крошки +- US-4: Кнопка обратной связи +- US-5: Кнопка прокрутки к началу +- US-6: Боковая панель с фильтрами +- US-7: Популярные запросы (popular-requests) +- US-8: История поиска (in-memory) +- US-9: Локализация заголовков и мета-тегов +- US-10: Адаптивный дизайн +- US-11: Отсутствие ошибок в консоли + +--- + +### 📄 [Документ 2: Онлайн доска полётов](user-stories-2-online-board.md) + +**US-12 до US-22 (без US-21)** — 10 историй + +- US-12: Поиск по номеру рейса (SU 1402) +- US-13: Выбор даты для поиска +- US-14: Поиск по городу отправления (с автодополнением) +- US-15: Поиск полётов с прибытием в город +- US-16: Поиск маршрута (А → Б) +- US-17: День вылета (переключение) +- US-18: Фильтр по времени вылета/прибытия +- US-19: Расширенный просмотр рейса +- US-20: Обработка пустых результатов +- US-22: Индикатор загрузки + +--- + +### 📄 [Документ 3: Поиск расписания полётов](user-stories-3-schedule-search.md) + +**US-23 до US-33** — 11 историй + +- US-23: Переход на вкладку "Расписание" +- US-24: Ввод города отправления +- US-25: Ввод города прибытия +- US-26: Кнопка "Обменять" +- US-27: Выбор недели вылета +- US-28: Поиск туров (туда и обратно) +- US-29: Фильтр "Только прямые рейсы" +- US-30: Фильтр по времени вылета +- US-31: Фильтр по времени прибытия +- US-32: Проверка валидности параметров +- US-33: URL параметры расписания + +--- + +### 📄 [Документ 4: Результаты расписания](user-stories-4-schedule-results.md) + +**US-35 до US-46 (без US-43, 44, 45; US-40, 41 в Doc 5)** — 7 историй + +- US-35: Страница результатов расписания +- US-36: Переключение между днями +- US-37: Навигация между неделями (week-tabs) +- US-38: Расширенный просмотр полёта +- US-39: Сортировка результатов (6 режимов) +- US-42: Многоугольные полёты (рейсы с пересадками) +- US-46: Кнопка "Назад" на странице деталей + +--- + +### 📄 [Документ 5: Детали полёта](user-stories-5-flight-details.md) + +**US-40, US-41, US-47 до US-56, US-62, US-63, US-64** — 15 историй + +- US-40: Услуги на борту +- US-41: Расписание полёта и время +- US-47: Страница деталей полёта +- US-48: Основная информация о полёте +- US-49: Статус и детали статуса +- US-50: Информация о воздушном судне +- US-51: Информация об авиакомпании (operator-logo) +- US-52: Информация об аэропортах (station) +- US-53: Дни работы рейса +- US-54: Действия с полётом (купить, регистрация, печать, поделиться) +- US-55: Схема маршрута / timeline +- US-56: Информация о пересадках +- US-62: Поделиться информацией +- US-63: Отсутствие ошибок на странице +- US-64: Целостность данных + +--- + +### 📄 [Документ 6: Карта полётов](user-stories-6-flights-map.md) + +**US-65 до US-79 (без US-77, 78)** — 13 историй + +- US-65: Переход на вкладку "Карта полётов" +- US-66: Отображение маршрутов на карте (Leaflet polyline) +- US-67: Выбор города отправления (city-autocomplete) +- US-68: Выбор города прибытия +- US-69: Обмен городов +- US-70: Выбор даты +- US-71: Фильтр "Внутренние рейсы" (toggle-switch) +- US-72: Фильтр "Международные рейсы" +- US-73: Фильтр "Соединительные рейсы" +- US-74: Зуммирование (Leaflet defaults, zoom 3-6) +- US-75: Панорамирование (Leaflet defaults, maxBounds) +- US-76: Popup при выборе маршрута +- US-79: Ссылка "Купить билет" (внешняя) + +--- + +### 📄 [Документ 7: Обработка ошибок и доступность](user-stories-7-errors-accessibility.md) + +**US-85 до US-104 (без US-87, 97)** — 18 историй + +**Ошибки:** + +- US-85: Ошибка 404 +- US-86: Ошибка 500 +- US-88: Timeout при загрузке +- US-89: Некорректный ввод +- US-90: Невалидная комбинация параметров + +**Граничные случаи:** + +- US-91: Пустой результат поиска +- US-92: Unicode символы +- US-93: Очень длинные имена +- US-94: Быстрая последовательность поисков + +**Доступность:** + +- US-95: Клавиатурная навигация (PrimeNG defaults) +- US-96: ARIA-метки +- US-98: Focus visible +- US-99: Масштабирование текста +- US-100: Сенсорная навигация + +**Состояние и кэш:** + +- US-101: Персистентное состояние (StateService) +- US-102: История браузера +- US-103: Обработка больших объёмов +- US-104: Кэширование (CacheService, 30s) + +--- + +## Статистика + +| Документ | Диапазон | Историй | Статус | +| ------------------------ | ----------------------- | ------- | --------------------------- | +| 1. Навигация | US-1 до US-11 | 11 | ✅ Все реализованы | +| 2. Онлайн-Табло | US-12 до US-22 | 10 | ✅ Все реализованы | +| 3. Поиск расписания | US-23 до US-33 | 11 | ✅ Все реализованы | +| 4. Результаты расписания | US-35-39, 42, 46 | 7 | ✅ Все реализованы | +| 5. Детали полёта | US-40, 41, 47-56, 62-64 | 15 | ✅ Все реализованы | +| 6. Карта полётов | US-65-76, 79 | 13 | ✅ Все реализованы | +| 7. Ошибки и доступность | US-85-86, 88-96, 98-104 | 18 | ✅ Все реализованы | +| **ИТОГО** | **85 историй** | **85** | ✅ Полностью верифицировано | + +--- + +## Удалённые документы и истории + +### Полностью удалённые документы + +| Документ | Историй | Причина | +| ------------------------------------ | ------- | ----------------------------------------------- | +| 8. Многолётные рейсы (US-106-120) | 15 | Только базовый показ работает (см. Doc 4 US-42) | +| 10. Производительность (US-136-150) | 15 | Service Worker, A/B, Web Workers — нет в коде | +| 11. Продвинутые функции (US-151-165) | 15 | Валюта, лояльность, RTL, IATA-поиск — нет | +| 12. Граничные случаи (US-166-175) | 10 | Кросс-таб синхронизация, recovery — нет | +| **Всего удалено** | **55** | | + +### Удалённые истории внутри сохранённых документов + +| Doc | Удалено | Причина | +| --------- | -------------- | ------------------------------------------------------------- | +| 2 | US-21 | Нет UI обработки сетевых ошибок | +| 3 | US-34 | Нет кнопки "Очистить" в форме | +| 4 | US-43,44,45 | Нет фильтра по авиакомпании, кнопки "Купить", live-обновлений | +| 5 | US-57-61 | Нет ограничений, рецензий, истории, сравнения, print-версии | +| 6 | US-77,78,80-84 | Нет кластеризации, выделения, легенды, ночного режима, моб. | +| 7 | US-87,97,105 | Нет Service Worker, WCAG-проверки контраста, session timeout | +| **Всего** | **35** | | + +--- + +## Источник верификации + +Каждая оставшаяся история подтверждена в исходном коде по следующим путям: + +- `src/app/features/online-board/` — Doc 2 +- `src/app/features/schedule/` — Docs 3, 4 +- `src/app/features/flights-map/` — Doc 6 +- `src/app/features/popular-requests/` — Doc 1 US-7 +- `src/app/modules/pages/details/` — Doc 5 +- `src/app/components/` (city-autocomplete, dates-selectors, breadcrumds, search-history, page) — Doc 1, общие +- `src/app/shared/services/` (localization, state, cache) — Doc 1, Doc 7 +- `src/app/modules/pages/error-pages/` — Doc 7 + +--- + +## Управление версиями + +| Версия | Дата | Историй | Документов | Примечания | +| ------- | -------------- | ------- | ---------- | ----------------------------------------------------- | +| 1.0 | Feb 2026 | 103 | 7 | Начальная версия | +| 1.4 | Mar 2026 | 103 | 7 | Исправления, восстановлены US-40, US-41 | +| 2.0 | Apr 2026 | 210 | 14 | Расширение (многолётные, история, производительность) | +| 3.0 | Apr 2026 | 175 | 11 | Удалены удалённые: история, уведомления, аккаунты | +| **4.0** | **Apr 9 2026** | **85** | **7** | **Кодовая верификация: удалено всё неподтверждённое** | diff --git a/docs/user-stories-1-navigation-ui.md b/docs/user-stories-1-navigation-ui.md new file mode 100644 index 00000000..48676213 --- /dev/null +++ b/docs/user-stories-1-navigation-ui.md @@ -0,0 +1,255 @@ +# Пользовательские истории: Навигация и элементы интерфейса + +## US-1: Навигация по основным вкладкам + +**Цель:** Пользователь может переключаться между основными разделами приложения (Онлайн-Табло, Расписание, Карта полётов) для поиска информации о рейсах в разных режимах. + +**Путь клиента:** + +1. **Открытие приложения** — пользователь заходит на сайт, срабатывает редирект с корневого пути на `/onlineboard`, в верхней части страницы отображается компонент `page-tabs` с двумя вкладками: «Онлайн-Табло» и «Расписание». +2. **Отображение третьей вкладки** — если включён feature flag `flightsMap`, дополнительно появляется вкладка «Карта полётов» во втором ряду; без флага она не рендерится. +3. **Индикация активной вкладки** — текущая вкладка помечена CSS-классом `active`; при наведении показывается tooltip с текстом из ключей `SHARED.TAB-BOARD-TOOLTIP`, `SHARED.TAB-SCHEDULE-TOOLTIP`, `SHARED.TAB-FLIGHTS-MAP-TOOLTIP`. +4. **Клик по вкладке «Расписание»** — Angular Router выполняет переход на `/schedule`, URL обновляется, загружается `ScheduleModule`, активный класс переходит на новую вкладку. +5. **Клик по вкладке «Карта полётов»** — роутер через `FeatureFlagGuard` проверяет флаг и, если он включён, загружает `FlightsMapModule` по пути `/flights-map`. +6. **Возврат на Онлайн-Табло** — пользователь кликает первую вкладку, URL меняется на `/onlineboard`, загружается `OnlineBoardModule`, активная вкладка снова подсвечивается. + +**Критерии приёмки:** + +- ✅ На старте пользователь попадает на `/onlineboard` (редирект с `/`). +- ✅ Видны ровно две вкладки, если `flightsMap` выключен, и три — если включён. +- ✅ Клик по вкладке меняет URL на `/onlineboard`, `/schedule` или `/flights-map` без перезагрузки страницы. +- ✅ Активная вкладка визуально отличается от неактивных (класс `active`). +- ✅ При наведении появляется tooltip с локализованным текстом. +- ✅ Переход между вкладками не вызывает ошибок в консоли. + +**Примечание:** Видимость вкладки «Карта полётов» управляется feature flag `flightsMap` (`FeatureFlagGuard` + `*ngIf="flightsMapEnabled"` в `page-tabs.component.html`). + +--- + +## US-2: Переключение языка интерфейса + +**Цель:** Пользователь может использовать приложение на одном из девяти поддерживаемых языков. + +**Путь клиента:** + +1. **Определение языка** — `LocalizationService` читает `APP_BASE_HREF` формата `/country-language` (например, `/ru-ru`) и извлекает код языка из позиций 4-6. +2. **Инициализация переводов** — сервис вызывает `translate.addLangs(...)` с полным списком (`ru`, `en`, `es`, `fr`, `it`, `jp`, `ko`, `zh`, `de`) и применяет `translate.use(language)`. +3. **Рендеринг интерфейса** — все строки UI проходят через пайп `| translate`, подставляются значения из соответствующих JSON-файлов переводов. +4. **Выбор календарной локали** — геттер `calendarTranslate` возвращает объект локализации PrimeNG Calendar (`calendarRu`, `calendarEn`, ...) согласно текущему языку. +5. **Смена языка** — пользователь переходит по URL с другим префиксом (например, `/en-us/onlineboard`); приложение перезагружается с новым `baseHref`, и весь интерфейс отображается на выбранном языке. +6. **Редиректы с коротких кодов** — запросы на `/ru`, `/en`, `/es`, `/fr`, `/it`, `/ja`, `/ko`, `/zh`, `/de` перенаправляются на `/onlineboard` с сохранением языка из baseHref. + +**Критерии приёмки:** + +- ✅ Поддерживаются все 9 языков из enum `Language`. +- ✅ Текущий язык определяется из `APP_BASE_HREF` при старте приложения. +- ✅ Все тексты, метки кнопок и плейсхолдеры локализованы через `ngx-translate`. +- ✅ Календарь PrimeNG отображается на выбранном языке. +- ✅ Короткие языковые пути в роутинге ведут на `/onlineboard`. + +**Примечание:** Переключатель языка находится в шапке внешней площадки aeroflot.ru и не входит в состав Angular-приложения; внутри модуля язык фиксируется через `baseHref`. + +--- + +## US-3: Навигация по хлебным крошкам + +**Цель:** Пользователь видит путь навигации на страницах результатов и деталей рейса и может вернуться на предыдущие уровни или на главную. + +**Путь клиента:** + +1. **Отображение компонента** — на страницах результатов поиска и деталей рейса рендерится `flights-page-breadcrumbs`, оборачивающий `` из PrimeNG. +2. **Формирование списка** — в `ngOnInit` компонент подписывается на `route.data` и получает массив `breadcrumbs` из `IRouteData`. +3. **Первый элемент** — в начало списка всегда подставляется `defaultMenuItem` с ярлыком `SHARED.MAIN` и ссылкой на `https://www.aeroflot.ru`. +4. **Локализация** — все элементы прогоняются через `translation.instant(item.label)`, ключи переводятся в текущий язык. +5. **Клик по элементу** — пользователь нажимает на любой уровень, PrimeNG `p-breadcrumb` выполняет навигацию по `url` элемента (внешний URL или внутренний путь). +6. **Отсутствие на главных страницах** — на стартовых страницах разделов и на `/flights-map` маршруты не содержат `breadcrumbs` в `data`, поэтому компонент не отображается. + +**Критерии приёмки:** + +- ✅ Хлебные крошки рендерятся только там, где в `route.data` есть массив `breadcrumbs`. +- ✅ Первый элемент всегда ведёт на `https://www.aeroflot.ru` с ярлыком из ключа `SHARED.MAIN`. +- ✅ Каждый элемент является кликабельной ссылкой. +- ✅ Метки переводятся на текущий язык интерфейса. +- ✅ На `/flights-map` и стартовых экранах разделов компонент отсутствует. + +--- + +## US-4: Кнопка обратной связи + +**Цель:** Пользователь может открыть форму обратной связи и отправить сообщение разработчикам приложения. + +**Путь клиента:** + +1. **Отображение кнопки** — в макете страницы присутствует компонент `feedback-button` с текстом из ключа `SHARED.FEEDBACK`. +2. **Клик по кнопке** — обработчик `showForm()` устанавливает `formVisible = true`, что активирует `*ngIf="formVisible"` и монтирует компонент `feedback-form`. +3. **Отображение формы** — на экране появляется блок `.feedback-form` с кнопкой закрытия и встроенным `