feat(cms): white-label email templates and API doc config
All checks were successful
Build and publish / build (pull_request) Successful in 4m38s

Replace all hardcoded muellerprints brand identity in email templates
with template variables (shopName, shopContactName, shopAddress,
shopPhone, shopEmail, shopLogoUrl, shopSecondaryLogoUrl) sourced from
env vars SHOP_NAME, SHOP_CONTACT_NAME, SHOP_ADDRESS, SHOP_PHONE,
SHOP_EMAIL, SHOP_LOGO_URL, SHOP_SECONDARY_LOGO_URL.

API documentation title/description now driven by API_TITLE and
API_DESCRIPTION env vars.

Closes #1
This commit is contained in:
2026-04-29 20:01:30 +02:00
parent a716f52dd4
commit f0855a07e7
6 changed files with 74 additions and 49 deletions

View File

@@ -2,7 +2,26 @@
All notable changes to libreshop/cms are documented here. All notable changes to libreshop/cms are documented here.
## Unreleased ## [0.1.1] - 2026-04-29
### Changed
- White-label email templates: replace all hardcoded muellerprints company
identity (name, contact, address, phone, email, logo URLs) with
`<%= shopName %>` / `<%= shopContactName %>` / `<%= shopAddress %>` /
`<%= shopPhone %>` / `<%= shopEmail %>` / `<%= shopLogoUrl %>` /
`<%= shopSecondaryLogoUrl %>` template variables, sourced from env vars
`SHOP_NAME`, `SHOP_CONTACT_NAME`, `SHOP_ADDRESS`, `SHOP_PHONE`,
`SHOP_EMAIL`, `SHOP_LOGO_URL`, `SHOP_SECONDARY_LOGO_URL`.
- `config/constants.ts`: export shop brand constants from env.
- `src/api/order/services/order.ts`: inject shop context into template calls.
- `config/plugins.ts`: API doc title/description driven by `API_TITLE` /
`API_DESCRIPTION` env vars (defaults: `"Paperwork API"`).
- `src/extensions/documentation/config/settings.json`: neutral placeholder.
Closes #1
## [0.1.0] - 2026-04-29
- Extracted from `mp/cms/` (2026-04-29). The component history before - Extracted from `mp/cms/` (2026-04-29). The component history before
the extraction lives in the `muellerprints` repository. the extraction lives in the `muellerprints` repository.

View File

@@ -10,6 +10,14 @@ export const paypalEnvironment = process.env.PAYPAL_ENVIRONMENT! === "production
export const adminEmail = process.env.ADMIN_EMAIL_ADDRESS!; export const adminEmail = process.env.ADMIN_EMAIL_ADDRESS!;
export const shopName = process.env.SHOP_NAME ?? "Shop";
export const shopContactName = process.env.SHOP_CONTACT_NAME ?? "";
export const shopAddress = process.env.SHOP_ADDRESS ?? "";
export const shopPhone = process.env.SHOP_PHONE ?? "";
export const shopEmail = process.env.SHOP_EMAIL ?? process.env.ADMIN_EMAIL_ADDRESS ?? "";
export const shopLogoUrl = process.env.SHOP_LOGO_URL ?? "";
export const shopSecondaryLogoUrl = process.env.SHOP_SECONDARY_LOGO_URL ?? "";
// TODO: Should be retrieved from DepotApi // TODO: Should be retrieved from DepotApi
export const vatIncludedDecimal = 1.19; export const vatIncludedDecimal = 1.19;
// TODO: Should be retrieved from DepotApi // TODO: Should be retrieved from DepotApi

View File

