Replace the inline 'Invalid parameters' fallbacks and the framework's
default '404' text with the existing Aeroflot 404 screen. Unknown
locale, malformed flight/route/station params, and unmatched URLs
(including bad paths like onlineboard//route/...) now all land on the
same ErrorPage component.
Angular's schedule renders 7 day pills ("20 пн … 26 вс") spanning the
active week, not weekly date ranges. Match that: tabs now render the
seven days of selectedMonday's week with day-num + weekday-abbr stack.
Prev/next arrows shift by full weeks. Day clicks scroll to the
matching day group in DayGroupedFlightList for the schedule UX.
Schedule list day accordion stays collapsed by default but auto-
opens the day matching today's date when it's in the visible week
window — mirrors Angular's p-accordion default-active behaviour
where today's flights are visible without a click. The user can
still collapse it; we never re-open after that for the same date.
Visual-diff URLs were hardcoded to a past date with the wrong React
URL format (Angular path-style /AAQ/16042026 instead of React's
single-segment /AAQ-20260420-00002400). Switch to dynamic
yyyyMMdd of today for onlineboard pages and Mon→Sun of the current
week for schedule. Schedule-route diff dropped from ~91% to ~28%
on desktop after these two fixes.
ANGULAR_BASE / ANGULAR_PATH_PREFIX / REACT_BASE / MOCK_ANGULAR /
MOCK_REACT env vars let the script target the live test env
(https://flights.test.aeroflot.ru/ru-ru) without code changes.
Used to rerun the Visual Parity Report against the live Angular
backend instead of a local ng serve.
Match Angular's p-accordion default-collapsed state on the schedule
results page. State now tracks expanded days (default empty)
instead of collapsed days (default empty), so the initial render
shows day headers only and the user clicks to reveal flights.
Schedule details page used to show only a one-line FlightCard and
stop. Reuse ScheduleFlightBody so each flight in the chain renders
the same per-leg layout the schedule results page uses (route
summary, leg cards, transit pill, share/Купить/Детали рейса
actions). Add a `Вернуться к Расписанию` back link to the header.
While here, fix the SEO title key — buildScheduleDetailsSeo was
calling SEO.SCHEDULE.DETAILS.TITLE with `flights={...}`, but the
i18n bundle only defines SEO.SCHEDULE.FLIGHT-DETAILS.TITLE with
`flightNumber={...}`. The unresolved key was leaking into the
document title as "SEO.SCHEDULE.DETAILS.TITLE".
Round-trip schedules used to render outbound and inbound lists
stacked. Mirror Angular's schedule-direction-switch: keep both
fetches running, but render only the active direction's list and add
a button group to the sticky header that swaps which one is shown.
WeekTabs track the active direction's week independently, and tab
navigation updates whichever direction is currently active.
Each schedule + onlineboard search now records itself into the
existing useSearchHistory localStorage hook, with a structured
params payload (departure/arrival/dates/flightNumber). The
SearchHistory sidebar renders the rich Angular layout: clock or
plane icon, optional sub-title (e.g. "Расписание рейсов, в одну
сторону"), city pair, and date range, with inbound dates appended
for round-trip searches.
Schedule flight cards now expand into the rich Angular layout instead
of the online-board time/transition rows. Mirrors connecting-flight-
body / multi-flight-body: horizontal timeline summary, per-leg card
with section number + flight number + operator + aircraft + dep/arr
times + leg duration + stations, transfer-inline-extended pill
between legs (Пересадка, ground time, transit city), and the actions
row (share, Купить, Детали рейса).
Wired via a renderExpandedBody render prop on FlightCard/FlightList so
ui/flights doesn't need to know about schedule-specific bodies.
Replace OnlineBoardFilter on schedule pages with a dedicated
ScheduleFilter that matches Angular's schedule-filter:
- Город вылета / Город прилета with swap arrows
- 'Показать расписание на' date range picker
- 'Время вылета' time slider
- 'Только прямые рейсы' checkbox (sets connections=0)
- 'Показать обратные рейсы' checkbox
- 'Показать расписание' submit button (blue, full-width)
The OnlineBoardFilter accordion (Номер рейса + Маршрут tabs) is no
longer rendered on schedule pages — Angular only ships flight-number
search on the online-board side.
Add sort arrows on ВЫЛЕТ / ВРЕМЯ В ПУТИ / ПРИЛЕТ headers — clicking
toggles ascending/descending order; clicking again clears the sort.
Day groups (Понедельник 20 апреля, etc.) are now collapsible via the
header chevron — matches Angular's p-accordion structure where each
day is an accordionTab. Default state expanded.
- Connecting (multi-leg via transit) flights are now folded into a
synthetic MultiLeg shape with combined flight numbers (SU 6188,
SU 6233) and per-leg airline logos, matching Angular's
schedule-list-flight-header.
- Schedule grid now uses Angular's 8-column layout
(80/120/100/240/100/100/240/16). The middle status icon is
replaced by a duration column with the blue clock icon and
'3ч. 48мин.' / '4h 19m' formatting.
- Multi-leg airline logos use the round badge variant (separate
round.png assets) so two carriers fit side-by-side without overlap.
- Action buttons removed from collapsed rows — Angular only shows
flight-actions in the expanded body. Added chevron column for
every schedule card and made schedule cards expandable by default.
- Removed 'Туда: MOW → KUF' subhead from outbound section, matching
Angular's bare flight list under the column header.
Angular's FlightsMapFilterComponent only sets departure when
UserLocationService.location emits an actual position — there's no
fallback to Moscow. Removing the React fallback aligns the empty
initial state (no splines drawn before user input).
Angular's getCityOrAirport walks airport→city when the input code is
an airport (SVO → Москва), only falling back to the airport name when
no parent city is dictionarised. React was returning the raw airport
name (Шереметьево) on the popular requests panel.
Match Angular's flight-actions layout — schedule rows now show the
orange Buy and outlined Status рейса buttons inline at the right edge
of the row instead of inside the expanded panel.
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.
The mobile day-select dropdown was rendering as an empty <select>
on detail pages where the calendar API hasn't shipped any usable
days for that view. The empty box took layout space and looked
broken. Match Angular: don't render the picker when there's
nothing to pick.
ScheduleStartPage now starts dateFrom/dateTo as null so the input
shows the `ДД.ММ.ГГГГ - ДД.ММ.ГГГГ` placeholder Angular ships
instead of pre-filling with the current week. The submit handler
defaults to current-week range when the user submits without
picking dates, preserving the legacy "find this week" UX.
Same pattern as the onlineboard date fix.
- ScheduleSearchPage: H1 now reads `Расписание по маршруту: …`
using SCHEDULE.SCHEDULE-BY-ROUTE — the existing onlineboard
variant was leaking through. Matches Angular's schedule-search
title-bar verbatim.
- DayGroupedFlightList: render a non-sortable column header bar
above the list with `Рейс / Авиакомпания, борт / Вылет / Время
в пути / Прилет`. Mirrors Angular's schedule-list-flight-header
column row. Sort arrows still TBD.
- New i18n keys: SCHEDULE.COL-FLIGHT, COL-AIRLINE, COL-DEPARTURE,
COL-DURATION, COL-ARRIVAL (RU + EN both filled).
Schedule-route mismatch now 11.99% (was 12.47% pre-heading fix).
Paint 3 known noise regions white in both screenshots before pixel-
matching:
- top-left ~200×90 (debug counter + orange `Тестовая версия` badge)
- top-right ~240×50 (build tag like `rc/2026-04-06`)
- bottom-right ~90×90 (chat-widget bubble)
These show only on the deployed Angular test env, not in the React
dev build, and were inflating every parity score by ~1-2pp.
Mismatch deltas vs prior run:
en-onlineboard-route 4.62% → 4.45%
flight-details 11.24% → 10.82%
mobile-flight-details 17.92% → 16.58%
mobile-onlineboard-start 20.37% → 18.66%
onlineboard-arrival 4.63% → 4.46%
onlineboard-departure 5.03% → 4.86%
onlineboard-route 4.78% → 4.60%
onlineboard-start 14.52% → 13.77%
schedule-route 12.47% → 11.87%
schedule-start 13.39% → 12.86%
flights-map 37.28% → 36.40%
- FlightCard: when the flight is multi-leg, render one OperatorLogo
per leg in the header so code-share / multi-carrier journeys show
both airline brands (Angular's `operator-logo-and-model x N` row).
Direct flights keep the single logo.
- FlightCard: add an orange "Купить" (buy ticket) link rendered next
to "Детали рейса" when the card is in the schedule context. Links
to aeroflot.ru's booking flow per Angular's flight-actions wiring.
- Reverted earlier per-leg flight-number stack — IFlightLeg in React
doesn't carry a per-leg flightId, so the parent SU number is the
authoritative label. The Angular dual-number stack belongs to the
ConnectingFlight shape (separate from MultiLeg) which the React
code already renders flat.