syncPolylines filtered endpoints by map.hasLayer(marker), which drops
polylines whose endpoint's zoom-tier layer was just removed by
syncVisibility. Result: in spider mode, arcs to small/distant cities
vanished when the user zoomed out.
Arc coordinates are fixed by the city's lat/lng; render them as long as
the markers exist in the index. User-level filtering (domestic /
international) already happens upstream in filterRoutes, so the
hasLayer gate was both incorrect and redundant.
Upstream /destinations and /days endpoints expect yyyy-MM-DD (dashed),
matching Angular's ApiFormatterService.formatDateOnly output. React was
sending the internal compact yyyyMMdd, triggering silent 400s.
Also fix dev-server.mjs status-code parsing: empty-body curl responses
start with the appended "\n%{http_code}" separator at index 0, so
`lastNewline > 0` mis-treated the status as body and defaulted to 200,
hiding real upstream 4xx/5xx responses. Changed to `>= 0`.
1. FlightsMap tiles didn't render: MapCanvas inline height:100% resolved
to 0 against min-height parents. Hand sizing to consumer CSS so
.flights-map-start__map height:500px wins.
2. FlightsMap /map/api/tile/{z}/{x}/{y}.jpeg requests fell through to
Modern.js SSR (HTML body). Dev proxy now forwards /map/* to the
test env via curl with image headers and binary-safe piping.
3. PopularRequestsPanel duplicate React key (Route-SVO-LED appears
twice in upstream). Suffix the key with the visible index.
4. OnlineBoardDetailsPage /onlineboard/details 400. Upstream expects
an ISO datetime (yyyy-MM-DDTHH:mm:ss), matching Angular's
ApiFormatterService.formatDate. Append T00:00:00.
5. Browser-level SignalR CORS errors on every details page: the
default SIGNALR_HUB_URL pointed at an unreachable placeholder.
Default to empty + skip the connection in useLiveFlights when
blank. Also configureLogging(LogLevel.None) so SignalR stops
writing its own negotiation failures to console. Live updates
re-enable by setting SIGNALR_HUB_URL on a deployment.
The tile URL was built as `${env.API_BASE_URL}/tiles/{z}/{x}/{y}.png`,
which has three problems on a real deployment:
1. Wrong path segment: the backend serves tiles under /map/api/tile/
(singular), not /tiles/.
2. Wrong extension: the backend emits .jpeg, not .png.
3. Wrong base: API_BASE_URL may be empty or point at the JSON API host.
Tiles are served by a dedicated upstream behind the same reverse
proxy that fronts the React SSR, so they must be same-origin and
relative (matches Angular environment.mapApiUrl).
With this fix, the map renders its base tiles on the deployed site
instead of issuing doomed requests and showing a blank canvas behind
the markers. The Leaflet marker layer was already rendering; only the
tile layer was missing.
A designer-source archive that got seeded from ClientApp/ alongside
the real SVG icons. No code under src/ or ClientApp/ references the
zip file (only the sibling .svg icons are imported). Removing so it
stops shipping in dist/standalone/public/ and the deploy image.
Three non-fatal warnings surfaced by the Jenkins build log, fixed in
the config layer:
- module-federation.config.ts: dts: false. The @module-federation/
dts-plugin fails under our strict tsconfig and logs TYPE-001 every
build. Remote types are not needed at runtime; consumers generate
their own via their dev toolchain.
- src/styles/_layout.scss: color-adjust → print-color-adjust. The
unprefixed color-adjust shorthand is deprecated; the standard name
is print-color-adjust. Matches the -webkit- prefixed sibling.
- modern.config.ts: tools.devServer.headers explicitly set. MF warns
when devServer.headers is empty and auto-assigns '*'. Providing an
explicit allowlist silences the banner in dev builds; production
behavior is unaffected (real reverse proxy manages CORS).
Playwright MCP v0.0.70 defaults to launching Chrome with --no-sandbox
because its sandbox-inference code in playwright-core mcp/config.js
only sets the default when browser.browserName is explicitly 'chromium';
the MCP leaves it undefined, so the default-to-true branch is skipped
and Playwright core pushes --no-sandbox into chromeArguments.
Chrome surfaces this as a yellow warning bar on every Playwright-driven
tab. Setting PLAYWRIGHT_MCP_SANDBOX=true via the MCP server env forces
chromiumSandbox=true, which skips the --no-sandbox push and removes the
warning. The override is scoped to this project; the plugin's own
.mcp.json is unchanged.
The config/public/ directory (fonts, images, leaflet icons, favicons) is
Modern.js's publicDir convention — copied into dist/standalone/public/ at
build time. Two pre-existing gaps caused this to break on the deployed
SSR image and any fresh sync:
- scripts/sync-to-flights-front.sh did not copy config/ to the target
repo, so the flights-front tree was missing /assets/** entirely.
- Dockerfile.react only copied src/, skipping config/; pnpm
build:standalone ran without a publicDir source.
Result was that every /assets/** URL served the SSR HTML index with
Content-Type: text/html, producing OTS font-parse errors
(sfntVersion 1008821359 == '<!DT') and silently broken images.
Fix mirrors what was applied ad-hoc in Aeroflot.Flights.Front; this makes
future syncs and Docker builds carry the assets automatically.
Commit e20ef94 set the default to https://flights.test.aeroflot.ru/api,
which broke the browser client (no CORS headers on the test env;
scripts/dev-server.mjs is the only layer that can bypass it).
Keep PROD_ORIGIN pointing at the test env for SEO, but restore
API_BASE_URL default to http://localhost:8080/api with a comment
explaining the proxy chain: dev → Express+curl → flights.test.aeroflot.ru.
Production deployments continue to set API_BASE_URL explicitly.
Previously API_BASE_URL defaulted to http://localhost:8080/api, which
only works inside the dev server proxy. For standalone/SSR runs without
the proxy, the default now points to https://flights.test.aeroflot.ru.
Dev continues to use the same-origin proxy because scripts/dev-server.mjs
explicitly injects API_BASE_URL=http://localhost:8080/api into the
Modern.js child process env, keeping browser fetches CORS/WAF safe.
Final C-gap sub-feature: calendarRange pure helpers
(getMinDate/getMaxDate/buildDisabledDates/findNextEnabledDate), snap-to-
nearest-enabled effect in FlightsMapFilter, and useGeolocationDefault
hook that pre-fills departure from browser position on mount when no
dep/arr is already set.
routesToPolylines + intermediateCityIds now normalize airport codes to city
codes via the dictionaries so API responses resolve correctly. The page adds
effectiveConnections state + two effects for Angular-parity fallback
(retry connections=1 on empty direct-route result, then flip the UI toggle),
a filterRoutes memo feeding polylines and intermediateIds, and a popups memo
rendering departure + arrival buy-ticket popups in route mode only.
Covers the final four Angular-parity gaps: filterRoutes pure helper,
buildBuyTicketUrl + escapeHtml, routesToPolylines/intermediateCityIds
airport→city normalization, and FlightsMapStartPage wiring for the
auto-fallback effect plus departure/arrival buy-ticket popups.
- routesToPolylines + intermediateCityIds pure helpers with unit coverage.
- IMapPolyline reshaped from points to cityIds for Angular-parity drawing.
- MapCanvas resolves coords via markerIndex, filters invisible cities on
every zoom/toggle change, and runs a second tooltip pass that keeps
intermediate-city tooltips open regardless of zoom/highlight rules.
Six TDD tasks covering the routes-to-polylines pure helper, IMapPolyline
reshape to cityIds, MapCanvas polyline sync with visibility filtering,
intermediate-tooltip force-open pass, page wiring, and integration tests.
Tasks 1-3 share a commit due to coupling between type and consumer.
Covers the polyline layer: routesToPolylines pure function, city-code-
based IMapPolyline shape, MapCanvas polyline sync via markerIndexRef
with visibility filtering, intermediate-city tooltip force-open pass.