gigafibre-fsm/scripts/campaigns/templates/gift-email-fr-native.json
louispaulb 0fd1e9f6b5 feat(campaigns/templates): Gemini-powered HTML→native converter
Scales the native-block migration from "one template per manual spec"
to "any compiled .html template, one CLI command, ~5 seconds, ~$0.001
per template" via Gemini Flash semantic interpretation.

Pipeline (ai-convert-to-native.js):
  1. Read existing compiled .html
  2. Send inner body to Gemini Flash with a tight JSON schema
     (block.type ∈ text/image/button/divider/html, plus type-specific
     fields like fontSize/color/padding/href).
  3. AI returns { preheader, ariaLabel, blocks: [...] }
  4. Deterministic emit of a templates-spec/<name>-native.js file —
     no AI-touched markup goes into the final compiled output.
  5. Validation: every {{var}} in source MUST survive into the spec;
     warn loudly if any are dropped (the AI occasionally omits minor
     placeholders like {{year}} in the copyright line).

Why deterministic emit matters:
  Gemini understands SEMANTICS reliably ("this paragraph is the
  greeting, this div is the CTA, this span is a chip") but
  hallucinates DETAILS when generating final HTML. Splitting the
  responsibilities means the AI only outputs structured JSON
  describing the layout, and build-native-template.js produces the
  bytes shipped to recipients.

First conversion: gift-email-fr → gift-email-fr-native
  - 15 blocks identified by Gemini in 3006 tokens (Flash, ~5s).
  - 4 row groups: view-in-browser, white card (intro/chips/CTA/
    footer copy), contact info, dark footer band.
  - 7 text + 1 image + 1 button + 6 html blocks (chips, multi-logo
    strip, brand-logo card, expiry section stay as raw HTML —
    correct, those have no native equivalent).
  - HTML payload: 19,664 bytes vs original 39,913 bytes — **-51%**.
  - One AI omission caught by the new sanity check: {{year}} was
    stripped from the © line in the dark footer. Hand-patched in the
    generated spec. Re-running with stricter prompt should reduce
    that occurrence rate.

Hub preview endpoint now defaults vars.year to current year (matches
the test-send endpoint that already did this), so the sample render
shows "© 2026 TARGO Communications" instead of "©  TARGO ...".

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 18:29:15 -04:00

665 lines
27 KiB
JSON

{
"counters": {
"u_row": 4,
"u_column": 4,
"u_content_text": 7,
"u_content_image": 1,
"u_content_button": 1,
"u_content_divider": 0,
"u_content_html": 6
},
"body": {
"id": "u_body",
"rows": [
{
"id": "u_row_1",
"cells": [
1
],
"columns": [
{
"id": "u_column_1",
"contents": [
{
"id": "u_content_html_1",
"type": "html",
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"containerPadding": "8px 36px 4px",
"anchor": "",
"_meta": {
"htmlID": "u_content_html_1",
"htmlClassNames": "u_content_html"
},
"html": "{{#view_url}}<div style=\"margin:0px auto;max-width:600px;padding:8px 36px 4px;text-align:center;\"><a href=\"{{view_url}}\" style=\"font-family:Plus Jakarta Sans, Helvetica, Arial, sans-serif;font-size:11px;color:#94a3b8;text-decoration:underline;\">Affichage incorrect ? Voir dans le navigateur</a></div>{{/view_url}}"
}
}
],
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"_meta": {
"htmlID": "u_column_1",
"htmlClassNames": "u_column"
},
"padding": "0px",
"border": {},
"borderRadius": "0px",
"backgroundColor": ""
}
}
],
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"columns": false,
"backgroundColor": "#F5FAF7",
"columnsBackgroundColor": "",
"backgroundImage": {
"url": "",
"fullWidth": true,
"repeat": "no-repeat",
"size": "custom",
"position": "center"
},
"padding": "0px",
"anchor": "",
"borderRadius": "",
"_meta": {
"htmlID": "u_row_1",
"htmlClassNames": "u_row"
}
}
},
{
"id": "u_row_2",
"cells": [
1
],
"columns": [
{
"id": "u_column_2",
"contents": [
{
"id": "u_content_image_1",
"type": "image",
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"containerPadding": "28px 36px 22px",
"anchor": "",
"src": {
"url": "https://xqy3m.mjt.lu/img2/xqy3m/eed4d18c-8065-4c5f-b47c-58af63171cd0/content",
"width": 140,
"height": "auto",
"autoWidth": false,
"maxWidth": "140px"
},
"textAlign": "left",
"altText": "TARGO",
"action": {
"name": "web",
"values": {
"href": "",
"target": "_blank"
}
},
"_meta": {
"htmlID": "u_content_image_1",
"htmlClassNames": "u_content_image"
}
}
},
{
"id": "u_content_text_1",
"type": "text",
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"containerPadding": "10px 25px 14px",
"anchor": "",
"fontWeight": 400,
"fontSize": "16px",
"color": "#374151",
"textAlign": "left",
"lineHeight": "150%",
"linkStyle": {
"inherit": true
},
"_meta": {
"htmlID": "u_content_text_1",
"htmlClassNames": "u_content_text"
},
"text": "Bonjour {{firstname}},"
}
},
{
"id": "u_content_text_2",
"type": "text",
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"containerPadding": "10px 25px 14px",
"anchor": "",
"fontWeight": 400,
"fontSize": "16px",
"color": "#374151",
"textAlign": "justify",
"lineHeight": "150%",
"linkStyle": {
"inherit": true
},
"_meta": {
"htmlID": "u_content_text_2",
"htmlClassNames": "u_content_text"
},
"text": "Avec l'arrivée de l'été, voici un <strong>cadeau pour toi, disponible pour un temps limité</strong>.<br><br>On veut te remercier pour ta loyauté envers l'achat local.<br />Comme toi, on aime les connexions stables et les relations durables."
}
},
{
"id": "u_content_text_3",
"type": "text",
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"containerPadding": "10px 25px 0px",
"anchor": "",
"fontWeight": 400,
"fontSize": "16px",
"color": "#374151",
"textAlign": "justify",
"lineHeight": "150%",
"linkStyle": {
"inherit": true
},
"_meta": {
"htmlID": "u_content_text_3",
"htmlClassNames": "u_content_text"
},
"text": "Grâce à la confiance de nos clients, on offre maintenant les forfaits à <strong>la plus haute vitesse dans le secteur</strong>, jusqu'à <strong>3.5&nbsp;Gbit/s</strong>.<br />Que tu souhaites plus de vitesse, battre une autre offre ou faire optimiser des équipements, n'hésite pas. On est juste à côté et on aime aider."
}
},
{
"id": "u_content_html_2",
"type": "html",
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"containerPadding": "18px 36px 8px",
"anchor": "",
"_meta": {
"htmlID": "u_content_html_2",
"htmlClassNames": "u_content_html"
},
"html": "<div style=\"font-family:Plus Jakarta Sans, Helvetica, Arial, sans-serif;font-size:16px;line-height:1.5;text-align:left;color:#1B2E24;\"><span style=\"display:inline-block;background:#E6F9EE;color:#00C853;font-size:13px;font-weight:700;padding:5px 12px;border-radius:6px;\">✅ Option 1</span></div>"
}
},
{
"id": "u_content_html_3",
"type": "html",
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"containerPadding": "18px 36px 22px",
"anchor": "",
"_meta": {
"htmlID": "u_content_html_3",
"htmlClassNames": "u_content_html"
},
"html": "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"\" width=\"100%\"><tbody><tr><td align=\"left\" style=\"font-size:0px;padding:0 0 8px;word-break:break-word;\"><div style=\"font-family:Plus Jakarta Sans, Helvetica, Arial, sans-serif;font-size:16px;font-weight:700;line-height:1.5;text-align:left;color:#1B2E24;\">🎁 {{amount}} chez des centaines de marques<br><br><span style=\"display:inline-block;\"><img src=\"https://xqy3m.mjt.lu/img2/xqy3m/4b0b2a4a-5f99-416c-8873-8d3e4389b6f7/content\" width=\"32\" alt=\"Tim Hortons\" style=\"width:32px;max-width:32px;height:auto;display:inline-block;border:0;margin-right:6px;vertical-align:middle;\"><img src=\"https://xqy3m.mjt.lu/img2/xqy3m/14df433d-583c-4602-a403-d47ee84966a6/content\" width=\"32\" alt=\"Walmart\" style=\"width:32px;max-width:32px;height:auto;display:inline-block;border:0;margin-right:6px;vertical-align:middle;\"><img src=\"https://xqy3m.mjt.lu/img2/xqy3m/b8d3db5a-d39e-43ce-a84a-2f5dddbf0192/content\" width=\"32\" alt=\"Home Depot\" style=\"width:32px;max-width:32px;height:auto;display:inline-block;border:0;margin-right:6px;vertical-align:middle;\"><img src=\"https://xqy3m.mjt.lu/img2/xqy3m/9c9dfa18-2a3a-414a-b5ad-16d490c961b5/content\" width=\"32\" alt=\"IGA\" style=\"width:32px;max-width:32px;height:auto;display:inline-block;border:0;margin-right:6px;vertical-align:middle;\"><img src=\"https://xqy3m.mjt.lu/img2/xqy3m/a1e5f032-a192-4499-97ba-53b939712fa9/content\" width=\"32\" alt=\"Home Hardware\" style=\"width:32px;max-width:32px;height:auto;display:inline-block;border:0;margin-right:6px;vertical-align:middle;\"><span style=\"font-size:13px;color:#64748B;vertical-align:middle;font-weight:400;\">et plus</span></span></div></td></tr><tr><td align=\"left\" style=\"font-size:0px;padding:0 0 4px;word-break:break-word;\"><div style=\"font-family:Plus Jakarta Sans, Helvetica, Arial, sans-serif;font-size:14px;line-height:1.5;text-align:left;color:#64748B;\">⚡ Disponible instantanément sur Giftbit en cliquant sur ton montant</div></td></tr><tr><td align=\"left\" style=\"font-size:0px;padding:0;word-break:break-word;\"><div style=\"font-family:Plus Jakarta Sans, Helvetica, Arial, sans-serif;font-size:14px;line-height:1.5;text-align:left;color:#64748B;\">🤝 Condition : Maintenir l'abonnement {{commitment_months}} mois ou +</div></td></tr></tbody></table>"
}
},
{
"id": "u_content_button_1",
"type": "button",
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"containerPadding": "10px 25px",
"anchor": "",
"href": {
"name": "web",
"values": {
"href": "{{gift_url}}",
"target": "_blank"
}
},
"buttonColors": {
"color": "#ffffff",
"backgroundColor": "#00C853",
"hoverColor": "#ffffff",
"hoverBackgroundColor": "#005026"
},
"size": {
"autoWidth": false,
"width": "100%"
},
"fontSize": "32px",
"fontWeight": 700,
"textAlign": "center",
"lineHeight": "120%",
"padding": "30px 24px",
"border": {},
"borderRadius": "12px",
"_meta": {
"htmlID": "u_content_button_1",
"htmlClassNames": "u_content_button"
},
"text": "<span style=\"font-size: 32px; line-height: 120%; font-weight: 700;\">🎁&nbsp;&nbsp;{{amount}}</span>"
}
},
{
"id": "u_content_html_4",
"type": "html",
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"containerPadding": "0 36px 4px",
"anchor": "",
"_meta": {
"htmlID": "u_content_html_4",
"htmlClassNames": "u_content_html"
},
"html": "{{#expires_at_date}}\n <div style=\"background:#ffffff;background-color:#ffffff;margin:0px auto;max-width:600px;\">\n <table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"background:#ffffff;background-color:#ffffff;width:100%;\">\n <tbody><tr><td style=\"border-left:1px solid #e5e7eb;border-right:1px solid #e5e7eb;direction:ltr;font-size:0px;padding:0 36px 4px;text-align:center;\">\n <div style=\"font-family:Plus Jakarta Sans, Helvetica, Arial, sans-serif;font-size:13px;line-height:1.4;text-align:center;color:#64748B;\">\n ⏰ Cadeau valide jusqu'au <strong style=\"color:#1B2E24;\">{{expires_at_date}}</strong>\n </div>\n </td></tr></tbody>\n </table>\n </div>\n {{/expires_at_date}}"
}
},
{
"id": "u_content_text_4",
"type": "text",
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"containerPadding": "10px 36px 22px",
"anchor": "",
"fontWeight": 400,
"fontSize": "14px",
"color": "#6b7280",
"textAlign": "left",
"lineHeight": "150%",
"linkStyle": {
"inherit": true
},
"_meta": {
"htmlID": "u_content_text_4",
"htmlClassNames": "u_content_text"
},
"text": "🪂 Annulation avant {{commitment_months}} mois : seulement à rembourser au prorata des mois restants."
}
},
{
"id": "u_content_html_5",
"type": "html",
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"containerPadding": "18px 36px 6px",
"anchor": "",
"_meta": {
"htmlID": "u_content_html_5",
"htmlClassNames": "u_content_html"
},
"html": "<div style=\"font-family:Plus Jakarta Sans, Helvetica, Arial, sans-serif;font-size:16px;line-height:1.5;text-align:left;color:#1B2E24;\"><span style=\"display:inline-block;background:#F5FAF7;color:#6b7280;font-size:13px;font-weight:700;padding:5px 12px;border-radius:6px;\">⏭️ Option 2</span></div>"
}
},
{
"id": "u_content_text_5",
"type": "text",
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"containerPadding": "6px 36px 22px",
"anchor": "",
"fontWeight": 400,
"fontSize": "15px",
"color": "#4b5563",
"textAlign": "left",
"lineHeight": "155%",
"linkStyle": {
"inherit": true
},
"_meta": {
"htmlID": "u_content_text_5",
"htmlClassNames": "u_content_text"
},
"text": "Ne rien faire. Aucun changement à ton abonnement actuel."
}
},
{
"id": "u_content_text_6",
"type": "text",
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"containerPadding": "18px 36px 28px",
"anchor": "",
"fontWeight": 400,
"fontSize": "15px",
"color": "#1B2E24",
"textAlign": "left",
"lineHeight": "150%",
"linkStyle": {
"inherit": true
},
"_meta": {
"htmlID": "u_content_text_6",
"htmlClassNames": "u_content_text"
},
"text": "🤝 Merci de faire rouler l'économie de notre région avec nous !<br><br>L'équipe TARGO"
}
}
],
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"_meta": {
"htmlID": "u_column_2",
"htmlClassNames": "u_column"
},
"padding": "0px",
"border": {},
"borderRadius": "0px",
"backgroundColor": ""
}
}
],
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"columns": false,
"backgroundColor": "#ffffff",
"columnsBackgroundColor": "",
"backgroundImage": {
"url": "",
"fullWidth": true,
"repeat": "no-repeat",
"size": "custom",
"position": "center"
},
"padding": "0px",
"anchor": "",
"borderRadius": "",
"_meta": {
"htmlID": "u_row_2",
"htmlClassNames": "u_row"
}
}
},
{
"id": "u_row_3",
"cells": [
1
],
"columns": [
{
"id": "u_column_3",
"contents": [
{
"id": "u_content_text_7",
"type": "text",
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"containerPadding": "18px 36px 8px",
"anchor": "",
"fontWeight": 400,
"fontSize": "12px",
"color": "#64748B",
"textAlign": "center",
"lineHeight": "155%",
"linkStyle": {
"inherit": true
},
"_meta": {
"htmlID": "u_content_text_7",
"htmlClassNames": "u_content_text"
},
"text": "Tu reçois ce courriel parce que tu es client(e) TARGO à <strong style=\"color:#1B2E24;\">{{description}}</strong>.<br />Une question ? N'hésite pas à nous écrire à <a href=\"mailto:support@targo.ca\" style=\"color:#00C853;text-decoration:none;\">support@targo.ca</a> ou nous appeler au <a href=\"tel:5144480773\" style=\"color:#00C853;text-decoration:none;\">514-448-0773</a>."
}
}
],
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"_meta": {
"htmlID": "u_column_3",
"htmlClassNames": "u_column"
},
"padding": "0px",
"border": {},
"borderRadius": "0px",
"backgroundColor": ""
}
}
],
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"columns": false,
"backgroundColor": "#F5FAF7",
"columnsBackgroundColor": "",
"backgroundImage": {
"url": "",
"fullWidth": true,
"repeat": "no-repeat",
"size": "custom",
"position": "center"
},
"padding": "0px",
"anchor": "",
"borderRadius": "",
"_meta": {
"htmlID": "u_row_3",
"htmlClassNames": "u_row"
}
}
},
{
"id": "u_row_4",
"cells": [
1
],
"columns": [
{
"id": "u_column_4",
"contents": [
{
"id": "u_content_html_6",
"type": "html",
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"containerPadding": "26px 36px 22px",
"anchor": "",
"_meta": {
"htmlID": "u_content_html_6",
"htmlClassNames": "u_content_html"
},
"html": "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"border-collapse:collapse;border-spacing:0px;\"><tbody><tr><td style=\"width:120px;\"><img alt=\"TARGO\" src=\"https://xqy3m.mjt.lu/img2/xqy3m/eed4d18c-8065-4c5f-b47c-58af63171cd0/content\" style=\"border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:13px;\" width=\"120\" height=\"auto\"/></td></tr></tbody></table><td align=\"center\" style=\"font-size:0px;padding:18px 0 0;word-break:break-word;\"><div style=\"font-family:Plus Jakarta Sans, Helvetica, Arial, sans-serif;font-size:11px;line-height:1.55;text-align:center;color:rgba(255,255,255,0.55);\"><a href=\"https://www.targo.ca\" style=\"color:rgba(255,255,255,0.7);text-decoration:none;\">www.targo.ca</a>&nbsp;·&nbsp; 1867 ch. de la rivière, Ste-Clotilde, QC<br />© {{year}} TARGO Communications · Tous droits réservés.</div></td>"
}
}
],
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"_meta": {
"htmlID": "u_column_4",
"htmlClassNames": "u_column"
},
"padding": "0px",
"border": {},
"borderRadius": "0px",
"backgroundColor": ""
}
}
],
"values": {
"selectable": true,
"draggable": true,
"duplicatable": true,
"deletable": true,
"hideable": true,
"hideDesktop": false,
"displayCondition": null,
"columns": false,
"backgroundColor": "#1C1E26",
"columnsBackgroundColor": "",
"backgroundImage": {
"url": "",
"fullWidth": true,
"repeat": "no-repeat",
"size": "custom",
"position": "center"
},
"padding": "0px",
"anchor": "",
"borderRadius": "",
"_meta": {
"htmlID": "u_row_4",
"htmlClassNames": "u_row"
}
}
}
],
"values": {
"popupPosition": "center",
"popupWidth": "600px",
"popupHeight": "auto",
"borderRadius": "10px",
"contentAlign": "center",
"contentVerticalAlign": "center",
"contentWidth": "600px",
"fontFamily": {
"label": "Plus Jakarta Sans",
"value": "'Plus Jakarta Sans', sans-serif",
"url": "https://fonts.googleapis.com/css?family=Plus+Jakarta+Sans:400,500,600,700"
},
"textColor": "#1B2E24",
"popupBackgroundColor": "#FFFFFF",
"backgroundColor": "#F5FAF7",
"preheaderText": "Comme toi, on aime les connexions stables et les relations durables.",
"linkStyle": {
"body": true,
"linkColor": "#00C853",
"linkHoverColor": "#005026",
"linkUnderline": true,
"linkHoverUnderline": true
},
"_meta": {
"htmlID": "u_body",
"htmlClassNames": "u_body"
}
}
},
"schemaVersion": 16
}