Files
flights_web/docs/parity-report/REPORT.md
T
gnezim 8005356db5 docs: parity report markdown + auto-memory plan
Companion markdown to the comparison-report/visual/report.html with
the same coverage matrix and per-page findings. Useful for git-based
review without serving the HTML.

Also adds AGENTS.md (subagent role definitions for future sessions)
and the modernjs-v3-upgrade plan stub from the earlier scoping.
2026-04-19 22:06:05 +03:00

18 KiB
Raw Blame History

Visual Parity Report — Angular vs React (full coverage)

Date: 2026-04-19 Tool: Playwright MCP (@playwright/mcp) Angular reference: https://flights.test.aeroflot.ru/{locale}/... React under test: http://localhost:8080/{locale}/... (pnpm dev:full proxy) Locales tested: ru-ru (primary), en-en (sample) Viewports: desktop 1440×900, mobile 375×812 Test scenarios:

  • Route SVO ↔ LED, 19 Apr 2026 (today)
  • Flight SU 6497, 19 Apr 2026
  • Departure ex-SVO / Arrival in LED
  • Schedule one-way SVO→LED, week of 1926 Apr 2026
  • Flights map (no filter)

Screenshots in screenshots-v2/. Legend: 🟢 visually equivalent · 🟡 minor diffs (spacing, dev chrome) · 🟠 functional/content gap · 🔴 major regression.


At a glance

# Page URL pattern Desktop Mobile EN
1 Onlineboard start /{locale}/onlineboard 🟢 🟢 🟢
2 Onlineboard route results /{locale}/onlineboard/route/{dep}-{arr}-{date} 🟢 🟢 🟡
3 Onlineboard departure-only /{locale}/onlineboard/departure/{dep}-{date} 🟢
4 Onlineboard arrival-only /{locale}/onlineboard/arrival/{arr}-{date} 🟢
5 Onlineboard flight-number search /{locale}/onlineboard/flight/{carrier}{num}-{date} 🟢
6 Flight details (single flight) /{locale}/onlineboard/{carrier}{num}-{date} 🟠 🟠 🟠
7 Schedule start /{locale}/schedule 🟢
8 Schedule route results (one-way) /{locale}/schedule/route/{dep}-{arr}-{from}-{to} 🔴
9 Schedule route results (round-trip) /{locale}/schedule/route/.../... 🔴
10 Schedule flight details /{locale}/schedule/{flightId} not tested
11 Flights map /{locale}/flights-map 🟡 🟡
12 Popular requests panel (inline) embedded on 1, 7 🟢 🟢 🟢
13 Error pages (404/500) /error/{code} not tested
14 Smoke / health /{locale}/smoke not user-facing

URL surface

Both apps now use the same BCP-47-like URL contract: /{xx-xx}/... where both halves are the language code (/ru-ru/, /en-en/, /zh-zh/, /ja-ja/, /de-de/, …). Bare short codes (/ru/onlineboard) auto-redirect to canonical (/ru-ru/onlineboard) on the React side; Angular config redirects the same way. URL parity.


1. Onlineboard — start page

Angular React

Diffs:

  • Angular shows test-env chrome React hides (orange "Тестовая версия", "rc/2026-04-06", dev counter "383", chat-widget bubble). Out of scope.
  • Date input placeholder: Angular ДД.ММ.ГГГГ vs React Сегодня (filled when date is today). React's behaviour matches Angular's loaded state once a date is picked.
  • Form-row vertical spacing slightly tighter in React (~6 px less between inputs).
  • 4 info tiles, popular-requests block, breadcrumb — pixel-equivalent.

🟢 Equivalent.

2. Onlineboard — route results (/onlineboard/route/SVO-LED-20260419)

Angular React

Diffs:

  • Both auto-expand the same closest-to-now flight (SU 6579) with the Время + Посадка accordion. Layout, columns, and label order match.
  • Angular shows the actual arrival time (20:22) as primary with the scheduled time (20:25) struck-through; React shows 20:25 primary with 20:22 in the expanded panel. Both convey the same data, slightly different emphasis.
  • Date-tab strip (18 апр 24 апр) and current-day highlight identical.
  • React keeps the filter "Дата рейса" / "Время рейса" rows visible after submit; Angular hides them. Minor.

