Add TZ РИ-07-2538С compliance-audit spec for 4.1 (Online-Board / Schedule / Flight Map)

This commit is contained in:
2026-04-21 15:45:11 +03:00
parent 9efc76bab1
commit 8e84c41243
@@ -0,0 +1,641 @@
# РИ-07-2538С — Online-Board & Schedule UI Redesign
**Spec kind:** TZ compliance audit + alignment plan
**TZ source:** `~/_projects/tims/Редизайн/РИ-07-2538C_ТЗ_Онлайн-Табло и Расписание_UI.docx` (revision С)
**Branch:** `redesign/ri-07-2538c-online-board-schedule-ui`
**Date:** 2026-04-21
**Repo:** `Aeroflot.Flights.Web`
> This is a contractual audit spec. Its job is to prove every 4.1.x rule in the TZ has been considered, map each rule to a concrete action, and track implementation to merge. The spec is the source of truth; six themed implementation plans off it do the actual work.
---
## Revision С note
Revision С (2026) extends revision В by adding subsection **4.1.24 Карта полетов** and Appendix 9 mockups. Everything else carries over from revision В. TZ-marked changes (vertical bar in the margin of the original docx) are implicitly covered by the per-subsection audit.
---
## Scope
### In scope for this repo
- **Section 4.1** — external (public) "Онлайн-Табло и Расписание" section on aeroflot.ru.
- All subsections 4.1.1 4.1.24 inclusive.
- **Binding NFRs** that touch the frontend:
- 4.8.2 — capacity (100 RPS).
- 4.9 — external integrations (СТБ, Yandex.Metrica events 4.9.2).
- 4.11 — reliability (geo-distributed hosting, ≤6h recovery) — *verified at deploy/infra layer, acknowledged here.*
- 4.12 — ergonomics / a11y.
- 4.14 — security (component isolation per CLAUDE.md contract #5).
- 4.15.1 — FE stack (Modern.js + MF 2.0 + React 18, per CLAUDE.md).
- **Appendices 4 (web mockups), 6 (mobile mockups), 7 (tablet mockups), 9 (map mockups)** — binding visual references for 4.1.
### Out of scope for this repo
- **4.2** — administrative UI (separate admin app, not `Aeroflot.Flights.Web`).
- **4.3, 4.4, 4.5** — backend REST APIs; this repo *consumes* them.
- **4.6, 4.7** — storage (S3) + SSM/ASM telegram processing (backend ingestion pipeline).
- **Sections 5, 6, 7** — implementation, acceptance, documentation — handled at program level, not per-PR.
### Viewport scope (Q3 = A)
Desktop, tablet, mobile all in scope for every 4.1.x subsection. Visual verification per Appendix 4 / 7 / 6 respectively. Behavioral rules that differ by viewport are called out in rule rows (example: 4.1.1-R5 mobile `Время рейса` default = `-1/+3ч`).
---
## Glossary (Russian → English / code term)
| Russian term | English gloss | Code term / alias |
|---|---|---|
| Онлайн-Табло | Online-Board | `onlineboard` |
| Расписание | Schedule | `schedule` |
| Карта полетов | Flight Map | `flights-map` |
| Рейс | Flight | `flight` |
| Сегмент | Segment / leg | `leg` |
| Прямой рейс | Direct flight | `direct` |
| Многосегментный рейс | Multi-segment flight (single flight number, multiple legs) | `multi-segment` |
| Стыковочный рейс | Connecting flight (multiple flight numbers, transfer) | `connecting` / `transfer` |
| Промежуточная посадка | Intermediate landing (technical stop, same flight number) | `intermediate-landing` |
| Пересадка | Transfer (between legs of a connecting flight) | `transfer` |
| Табы-дни | Day tabs (results list) | `DayTabs` |
| Табы-недели | Week tabs (schedule results) | `WeekTabs` |
| Мини-список | Mini-list (compact flight strip at top of details page) | `FlightsMiniList` |
| Временная шкала | Timeline (direct-flight timeline in details) | `FlightSchedule` / `FullRouteTimeline` |
| «Вы искали» | "You searched" (recent-search history in filter) | `SearchHistory` |
| Хлебные крошки | Breadcrumbs | `Breadcrumbs` |
| Свернутое представление | Collapsed row (results list) | `collapsed` |
| Развернутое представление | Expanded row (results list) | `expanded` |
| Режим «Маршрут» | "Route" mode (city-based search) | `routeMode` |
| Режим «Номер рейса» | "Flight number" mode (number-based search) | `flightNumberMode` |
| Уточняется | "Being clarified" fallback text | `tbd` / copy key |
| ServiceType | Service-type code (J,S,U,Q,G,B,R,C) | `serviceType` |
### TZ-defined constants
- **Online-Board date window**: `[-1 day, +14 days]` from today.
- **Schedule date window**: `[-1 day, +330 days]` from today.
- **Flight Map date window**: `[-1 day, +6 months]` from today.
- **Included `ServiceType`s**: `J, S, U, Q, G, B, R, C`. Flight numbers > 7000 excluded (see Appendix 3).
---
## Reading the audit tables
Each subsection section has:
- Russian title (verbatim from TZ) + English gloss.
- 13 sentence summary of the subsection intent.
- An audit table with these columns:
| Column | Meaning |
|---|---|
| `#` | Stable rule ID — `{subsection}-R{n}`. Cited by implementation plans and test names. |
| `Rule` | Short English restatement. Russian key phrase in quotes when exact wording matters. |
| `TZ cite` | Section + one-line quote. Mockup references in `Appendix N → media/imageNN.png` form when applicable. |
| `Viewport` | `desktop` / `tablet` / `mobile` / `all` — which viewports the rule applies to. |
| `Current impl` | File + line (or `—` if not yet present). |
| `Status` | `Implemented` / `Partial` / `Missing` / `Conflict` / `TBD`. |
| `Action` | One-line directive for the plan. `—` if no action needed. |
| `Plan` | `P1` through `P6`. |
Rule IDs are stable. If a rule is removed, its ID is retired (not reused). New rules get `-R(n+1)`.
### Status shorthand
- **Implemented** — current code satisfies the rule; verified by existing test or file inspection.
- **Partial** — some aspects satisfied, gaps remain (gaps listed in `Action`).
- **Missing** — not implemented.
- **Conflict** — TZ text and Angular reference site (or current React impl) disagree. Listed in **Conflicts register** below, blocks plan start until arbitrated.
- **TBD** — needs more TZ reading + reference-site inspection to classify. Populated at plan kickoff.
---
## Plan index
Six themed plans, merged in dependency order. Each plan consumes a subset of rule IDs from this spec.
| Plan | Name | Rule sources | Depends on | Merge order |
|---|---|---|---|---|
| **P1** | URLs, breadcrumbs, page names, cross-section nav | 4.1.2, 4.1.3, 4.1.4, 4.1.8 | — | 1 |
| **P2** | Start pages + first-entry + popular sections | 4.1.1, 4.1.5, 4.1.6, 4.1.7 | P1 | 2 |
| **P3** | Filter + validation + search history + search execution + cancel | 4.1.9 (+ .1.5), 4.1.10, 4.1.11, 4.1.12 | P1 | 3 |
| **P4** | Results lists (collapsed + expanded) | 4.1.13, 4.1.14 | P3 | 4 |
| **P5** | Flight cards + timeline + aircraft icons + "Уточняется" | 4.1.15, 4.1.16, 4.1.17, 4.1.22, 4.1.23 | P4 | 5 |
| **P6** | SEO, errors, cache, Карта полетов | 4.1.18, 4.1.19, 4.1.20, 4.1.21, 4.1.24 | P1 (map routing) | 6 |
Each plan is produced by invoking the `superpowers:writing-plans` skill with its rule IDs. Each plan merges independently off `main` (rebase + fast-forward). After each merge, this spec's status column is updated (`Status → Done + <commit-sha>`).
---
## Coverage summary
_Updated after each plan merges. Plan task: after every merge, append a row to the log below and update per-plan counts._
| Metric | Count |
|---|---|
| Total rules extracted | (populated as subsections are filled) |
| Implemented | — |
| Partial | — |
| Missing | — |
| Conflict | — |
| TBD | — |
| Done | — |
### Merge log
_Empty until P1 ships._
---
## Conflicts register
Arbitrated case-by-case (Q2 = C). Each conflict blocks its owning plan's kickoff until `Resolution` is filled. When a conflict is resolved, convert the relevant rule row(s) to non-conflict status and cross-reference the `Resolution` back to the rule ID.
| # | Rule IDs | TZ says | Angular reference says | Current React says | Diagnostic | Resolution |
|---|---|---|---|---|---|---|
| _(empty — populated during plan kickoffs)_ | | | | | | |
---
# 4.1.1 — Правила поведения Системы при первоначальном входе
*First-entry behavior when user enters Online-Board / Schedule / Flight Map.*
Defines what the filter shows on the very first session visit: with geolocation consent, auto-fill `Город вылета` with the user's city; without consent, show the plain start page. Also defines placeholder values and default date/time attributes per mode. Mode-switch within session preserves user input.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.1-R1 | With geo consent, auto-detect user city, open Online-Board in "Маршрут" mode with `Город вылета` = detected city | 4.1.1 ¶1 | all | `src/features/online-board/components/OnlineBoardStartPage.tsx` | TBD | Verify geo-detection on first session entry; verify city auto-fill. Playwright e2e needed. | P2 |
| 4.1.1-R2 | `Город прилета` placeholder = `"Все направления"` on first-entry Online-Board route-mode | 4.1.1 ¶1 | all | `OnlineBoardFilter.tsx` | TBD | Verify placeholder string matches. | P2 |
| 4.1.1-R3 | `Дата рейса` default = today | 4.1.1 ¶1 | all | `OnlineBoardFilter.tsx` | TBD | Verify. | P2 |
| 4.1.1-R4 | `Время рейса` default = `00:00-24:00` on desktop/tablet | 4.1.1 ¶1 | desktop, tablet | `OnlineBoardFilter.tsx` | TBD | Verify. | P2 |
| 4.1.1-R5 | `Время рейса` default = `-1/+3ч` from user's current time on mobile phone | 4.1.1 ¶1 | mobile | `OnlineBoardFilter.tsx` | TBD | Verify mobile-specific default; add viewport test. | P2 |
| 4.1.1-R6 | Do **not** auto-execute search after first-entry defaulting | 4.1.1 ¶1 | all | — | TBD | Verify no network call on first entry. | P2 |
| 4.1.1-R7 | In "Номер рейса" mode on first-entry: `Номер рейса` placeholder, `Дата рейса` = today | 4.1.1 ¶2 | all | `OnlineBoardFilter.tsx` (mode switch) | TBD | Verify mode-switch defaults. | P2 |
| 4.1.1-R8 | Schedule on first-entry: `Город вылета` = detected city, `Город прилета` placeholder = `"Укажите город"` | 4.1.1 ¶3 | all | `ScheduleFilter.tsx` | TBD | Verify. | P2 |
| 4.1.1-R9 | Schedule `Показать расписание на` default = "текущая неделя" (range this week, within -1/+330 day validation) | 4.1.1 ¶3 | all | `ScheduleFilter.tsx` | TBD | Verify. | P2 |
| 4.1.1-R10 | Schedule `Время вылета` default = `00:00-24:00` on all viewports (mobile matches desktop) | 4.1.1 ¶3 | all | `ScheduleFilter.tsx` | TBD | Verify mobile behaves like desktop (not like Online-Board mobile). | P2 |
| 4.1.1-R11 | Schedule `Только прямые рейсы` unchecked on first-entry | 4.1.1 ¶3 | all | `ScheduleFilter.tsx` | TBD | Verify. | P2 |
| 4.1.1-R12 | Schedule `Показать обратные рейсы` unchecked on first-entry | 4.1.1 ¶3 | all | `ScheduleFilter.tsx` | TBD | Verify. | P2 |
| 4.1.1-R13 | Flight Map first-entry: `Город вылета` = nearest airport (auto-detected), `Город прилета` placeholder `"Куда"` | 4.1.1 ¶4 | all | `FlightsMapFilter.tsx` | TBD | Verify nearest-airport detection. | P2 |
| 4.1.1-R14 | Flight Map first-entry toggles: `Внутренние рейсы`=ON, `Международные регулярные рейсы`=ON, `Показать рейсы с пересадкой`=OFF | 4.1.1 ¶4 | all | `FlightsMapFilter.tsx` | TBD | Verify toggle defaults. | P2 |
| 4.1.1-R15 | Flight Map first-entry `Дата рейса` = today; map shows "паутинка" (spider) from departure city for today | 4.1.1 ¶4 | all | `MapCanvas.tsx` | TBD | Verify spider rendering on first entry. | P6 |
| 4.1.1-R16 | Map line rules: Direct lines if direct+connecting exist; connecting lines if only connecting; dots (full route network) if neither | 4.1.1 ¶4 | all | `MapCanvas.tsx` | TBD | Verify three rendering modes. | P6 |
| 4.1.1-R17 | If geo-detection fails, fall back to Online-Board start page (§4.1.6) — **no** auto-fill | 4.1.1 ¶5 | all | — | TBD | Verify fallback path; add test. | P2 |
| 4.1.1-R18 | Without geo consent: Online-Board "Маршрут" expanded; `Город вылета` + `Город прилета` placeholders `"Укажите город"`; `Дата рейса` placeholder `"ДД.ММ.ГГГГ"`; `Время рейса` `00:00-24:00` | 4.1.1 ¶6 | all | `OnlineBoardStartPage.tsx` | TBD | Verify placeholders. | P2 |
| 4.1.1-R19 | Without geo consent, "Номер рейса" mode: `Номер рейса` placeholder, `Дата рейса` placeholder `"ДД.ММ.ГГГГ"` | 4.1.1 ¶7 | all | `OnlineBoardFilter.tsx` | TBD | Verify. | P2 |
| 4.1.1-R20 | Without geo consent, Schedule start page per §4.1.7; all city/date placeholders; toggles unchecked | 4.1.1 ¶8 | all | `ScheduleStartPage.tsx` | TBD | Verify. | P2 |
| 4.1.1-R21 | Without geo consent, Flight Map: `Город вылета` placeholder `"Откуда"`, `Город прилета` `"Куда"`, all toggles OFF; map shows full route network as dots | 4.1.1 ¶9 | all | `FlightsMapFilter.tsx`, `MapCanvas.tsx` | TBD | Verify placeholders + dots rendering. | P6 |
| 4.1.1-R22 | Without geo consent, Flight Map `Дата рейса` placeholder `"ДД.ММ.ГГГ"` (sic — TZ typo, 3 Г; treat as `ДД.ММ.ГГГГ`) | 4.1.1 ¶9 | all | `FlightsMapFilter.tsx` | Conflict | TZ has obvious typo. Flag; treat as `ДД.ММ.ГГГГ`. | P6 |
| 4.1.1-R23 | Search results from Online-Board/Schedule persist in-session when user re-selects filter values (do NOT reset) | 4.1.1 ¶10 | all | state: `src/shared/state/` | TBD | Verify session persistence; add test. | P2 |
| 4.1.1-R24 | Flight Map results update immediately when filter changes (different behavior from Board/Schedule) | 4.1.1 ¶10 | all | `flights-map/hooks/*` | TBD | Verify immediate-update behavior. | P6 |
| 4.1.1-R25 | Clearing `Дата рейса` on Flight Map → map shows range `-1 day, +6 months` | 4.1.1 ¶11 | all | `flights-map/*` | TBD | Verify default range on clear. | P6 |
| 4.1.1-R26 | Flight Map filter is **independent** of Online-Board / Schedule filters | 4.1.1 ¶12 | all | state isolation: `src/shared/state/` | TBD | Verify no cross-section filter leak. | P6 |
| 4.1.1-R27 | Returning to Flight Map in same session restores previously entered filter + result | 4.1.1 ¶13 | all | state | TBD | Verify in-session restore. | P6 |
**Rules in this subsection: 27 (R22 is a flagged conflict: TZ typo).**
---
# 4.1.2 — Правила формирования URL-ссылок
*URL formation for Online-Board, Schedule, Flight Map.*
URLs encode language, area (onlineboard/schedule/flights-map), mode (route / flight-number / departure / arrival), and search parameters. TZ Table 5 enumerates every URL pattern with examples. Invalid dates outside the `-1/+14` (board), `-1/+330` (schedule), `-1/+6mo` (map) windows redirect to the respective start page. Invalid directories → 404.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.2-R1 | URL pattern (Web and Mobile identical): `https://flights.aeroflot.ru/{lang}/{area}[/{mode}/{params}]` | 4.1.2 Table 5 | all | `src/routes/[lang]/*` | TBD | Verify routes file-layout matches Table 5. | P1 |
| 4.1.2-R2 | `{lang}` = locale+language pair (`ru-ru`, `en-us`, …). All site languages must be supported | 4.1.2 ¶1 | all | `src/i18n/` | TBD | Verify all 9 languages exposed as route params. | P1 |
| 4.1.2-R3 | Online-Board title page: `/{lang}/onlineboard` | 4.1.2 Table 5 row 1 | all | `src/routes/[lang]/onlineboard/page.tsx` | Implemented | — | P1 |
| 4.1.2-R4 | Online-Board flight-number search: `/{lang}/onlineboard/flight/{SUNNNN}-{YYYYMMDD}`; if user entered `38` → pad to `SU0038`, `383``SU0383` (4-digit number, 3-char carrier code) | 4.1.2 Table 5 row 2 | all | `src/routes/[lang]/onlineboard/flight/[params]/*` | TBD | Verify 4-digit padding; add unit test for padder. | P1 |
| 4.1.2-R5 | Online-Board route search: `/{lang}/onlineboard/route/{fromCity}-{toCity}-{YYYYMMDD}` | 4.1.2 Table 5 row 3 | all | `src/routes/[lang]/onlineboard/route/[params]/*` | TBD | Verify. | P1 |
| 4.1.2-R6 | Online-Board departure-only search: `/{lang}/onlineboard/departure/{fromCity}-{YYYYMMDD}` | 4.1.2 Table 5 | all | `src/routes/[lang]/onlineboard/departure/[params]/*` | TBD | Verify. | P1 |
| 4.1.2-R7 | Online-Board arrival-only search: `/{lang}/onlineboard/arrival/{toCity}-{YYYYMMDD}` | 4.1.2 Table 5 | all | `src/routes/[lang]/onlineboard/arrival/[params]/*` | TBD | Verify. | P1 |
| 4.1.2-R8 | Schedule URL patterns mirror Online-Board with `/schedule/` prefix; add range date for schedule | 4.1.2 Table 5 | all | `src/routes/[lang]/schedule/*` | TBD | Enumerate + verify each. | P1 |
| 4.1.2-R9 | Flight-Map URL pattern (route, validation) | 4.1.2 Table 5 (§4.1.24 refers) | all | `src/routes/[lang]/flights-map/*` | TBD | Populate routing from 4.1.24 text; owned by P1 because URL rules cluster there. | P1 |
| 4.1.2-R10 | Unknown directory → 404 page (§4.1.21) | 4.1.2 ¶2 | all | `src/routes/error/[code]/*` | TBD | Verify 404 on bogus URLs. | P1 |
| 4.1.2-R11 | Out-of-range date → redirect to the respective **start page** (not 404) | 4.1.2 ¶34 | all | — | TBD | Add date-window guard + redirect. | P1 |
| 4.1.2-R12 | Date window constants: Online-Board `[-1, +14]`, Schedule `[-1, +330]`, Flight Map `[-1, +6 months]` | 4.1.2 ¶34 | all | — | TBD | Centralize as constants; reference from URL guards and filter validators. | P1 |
**Remaining rules (language-suffix encoding, anchor fragments, query-string vs path style, deep-link behavior from email, etc.) → populated at P1 kickoff after full read of 4.1.2 text + Table 5 in detail.**
---
# 4.1.3 — Правила наименования страниц
*Page-title rules (document `<title>` + visible H1).*
Each page in the section gets a TZ-prescribed title format driven by context (area, mode, filter values, language). Translatable across all 9 site languages.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.3-R1 | Online-Board start page title per TZ Table (populate at P1 kickoff) | 4.1.3 | all | `src/ui/seo/*` | TBD | Populate. | P1 |
| 4.1.3-R2 | Schedule start page title per TZ | 4.1.3 | all | — | TBD | Populate. | P1 |
| 4.1.3-R3 | Flight-Map start page title per TZ | 4.1.3 | all | — | TBD | Populate. | P1 |
| 4.1.3-R4 | Search-result page titles per mode (route / flight-number / departure / arrival) | 4.1.3 | all | — | TBD | Populate. | P1 |
| 4.1.3-R5 | Flight-details page title per TZ (direct / multi-segment / connecting) | 4.1.3 | all | — | TBD | Populate. | P1 |
| 4.1.3-R6 | All titles translated for each of 9 languages | 4.1.3 | all | `src/i18n/*` | TBD | Add keys + verify per locale. | P1 |
**Rules to populate at P1 kickoff after reading 4.1.3 tables in full.**
---
# 4.1.4 — Правила формирования хлебных крошек
*Breadcrumb rules.*
All pages in the section must have breadcrumbs; each crumb is a link except the last. Breadcrumb labels follow the same translation table as page titles.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.4-R1 | Every page has breadcrumbs (root → area → mode → result) | 4.1.4 | all | `src/ui/layout/Breadcrumbs*` | TBD | Verify presence on every page. | P1 |
| 4.1.4-R2 | Last crumb = non-link with `aria-current="page"` | 4.1.4 + CLAUDE.md a11y | all | (see commit `826a583`) | Implemented | — | P1 |
| 4.1.4-R3 | Crumb labels translatable | 4.1.4 | all | `src/i18n/*` | TBD | Verify all locales. | P1 |
| 4.1.4-R4 | Per-page crumb list per TZ Table (populate at P1 kickoff) | 4.1.4 | all | — | TBD | Populate. | P1 |
---
# 4.1.5 — Популярные разделы Онлайн-Табло и Расписания
*"Popular sections" — curated popular-request tiles on start pages.*
On Online-Board and Schedule start pages, a "Popular" panel lists curated search tiles. Clicking a tile hydrates filter + navigates to result.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.5-R1 | Popular panel visible on Online-Board start page | 4.1.5 | all | `src/features/popular-requests/*` | Implemented | — | P2 |
| 4.1.5-R2 | Popular panel visible on Schedule start page | 4.1.5 | all | `src/features/popular-requests/*` | Implemented | — | P2 |
| 4.1.5-R3 | Tile click hydrates filter + navigates per URL rules | 4.1.5 | all | `PopularRequestItem.tsx` + routing | Implemented | Verify URL matches §4.1.2 post-hydration. | P2 |
| 4.1.5-R4 | Tile content (cities/dates/flight numbers) sourced from backend/config | 4.1.5 | all | `RequestInfo.tsx` | TBD | Verify data source matches TZ. | P2 |
| 4.1.5-R5 | Translation for all tile labels across 9 languages | 4.1.5 | all | `src/i18n/*` | TBD | Verify. | P2 |
| 4.1.5-R6 | Popular panel NOT shown on Flight Map | 4.1.5 | all | — | TBD | Verify absence. | P2 |
| 4.1.5-R7 | Curated list content source, refresh cadence, and fallback when source empty | 4.1.5 | all | — | TBD | Populate from 4.1.5 text. | P2 |
**Remaining rules to populate at P2 kickoff.**
---
# 4.1.6 — Стартовая страница «Онлайн-Табло»
*Online-Board start page composition.*
Composition: filter (collapsed or expanded per first-entry state), popular panel, SEO text block, footer links. No auto-search. Accepts deep-link URLs per §4.1.2.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.6-R1 | Start page renders filter (default state per 4.1.1) + popular panel | 4.1.6 | all | `OnlineBoardStartPage.tsx` | Implemented | Verify composition. | P2 |
| 4.1.6-R2 | Start page shows subsection tooltip on `Онлайн-Табло` hover: `"Информация о фактическом выполнении рейсов в ближайшие дни"` | 4.1 ¶ intro (tooltips) | desktop, tablet | — | TBD | Add tooltip. | P2 |
| 4.1.6-R3 | Start page does NOT auto-execute search | 4.1.6 | all | — | Implemented | — | P2 |
| 4.1.6-R4 | SEO meta tags + JSON-LD microdata present (see §4.1.19) | 4.1.6 | all | `src/ui/seo/*` | TBD | Populate microdata. | P6 |
| 4.1.6-R5 | Mobile-specific start-page layout (filter takes full width, popular panel stacks) | 4.1.6 + Appendix 6 | mobile | — | TBD | Verify against Appendix 6. | P2 |
| 4.1.6-R6 | Tablet-specific start-page layout | 4.1.6 + Appendix 7 | tablet | — | TBD | Verify against Appendix 7. | P2 |
---
# 4.1.7 — Стартовая страница «Расписания»
*Schedule start page composition.*
Same composition as Online-Board start page, but filter defaults per §4.1.1 Schedule rules and subsection tooltip says `"Информация о планируемом выполнении рейсов на ближайший год"`.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.7-R1 | Renders filter (schedule defaults per 4.1.1) + popular panel | 4.1.7 | all | `ScheduleStartPage.tsx` | Implemented | Verify. | P2 |
| 4.1.7-R2 | Subsection tooltip text: `"Информация о планируемом выполнении рейсов на ближайший год"` | 4.1 ¶ intro | desktop, tablet | — | TBD | Add tooltip. | P2 |
| 4.1.7-R3 | No auto-search | 4.1.7 | all | — | Implemented | — | P2 |
| 4.1.7-R4 | SEO meta + JSON-LD (see §4.1.19) | 4.1.7 | all | — | TBD | Populate. | P6 |
| 4.1.7-R5 | Mobile-specific layout per Appendix 6 | 4.1.7 | mobile | — | TBD | Verify. | P2 |
| 4.1.7-R6 | Tablet-specific layout per Appendix 7 | 4.1.7 | tablet | — | TBD | Verify. | P2 |
| 4.1.7-R7 | Flight-Map tooltip: `"Картографический сервис представления информации об маршрутной сети «Аэрофлот»"` (on the tab switcher) | 4.1 ¶ intro | desktop, tablet | — | TBD | Add tooltip. | P2 |
---
# 4.1.8 — Правила перехода между Табло, Расписание, Картой полетов в рамках одной сессии
*Cross-section navigation within a session.*
Switching tabs between Online-Board / Schedule / Flight Map preserves user input per rules: filter values carry over where applicable, results persist per §4.1.1-R23 / R27.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.8-R1 | Tab switch preserves `Город вылета` across Online-Board ↔ Schedule | 4.1.8 | all | `src/shared/state/*` | TBD | Verify. | P1 |
| 4.1.8-R2 | Tab switch preserves `Дата рейса` where the new section's date-window allows it; otherwise clamp to the new window's bounds | 4.1.8 | all | — | TBD | Verify clamp behavior. | P1 |
| 4.1.8-R3 | Tab switch to Flight Map does **not** inherit Board/Schedule filter (§4.1.1-R26 — independence) | 4.1.8 / 4.1.1 ¶12 | all | — | TBD | Verify. | P1 |
| 4.1.8-R4 | Closing popovers on focus-change (4.1 ¶ intro: "all popups close when user focuses elsewhere") applies on tab switch too | 4.1 ¶ intro | desktop, tablet | — | TBD | Verify. | P1 |
| 4.1.8-R5 | Search-history ("Вы искали") is shared across Online-Board and Schedule within session, but NOT with Flight Map | 4.1.8 / 4.1.9.5 | all | — | TBD | Verify scoping rules. | P1 |
**Remaining rules at P1 kickoff.**
---
# 4.1.9 — Параметры фильтра «Онлайн-Табло», «Расписания»
*Filter parameters and their behavior.*
The biggest and most rule-dense subsection. Specifies every filter attribute across all three modes (Route / Flight number / Departure-only / Arrival-only), plus validation (4.1.9.3, 4.1.9.4), autocomplete/dictionary behavior (4.1.9.1, 4.1.9.2), and "Вы искали" history (4.1.9.5). ~80 pages of rules. Target rule count: **100150**.
> **Populated at P3 kickoff.** Skeleton only here. Every rule in this subsection maps to Plan P3.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.9-R1 | **Cluster A**: Route-mode attributes (Город вылета, Город прилета, Дата рейса, Время рейса) — each with its own placeholder / validation / default rules | 4.1.9 ¶ main | all | `OnlineBoardFilter.tsx` | TBD | Enumerate rules at P3 kickoff. | P3 |
| 4.1.9-R2 | **Cluster B**: Flight-number-mode attributes (Номер рейса, Дата рейса) + format `SU{4-digit}` per 4.1.2-R4 | 4.1.9 | all | `OnlineBoardFilter.tsx` | TBD | Enumerate at P3. | P3 |
| 4.1.9-R3 | **Cluster C**: Schedule attributes (add Показать расписание на, Дата обратного рейса, Только прямые рейсы, Показать обратные рейсы) | 4.1.9 | all | `ScheduleFilter.tsx` | TBD | Enumerate at P3. | P3 |
| 4.1.9-R4 | **4.1.9.1** Manual-entry behavior for city fields | 4.1.9.1 | all | `city-autocomplete/*` | TBD | Enumerate. | P3 |
| 4.1.9-R5 | **4.1.9.2** Dictionary-picker behavior for city fields | 4.1.9.2 | all | `CityAutocomplete.tsx` | TBD | Enumerate. | P3 |
| 4.1.9-R6 | **4.1.9.3** Filter validation (per-attribute error rules, error-tooltip placement) | 4.1.9.3 | all | `OnlineBoardFilter.tsx` + `ScheduleFilter.tsx` | TBD | Enumerate. | P3 |
| 4.1.9-R7 | **4.1.9.4** Validation for `Показать расписание на` and `Дата обратного рейса` (range ≤ 7 days, return-date after outbound, etc.) | 4.1.9.4 | all | `ScheduleFilter.tsx` | TBD | Enumerate. | P3 |
| 4.1.9-R8 | **4.1.9.5** "Вы искали" search-history: storage scope, item limit, order, icon per item type, rehydration on click | 4.1.9.5 | all | `src/shared/storage.ts` + filter | TBD | Enumerate. | P3 |
**Rules to be enumerated at P3 kickoff. Expected 100150 rows total for §4.1.9.**
---
# 4.1.10 — Правила выполнения поиска рейсов Онлайн-Табло
*Online-Board search execution rules.*
Rules for when the search runs (explicit submit vs auto), backend endpoint selection per mode, loader behavior, error handling (4.1.10.1). Short subsection.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.10-R1 | Search executes only on explicit submit (button click / Enter) — not on attribute change | 4.1.10 | all | `OnlineBoardFilter.tsx` | TBD | Verify. | P3 |
| 4.1.10-R2 | Loader shown during search | 4.1 ¶ intro | all | — | TBD | Verify loader per 4.1 ¶ intro. | P3 |
| 4.1.10-R3 | Submit maps to correct endpoint per mode (route / flight-number / departure / arrival) | 4.1.10 | all | `src/shared/api/*` | TBD | Verify. | P3 |
| 4.1.10-R4 | Successful search → navigate to result URL per §4.1.2 (URL change **before** render to keep refresh-safe) | 4.1.10 | all | — | TBD | Verify URL-first navigation. | P3 |
| 4.1.10-R5 | **4.1.10.1** Error handling: network timeout, API 4xx/5xx, empty result — each gets a specific error banner text (enumerate at P3) | 4.1.10.1 | all | `src/ui/errors/*` | TBD | Enumerate. | P3 |
---
# 4.1.11 — Правила выполнения поиска рейсов Расписания
*Schedule search execution rules. Symmetric to §4.1.10 but with schedule-specific backend + date-range handling.*
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.11-R1 | Symmetric to 4.1.10-R1 (explicit submit) | 4.1.11 | all | `ScheduleFilter.tsx` | TBD | Verify. | P3 |
| 4.1.11-R2 | Loader shown during search | 4.1 ¶ intro | all | — | TBD | Verify. | P3 |
| 4.1.11-R3 | Submit maps to schedule endpoints | 4.1.11 | all | — | TBD | Verify. | P3 |
| 4.1.11-R4 | Handles range date (Показать расписание на) | 4.1.11 | all | — | TBD | Verify. | P3 |
| 4.1.11-R5 | Round-trip search: if `Показать обратные рейсы` checked and `Дата обратного рейса` set, execute second symmetric query | 4.1.11 | all | — | TBD | Verify. | P3 |
| 4.1.11-R6 | **4.1.11.1** Error handling (enumerate at P3) | 4.1.11.1 | all | — | TBD | Enumerate. | P3 |
---
# 4.1.12 — Отмена поиска рейсов Онлайн-Табло, Расписания
*Search cancellation rules.*
Short subsection — user can cancel in-flight search; subsequent filter changes abort prior in-flight request.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.12-R1 | New search aborts any in-flight search (latest-wins) | 4.1.12 | all | — | TBD | Verify AbortController wiring. | P3 |
| 4.1.12-R2 | Escape (desktop/tablet) cancels in-flight search if loader shown | 4.1.12 | desktop, tablet | — | TBD | Implement + test. | P3 |
| 4.1.12-R3 | Navigating away (back button, tab switch) cancels in-flight search | 4.1.12 | all | — | TBD | Verify. | P3 |
---
# 4.1.13 — Список результатов поиска рейсов Онлайн-Табло
*Online-Board results list: day tabs (4.1.13.1), sort (4.1.13.2), collapsed row (4.1.13.3), expanded row (4.1.13.4). ~15 pages of UI rules, many mockup references. Target rule count: **80100**.*
> **Populated at P4 kickoff.** Skeleton only.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.13-R1 | **4.1.13.1** Day tabs — behavior (today/future/past styling, active-day visuals, keyboard nav, scroll/paging) | 4.1.13.1 | all | `DayTabs/` | TBD | Enumerate. | P4 |
| 4.1.13-R2 | **4.1.13.2** Sort rules (default order, user-toggle options, stable ordering by secondary key) | 4.1.13.2 | all | — | TBD | Enumerate. | P4 |
| 4.1.13-R3 | **4.1.13.3** Collapsed row — layout + per-field rendering (carrier, flight number, from-to, times, status, aircraft icon, etc.) | 4.1.13.3 | all | `src/ui/flights/*` | TBD | Enumerate. | P4 |
| 4.1.13-R4 | **4.1.13.4** Expanded row — layout, accordion behavior, mini-timeline, carriers operator+marketing, terminal/gate, registration/boarding blocks, live status | 4.1.13.4 | all | `OnlineBoardSearchPage.tsx` + `src/ui/flights/*` | TBD | Enumerate. | P4 |
| 4.1.13-R5 | Scroll-to-top "иконка-кнопка" appears when list scrolled past threshold | 4.1 ¶ intro | all | — | TBD | Verify + add if missing. | P4 |
**Rules enumerated at P4 kickoff.**
---
# 4.1.14 — Список результатов поиска рейсов Расписания
*Schedule results list: week tabs (4.1.14.1), sort (4.1.14.2), collapsed (4.1.14.3), expanded (4.1.14.4). Largest subsection by page count (~100 pages in TZ). Target rule count: **150200**.*
> **Populated at P4 kickoff.** Skeleton only.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.14-R1 | **4.1.14.1** Week tabs — month spanning, today highlight, range selection, keyboard nav | 4.1.14.1 | all | `WeekTabs.tsx` | TBD | Enumerate. | P4 |
| 4.1.14-R2 | **4.1.14.2** Sort rules | 4.1.14.2 | all | — | TBD | Enumerate. | P4 |
| 4.1.14-R3 | **4.1.14.3** Collapsed row — day-grouping, weekday-mask, operator logos, times, duration | 4.1.14.3 | all | `DayGroupedFlightList.tsx` + `ScheduleFlightBody.tsx` | TBD | Enumerate. | P4 |
| 4.1.14-R4 | **4.1.14.4** Expanded row — per-segment breakdown, transfer bars, connecting-flight layout, onward-link | 4.1.14.4 | all | `src/features/schedule/components/*` | TBD | Enumerate. | P4 |
| 4.1.14-R5 | Multi-leg operator-logo compactness preserved on expand (see commit `3ae59da` for parity) | 4.1.14.4 | all | `src/features/schedule/*` | Implemented | — | P4 |
**Rules enumerated at P4 kickoff.**
---
# 4.1.15 — Карточка рейса, открытого из Онлайн-Табло
*Flight details page entered from Online-Board.*
Covers: form structure (4.1.15.1), mini-list (4.1.15.2), day tabs (4.1.15.3), direct-flight info (4.1.15.4), multi-segment info (4.1.15.5), intermediate landing (4.1.15.6), timeline-time algorithm (4.1.15.7), status rules (4.1.15.8), previous-flight algorithm (4.1.15.9), onboard meals (4.1.15.10), onboard services (4.1.15.11). ~50 pages. Target rule count: **100140**.
> **Populated at P5 kickoff.** Skeleton only.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.15-R1 | **4.1.15.1** Screen-form structure — header, mini-list, day tabs, main content, footer | 4.1.15.1 | all | `OnlineBoardDetailsPage.tsx` | TBD | Enumerate. | P5 |
| 4.1.15-R2 | **4.1.15.2** Mini-list composition, item click behavior, selected-item styling | 4.1.15.2 | all | `FlightsMiniList/` | TBD | Enumerate. | P5 |
| 4.1.15-R3 | **4.1.15.3** Day-tab behavior within details page (same day tabs as results list but filtered to this flight number) | 4.1.15.3 | all | `BoardDetailsHeader/` | TBD | Enumerate. | P5 |
| 4.1.15-R4 | **4.1.15.4** Direct-flight info — carrier, aircraft, from-to, times, terminal, gate, live status ladder (registration/boarding/deboarding blocks) | 4.1.15.4 | all | `FlightSchedule/` + `details-panels/` | TBD | Enumerate. | P5 |
| 4.1.15-R5 | **4.1.15.5** Multi-segment flight info — per-leg breakdown, FullRouteTimeline visualization | 4.1.15.5 | all | `FullRouteTimeline/` | TBD | Enumerate. | P5 |
| 4.1.15-R6 | **4.1.15.6** Intermediate-landing rules (same flight number, connecting stop, landed/took-off substates) | 4.1.15.6 | all | `FullRouteTimeline/` | TBD | Enumerate. | P5 |
| 4.1.15-R7 | **4.1.15.7** Timeline time algorithm — which time to show for which block (scheduled vs estimated vs actual) | 4.1.15.7 | all | — | TBD | Enumerate + validate algorithm. | P5 |
| 4.1.15-R8 | **4.1.15.8** Status-on-timeline display rules (colors, labels, icon states) | 4.1.15.8 | all | `details-panels/` | TBD | Enumerate. | P5 |
| 4.1.15-R9 | **4.1.15.9** Previous-flight algorithm — how "was previously" chip is populated | 4.1.15.9 | all | — | TBD | Enumerate. | P5 |
| 4.1.15-R10 | **4.1.15.10** On-board meals — data source, display rules | 4.1.15.10 | all | — | TBD | Enumerate. | P5 |
| 4.1.15-R11 | **4.1.15.11** On-board services — data source, display rules | 4.1.15.11 | all | — | TBD | Enumerate. | P5 |
**Rules enumerated at P5 kickoff.**
---
# 4.1.16 — Карточка рейса, открытого из Расписания
*Flight details page entered from Schedule.*
Same sub-structure as 4.1.15 plus connecting-flight variant (4.1.16.6) and intermediate-landing+transfer (4.1.16.7) and execution-days algorithm (4.1.16.8). Largest single subsection (~100 pages). Target rule count: **150200**.
> **Populated at P5 kickoff.** Skeleton only.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.16-R1 | **4.1.16.1** Screen-form structure | 4.1.16.1 | all | `ScheduleDetailsPage.tsx` | TBD | Enumerate. | P5 |
| 4.1.16-R2 | **4.1.16.2** Mini-list | 4.1.16.2 | all | `FlightsMiniList/` | TBD | Enumerate. | P5 |
| 4.1.16-R3 | **4.1.16.3** Day tabs behavior | 4.1.16.3 | all | — | TBD | Enumerate. | P5 |
| 4.1.16-R4 | **4.1.16.4** Direct-flight info | 4.1.16.4 | all | — | TBD | Enumerate. | P5 |
| 4.1.16-R5 | **4.1.16.5** Multi-segment info | 4.1.16.5 | all | — | TBD | Enumerate. | P5 |
| 4.1.16-R6 | **4.1.16.6** Connecting-flight info — multiple flight numbers, transfer-time display, walk-between-gates visuals | 4.1.16.6 | all | `TransferBar/` | TBD | Enumerate. | P5 |
| 4.1.16-R7 | **4.1.16.7** Intermediate-landing + transfer rules | 4.1.16.7 | all | — | TBD | Enumerate. | P5 |
| 4.1.16-R8 | **4.1.16.8** Execution-days algorithm (weekday mask from schedule rules) | 4.1.16.8 | all | — | TBD | Enumerate. | P5 |
**Rules enumerated at P5 kickoff.**
---
# 4.1.17 — Алгоритм расчета признака перехода суток
*Day-change indicator algorithm.*
Specifies when the "+1 day" / "+2 days" / "-1 day" chip appears next to an arrival/departure time. Logic compares leg arrival local date vs leg departure local date (both in respective local timezones).
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.17-R1 | `dayChange` = (arrLocalDate depLocalDate) in whole days, where both dates are in their respective airport's local TZ | 4.1.17 | all | existing per-leg logic (see memory "Details page parity") | Implemented | Verify algorithm matches TZ exactly. | P5 |
| 4.1.17-R2 | Badge shown as `+1`, `+2`, `-1`, etc.; hidden if 0 | 4.1.17 | all | — | Implemented | Verify. | P5 |
| 4.1.17-R3 | Badge appears next to the arrival/departure *time*, not the date | 4.1.17 | all | — | TBD | Verify positioning per mockup. | P5 |
| 4.1.17-R4 | Badge applies consistently in results list + details page + mini-list | 4.1.17 | all | — | TBD | Verify cross-surface consistency. | P5 |
---
# 4.1.18 — Кеширование данных
*Data caching.*
Single-paragraph section on acceptable client-side caching behavior (session cache of results per §4.1.1-R23, dictionary cache for cities/airports, etc.).
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.18-R1 | Session-scope cache for search results per §4.1.1-R23/R27 | 4.1.18 | all | `src/shared/state/*` | TBD | Verify TTL + scope. | P6 |
| 4.1.18-R2 | Dictionary cache (cities, airports, aircraft types) — TTL per TZ | 4.1.18 | all | `src/shared/dictionaries/*` | TBD | Verify TTL + refresh policy. | P6 |
| 4.1.18-R3 | SSR-rendered initial payload must not expose stale data older than TZ-specified TTL | 4.1.18 | all | `src/server/*` | TBD | Verify SSR cache headers. | P6 |
---
# 4.1.19 — Микроразметка страниц «Онлайн-Табло и Расписания»
*Microdata: JSON-LD + OpenGraph.*
Each page must emit JSON-LD (schema.org types per TZ table) and OpenGraph meta tags. CLAUDE.md contract #6 lists this as binding.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.19-R1 | Every page emits JSON-LD `<script type="application/ld+json">` in `<head>` | 4.1.19 | all | `src/ui/seo/*` | TBD | Verify presence per page. | P6 |
| 4.1.19-R2 | Start pages JSON-LD schema type per TZ | 4.1.19 | all | — | TBD | Populate schema. | P6 |
| 4.1.19-R3 | Results-list JSON-LD schema (Itemlist?) per TZ | 4.1.19 | all | — | TBD | Populate. | P6 |
| 4.1.19-R4 | Flight-details JSON-LD schema (Flight?) per TZ | 4.1.19 | all | — | TBD | Populate. | P6 |
| 4.1.19-R5 | OpenGraph meta tags (`og:title`, `og:description`, `og:url`, `og:image`, `og:locale`) per page | 4.1.19 | all | `src/ui/seo/*` | TBD | Verify. | P6 |
| 4.1.19-R6 | `og:locale` matches the active language | 4.1.19 | all | — | TBD | Verify. | P6 |
**Rules to refine from 4.1.19 text at P6 kickoff.**
---
# 4.1.20 — Robots.txt
*Crawler policy.*
Specifies indexable paths (start pages, results with canonical params) vs disallowed paths (pages with volatile params, search mutations). Actual `robots.txt` lives at the host site, but the app must emit correct `<link rel="canonical">` and `<meta name="robots">` per page.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.20-R1 | Start pages emit `<meta name="robots" content="index,follow">` | 4.1.20 | all | — | TBD | Verify. | P6 |
| 4.1.20-R2 | Canonical link per page (normalized URL, no volatile query params) | 4.1.20 | all | — | TBD | Verify per page. | P6 |
| 4.1.20-R3 | Pages TZ marks as non-indexable emit `noindex` | 4.1.20 | all | — | TBD | Populate list. | P6 |
| 4.1.20-R4 | hreflang alternates for all 9 languages per page | 4.1.20 | all | — | TBD | Verify. | P6 |
---
# 4.1.21 — Внештатные ситуации, ошибки 404 и 500
*Error pages: 404 + 500.*
Must render the Aeroflot-standard 404/500 pages. Centralized error page at `/error/404` and `/error/500`.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.21-R1 | Unknown route → `/error/404` | 4.1.21 | all | `src/routes/error/[code]/*` | Implemented | Verify. | P6 |
| 4.1.21-R2 | Server error → `/error/500` | 4.1.21 | all | `src/routes/error/[code]/*` | Implemented | Verify. | P6 |
| 4.1.21-R3 | 404 page includes link back to section root + top-level breadcrumb | 4.1.21 | all | — | TBD | Verify. | P6 |
| 4.1.21-R4 | 500 page includes refresh CTA + support contact | 4.1.21 | all | — | TBD | Verify. | P6 |
| 4.1.21-R5 | Both pages SEO: `noindex`; translated for all 9 languages | 4.1.21 | all | — | TBD | Verify. | P6 |
---
# 4.1.22 — Алгоритм вывода иконок типов ВС
*Aircraft-type icon display algorithm.*
Maps aircraft-type code (from IATA/ICAO tables) → icon asset. Fallback to generic icon when unknown.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.22-R1 | Aircraft-type code from API → icon asset via lookup table | 4.1.22 | all | `src/shared/dictionaries/*` | TBD | Verify lookup. | P5 |
| 4.1.22-R2 | Unknown aircraft-type → generic icon (not blank) | 4.1.22 | all | — | TBD | Verify fallback. | P5 |
| 4.1.22-R3 | Icon shown in collapsed row, expanded row, details page, mini-list consistently | 4.1.22 | all | — | TBD | Verify consistency. | P5 |
| 4.1.22-R4 | Icon has `title` / tooltip with aircraft-type name (e.g. `"Airbus A320"`) | 4.1.22 + CLAUDE.md a11y | desktop, tablet | — | TBD | Verify. | P5 |
**Aircraft-type table populated at P5 kickoff from 4.1.22 text.**
---
# 4.1.23 — Правила вывода «Уточняется»
*"Being clarified" fallback text rules.*
Short subsection: when a data field is missing/pending from the API, UI shows the localized string `"Уточняется"` (not empty / not "—" / not "N/A").
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.23-R1 | Missing field renders translated "Уточняется" string | 4.1.23 | all | `src/i18n/*` | TBD | Add+verify key per language; verify all display surfaces use it. | P5 |
| 4.1.23-R2 | Only applies to fields TZ enumerates (populate list at P5 kickoff) — NOT a blanket fallback | 4.1.23 | all | — | TBD | Populate list. | P5 |
| 4.1.23-R3 | Styling: same as regular field text (not italic, not greyed) per TZ | 4.1.23 | all | — | TBD | Verify. | P5 |
---
# 4.1.24 — Карта полетов
*Flight Map (new in revision С). Appendix 9 = binding mockup reference.*
Six sub-subsections: start page (4.1.24.1), filter (4.1.24.2), search+map rendering (4.1.24.3), interactive map (4.1.24.4), internal API (4.1.24.5), "Buy ticket" CTA (4.1.24.6). Target rule count: **4060**.
> Current impl: `src/features/flights-map/` exists (phase-1 rewrite). Gap audit = verify existing code against revision-С spec.
| # | Rule | TZ cite | Viewport | Current impl | Status | Action | Plan |
|---|---|---|---|---|---|---|---|
| 4.1.24-R1 | **4.1.24.1** Start page composition (filter + empty map or route network as dots per §4.1.1-R21) | 4.1.24.1 + App. 9 | all | `FlightsMapStartPage.tsx` | TBD | Verify against Appendix 9 mockups. | P6 |
| 4.1.24-R2 | **4.1.24.2** Filter attributes: `Откуда`, `Куда`, `Дата рейса`, toggles (Внутренние / Международные / С пересадкой) | 4.1.24.2 | all | `FlightsMapFilter.tsx` | TBD | Enumerate per-attribute rules. | P6 |
| 4.1.24-R3 | **4.1.24.3** Search and map rendering — spider (direct), connecting lines, dots (full network). §4.1.1-R16 summarizes the three modes | 4.1.24.3 | all | `MapCanvas.tsx` | TBD | Verify rendering logic. | P6 |
| 4.1.24-R4 | **4.1.24.4** Interactive behavior — click on destination, hover tooltip, zoom, pan, route highlight | 4.1.24.4 | all | `MapCanvas.tsx` | TBD | Enumerate interactions. | P6 |
| 4.1.24-R5 | **4.1.24.5** Internal API — endpoints used by map (likely a subset of §4.3/4.5 methods) | 4.1.24.5 | all | `flights-map/hooks/*` | TBD | Verify endpoints match TZ. | P6 |
| 4.1.24-R6 | **4.1.24.6** "Buy ticket" button navigates to booking flow with prefilled from/to/date (URL hand-off to booking subsystem) | 4.1.24.6 | all | — | TBD | Verify CTA target + params. | P6 |
| 4.1.24-R7 | No loader shown on Flight Map (per 4.1 ¶ intro: "Для «Карты полетов» «лоадера» не предусмотрено") | 4.1 ¶ intro | all | — | TBD | Verify loader absence. | P6 |
**Rules enumerated at P6 kickoff.**
---
## NFR checklist (binding, cross-cutting)
Verified during P6 and `finishing-a-development-branch` check for each plan.
| # | NFR | TZ cite | Verification method | Status |
|---|-----|---------|---------------------|--------|
| NFR-1 | 100 RPS sustained | 4.8.2 | Load-test script (`scripts/load-test/`) run once; result archived in compliance report | TBD |
| NFR-2 | Yandex.Metrica event tracking per TZ table | 4.9.2 | Unit tests on event dispatch + one manual observation in dev tools | TBD |
| NFR-3 | СТБ integration (checkout hand-off) | 4.9.1.3 | Contract test against СТБ endpoint | TBD |
| NFR-4 | Reliability: geo-distributed VMs, ≤6h recovery | 4.11 | Infra concern; acknowledge here, defer to deploy program | Deferred |
| NFR-5 | A11y: keyboard nav + screen reader support | 4.12 + CLAUDE.md | Automated Axe pass per page + manual screen-reader spot-check | Partial (many a11y commits present) |
| NFR-6 | Component isolation (no attack surface) | 4.14 + CLAUDE.md #5 | CSP validation + code-review check per plan | TBD |
| NFR-7 | Stack: Modern.js + MF 2.0 + React 18 + `<Suspense>` + no fetch outside `useEffect` + `React.lazy()` | 4.15.1 + CLAUDE.md #1 | Lint rule + code-review check | Implemented (phase-1) |
| NFR-8 | MF manifest exposed at `https://<domain>/mf-manifest.json` | CLAUDE.md #1 | Integration test hits the URL | Implemented |
| NFR-9 | All 9 languages supported | 4.16 | i18n key-coverage test | Partial (keys present; coverage not all audited) |
---
## Appendix inventory (mockup → subsection map)
Built at P0 (= this spec's commit). Every image in `word/media/imageNN.{png,tiff,emf,jpeg}` is mapped to the TZ subsection that references it. Images total: 197.
Inventory lives in a separate file for size: `docs/superpowers/specs/2026-04-21-online-board-schedule-tz-mockup-inventory.md` (generated at P1 kickoff by parsing the TZ docx).
---
## Assumptions & open questions
1. **Responsive mockups completeness.** Appendices 4 (web), 6 (mobile), 7 (tablet) are assumed to cover every subsection's UI. If a subsection lacks a mobile/tablet mockup, we fall back to responsive-CSS-driven layout and flag the gap in the subsection's Action column.
2. **Language-parity.** TZ does not enumerate every string per language; we trust the existing `src/i18n/` coverage and add keys for any new strings introduced by this audit. P1 will spot-audit 9-language coverage for page titles + breadcrumbs; other plans follow per-surface.
3. **SignalR live updates.** TZ does not explicitly mention live-updates via SignalR, but current impl uses it. We treat SignalR as an implementation detail that must preserve TZ behavior, not an additional TZ requirement. SignalR-specific bugs fall under their current owner, not this audit.
4. **Load test (NFR-1).** Load testing requires a backend endpoint and infra access; if not available, NFR-1 is deferred to the deploy program with a note in the compliance report. Frontend-side perf targets (LCP, TTFB, bundle size) are still verified per-plan.
5. **Phase-1 compatibility.** We keep phase-1 architecture (Modern.js 2.70.8 + MF 2.3.3) unchanged unless TZ requires otherwise — CLAUDE.md documents constraints that make phase-1 stack currently best-available.
---
## Process for each plan
Each of P1P6 follows this sequence:
1. **Populate remaining rule rows** in its subsections (reading the full TZ text for those subsections + inspecting mockups).
2. **Arbitrate any `Conflict`-status rules** assigned to this plan — populate the Conflicts register with Resolution before writing the plan.
3. **Invoke `superpowers:writing-plans`** with the rule IDs as input.
4. **Execute plan** per `superpowers:executing-plans` (TDD-first where applicable per `superpowers:test-driven-development`).
5. **Code review** per `superpowers:requesting-code-review`.
6. **Finish branch** per `superpowers:finishing-a-development-branch` — merge to main (after user authorization for the push).
7. **Update this spec** — change rule `Status` from `TBD`/`Missing`/`Partial` to `Done` + commit SHA. Append row to Merge log.
---
## Out-of-scope explicitly called out
- No database / telegram / backend work is initiated from this spec. Backend changes discovered during audit are flagged in a separate "Backend escalations" file, not addressed here.
- No refactoring beyond what serves a specific rule row. Cosmetic cleanups sit in a separate backlog.
- No new architectural patterns (e.g. state-management rewrite). If a rule is implementable with the existing pattern, we use it.