feat(cms): white-label email templates and API doc config (#2)
All checks were successful
Build and publish / build (push) Successful in 7m11s

## Summary

- Replace all hardcoded muellerprints brand identity in email templates with template variables sourced from env vars
- Inject shop context into both `sendInvoice` and `sendDeliveryNote` template calls in `order.ts`
- Make API documentation title/description env-var driven

## New env vars (all optional with safe defaults)

| Var | Default | Used in |
|-----|---------|---------|
| `SHOP_NAME` | `"Shop"` | Email subject, body, footer |
| `SHOP_CONTACT_NAME` | `""` | Email footer |
| `SHOP_ADDRESS` | `""` | Email footer |
| `SHOP_PHONE` | `""` | Email footer |
| `SHOP_EMAIL` | `ADMIN_EMAIL_ADDRESS` | Email footer |
| `SHOP_LOGO_URL` | `""` | Email header logo |
| `SHOP_SECONDARY_LOGO_URL` | `""` | Email footer logo |
| `API_TITLE` | `"Paperwork API"` | Swagger/OpenAPI title |
| `API_DESCRIPTION` | `"Paperwork API"` | Swagger/OpenAPI description |

## Test plan

- [ ] Set `SHOP_NAME=TestShop` and trigger invoice send → confirm subject and body use `TestShop`
- [ ] Leave `SHOP_NAME` unset → confirm default `"Shop"` appears
- [ ] Set `SHOP_LOGO_URL` → confirm logo renders in email header; unset → confirm no broken `<img>` tag
- [ ] Check Strapi admin `/documentation` with `API_TITLE=MyAPI` env var

Closes #1

Reviewed-on: #2
Co-authored-by: Michael Czechowski <mail@dailysh.it>
Co-committed-by: Michael Czechowski <mail@dailysh.it>
This commit is contained in:
2026-04-29 20:13:23 +02:00
committed by Michael Czechowski
parent a716f52dd4
commit defd078e4b
6 changed files with 74 additions and 49 deletions

View File

@@ -3,7 +3,7 @@ import fs from "fs";
import { factories } from "@strapi/strapi";
import { sanitize } from "@strapi/utils";
import { ID } from "@strapi/database/dist/types";
import { vatDecimal, vatIncludedDecimal, baseUrl, adminEmail } from "../../../../config/constants";
import { vatDecimal, vatIncludedDecimal, baseUrl, adminEmail, shopName, shopContactName, shopAddress, shopPhone, shopEmail, shopLogoUrl, shopSecondaryLogoUrl } from "../../../../config/constants";
import { calculateTotalProductPrice, productDefaultParams } from "../../product/services/product";
import { CartProduct, Order, PdfBody } from "../../../../types";
import { pdfApi } from "../../../services/PdfApi";
@@ -81,12 +81,13 @@ export default factories.createCoreService("api::order.order", ({ strapi }) => (
strapi.log.info(`app:i:order-service: - Sending invoice for order ${uuid}`);
const oderUnsafe = (await strapi.service("api::order.order").findOneByUuid(uuid)) as Partial<Order>;
const shopContext = { shopName, shopContactName, shopAddress, shopPhone, shopEmail, shopLogoUrl, shopSecondaryLogoUrl };
try {
const emailConfig: MessageBody = {
to_email: oderUnsafe.email,
subject: template(invoiceEmailTemplate.subject)(oderUnsafe),
message: template(invoiceEmailTemplate.text)({ baseUrl, ...oderUnsafe }),
html: template(invoiceEmailTemplate.html)({ baseUrl, ...oderUnsafe })
subject: template(invoiceEmailTemplate.subject)({ ...shopContext, ...oderUnsafe }),
message: template(invoiceEmailTemplate.text)({ baseUrl, ...shopContext, ...oderUnsafe }),
html: template(invoiceEmailTemplate.html)({ baseUrl, ...shopContext, ...oderUnsafe })
};
strapi.log.debug(`app:d:order-service: - Email config ${emailConfig.html}`);
@@ -118,12 +119,13 @@ export default factories.createCoreService("api::order.order", ({ strapi }) => (
sendDeliveryNote: async (uuid: string, blob?: ArrayBuffer) => {
strapi.log.info(`app:i:order-service: - Sending delivery note for order ${uuid}`);
const oderUnsafe = (await strapi.service("api::order.order").findOneByUuid(uuid)) as Partial<Order>;
const shopContext = { shopName, shopContactName, shopAddress, shopPhone, shopEmail, shopLogoUrl, shopSecondaryLogoUrl };
try {
const emailConfig: MessageBody = {
to_email: oderUnsafe.email,
subject: template(deliveryNoteEmailTemplate.subject)(oderUnsafe),
message: template(deliveryNoteEmailTemplate.text)(oderUnsafe),
html: template(deliveryNoteEmailTemplate.html)({ ...oderUnsafe, baseUrl })
subject: template(deliveryNoteEmailTemplate.subject)({ ...shopContext, ...oderUnsafe }),
message: template(deliveryNoteEmailTemplate.text)({ ...shopContext, ...oderUnsafe }),
html: template(deliveryNoteEmailTemplate.html)({ baseUrl, ...shopContext, ...oderUnsafe })
};
await mailApi.sendTextMessage(emailConfig);
strapi.log.info(`app:i:order-service: ✔ Sending delivery note for order ${uuid}`);

View File

@@ -2,8 +2,8 @@
"openapi": "3.0.1",
"info": {
"version": "1.0.0",
"title": "MUELLERPTINTS. Paperwork",
"description": "API Documentation for MUELLERPRINTS. Paperwork",
"title": "Paperwork API",
"description": "Paperwork API",
"termsOfService": false,
"contact": false,
"license": false

View File

@@ -1,5 +1,5 @@
export const invoiceEmailTemplate = {
subject: "MUELLERPRINTS Rechnungsnummer <%= invoiceNumber %>",
subject: "<%= shopName %> Rechnungsnummer <%= invoiceNumber %>",
text: `Rechnungsnummer: <%= invoiceNumber %>
Ausstellungsdatum: <%= new Date(acceptedTermsAndConditionsAt).toLocaleDateString("de-DE") %>
@@ -7,7 +7,7 @@ Ausstellungsdatum: <%= new Date(acceptedTermsAndConditionsAt).toLocaleDateString
Hallo <%= invoiceAddressStructured.givenName %>,
vielen Dank für deinen Einkauf bei MUELLERPRINTS.
vielen Dank für deinen Einkauf bei <%= shopName %>.
Deine Bestellnummer: <%= id %>
Zur Bestellübersicht: <%= baseUrl %>/checkout/result/<%= uuid %>
@@ -49,14 +49,14 @@ inkl. MwSt. (19%): <%= VAT.toFixed(2) %> EUR
Deine Rechnung kannst du jederzeit über diesen Link herunterladen: <%= baseUrl %><%= invoice.url %>
<% } %>
Vielen Dank, dass du dich für MUELLERPRINTS entschieden hast.
Vielen Dank, dass du dich für <%= shopName %> entschieden hast.
------------------
MUELLERPRINTS
Max Müller
Rotenbergstraße 39, 70190 Stuttgart
T +49 (0)711/262 49 64
paperwork@muellerprints.de`,
<%= shopName %>
<%= shopContactName %>
<%= shopAddress %>
<%= shopPhone ? "T " + shopPhone : "" %>
<%= shopEmail %>`,
html: `<!DOCTYPE html>
<html lang="de">
<head>
@@ -74,7 +74,7 @@ paperwork@muellerprints.de`,
<!-- Header -->
<tr>
<td style="background-color: #E31E26; padding: 30px 40px;">
<img src="https://muellerprints-paperwork.com/paperwork-logo.png" alt="MUELLERPRINTS PAPERWORK" style="max-width: 200px; height: auto;">
<% if (shopLogoUrl) { %><img src="<%= shopLogoUrl %>" alt="<%= shopName %>" style="max-width: 200px; height: auto;"><% } %>
</td>
</tr>
@@ -83,7 +83,7 @@ paperwork@muellerprints.de`,
<td style="padding: 40px;">
<!-- Greeting -->
<h1 style="margin: 0 0 20px; color: #333; font-size: 24px; font-weight: normal;">
Vielen Dank für deinen Einkauf bei MUELLERPRINTS.
Vielen Dank für deinen Einkauf bei <%= shopName %>.
</h1>
<!-- Order Info -->
@@ -197,7 +197,7 @@ paperwork@muellerprints.de`,
<% } %>
<p style="color: #666; font-size: 14px; margin: 20px 0;">
Vielen Dank, dass du dich für MUELLERPRINTS entschieden hast.
Vielen Dank, dass du dich für <%= shopName %> entschieden hast.
</p>
</td>
</tr>
@@ -209,15 +209,15 @@ paperwork@muellerprints.de`,
<tr>
<td style="color: #666; font-size: 12px; line-height: 1.5;">
<p style="margin: 0 0 10px;">
MUELLERPRINTS<br>
Max Müller<br>
Rotenbergstraße 39, 70190 Stuttgart<br>
T +49 (0)711/262 49 64<br>
paperwork@muellerprints.de
<%= shopName %><br>
<% if (shopContactName) { %><%= shopContactName %><br><% } %>
<% if (shopAddress) { %><%= shopAddress %><br><% } %>
<% if (shopPhone) { %>T <%= shopPhone %><br><% } %>
<% if (shopEmail) { %><%= shopEmail %><% } %>
</p>
</td>
<td style="text-align: right; vertical-align: bottom;">
<img src="https://www.muellerprints.de/images/digi_logo.png" alt="MUELLERPRINTS" style="max-width: 100px; height: auto;">
<% if (shopSecondaryLogoUrl) { %><img src="<%= shopSecondaryLogoUrl %>" alt="<%= shopName %>" style="max-width: 100px; height: auto;"><% } %>
</td>
</tr>
</table>
@@ -243,7 +243,7 @@ paperwork@muellerprints.de`,
};
export const deliveryNoteEmailTemplate = {
subject: "Your Delivery Note <%= deliveryNoteNumber %> from MUELLERPRINTS",
subject: "Your Delivery Note <%= deliveryNoteNumber %> from <%= shopName %>",
text: `Dear Customer,
Thank you for your Your delivery note <%= deliveryNoteNumber %> is attached to this email.
@@ -272,14 +272,14 @@ Delivery Address:
If you have any questions about your delivery, please don't hesitate to contact us.
Best regards,
MUELLERPRINTS PAPERWORK
<%= shopName %>
------------------
MUELLERPRINTS PAPERWORK
Max Müller
Rotenbergstraße 39, 70190 Stuttgart
T +49 (0)711/262 49 64
paperwork@muellerprints.de`,
<%= shopName %>
<%= shopContactName %>
<%= shopAddress %>
<%= shopPhone ? "T " + shopPhone : "" %>
<%= shopEmail %>`,
html: `<!DOCTYPE html>
<html lang="de">
<head>
@@ -295,7 +295,7 @@ paperwork@muellerprints.de`,
<!-- Header -->
<tr>
<td style="background-color: #E31E26; padding: 30px 40px;">
<img src="https://muellerprints-paperwork.com/paperwork-logo.png" alt="MUELLERPRINTS PAPERWORK" style="max-width: 200px; height: auto;">
<% if (shopLogoUrl) { %><img src="<%= shopLogoUrl %>" alt="<%= shopName %>" style="max-width: 200px; height: auto;"><% } %>
</td>
</tr>
@@ -407,15 +407,15 @@ paperwork@muellerprints.de`,
<tr>
<td style="color: #666; font-size: 12px; line-height: 1.5;">
<p style="margin: 0 0 10px;">
MUELLERPRINTS PAPERWORK<br>
Max Müller<br>
Rotenbergstraße 39, 70190 Stuttgart<br>
T +49 (0)711/262 49 64<br>
paperwork@muellerprints.de
<%= shopName %><br>
<% if (shopContactName) { %><%= shopContactName %><br><% } %>
<% if (shopAddress) { %><%= shopAddress %><br><% } %>
<% if (shopPhone) { %>T <%= shopPhone %><br><% } %>
<% if (shopEmail) { %><%= shopEmail %><% } %>
</p>
</td>
<td style="text-align: right; vertical-align: bottom;">
<img src="https://www.muellerprints.de/images/digi_logo.png" alt="MUELLERPRINTS" style="max-width: 100px; height: auto;">
<% if (shopSecondaryLogoUrl) { %><img src="<%= shopSecondaryLogoUrl %>" alt="<%= shopName %>" style="max-width: 100px; height: auto;"><% } %>
</td>
</tr>
</table>