🟢 Equivalent on layout; 🟡 minor on time-emphasis treatment.

3. Onlineboard — departure-only (/onlineboard/departure/SVO-20260419)

Angular React

Diffs:

  • Angular's Город прилета field defaults to Все направления; React leaves it empty. Functionally equivalent (both query "all destinations from SVO"); cosmetic.
  • Both list flights to varied destinations (Сыктывкар, Махачкала, Ереван, Санкт-Петербург, …) with the same time/airline/airport columns.
  • Same card-expansion behaviour.

🟢 Equivalent.

4. Onlineboard — arrival-only (/onlineboard/arrival/LED-20260419)

Angular React

Diffs:

  • Same Все направления placeholder difference as #3.
  • Boarding section in Angular labelled Высадка (deboarding); React labels it Посадка (boarding) but with the same fields. Consider switching React to Высадка for arrival-direction flights to match Angular wording.
  • Status pill colours match: green check-mark (Прибыл), blue plane (Вылетел).

🟢 Equivalent on layout; 🟡 boarding/deboarding label.

5. Onlineboard — flight-number search (/onlineboard/flight/SU6497-20260419)

Equivalent to the route-results page in chrome (same OnlineBoardSearchPage shell). Both render a single-card list filtered to the flight number, with the same expanded card. H1 heading reads Рейс: SU 6497, Сегодня on both. 🟢 Equivalent.

6. Flight details — full page (/onlineboard/SU6497-20260419)

Angular React

Diffs:

  • H1 wording matches: Информация о рейсе: SU 6497, Москва - Санкт-Петербург.
  • Carrier logo (RU): Angular renders the RU variant РОССИЯ (Cyrillic); React serves the EN variant ROSSIYA (Latin) even on the Russian site. 🔴 BugBoardDetailsHeader's OperatorLogo is still passing locale="en" or the asset fallback is wrong. The fix that landed for FlightCard didn't reach the details-page header.
  • Sidebar mini-list: Angular shows arrows pointing right between origin/destination; React's mini-list item is plainer (just times + cities, no arrows). Angular uses the localised Прибыл time; React shows blank status row in the mini-list.
  • Регистрация row times: Angular shows 16:00 ⁻¹ (with a small superscript day-change marker for the day-before start) plus 15:15 end time; React shows the same.
  • Посадка (boarding) — in flight-details accordion: matching Закончена status, same start/end times.
  • Высадка (deboarding) row: matching status + times.
  • Последнее обновление stamp: both show fresh client-side load timestamp.
  • Footer note * Время прилета и расстояния являются расчётными...: present on both.

🟠 — H1 + accordion match Angular; the carrier-logo locale slip is the only visible regression.

7. Schedule — start page

Angular React

Diffs:

  • Date-range field: Angular shows placeholder ДД.ММ.ГГГГ - ДД.ММ.ГГГГ; React fills with the default current-week range 19.04.2026 - 26.04.2026 (calendar shows actual values). React's behaviour matches Angular's after the calendar mounts.
  • 4 info tiles, popular-requests block, "Расписание рейсов Аэрофлота" SEO body — equivalent.

🟢 Equivalent.

8. Schedule — route results, one-way (/schedule/route/SVO-LED-20260419-20260426)

Angular React

Diffs (major):

  • Day-grouping headers: Angular groups flights by day (Воскресенье 19 Апреля); React shows a flat list with no day grouping.
  • Code-share + multi-leg expansion: Angular shows multi-carrier flights bundled (SU 1942, SU 6532 with two airline logos), then a route diagram (4ч.25мин. + 2ч.20мин. transfer + 5ч.10мин.) and the legs broken out below. React renders each leg as a separate row with no diagram, no transfer pill, and no parent-flight grouping.
  • Column headers: Angular has a sortable header row (РЕЙС / АВИАКОМПАНИЯ, БОРТ / ВЫЛЕТ / ВРЕМЯ В ПУТИ / ПРИЛЕТ) with sort arrows on ВЫЛЕТ and ПРИЛЕТ; React shows no headers.
  • Date-range tab strip: Angular shows weekly windows (13 апр - 19 апр, 20 апр - 26 апр, …); React shows daily tabs (17 апр., 18 апр., 19 апреля, …).
  • Aircraft model: Angular shows Airbus A321 / Airbus A319 per leg; React doesn't show aircraft model in the row.
  • Action buttons: Angular has both Статус рейса and Детали рейса per flight; React has only Детали рейса.
  • Вы искали (search history) sidebar accordion: Angular has one; React has it elsewhere or not at all on this page.