@@ -10,15 +10,11 @@ export default ({ env }) => ({
openapi: "3.0.1", openapi: "3.0.1",
info: { info: {
version: "1.0.0", version: "1.0.0",
title: "MUELLERPTINTS. Paperwork", title: env("API_TITLE", "Paperwork API"),
description: "API Documentation for MUELLERPRINTS. Paperwork", description: env("API_DESCRIPTION", "Paperwork API"),
termsOfService: false, termsOfService: false,
contact: { contact: false,
name: "Michael W. Czechowski", license: false,
email: "mail@dailysh.it",
url: "https://dailysh.it"
},
license: "Copyright (C) 2024 Michael W. Czechowski",
externalDocs: false externalDocs: false
}, },
"x-strapi-config": { "x-strapi-config": {

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
export const invoiceEmailTemplate = { export const invoiceEmailTemplate = {
subject: "MUELLERPRINTS Rechnungsnummer <%= invoiceNumber %>", subject: "<%= shopName %> Rechnungsnummer <%= invoiceNumber %>",
text: `Rechnungsnummer: <%= invoiceNumber %> text: `Rechnungsnummer: <%= invoiceNumber %>
Ausstellungsdatum: <%= new Date(acceptedTermsAndConditionsAt).toLocaleDateString("de-DE") %> Ausstellungsdatum: <%= new Date(acceptedTermsAndConditionsAt).toLocaleDateString("de-DE") %>
@@ -7,7 +7,7 @@ Ausstellungsdatum: <%= new Date(acceptedTermsAndConditionsAt).toLocaleDateString
Hallo <%= invoiceAddressStructured.givenName %>, Hallo <%= invoiceAddressStructured.givenName %>,
vielen Dank für deinen Einkauf bei MUELLERPRINTS. vielen Dank für deinen Einkauf bei <%= shopName %>.
Deine Bestellnummer: <%= id %> Deine Bestellnummer: <%= id %>
Zur Bestellübersicht: <%= baseUrl %>/checkout/result/<%= uuid %> 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 %> 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 <%= shopName %>
Max Müller <%= shopContactName %>
Rotenbergstraße 39, 70190 Stuttgart <%= shopAddress %>
T +49 (0)711/262 49 64 <%= shopPhone ? "T " + shopPhone : "" %>
paperwork@muellerprints.de`, <%= shopEmail %>`,
html: `<!DOCTYPE html> html: `<!DOCTYPE html>
<html lang="de"> <html lang="de">
<head> <head>
@@ -74,7 +74,7 @@ paperwork@muellerprints.de`,
<!-- Header --> <!-- Header -->
<tr> <tr>
<td style="background-color: #E31E26; padding: 30px 40px;"> <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> </td>
</tr> </tr>
@@ -83,7 +83,7 @@ paperwork@muellerprints.de`,
<td style="padding: 40px;"> <td style="padding: 40px;">
<!-- Greeting --> <!-- Greeting -->
<h1 style="margin: 0 0 20px; color: #333; font-size: 24px; font-weight: normal;"> <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> </h1>
<!-- Order Info --> <!-- Order Info -->
@@ -197,7 +197,7 @@ paperwork@muellerprints.de`,
<% } %> <% } %>
<p style="color: #666; font-size: 14px; margin: 20px 0;"> <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> </p>
</td> </td>
</tr> </tr>
@@ -209,15 +209,15 @@ paperwork@muellerprints.de`,
<tr> <tr>
<td style="color: #666; font-size: 12px; line-height: 1.5;"> <td style="color: #666; font-size: 12px; line-height: 1.5;">
<p style="margin: 0 0 10px;"> <p style="margin: 0 0 10px;">
MUELLERPRINTS<br> <%= shopName %><br>
Max Müller<br> <% if (shopContactName) { %><%= shopContactName %><br><% } %>
Rotenbergstraße 39, 70190 Stuttgart<br> <% if (shopAddress) { %><%= shopAddress %><br><% } %>
T +49 (0)711/262 49 64<br> <% if (shopPhone) { %>T <%= shopPhone %><br><% } %>
paperwork@muellerprints.de <% if (shopEmail) { %><%= shopEmail %><% } %>
</p> </p>
</td> </td>
<td style="text-align: right; vertical-align: bottom;"> <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> </td>
</tr> </tr>
</table> </table>
@@ -243,7 +243,7 @@ paperwork@muellerprints.de`,
}; };
export const deliveryNoteEmailTemplate = { export const deliveryNoteEmailTemplate = {
subject: "Your Delivery Note <%= deliveryNoteNumber %> from MUELLERPRINTS", subject: "Your Delivery Note <%= deliveryNoteNumber %> from <%= shopName %>",
text: `Dear Customer, text: `Dear Customer,
Thank you for your Your delivery note <%= deliveryNoteNumber %> is attached to this email. 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. If you have any questions about your delivery, please don't hesitate to contact us.
Best regards, Best regards,
MUELLERPRINTS PAPERWORK <%= shopName %>
------------------ ------------------
MUELLERPRINTS PAPERWORK <%= shopName %>
Max Müller <%= shopContactName %>
Rotenbergstraße 39, 70190 Stuttgart <%= shopAddress %>
T +49 (0)711/262 49 64 <%= shopPhone ? "T " + shopPhone : "" %>
paperwork@muellerprints.de`, <%= shopEmail %>`,
html: `<!DOCTYPE html> html: `<!DOCTYPE html>
<html lang="de"> <html lang="de">
<head> <head>
@@ -295,7 +295,7 @@ paperwork@muellerprints.de`,
<!-- Header --> <!-- Header -->
<tr> <tr>
<td style="background-color: #E31E26; padding: 30px 40px;"> <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> </td>
</tr> </tr>
@@ -407,15 +407,15 @@ paperwork@muellerprints.de`,
<tr> <tr>
<td style="color: #666; font-size: 12px; line-height: 1.5;"> <td style="color: #666; font-size: 12px; line-height: 1.5;">
<p style="margin: 0 0 10px;"> <p style="margin: 0 0 10px;">
MUELLERPRINTS PAPERWORK<br> <%= shopName %><br>
Max Müller<br> <% if (shopContactName) { %><%= shopContactName %><br><% } %>
Rotenbergstraße 39, 70190 Stuttgart<br> <% if (shopAddress) { %><%= shopAddress %><br><% } %>
T +49 (0)711/262 49 64<br> <% if (shopPhone) { %>T <%= shopPhone %><br><% } %>
paperwork@muellerprints.de <% if (shopEmail) { %><%= shopEmail %><% } %>
</p> </p>
</td> </td>
<td style="text-align: right; vertical-align: bottom;"> <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> </td>
</tr> </tr>
</table> </table>