# 10-Mar-2026 — map hang, GPX route parsing, mail API resilience, walk search layout

## [build 515](https://github.com/nbarrett/ngx-ramblers/actions/runs/22894482875) — [commit 0cad242](https://github.com/nbarrett/ngx-ramblers/commit/0cad242aac84cb3cef60ff906d86c1a8304cddd0)

_____

## GPX Parser: Support <rte> Route Elements
- **Root cause**: GPX parser only handled `<trk>/<trkpt>` (track)
elements but ignored `<rte>/<rtept>` (route) elements. 37 of 39
Sevenoaks walking route GPX files use `<rte>` format, so only 2
routes were rendering on the map
- **Fix**: added `parseRoute()` and `parseRoutePoints()` methods to
convert `<rte>/<rtept>` elements into renderable `GpxTrack` objects
alongside existing `<trk>` parsing
- **Waypoint dedup**: changed `parseWaypoints()` from selecting
`"wpt, rtept"` to just `"wpt"` — `<rtept>` elements are now parsed
as route tracks, not waypoints, preventing duplicate rendering
## Map Viewport Hang Fix
- **Root cause**: Dragging/zooming the map triggered an infinite feedback
loop — `moveend` → `loadRoutes()` → layer reassignment + `fitBounds`
→ Leaflet re-render → `moveend` again
- **Debounced viewport handler**: 300ms debounce on `moveend`/`zoomend`
prevents rapid-fire reloads during panning
- **Re-entrancy guard**: `loadRoutesInProgress` flag skips concurrent
`loadRoutes()` calls
- **Suppress programmatic events**: `suppressViewportHandler` flag
prevents layer/bounds assignment from re-triggering the viewport
handler (cleared after 200ms)
- **Skip fitBounds on viewport reloads**: `loadRoutes(skipFitBounds)`
parameter prevents `calculateFitBounds` on user-initiated pan/zoom,
which was the primary loop trigger
- **Removed cache eviction on viewport change**: the viewport filtering
already uses `currentBounds.intersects()` on cached data, so deleting
and re-fetching GPX on every drag was unnecessary
## Mail API Resilience (No API Key / Invalid Key)
- **Short-circuit when no API key**: `MailMessagingService.initialise()`
checks `mailConfig.apiKey` after loading config — if absent, skips all
Brevo API calls (account, lists, folders, templates) and sets safe
empty defaults. Zero 401 errors in the console
- **Short-circuit on account error**: if the account query fails (invalid
key), remaining Brevo calls are skipped with empty defaults
- **Senders list guard**: `MailSendersListComponent` waits for the
`mailMessagingConfig` via the `events()` observable before calling
senders/domain APIs — skips if `accountError` is set
- **Create-or-amend sender guard**: checks `brevoAccountConfigured()`
before calling `querySenders()`
- **Mail provider stats guard**: `calculateMailProviderStats()` handles
`this.list` being undefined when Brevo lists fail to load, showing
"No Brevo lists available" instead of crashing
- **List key values null safety**: added `?.` and `|| []` fallback when
`brevo.lists.lists` is undefined
- **Alert icon**: changed error alert icon from `faCircleCheck` to
`faExclamationTriangle` for the account error panel
## CommonDataService Double HTTP Request Fix
- **Root cause**: `responseFrom()` used `.subscribe()` + `.toPromise()`
on a shared observable, causing two subscriptions and duplicate HTTP
requests
- **Fix**: replaced with single `firstValueFrom()` call — one
subscription, one HTTP request, proper error propagation via `throw`
## Config Save: Allow Clearing Sensitive Fields
- **Root cause**: `restoreSensitiveFields()` in the backend config
controller treated both missing keys AND falsy values (`""`, `null`)
as "restore from DB", making it impossible to clear the API key
- **Fix**: changed condition from `!(k in incoming) || !incoming[k]` to
`!(k in incoming)` — only restores when the key is truly absent
(redacted), not when explicitly cleared
## Mail Settings: Prevent Config Overwrite During Editing
- **Root cause**: `MailMessagingService.initialise()` created new
subscriptions to `committeeConfig` and `systemConfigService` on every
call, causing accumulated subscriptions that re-emitted config and
overwrote unsaved edits
- **Fix**: moved one-time subscriptions to the constructor;
`acceptNextConfigEmission` flag in `MailSettingsComponent` prevents
subscription emissions from overwriting local edits except after
save or undo
## Domain API URL Refactor
- Changed domain endpoints from path parameters
(`/domains/:domainName/configuration`) to query parameters
(`/domains/configuration?domainName=...`) across backend routes and
frontend service
## Walk Search Layout
- Alert inline when default filtering, own row with pagination/filters
- Clear filters resets to default preset
- Bug button hidden by default
## Events
- Bug button visibility fix