🔴 Major regression — schedule results page is the largest gap in the entire app. The React page is essentially the onlineboard list reskinned, missing all of: day grouping, multi-leg/code-share grouping, transfer diagram, sortable headers, weekly date tabs, aircraft column, and the secondary action button.

9. Schedule — route results, round-trip

Not separately captured in this run. Same structural gaps as #8 are expected (Angular shows two side-by-side panels for outbound + return, each with full grouping). 🔴

10. Schedule — flight details

Not captured. Angular has a dedicated detail page reachable via Детали рейса/Статус рейса buttons; React's catch-all route handles this URL but renders the onlineboard details page. Worth a dedicated capture pass.

11. Flights map

Angular React

Diffs:

  • Origin marker: Angular shows red dot on Москва (geolocation result). React shows no marker — useGeolocationDefault() either silently failed or the headless Playwright didn't grant permission. In a real browser with geo enabled both should show the dot.
  • Default zoom/extent: Angular includes Санкт-Петербург at top of viewport; React's viewport is shifted south, cutting off SPb. Both use Leaflet center [53,45] zoom 5; the diff is viewport-width and tile-loading order, not code.
  • Swap arrows: vertical blue ↑↓ on both.
  • City labels: text-only with text-shadow halo on both.
  • Form panel: no Найдите свой маршрут header on either.
  • Date input: React still has the filled-blue calendar tile, Angular has an outline icon. Minor.

🟡 Minor — geo marker + slight zoom drift.

