# 04-Apr-2026 — Mobile-friendly templates, GDPR link fix, and data-driven override model [#213](https://github.com/nbarrett/ngx-ramblers/issues/213)

## [build 574](https://github.com/nbarrett/ngx-ramblers/actions/runs/23983422012) — [commit 1368240](https://github.com/nbarrett/ngx-ramblers/commit/136824014490f0629098531bae74e7fdc2e39382)
_____

### Emails now readable on mobile devices
* All Brevo email templates are now mobile-friendly. Emails that previously required rotating to landscape on a phone will now
reflow to fit the screen in portrait mode. 
* This applies to all email types: welcome emails, password resets, membership expiry notifications, campaigns, and more.
### Broken GDPR link fixed
* The GDPR link in the "Unsubscribing" section of the welcome email pointed to eugdpr.org which has been returning 404 for some time.
* This now links to the ICO (Information Commissioner's Office) UK GDPR guidance page at https://ico.org.uk.

### Site-specific image overrides for welcome email

* in order to see where this configuration is performed, navigate to **Admin  >  Mail Settings**.
* Site specific image overrides are demonstrated with reference to the "Welcome to the Group" Email Configuration 12 of 13 — which is the the first template where new Template Image Overrides section have been implemented. 
* You can select this by choosing this value in the email configuration selector:

![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/5194b7c5-5ad0-4b84-9126-ada74acf9aae.jpeg)

* The original welcome email template contained placeholder text e.g. `<homepage-image-goes-here>` where each group's webmaster should add screenshots of their site (walks programme, social events page, login prompts, etc). 
* However, this was just a generic placeholder that required the Webmaster to know what to do in order to replace it within the Brevo editor. 
This was not discoverable, and also required images to be exported to Brevo, requiring extra effort and the need to save image data  outside of the realm of the group's website. 
* Additionally, this approach could easily cause customisation to be overridden when NGX Ramblers releases affected email template content, causing data to be undesirably overwritten. 
* To resolve all of the above issues, these placeholders are now managed through the admin UI using the CMS **Image Cropper And Resizer** — webmasters upload/crop images through the standard CMS interface, no HTML knowledge needed.
* Backend auto-wraps stored image URLs in responsive img tags at send time.
* These images are preserved when the central base template is updated — your group's customisations will never be overwritten by a template push.

* The **Template Image Overrides** panel when first opened — each slot shows **not configured**. Every override slot shown here is discovered automatically from `{{override.*}}` markers in the template HTML.

![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/8dca117b-4274-43c0-b022-c27768e017cc.jpeg)

* Opening a slot reveals the shared **Image Actions → Add image** dropdown. Selecting *Add image* launches the standard CMS image cropper, so there is no bespoke image-upload UI to learn.

![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/39b32718-9688-445b-b665-39f387822474.png)

* Once the screenshot has been cropped and saved, the slot header flips to **configured** and a preview is shown inline. The same **Image Actions** dropdown now offers edit, replace, and remove.
* Below is a real example of what an admin would see for the **Walks Programme Image** override — the live Walks Programme page from [East Kent Walking Group](https://www.ekwg.co.uk).

![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/e74f5287-84df-4b1c-90fe-592c60549942.png)

* A screenshot of the final rendered welcome email, with the two configured overrides (Walks Programme page and site home page) embedded responsively alongside the template's own intro text is shown below: 

![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/efa9a623-84eb-4a3f-a114-b5d82d755df1.jpeg)

## Technical Details
### Fully data-driven override discovery
Override definitions are NOT hardcoded in code. Instead, the
system scans template HTML for `{{override.KEY}}` markers at
runtime and dynamically generates override slots in the admin UI.
This is essential for rollout to 500+ groups — each group's admin
UI automatically reflects whatever markers exist in the current
template, with no code changes or deployments needed.
- `extractOverrideKeys()` scans any template HTML for
`{{override.*}}` patterns and returns unique keys
- `overrideKeyToLabel()` auto-generates human-readable labels
from keys (e.g. `WALKS_PROGRAMME_IMAGE` → "Walks Programme Image")
- Default placeholder content is generated dynamically
(e.g. "[Walks Programme Image — to be added by your webmaster]")
- The server returns discovered override keys via the template
diff endpoint (`TemplateDiffResponse.overrideKeys`)
- The admin UI renders override slots from these server-discovered
keys, not from any static registry
- Adding a new `{{override.XXX}}` marker to a template and pushing
it centrally is all that's needed — every group's admin UI
immediately shows the new image upload slot
Removed the hardcoded `TEMPLATE_METADATA` registry,
`TemplateCategory` enum, and `TemplateOverrideDefinition` interface
which were not scalable for multi-tenant rollout.

### Responsive CSS — DRY injection
- Rather than duplicating responsive CSS across all 8 template HTML
files, a shared module (`responsive-email-styles.ts`) defines the
styles once. The `readLocalTemplate()` function in
`local-template-reader.ts` auto-injects viewport meta, charset,
and media query styles into any template that lacks them. Templates
that already have responsive CSS (e.g. `fully-automated-text-body`)
are left untouched. Template HTML files on disk remain clean.


### Base vs override template model
- `NotificationConfig` and `EmailRequest` gain an optional
`templateOverrides: Record<string, string>` field
- MongoDB schema updated to persist overrides per notification config
- Welcome template image placeholders replaced with named markers
(`{{override.WALKS_PROGRAMME_IMAGE}}`, etc — 6 unique keys,
7 occurrences)
- `applyTemplateOverrides()` in `messages.ts` scans the template
HTML for override markers and resolves them: site override image
if configured, otherwise a styled default placeholder
- Override substitution runs after HTML sanitisation but before
merge field substitution in `performTemplateSubstitution()`
- `createEmailRequest()` in `mail-messaging.service.ts` passes
`templateOverrides` from the notification config through to
the backend


### Override discovery pipeline
1. Admin selects a template in Email Configurations
2. Frontend calls `templateDiff` endpoint
3. Server fetches template HTML from Brevo, scans for
`{{override.*}}` markers via `extractOverrideKeys()`
4. Returns discovered keys in `TemplateDiffResponse.overrideKeys`
5. Frontend renders an image upload slot per key using
`overrideKeyToLabel()` for display labels
6. Webmaster uploads images via CMS ImageCropperAndResizerComponent
7. Values stored in `NotificationConfig.templateOverrides` (MongoDB)
8. At send time, `applyTemplateOverrides()` replaces markers with
img tags or default placeholders


### Files changed
- `mail.model.ts` — extractOverrideKeys(), overrideKeyToLabel(),
overrideKeys on TemplateDiffResponse, templateOverrides on
NotificationConfig and EmailRequest interfaces. Removed
TEMPLATE_METADATA, TemplateCategory, TemplateOverrideDefinition
- `mail-notification-template-editor.ts` — override slots driven
by server-discovered keys via discoveredOverrideKeys array,
labelForKey() for display labels, image upload via CMS
ImageCropperAndResizerComponent
- `mail-messaging.service.ts` — pass templateOverrides in request
- `welcome-to-the-group.html` — GDPR link fix, override markers
- `messages.ts` — data-driven applyTemplateOverrides() scans HTML
for markers instead of using hardcoded registry
- `template-diff.ts` — returns overrideKeys discovered from
template HTML
- `local-template-reader.ts` — responsive CSS injection
- `responsive-email-styles.ts` — shared responsive CSS module (new)
- `notification-config.ts` — templateOverrides in MongoDB schema
Reported by Charlie Bigley (via Bolton Ramblers) — 2 Apr 2026


### Follow-up fixes and polish
- Brevo editor URL corrected to `https://editor-app.brevo.com`
- Template sanitisation now collapses blank lines before push/diff operations
- Nested Brevo/API error extraction improved so the UI shows the real underlying error message
- Sensitive config redaction now preserves existing secrets on save when masked values are posted back
- Selected email configuration is reflected in the URL via `?configuration=...`
- Mail settings/template bindings were stabilised to remove the NG0103 change-detection loop on Email Configurations
- CMS image cropper now supports clipboard image paste, image URLs, `site-content/...` paths, existing-image preload editing, and live unsaved preview updates
- PNG/WebP uploads can now be cropped, and compression updates the generated output more reliably
- Template Image Overrides now render as collapsible accordion panels and use the shared Image Actions dropdown so existing images can be edited, replaced, or removed consistently with the inline image editor
- After pushing the default template, the local/default diff badge now updates immediately to show the matched state
- Merge field tokens inside HTML attribute values (e.g. `href="..."` or `src="..."`) are no longer wrapped in Brevo editor pill spans during template push, fixing a bug where broken `<a href="<span>...</span>">` markup was leaking into the Brevo rich text editor. Merge fields in visible text content are still wrapped as editable pills as intended.
