From 61cea95697ccb56c525002b08f76bf57da896837 Mon Sep 17 00:00:00 2001 From: Dries Augustyns Date: Thu, 25 Dec 2025 17:59:52 +0100 Subject: [PATCH] fix: Correctly reserve fields from being set on contact --- apps/api/src/services/ContactService.ts | 13 ++++++++----- .../content/docs/concepts/contacts-and-data.mdx | 9 ++++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/api/src/services/ContactService.ts b/apps/api/src/services/ContactService.ts index 35ae603..e3b792d 100644 --- a/apps/api/src/services/ContactService.ts +++ b/apps/api/src/services/ContactService.ts @@ -225,12 +225,14 @@ export class ContactService { // Merge new data (if provided) if (data) { for (const [key, value] of Object.entries(data)) { - // Skip reserved fields - if (key === 'plunk_id' || key === 'plunk_email') { + // Skip reserved system-generated fields + // These fields are dynamically added during template rendering and cannot be overridden + const reservedFields = ['plunk_id', 'plunk_email', 'email', 'unsubscribeUrl', 'subscribeUrl', 'manageUrl']; + if (reservedFields.includes(key)) { continue; } - // Validate locale field + // Validate locale field (special user-settable field) if (key === 'locale') { if (typeof value === 'string') { if (!isValidLanguageCode(value)) { @@ -321,8 +323,9 @@ export class ContactService { // Add temporary (non-persistent) data if (temporaryData) { for (const [key, value] of Object.entries(temporaryData)) { - // Skip reserved fields - if (key === 'plunk_id' || key === 'plunk_email') { + // Skip reserved system-generated fields + const reservedFields = ['plunk_id', 'plunk_email', 'email', 'unsubscribeUrl', 'subscribeUrl', 'manageUrl']; + if (reservedFields.includes(key)) { continue; } diff --git a/apps/wiki/content/docs/concepts/contacts-and-data.mdx b/apps/wiki/content/docs/concepts/contacts-and-data.mdx index c6cbcae..11bb17d 100644 --- a/apps/wiki/content/docs/concepts/contacts-and-data.mdx +++ b/apps/wiki/content/docs/concepts/contacts-and-data.mdx @@ -85,7 +85,14 @@ Use `{{fieldName}}` in emails: **Fallback:** `{{firstName ?? 'there'}}` -**Predefined fields:** `{{email}}`, `{{unsubscribeUrl}}`, `{{subscribeUrl}}`, `{{manageUrl}}`, `{{locale}}` +**System-generated fields (always available):** +- `{{email}}` - Contact's email address +- `{{unsubscribeUrl}}` - Link to unsubscribe page +- `{{subscribeUrl}}` - Link to subscribe page +- `{{manageUrl}}` - Link to preference center + +**Special fields:** +- `{{locale}}` - Contact's language preference (user-settable, overrides project default) ## Temporary data