02-May-2026 — Inbound Forwarding warnings + Committee Settings catch-all admin closes #256
build 637 — commit 4147694
Part 1 — Inbound Forwarding warnings
Two alert-warning banners on the Inbound Forwarding tab, both rendered before the rule UI:
- Domain mismatch: fires when the site's primary host (from
systemConfig.group.href) is not under the deployed Cloudflare zone's apex domain. This catches the Winchester-style failure where a per-envzoneIdwas empty, the deploy fell back to the globalzoneId, and rules were silently created in the wrong zone. - Stale deploy: fires when a per-env
zoneIdhas been set in the stagingenvironmentsdoc but the running app's deployedCLOUDFLARE_CONFIGstill has a differentzoneIdbaked in (i.e. needs a redeploy).
The resolution chain in cloudflare-config.ts is unchanged; the new fields (cloudflareZoneBaseDomain, primaryHost, perEnvironmentDbZoneId) are added to nonSensitiveCloudflareConfig() purely to drive the warnings. Per-env zoneId is looked up by stripping the ngx-ramblers- prefix from APP_NAME and matching the environments[] entry.
Suffix matching uses a new isHostUnderDomain() helper in projects/ngx-ramblers/src/app/functions/hosts.ts (apex or subdomain, case-insensitive, strips a leading www.). Spec covers the apex, subdomain, www-prefix, the deceptive notngx-ramblers.org.uk non-match, and missing inputs.
Part 2 — Manage zone catch-all rule from the Committee Settings admin
Today the catch-all rule for a zone (e.g. *@ngx-ramblers.org.uk -> nick.barrett36@gmail.com) is only configurable from Cloudflare's own dashboard. This brings it into NGX so the same admin surface that manages per-role rules also handles the catch-all, and adds the worker-based fan-out for multi-recipient catch-all delivery.
A new "Catch-all rule for *@<baseDomain>" card sits on the Committee Members tab of Committee Settings, between the action toolbar and the role table. It shows the current state as a status badge (Disabled / Drop / Forward -> <addr> / Multiple recipients (Worker)) and an Edit button. The editor exposes an action selector with four choices and a destination input that switches shape based on the action: a single email field for Forward, an add/remove list for Multiple. Worker-backed catch-all rules pre-load their existing recipients when editing so the operator sees what's currently configured rather than starting blank.
Server side adds an updateCatchAllRule helper that PUTs to /zones/<zoneId>/email/routing/rules/catch_all, plus a PUT /api/cloudflare/email-routing/rules/catch-all route. The route resolves the request shape via a planCatchAllRule helper that uploads a worker named email-fwd-<zone>-catch-all for the Multiple action (reusing the existing worker template machinery and BREVO_RESEND mode wiring from per-role workers) and tears down any previously-bound worker when switching to Drop, Disabled, or Forward. Rule names follow the existing "<Mode label> - <description>" convention so they read sensibly in Cloudflare's UI alongside per-role rules.
Frontend service exposes updateCatchAllRule which invalidates the relevant caches and pushes the new rule onto the existing catchAllNotifications BehaviorSubject so the badge refreshes after a save.
New model types: CatchAllAction enum, UpdateCatchAllRequest interface, CatchAllResolution interface (the latter for use by Part 3's catch-all-aware role view).
727/727 frontend tests pass.