Embedded inline on Onlineboard start (#1) and Schedule start (#7). Renders 4 items in 2 columns; each is Маршрут: City - City, Номер рейса: SU XXXX, Вылет: City, or Прилет: City. Both apps use a service singleton (Angular *FiltersStateService) / sessionStorage prefill (React) to hand off click data without polluting the URL — confirmed in earlier patches. 🟢

13. Error pages

The React app has /error/{code}/page.tsx covering 404/500/etc. with a localised header + search box. Angular has /error-pages/error-page with the same shape. Not captured this round (need a deliberately broken URL); structurally aligned per the code.

14. Smoke / health

/{locale}/smoke is React-only — used by health-check probes. No Angular equivalent expected.


English (/en-en/) — locale parity sample

Angular React

Diffs:

  • All form labels (Flight number, Route, City of departure, City of destination, Flight date, Search) — match.
  • Date tabs (18 Apr, April 19, 20 Apr, …): Angular uses apr lowercase weekday-relative form; React capitalised Apr. Minor.
  • Status pills (Arrived, In flight, Scheduled) — match.
  • Carrier logos — both render the EN variants ROSSIYA / AEROFLOT.
  • Boarding row labels (Status, Start time, End time/Close time): Angular uses Close Time, React uses End time. Cosmetic.

🟢 Equivalent. EN translation now complete (was 21 keys empty before — all filled).


Mobile (375×812)

Onlineboard start

Angular React

Diffs:

  • Both surface the 3-day quick-pick row (19 Вс. Апреля / 20 Пн. Апреля / 21 Вт. Апреля) above the manual ДД.ММ.ГГГГ input. React's selected-day chip uses solid blue fill; Angular leaves all three white. Minor.
  • Tabs (Онлайн-Табло / Расписание / Карта полетов) — match.
  • Form fields, swap arrow, accordion behaviour — match.

🟢 Equivalent.

Flight details

Angular React

Diffs:

  • Carrier logo: Angular РОССИЯ (RU); React ROSSIYA (EN). Same bug as desktop #6. 🔴
  • Both show the date-picker (19 Апреля 2026 / Сегодня) and the back-to-board button.
  • Both show the same flight-progress timeline (16:00 → 17:23 with Прибыл, strikethrough scheduled 17:25).
  • Both show the same По расписанию / Фактическое time blocks.
  • Last-update stamp (Последнее обновление: 19:09 19.04.2026) — both fresh client-load time.
  • React shows an extra wrapped header with "SU 6497 / 16:00 / 17:23 / Москва / Санкт-Петербург" above the main accordion — duplicates info that's already in the main card. Angular doesn't have this duplicate.

🟠 — Carrier logo locale + duplicate sidebar-card on mobile.


Cross-cutting findings

What's already at parity

  • URL contract (BCP-47 /xx-xx/, both halves matching).
  • 9-language i18n coverage (RU complete, EN complete after this round, others have file-level coverage from the prior project).
  • API client locale (now mutable, follows [lang]/layout.tsx) — cities/airports/statuses respond in the active language.
  • Onlineboard start, route, departure, arrival, flight-search pages — visually equivalent.
  • Schedule start page — equivalent.
  • Popular requests panel + cross-page prefill via sessionStorage.
  • Mobile day-quick-pick (3-day chip row).
  • Flights map: swap arrows, city labels, form panel header, leaflet tooltip styling.
  • Last-update stamp using client-side load time (matches Angular's flight.lastUpdate = new Date()).
  • Share menu (translated labels + brand-icon-on-top layout).
  • Footer note * Время в системе - МЕСТНОЕ. on search results.
  • Boarding-status leading dot (grey for Уточняется).

Open gaps 🟠/🔴

Severity Page Gap
🔴 Schedule results (#8, #9) No day grouping, no code-share/multi-leg bundling, no transfer-diagram, no sortable headers, no weekly date tabs, no aircraft column, missing Статус рейса button. Schedule is a markedly different feature in Angular than what React currently ships.
🔴 Flight-details carrier logo (#6, mobile) BoardDetailsHeader still serves the EN logo variant on Russian pages. FlightCard was fixed in the i18n migration, but the details-page header was missed. One-line fix in BoardDetailsHeader.tsx to pass useLocale().language.
🟠 Flight-details mobile (#6) React renders an extra summary-card above the main details card that Angular doesn't have.
🟠 Onlineboard arrival (#4) Boarding-row label says Посадка for arrival-direction flights; Angular says Высадка.
🟡 Onlineboard departure/arrival (#3, #4) Empty Город прилета / Город вылета field instead of Angular's Все направления placeholder.
🟡 Flights map Default origin red dot (geo-driven, not code).
🟡 Flights map calendar icon Filled blue tile vs Angular outline icon (PrimeReact theme).
🟡 Onlineboard route filter Date / time inputs stay visible after submit; Angular hides them.
🟡 EN tabs label casing Apr vs apr weekday header.

Items intentionally divergent

  • React [lang]/smoke route — health probe, not present in Angular.
  • React [lang]/popular route was deleted to match Angular's 404 (popular requests are inline only).
  • React in-page test/dev chrome (Тестовая версия badge, env counter, chat widget) — Angular reflects the test-env deployment; React's dev:full is dev-only.

P0 — content correctness on the Russian site:

  1. Fix BoardDetailsHeader to pass useLocale().language to OperatorLogo so RU pages get РОССИЯ not ROSSIYA (desktop + mobile #6).

P1 — feature gaps on schedule: 2. Schedule results page (#8) — port Angular's day-grouped, multi-leg / code-share bundled, weekly-date-tab layout. This is the single biggest UX gap remaining in the React app. 3. Schedule round-trip results — same approach, two-pane.

P2 — small parity wins: 4. Mobile flight-details: drop the duplicate summary card above the main details card (#6 mobile). 5. Onlineboard arrival page: rename boarding row to Высадка when direction = arrival (#4). 6. Departure / arrival pages: prefill the opposite-direction field with Все направления placeholder (#3, #4).

P3 — polish: 7. Onlineboard route filter: hide Дата рейса / Время рейса rows post-submit. 8. Flights map: outline calendar icon instead of filled blue tile. 9. EN onlineboard date tabs: lowercase short month name to match Angular (apr not Apr).