Webseiten umsetzen
Öffentliche Websites lassen sich mit Workspace als normale Site, Produktkatalog, Portal oder vollständiger Onlineshop umsetzen. Wählen Sie den passenden Seitentyp und binden Sie nur die dafür vorgesehenen öffentlichen Verträge ein. Planen Sie Sprachversionen einer Site-Page gemeinsam mit den zugehörigen Metadaten und Veröffentlichungen.
Grundmodell
Fast alle öffentlichen Websites folgen demselben Modell: Eine Site liefert Seiten, Vorlagen, Navigation, Assets, Domains und Releases aus. Entwickler bauen die Site-Struktur und binden nur die öffentlichen Verträge ein, die der Seitentyp wirklich braucht.
| Ebene | Wofür sie zuständig ist | Wichtig für Entwickler |
|---|---|---|
| Site und Domain | Öffentliche Erreichbarkeit, Sprache, Release und Host-Auflösung | Trennen Sie Website-Hosts von Admin-Hosts. Die Einrichtung steht in Sites und CMS. |
| Page, PageType und Template | Seitenstruktur, wiederkehrende Layouts, Container und Navigation | Nutzen Sie PageTypes für wiederkehrende Seitenarten statt jede Seite einzeln zu verdrahten. |
| Inhalte und Assets | Texte, Bilder, Downloads, CSS, JavaScript und öffentliche Dateien | Legen Sie öffentliche Dateien bewusst ab und veröffentlichen Sie keine Entwürfe, Secrets oder internen URLs. |
| Öffentliche Integrationen | Formulare, Website Chat, Public Catalog, Account oder Commerce | Binden Sie nur veröffentlichte Public- oder Storefront-Verträge ein. |
| Release und Prüfung | Strukturprüfung, Build, Review, Veröffentlichung und Live-Stand | Live wird nur der explizit veröffentlichte Release, nicht die Entwicklungsvorschau. |
Ablauf für fast alle Websites
- Klären Sie Zielgruppe, Seitentyp, Sprache, Domain und Verantwortlichkeit.
- Legen Sie fest, ob die Site statische Inhalte, öffentliche Formulare, Produktdaten, Login oder Checkout braucht.
- Planen Sie PageTypes für wiederkehrende Seitenarten wie Startseite, Detailseite, Artikel, Landingpage oder rechtliche Seite.
- Strukturieren Sie Templates, Navigation, Übersetzungen, Styles, Scripts und öffentliche Dateien nach der Site-Projektstruktur.
- Setzen Sie SEO-Grundlagen pro Seite: sprechender Slug, Titel, Beschreibung, Sitemap-Regel, Canonical-Verhalten und passende Sprachvariante.
- Binden Sie dynamische Daten nur über veröffentlichte Verträge ein.
- Prüfen Sie die Site mit Vorschau,
validate, Build und fachlichem Review. - Veröffentlichen Sie nur den freigegebenen Release.
Die Betriebsbegriffe bedeuten hier:
| Begriff | Bedeutung |
|---|---|
| Vorschau | Gerenderter Site-Stand für Prüfung und Review, noch nicht live. |
validate | Strukturprüfung für Site-Dateien, Referenzen und offensichtliche Fehler. |
| Build | Erzeugt einen gefrorenen Site Release, veröffentlicht ihn aber noch nicht. |
Veröffentlichung / publish | Schaltet genau den freigegebenen Site Release live. |
| Dev-Mode | Zeitlich begrenzter Bearbeitungs- und Vorschauzustand mit Dateischreibzugriff. |
| Mount | Lokaler Zugriff auf Site-Dateien im Dev-Mode, damit Sie viele Dateien mit Editor oder IDE bearbeiten können. |
| Domainbindung | Ordnet einen öffentlichen Host einer Site zu, damit die Site über diese Domain erreichbar wird. |
Wenn Sie Site-Dateien verwalten, Dev-Mode starten, einen Mount einrichten, Build oder Veröffentlichung ausführen oder Domains binden, verwenden Sie Sites und CMS. Diese Entwicklerseite beschreibt die technische Einordnung; die Administrationsseite beschreibt den Bedien- und Betriebsablauf.
Quickstart: einfache Website bauen
Nutzen Sie diesen Quickstart, wenn Sie eine kleine öffentliche Website oder Landingpage ohne Warenkorb bauen möchten. Wenn der Seitentyp noch unklar ist, wählen Sie zuerst einen passenden Eintrag unter Website-Typen wählen.
- Klären Sie Zweck, Zielgruppe, Sprache, Domain und Verantwortliche.
- Legen Sie fest, ob die Site nur statische Inhalte braucht oder zusätzlich Formulare, Produktdaten, Login oder Checkout einbindet.
- Verwenden Sie für Startseite, Detailseiten, Landingpages und rechtliche Seiten eigene PageTypes, wenn Layout oder Assets wiederkehren.
- Erstellen Sie Pages mit stabilem Slug, Titel, Beschreibung, Navigation und passenden Container-Inhalten.
- Planen Sie Sprachversionen früh, wenn die Seite mehrsprachig erscheinen soll. Verwenden Sie je Sprache eine eigene Page-Variante mit gleichem
translationKey. - Legen Sie größere Inhaltsblöcke unter
snippets/ab und binden Sie sie mittype: fileein, wenn die Page-YAML sonst unübersichtlich wird. - Referenzieren Sie Styles und Scripts über Page oder PageType. Legen Sie Bilddateien unter
images/ab und öffentliche Dateien wierobots.txt,security.txtoder Downloads unterpublic/. - Prüfen Sie die Site in der Vorschau und führen Sie
validateaus. - Erzeugen Sie einen Build und veröffentlichen Sie nur den freigegebenen Release.
Der Quickstart ist abgeschlossen, wenn die Vorschau den erwarteten Stand zeigt, validate keine Blocker meldet und ein freigegebener Release veröffentlicht ist. Verwaltung, Dev-Mode, Vorschau, Build und Veröffentlichung stehen in Sites und CMS.
Angrenzende Aufgaben
| Aufgabe | Nutzen Sie |
|---|---|
| Site verwalten, Dev-Mode starten, Vorschau teilen, Build erzeugen und Release veröffentlichen | Sites und CMS |
| Sprachversion einer bestehenden Page anlegen | Sprachversion einer Page anlegen |
| Produkttexte, Medien und kanalbezogene Inhalte pflegen | Produktinhalte pflegen |
| Produktdaten veröffentlichen, Produkt-Routen prüfen und Readiness abarbeiten | Produktdaten veröffentlichen |
| Einen vollständigen Onlineshop bauen | B2B-Onlineshop bauen |
Site-Projektstruktur
Lesen Sie die Struktur einer Site vor Änderungen aus:
nucli --tenant <tenant> sites structure <site-id>Arbeiten Sie in den Quellverzeichnissen der Site. Schreiben Sie nicht direkt in dist/, releases/ oder andere generierte Build-Artefakte.
| Verzeichnis | Zweck | Hinweise |
|---|---|---|
pages/ | Seitendefinitionen als YAML | Jede öffentliche Seite braucht eine Page-Datei. |
pagetypes/ | Standards für Seitenarten | Nutzen Sie PageTypes für wiederkehrende Layout-, Asset-, Sitemap- und Container-Regeln. |
templates/ | Go-HTML-Templates | Templates rendern Pages, Container, Navigation und Assets. |
snippets/ | Wiederverwendbare Template-Teile | Nutzen Sie Snippets für gemeinsame Markup-Teile, nicht für globale Seiteneffekte. |
i18n/ | Übersetzungsbündel | Legen Sie wiederverwendbare Texte sprach- und scope-bezogen ab. |
config/ | Site-Konfiguration | Die öffentliche Root-Seite kommt aus defaultPage, nicht aus einem hart codierten Slug. |
scripts/ | JavaScript-Module | Pages oder PageTypes referenzieren Scripts; der Build bündelt sie. |
styles/ | CSS-Dateien | Pages oder PageTypes referenzieren Styles; der Build bündelt sie. |
public/ | Statische Dateien | Dateien werden unverändert veröffentlicht. Legen Sie dort keine Secrets oder Entwürfe ab. |
images/ | Bilddateien | Laden Sie Webbilder über den Siteeditor oder per nucli sites files image-upload hoch. |
Bilddateien unter images/ laufen über einen eigenen Binärvertrag. Nutzen Sie für Textdateien weiter sites files get/create/put/delete und für Bilder sites files image-get/image-upload/image-replace/image-delete. Ersetzen und Löschen von Bildern benötigen den aktuellen ETag.
Page, PageType und Template
Eine Page-Datei beschreibt eine konkrete Seite:
type: default
variant:
translationKey: home
locale: de
slug: /
title: Startseite
description: Öffentliche Startseite
navigation:
main:
id: home
label: Start
ranking: 10
containers:
mainContent:
- type: markdown
content: |
Willkommen.type verweist auf pagetypes/<type>.yaml. Der PageType setzt gemeinsame Vorgaben, zum Beispiel Standard-Template, Styles, Scripts, Sitemap-Regel und Standard-Container. Eine Page kann Vorgaben überschreiben, wenn eine konkrete Seite fachlich abweicht. Nutzen Sie Overrides sparsam, damit wiederkehrende Seitenarten konsistent bleiben.
Templates lesen die vorbereiteten Werte der Page. Das Haupttemplate rendert Container über .Containers.<slot>, Assets über .Assets und freigegebene Seitendaten wie .Title oder .Language.
<!doctype html>
<html lang="{{ .Language }}">
<head>
<title>{{ .Title }}</title>
<meta name="description" content="{{ .Description }}">
<link rel="canonical" href="{{ .CanonicalURL }}">
{{ range .AlternateLinks }}
<link rel="alternate" hreflang="{{ .Lang }}" href="{{ .URL }}">
{{ end }}
{{ .Assets }}
</head>
<body>
{{ .Containers.mainNav }}
<main>{{ .Containers.mainContent }}</main>
</body>
</html>Container-Slots und Komponenten-Typen
containers ist eine Map von Slotnamen zu Komponentenlisten. Der Slotname bestimmt, wo das Haupttemplate den Inhalt einsetzt. type bestimmt, wie eine Komponente gerendert wird.
containers:
mainContent:
- type: markdown
content: |
Willkommen.
mainNav:
- type: navigation
name: main
template: navigation-main.tmplDer Renderer kennt diese Komponenten-Typen:
| Typ | Pflichtfelder | Zweck |
|---|---|---|
html | content | Rendert eingebettetes HTML. Der Inhalt wird vorher als Go-Template ausgewertet. |
markdown | content | Rendert eingebettetes Markdown zu HTML. Der Inhalt wird vorher als Go-Template ausgewertet. |
asciidoc | content | Rendert eingebettetes AsciiDoc zu HTML. Der Inhalt wird vorher als Go-Template ausgewertet. |
file | path | Lädt eine Datei aus snippets/ und rendert sie je nach Dateiendung oder format. |
plugin | name | Ruft nur dann ein serverseitig registriertes Sitegenerator-Plugin mit params auf, wenn dieser Plugin-Name in der konkreten Workspace-Instanz bereitgestellt ist. |
navigation | name, template | Rendert ein vorbereitetes Navigationsmenü über ein Template. |
productSnippet | name | Rendert oder markiert ein Produkt-Snippet für dynamische Produktdetailseiten. |
Für file erkennt Workspace html, htm, markdown, md, asciidoc und adoc. Setzen Sie format, wenn die Dateiendung das Zielformat nicht eindeutig beschreibt:
containers:
mainContent:
- type: file
path: hero.txt
format: markdownVerwenden Sie html, markdown und asciidoc für kurze, seitenspezifische Inhalte. Verwenden Sie file, wenn mehrere Pages denselben Snippet-Inhalt einbinden oder wenn Sie Markup in snippets/ versionieren möchten.
type: file liest Dateien relativ zu snippets/. Ein Eintrag wie path: content/faq.md lädt also snippets/content/faq.md.
containers:
mainContent:
- type: file
path: content/home.html
- type: file
path: content/faq.mdVerwenden Sie für normalen Seiteninhalt nicht type: template. Das Feld template gehört bei PageTypes, Pages und Navigations-Komponenten zum Template-Vertrag, nicht zu einem frei wählbaren Content-Include. Verwenden Sie auch keine YAML-Syntax wie !include; der Site-Loader wertet sie nicht als Include aus.
type: file bindet statische Inhaltsdateien ein. Go-Template-Ausdrücke in type: html, type: markdown und type: asciidoc werden ausgewertet; bei type: file bleibt die Datei bewusst statischer Seiteninhalt. Wenn Sie Produktkarten, Preise oder Varianten darstellen, verwenden Sie die dokumentierten Storefront- und Snippet-Verträge.
Navigation rendern
Navigation entsteht aus den navigation-Einträgen der Pages und aus Navigations-Komponenten in PageTypes oder Pages. Arbeiten Sie mit stabilen technischen IDs:
- Verwenden Sie
idals dauerhaften Navigationsanker. - Lokalisieren Sie
labelpro Sprache. - Steuern Sie die Reihenfolge über
ranking. - Verweisen Sie bei Unterpunkten mit
parentauf die ID des Elternpunkts. - Schreiben Sie keine eigenen
children-Arrays. Workspace baut Kinder aus den Parent-Bezügen.
Ein PageType kann Navigations-Slots definieren:
template: main.tmpl
containers:
mainNav:
- type: navigation
name: main
template: navigation-main.tmpl
legalNav:
- type: navigation
name: legal
template: navigation-legal.tmplname wählt das Menü, zum Beispiel navigation.main aus den Page-Dateien. template zeigt auf eine Datei unter templates/. Das Navigationstemplate bekommt .Name, .Links und .Component; Einträge in .Links können .Children enthalten.
<nav aria-label="{{ .Name }}">
{{ range .Links }}
<a href="{{ .URL }}">{{ .Label }}</a>
{{ range .Children }}
<a href="{{ .URL }}">{{ .Label }}</a>
{{ end }}
{{ end }}
</nav>Dynamische Produktdetailseiten
Nutzen Sie eine dynamische Produktdetailseite, wenn viele Produkte dasselbe Detail-Layout verwenden sollen. Legen Sie keine Page-Datei pro Produkt an. Eine einzige Site-Page definiert Layout, Sprache, Navigation und Produktbereiche; das konkrete Produkt kommt zur Laufzeit aus der ProductRoute des aktuellen Sales Channels.
Die dynamische Produktdetailseite verbindet drei Verträge:
| Vertrag | Aufgabe |
|---|---|
| Site-Page, PageType und Template | Definieren den festen Seitenrahmen, Container-Slots, Navigation, Assets und SEO-Grundlagen. |
| ProductRoute | Liefert den öffentlichen Slug für ein veröffentlichtes Produkt im aktuellen Sales Channel und in der aktuellen Sprache. |
| Produkt-Snippet | Liefert vorgerendertes HTML für einen Produktbereich, zum Beispiel Hero, technische Daten oder Empfehlungen. |
Produkt-Snippets sind nicht dasselbe wie Dateien im Site-Verzeichnis snippets/. Dateien unter snippets/ sind statische, wiederverwendbare Site-Teile für type: file. Ein productSnippet verweist dagegen auf ein generiertes Varianten-Artefakt aus PIM. Der Wert name ist ein exakter, groß-/kleinschreibungssensitiver Artefakt-Pfadvertrag und muss mit SnippetTemplate.Name übereinstimmen. Wie Sie solche Produkt-Snippets planen, bauen, per Preview prüfen und per Snippet-Rebuild ausliefern, steht in Snippet-Vorlagen entwickeln.
Die dynamische Page setzt dynamicRoute.kind: productDetail und einen öffentlichen Prefix. Der Prefix bildet zusammen mit ProductRoute.slug die sichtbare URL.
Definieren Sie pro Site, Locale und Jurisdiction höchstens eine dynamische productDetail-Page. Eine leere Jurisdiction zählt wie global. Länderspezifische Varianten dürfen eigene Pages verwenden, solange sich ihre Jurisdiction unterscheidet. Workspace weist eine zweite Produktdetail-Page im gleichen Scope bereits beim Laden des CMS-Quellstands zurück; der Release-Build prüft denselben Vertrag erneut.
Nutzen Sie für Kampagnen oder Landingpages normale CMS-Pages mit Produkt-Snippets oder Produktteasern. So bleibt die ProductRoute die eindeutige kanonische Detail-URL für Suche, Produktkarten und strukturierte Produktdaten.
type: product-detail
variant:
translationKey: product-detail
locale: de-DE
slug: _dynamic/product-detail
dynamicRoute:
kind: productDetail
prefix: de/produkte
containers:
mainContent:
- type: productSnippet
name: product-detail-hero
params:
required: true
- type: productSnippet
name: product-detail-specsBei einem Aufruf wie /de/produkte/<product-route-slug> löst Workspace zuerst Host, Site, Sales Channel und Sprache auf. Danach sucht Workspace die passende ProductRoute, rendert die dynamische Page und ersetzt jeden productSnippet-Marker durch das passende Snippet-Artefakt für Tenant, Variante, Locale und Sales Channel.
Produktdetail-URLs unter dem dynamischen Prefix gehören der ProductRoute. Legen Sie keine statische Page-Datei mit demselben Pfad an. Die Runtime behandelt passende Product-Detail-Pfade als dynamische Produktseiten, damit statische Altseiten Produktdaten, Snippets und SEO-Purpose nicht verdrängen.
Für HTML-Titel und Meta-Beschreibung nutzt die dynamische Produktseite zuerst freigegebenen Produktinhalt mit dem konfigurierten SEO-Zweck. Der Default ist purposeKey=seo; Betreiber können den Schlüssel über public.product_content.seo_purpose_key ändern. Kanalgebundener SEO-Inhalt gewinnt vor allgemeinem SEO-Inhalt ohne Sales Channel. Die dynamische Produktseite liest keine SEO-Felder aus der ProductRoute. Wenn kein freigegebener SEO-Inhalt existiert, verwendet sie den sichtbaren Produktinhalt als technischen Fallback. Das SEO-Schema sollte die Felder seo_title und seo_description bereitstellen.
params.required: true macht ein Produkt-Snippet verpflichtend. Nutzen Sie required nur für Bereiche, ohne die die Detailseite fachlich nicht ausgeliefert werden soll. Wenn ein verpflichtendes Produkt-Snippet fehlt, liefert die Live-Seite 503 Service Unavailable mit Retry-After, statt einen unvollständigen Produktbereich still auszuliefern. Das gilt auch, wenn eine Snippet-Vorlage nur nach Groß-/Kleinschreibung anders heißt als productSnippet.name. Optionale Snippets bleiben leer, wenn kein passendes Artefakt existiert.
Erstellen Sie für diesen Zustand eine statische Fehlerseite im Site-Design. Eine Page mit Slug 503 wird im Release als global/<default-locale>/503.html veröffentlicht und bei HTML-Requests mit Status 503 ausgeliefert. Die Datei darf nicht von ProductSnippets, Runtime-Navigation oder dynamischen Routenmarkern abhängen, weil sie gerade dann funktionieren muss, wenn Produktdetail-Artefakte fehlen. Verwenden Sie statische Links und kopieren Sie nur die für das Design nötige Struktur. Setzen Sie robots: noindex, follow und sitemap: false.
variant:
translationKey: error-503
locale: de
slug: "503"
robots: noindex, follow
sitemap: false
containers:
mainContent:
- type: file
source: snippets/errors/503.htmlVeröffentlichen Sie nach Template-Änderungen einen neuen Site Release. Nach Inhalts-, Medien- oder Snippet-Vorlagenänderungen muss der Snippet-Rebuild die benötigten Variant-Artefakte erzeugen.
Wenn die Produktdetailseite zusätzlich Anfrage, Newsletter-Anmeldung, Website Chat oder Kampagnenmessung braucht, nutzen Sie die fertigen Website-Integrationen im nächsten Abschnitt.
Fertige Website-Integrationen einbinden
Produktdetailseiten, Landingpages und Corporate-Sites brauchen oft mehr als Produktdarstellung: Anfrageformular, Newsletter-Anmeldung, Website Chat oder Kampagnenmessung. Bauen Sie diese Funktionen nicht als Sitegenerator-Plugin nach. Workspace stellt dafür fertige öffentliche Verträge bereit.
| Baustein | Verwenden Sie | Wofür zuständig? |
|---|---|---|
| Kontaktformular | Contact Forms mit öffentlichem formKey | Die Website sammelt Nachricht und Kontaktwert. Workspace prüft Origin, Abuse-Signale, Routing, Quarantäne und interne Triage. |
| Vorgangseinreichung | Vorgangs-Intake mit öffentlichem intakeKey | Die Website eröffnet Vorgänge. Workspace prüft Origin, Zielgruppenfreigabe, erlaubte Vorgangstypen, Abuse-Signale, Routing, ACLs und optionale öffentliche Antworten. |
| Website Chat | Offizielles Widget-Script mit öffentlichem widgetKey | Die Website bettet das Widget ein. Workspace steuert Status, Routing, Verfügbarkeit, Konversationen und interne Bearbeitung. |
| Newsletter-Anmeldung | Öffentlicher DOI-Subscribe-Endpunkt | Die Website sendet E-Mail, Liste, Tenant und optional Locale. Workspace übernimmt Double-Opt-in, Listenmitgliedschaft, Abmeldung und Newsletter-Governance. |
| Public-Site-Telemetry | Sitegenerator-Default-Script oder installPublicSiteTelemetry() | Die Website meldet globale JavaScript-Fehler tenant- und sitegebunden, ohne einen Storefront-Sales-Channel zu verlangen. |
| Newsletter- und Kampagnen-Tracking | Tracking-Links, Newsletter-Link-Rewrite und Site-Analytics | Workspace ordnet Klicks, Kampagnen, Newsletter-Empfänger und Conversions datensparsam zu. |
Für Contact Forms und Website Chat nutzen Sie die technische Anleitung Storefront-Erweiterungen. Die Seite gilt auch für normale Websites, wenn diese nur Formular oder Chat einbinden und keinen vollständigen Onlineshop bauen.
Vorgangseinreichung für öffentliche oder geschützte Bereiche bauen
Nutzen Sie Vorgangs-Intake, wenn ein Website-Formular direkt einen Vorgang eröffnen soll. Das ist strenger als ein Kontaktformular: Die Website darf nur Inhalte und Kontaktdaten senden. Workspace bestimmt Vorgangstyp, Routing, Zielgruppe, ACLs und optionale öffentliche Antwortlinks aus dem konfigurierten Vorgangs-Intake-Ingress.
Bevor Sie das Formular einbauen, konfigurieren Sie in Workspace einen Vorgangs-Intake-Ingress:
allowedOriginsenthält die echte Website-Origin, zum Beispielhttps://www.example.com.allowedCaseTypesenthält nur die Vorgangstypen, die dieser Einstieg eröffnen darf.ownerGroupIdist gesetzt. Diese Gruppe erhält die Owner-ACL am neuen Vorgang.accessModeistpublic,authenticatedoderrestricted.- Bei
restrictedenthältaccessPolicydie erlaubten Kundengruppen, Personensegmente, Company-Rollen oder Access Groups. - Optional ist
issuePublicReplyTokenaktiv. Dann erzeugt Workspace für anonyme Public-Submits einen öffentlichen Antwortlink zum neuen Vorgang.
Laden Sie die sichtbare Formular-Konfiguration vor dem Rendern:
GET /api/v1/public/v1/case-intakes/{intakeKey}
Origin: https://www.example.comDie Antwort enthält nur die für diesen Ingress erlaubten Vorgangstypen. Bauen Sie das Auswahlfeld aus dieser Antwort. Verwenden Sie keine hart codierte Liste und lassen Sie den Nutzer keinen freien Vorgangstyp-Wert senden.
Senden Sie das Formular an:
POST /api/v1/public/v1/case-intakes/{intakeKey}/submissions
Origin: https://www.example.com
Content-Type: application/jsonErlaubte Payload-Felder sind:
| Feld | Inhalt |
|---|---|
caseType | ein Key aus der geladenen Konfiguration; bei genau einem erlaubten Typ kann das Feld verborgen werden |
subject | kurzer Betreff |
message | Beschreibung des Anliegens |
name, companyName, email, phone | Kontaktwerte; mindestens ein Kontaktwert ist erforderlich |
pageUrl | aktuelle Seite ohne sensible Tokens |
filledSeconds | Zeit bis zum Submit |
honeypot | verborgenes Feld; muss für normale Nutzer leer bleiben |
Workspace antwortet neutral mit 202 received. Bei angenommenen Einreichungen kann die Antwort zusätzlich caseNumber enthalten. Wenn der Ingress öffentliche Antworten für anonyme Einreichungen ausstellt, enthält die Antwort publicUrl. Zeigen Sie diesen Link nur nach dem Submit an und speichern Sie ihn nicht in öffentlich auslesbaren Seiteninhalten.
Noch nicht geprüfte Einreichungen erscheinen im Dashboard-Handlungsbedarf. Wenn Workspace wegen Routing oder Workflow keinen Vorgang anlegen kann, öffnen Sie die Einreichung unter CRM > Pipeline > Vorgangseinreichungen und setzen nach der Korrektur OK; Workspace versucht dann erneut, den Vorgang anzulegen.
Behandeln Sie Fehler allgemein. Ein 404 kann bedeuten, dass der Ingress nicht aktiv ist, die Origin nicht erlaubt ist oder der angemeldete Nutzer nicht zur freigegebenen Zielgruppe gehört. Zeigen Sie keine internen Routing-, SQL-, Schema- oder Berechtigungsdetails an.
Kundenbereich für Vorgänge einbinden
Nutzen Sie den Kundenbereich, wenn angemeldete Kunden ihre eigenen Vorgänge sehen, öffnen und beantworten sollen. Bauen Sie dafür keine eigene Vorgangssuche gegen interne Admin-Endpunkte. Die öffentliche Account-Fläche liefert bereits eine komponentenfähige, berechtigte Sicht auf Vorgänge.
Binden Sie die Komponente in eine geschützte Account-Seite ein:
<nucleus-account-cases></nucleus-account-cases>Wenn die Seite einen konkreten Firmenkontext vorgibt, übergeben Sie ihn explizit:
<nucleus-account-cases data-company-id="COMPANY_UUID"></nucleus-account-cases>Die Komponente nutzt dieselbe Account-Session wie die übrige Kundenbereichsfläche und ruft die öffentlichen Account-Endpunkte auf:
GET /api/v1/public/v1/account/cases
GET /api/v1/public/v1/account/cases/{caseID}
POST /api/v1/public/v1/account/cases/{caseID}/commentsFür neue Kundenkommentare sendet das Frontend nur den sichtbaren Text:
{
"content": "Danke, hier sind die fehlenden Informationen."
}Rendern Sie ausschließlich die zurückgegebenen Vorgänge, Kommentare und Berechtigungen. Interne Kommentare erscheinen im Kundenbereich nicht. Wenn die Antwort canComment nicht erlaubt, blenden Sie die Antwortfunktion aus. Übernehmen Sie keinen Vorgangstyp, keine Company-ID und keine ACL-Entscheidung aus frei editierbaren Frontend-Daten; Workspace prüft Sichtbarkeit und Kommentierrecht serverseitig.
Behandeln Sie fehlende Anmeldung, fehlende Firmenberechtigung und leere Listen generisch. Ein Kunde soll erkennen, dass er keine sichtbaren Vorgänge hat oder sich anmelden muss, aber keine internen Vorgangs-IDs, Gruppen, Rollen oder Routingdetails sehen.
Vorgänge ohne Login zugänglich machen
Nicht jeder Kunde soll einen Login erhalten. Dafür nutzen Sie öffentliche Vorgangslinks. Der Link führt auf die öffentliche Vorgangsansicht und ist tokenbasiert. Das Website-Frontend erzeugt diesen Token nicht selbst.
Wenn ein Mitarbeiter aus einer E-Mail, einem Posteingang oder einer Kontaktformular-Einreichung einen Vorgang angelegt hat, sendet Workspace den öffentlichen Link aus dem Vorgang heraus:
POST /api/v1/cases/{caseID}/share/send
Content-Type: application/json{
"recipientEmail": "kunde@example.com",
"publicBaseUrl": "https://www.example.com",
"scope": "case_public_reply",
"ttlDays": 14
}Verwenden Sie case_public_read, wenn der Empfänger nur lesen darf, und case_public_reply, wenn Antworten erlaubt sind. publicBaseUrl muss die gewünschte öffentliche Website-Basis enthalten; leiten Sie sie nicht aus einem Host-Header ab. Der versendete Link öffnet die öffentliche Vorgangsseite. Zeigen Sie Token nie in Listen, HTML-Attributen, Analytics-Events oder Logs an.
Für eingeloggte Kunden ist der Kundenbereich der Standardweg. Ein öffentlicher Link bleibt sinnvoll, wenn ein externer Ansprechpartner keinen Account hat, keinen bekommen soll oder nur für diesen einzelnen Vorgang antworten darf.
Vorgangseingänge im Frontend wählen
Wählen Sie den Einstieg nach fachlichem Zweck:
| Eingang | Frontend-Vertrag | Danach passiert |
|---|---|---|
| Vorgangs-Intake | Formular lädt GET /api/v1/public/v1/case-intakes/{intakeKey} und sendet an /submissions | Workspace eröffnet den Vorgang direkt, sofern Origin, Zielgruppe, Vorgangstyp, Rate Limit und Spam-Prüfung bestehen. |
| Kontaktformular | Contact-Form-Submit mit formKey | Workspace nimmt die Anfrage auf. Ein Mitarbeiter prüft die Einreichung und erzeugt daraus einen Vorgang oder hängt sie an einen bestehenden Vorgang. |
| Allgemeiner Posteingang | Posteingangs- oder Mail-Workflow | Workspace verarbeitet den Eingang intern. Ein Mitarbeiter oder eine konfigurierte Handoff-Regel erzeugt den Vorgang. |
Nach der Vorgangseröffnung entscheidet die Kundenbeziehung über den Rückweg:
| Empfänger | Rückweg |
|---|---|
| Kunde mit Login und Vorgangs-ACL | Vorgang erscheint im Kundenbereich über nucleus-account-cases. |
| Kunde ohne Login | Mitarbeiter sendet einen öffentlichen Vorgangslink mit share/send. |
| Partner, Gruppe oder eingeschränkter Nutzerkreis | Vorgangs-Intake oder Kundenbereich nutzen die serverseitige Access-Policy; das Frontend zeigt nur die vom Backend freigegebenen Optionen. |
Hardcoden Sie keine Vorgangstypen, Gruppen, Rollen, Workflow-IDs oder Fehlerdetails im Website-Frontend. Laden Sie Auswahlwerte aus dem öffentlichen Ingress, übersetzen Sie eigene Seitentexte über das Site-i18n-System und nutzen Sie generische Fehlertexte für 404, 429 und nicht erlaubte Zugriffe.
Wenn ein Kontaktformular Fotos, Typenschilder, Lastlisten oder Leistungsverzeichnisse annehmen soll, bauen Sie den Upload vor dem finalen Submit. So bleiben bereits eingegebene Formularwerte erhalten, wenn eine Datei zu groß ist oder einen nicht erlaubten Typ hat.
Kontaktformular mit Datei-Upload bauen
Bevor Sie das Frontend ausliefern, muss der Kontaktformular-Eingang in Workspace bereit sein:
uploadsEnabledist aktiv.accessGroupIdist gesetzt, damit interne Bearbeiter die Dateien sehen.allowedOriginsenthält die echte Website-Origin, zum Beispielhttps://www.example.com.- Optional sind
uploadMaxFiles,uploadMaxFileBytesunduploadMaxTotalBytesgesetzt. Wenn Sie keine Werte setzen, gelten die konfigurierten Defaults. - Optional sind
consentTopics,consentRequiredTopics,consentViaundconsentLegalDocVersiongesetzt. Dann kann oder muss das Formular passende Checkboxen mitsenden.
Bauen Sie die Upload-Oberfläche als Teil des Formulars. Nutzen Sie dafür ein Drag-and-drop-Feld oder einen normalen Dateiauswahldialog. Akzeptieren Sie im Browser nur PDF, JPG/JPEG, PNG und HEIC/HEIF. Zeigen Sie direkt am Upload-Feld, welche Dateien ausgewählt, hochgeladen oder abgelehnt wurden.
- Starten Sie die Upload-Session, sobald der Nutzer die erste Datei auswählt:
POST /api/v1/public/v1/contact-forms/{formKey}/upload-sessions
Origin: https://www.example.comMerken Sie sich sessionId, sessionToken, maxFiles, maxFileBytes, maxTotalBytes und acceptedMediaTypes aus der Antwort. Speichern Sie das Token nur im aktuellen Formularzustand, nicht in Local Storage und nicht in öffentlich sichtbaren HTML-Attributen.
- Laden Sie jede Datei einzeln per Multipart-Request hoch:
POST /api/v1/public/v1/contact-forms/{formKey}/upload-sessions/{sessionId}/files
Origin: https://www.example.com
Content-Type: multipart/form-dataSenden Sie den Header X-Upload-Session-Token mit dem Session-Token aus der Upload-Session. Senden Sie im Multipart-Body:
file: die Dateipurpose: optional, zum Beispielphoto,type_plate,load_list,bill_of_quantities,supporting_documentoderother
Die Antwort enthält die öffentliche attachmentId für diese Upload-Session. Verwenden Sie diese ID nur, um die Datei vor dem Submit wieder zu entfernen.
- Entfernen Sie falsch gewählte Dateien vor dem Submit:
DELETE /api/v1/public/v1/contact-forms/{formKey}/upload-sessions/{sessionId}/files/{attachmentId}
Origin: https://www.example.comSenden Sie auch hier den Header X-Upload-Session-Token mit dem Session-Token aus der Upload-Session.
- Senden Sie das Formular erst ab, wenn alle gewünschten Dateien erfolgreich hochgeladen oder bewusst entfernt wurden:
| Feld | Inhalt |
|---|---|
name, email, phone, companyName | die normalen Kontaktwerte |
message | die Anfrage |
pageUrl | die aktuelle Seite |
filledSeconds | die Zeit bis zum Submit |
consentTopics | optional, die bestätigten Consent-Themen, zum Beispiel ["privacy"] |
consentAction | optional; wenn gesetzt, nur granted |
uploadSessionId | die ID aus der Upload-Session |
uploadSessionToken | das Session-Token aus der Upload-Session |
Senden Sie diese Payload an:
POST /api/v1/public/v1/contact-forms/{formKey}/submissionsSchreiben Sie Dateiobjekte nie in message und senden Sie keine File- oder FileList-Objekte im JSON-Submit. JavaScript wandelt solche Objekte sonst zu Texten wie [object File] oder [object FileList] um. Dieser Text ist nur ein Serialisierungsfehler im Formular und kein verwertbarer Anhang.
Falsch:
const file = fileInput.files[0];
await fetch(submitUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email,
message: `${message}\nfiles: ${file}`
})
});Richtig:
const files = Array.from(fileInput.files);
let uploadSession = null;
if (files.length > 0) {
uploadSession = await createUploadSession(formKey);
for (const file of files) {
await uploadContactFile(formKey, uploadSession, file);
}
}
await fetch(submitUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email,
message,
consentTopics: privacyAccepted ? ["privacy"] : [],
consentAction: privacyAccepted ? "granted" : undefined,
uploadSessionId: uploadSession?.sessionId,
...(uploadSession
? { ["uploadSession" + "Token"]: uploadSession.sessionToken }
: {})
})
});- Behandeln Sie die Submit-Antwort neutral. Workspace antwortet mit
202 received, ohne offenzulegen, ob die Anfrage angenommen, quarantänisiert oder als Spam verworfen wurde.
Zeigen Sie Uploadfehler direkt am Dateifeld und leeren Sie die Textfelder nicht. Typische Fehler sind zu große Dateien, zu viele Dateien, eine abgelaufene Upload-Session, eine nicht erlaubte Origin oder ein deaktivierter Upload am Ingress. Der Nutzer soll die Datei ersetzen oder entfernen können, ohne die Anfrage neu schreiben zu müssen.
Zeigen Sie vor dem Upload oder Submit einen kurzen Datenschutzhinweis an. Er soll erklären, dass Workspace die Anfrage und optionale Dateien zur Bearbeitung speichert und intern prüft. Wenn der Ingress consentTopics konfiguriert, darf das Formular bestätigte Themen in consentTopics mitsenden. Wenn der Ingress consentRequiredTopics setzt, muss das Formular diese Topics mitsenden, sonst lehnt Workspace den Submit mit einem Validierungsfehler ab.
Verwenden Sie für die Kenntnisnahme der Datenschutzhinweise ein eigenes Topic wie privacy. Marketing darf nur über eine separate optionale Checkbox gesendet werden, zum Beispiel marketing; koppeln Sie Marketing nicht an die Kontaktanfrage. Workspace dokumentiert akzeptierte Consent-Angaben am erzeugten Lead mit Topic-Liste, Aktion granted, Kanal aus consentVia, Dokumentversion aus consentLegalDocVersion, Zeitstempel, IP-Adresse und User-Agent. In der Kontaktformular-Einreichung steht nur eine nicht-sensitive Consent-Zusammenfassung.
Nach erfolgreichem Submit verknüpft Workspace die Dateien mit der Kontaktformular-Einreichung; bei angenommenen Einreichungen erscheinen sie zusätzlich am internen Lead-Kommentar.
Der Ablauf ist erfolgreich, wenn ein Test-Submit in Workspace eine Kontaktformular-Einreichung erzeugt und die hochgeladenen Dateien dort nachvollziehbar sind. Bei angenommenen Einreichungen muss der interne Lead-Kommentar die Anhänge anzeigen. Im Nachrichtentext darf kein Eintrag wie files: [object File], files: [object FileList] oder [object Object] stehen. Wenn solche Texte sichtbar sind, hat das Website-Frontend Dateien als Text serialisiert, statt sie über die Upload-Session hochzuladen.
Newsletter-Anmeldungen senden Sie an den öffentlichen Subscribe-Endpunkt:
POST /api/v1/public/v1/newsletter/subscribeDie Payload enthält tenantId, newsletterListId, email und optional locale. Behandeln Sie die Annahme neutral und bauen Sie keinen lokalen Listen-Fallback. Workspace versendet die Bestätigung und trägt Empfänger erst nach erfolgreichem Double-Opt-in als subscribed ein.
Kampagnen- und Newsletter-Auswertung richten Betreiber über Website-Analytics und Marketing-Attribution ein. Newsletter-Links werden beim finalen Newsletter-Versand umgeschrieben; manuelle Tracking-Links gehören in Marketing-Kampagnen, nicht hart in Templates. Website-Seiten dürfen Tracking nur mit fachlich freigegebenen Datenschutz- und Consent-Grundlagen verwenden.
Public-Site-Telemetry nutzen
Das Default-Script einer Workspace-Site installiert Public-Site-Telemetry automatisch. Es meldet window.onerror und unhandledrejection an:
POST /api/v1/public/v1/site/telemetry/reportWenn Sie ein eigenes Script-Bundle verwenden, importieren Sie die Runtime explizit:
import { installPublicSiteTelemetry } from "./core/telemetry.mjs";
installPublicSiteTelemetry();Der Endpunkt funktioniert für normale veröffentlichte Public-Sites ohne Sales Channel. Verwenden Sie ihn nicht für Checkout- oder PayPal-Ereignisse: Diese Storefront-Quellen gehören weiter zu /api/v1/public/v1/storefront/telemetry/report und zum installPublicStorefrontTelemetry()-Alias.
Die Anbindung ist erfolgreich, wenn ein ausgelöster Browserfehler mit 202 Accepted angenommen wird und der Telemetry-Eintrag den aufgelösten Site- Kontext enthält. Wenn der Endpunkt SITE_UNAVAILABLE liefert, prüfen Sie Domainbindung, Live-Veröffentlichung und ob der Host wirklich als Public-Site und nicht als Admin- oder System-Host aufgelöst wird.
Sitegenerator-Plugins einbinden
Eine Plugin-Komponente ist nur eine Einbindestelle im Site-YAML. Sie erzeugt kein Plugin und lädt keinen Code aus dem Site-Projekt. Das eigentliche Plugin muss vorher serverseitig im Sitegenerator registriert sein. Page-Autoren können keinen neuen Go-Plugin-Code allein durch YAML erzeugen.
In einer Standard-Site kann es deshalb null nutzbare Sitegenerator-Plugins geben. Das ist kein Fehler: type: plugin ist eine Erweiterungsstelle für bereitgestellte serverseitige Bausteine, kein Plugin-Marktplatz und kein Mechanismus, mit dem Site-Dateien eigene Backend-Logik installieren. Verwenden Sie type: plugin nur, wenn Ihre Workspace-Instanz einen konkreten Plugin-Namen und dessen params-Vertrag dokumentiert.
containers:
mainContent:
- type: plugin
name: contactTeaser
params:
headline: Beratung anfragen
target: /kontaktDieses Beispiel ist nur das YAML-Muster. contactTeaser funktioniert erst, wenn genau dieser Name serverseitig registriert wurde. Wenn kein Plugin unter diesem Namen existiert, ist der Eintrag ungültig.
Der Renderer sucht ein registriertes Plugin mit diesem name und übergibt params als strukturierte Werte. Das Plugin gibt HTML zurück oder meldet einen Fehler. Wenn kein Plugin unter diesem Namen registriert ist, rendert Workspace einen Fehlerhinweis im Container.
Prüfen Sie vor dem Einsatz eines Plugins:
- Welcher Plugin-Name ist für diese Workspace-Instanz freigegeben?
- Welche
paramssind Pflicht, optional und stabil? - Welche Daten darf das Plugin lesen und welche öffentlichen Verträge nutzt es?
- Wie verhält sich das Plugin bei fehlenden Daten oder Build-Fehlern?
- Gibt es eine einfachere Umsetzung mit
markdown,html,asciidoc,file,navigationoderproductSnippet?
Nutzen Sie Plugins nur für bewusst bereitgestellte serverseitige Bausteine. Für normale Inhaltsblöcke sind markdown, html, asciidoc oder file leichter prüfbar. Für Storefront-Funktionen bleiben veröffentlichte Public- und Storefront-Verträge die Integrationsgrenze; bauen Sie keine internen API- Fallbacks in ein Plugin.
Internationalisierung und Assets
Mehrsprachige Sites verwenden Page-Varianten. Eine Sprachversion ist keine frei kopierte Seite, sondern die Variante derselben fachlichen Page in einer anderen Sprache. Nach der Umsetzung erkennt Workspace die zusammengehörigen Varianten, erzeugt Canonical- und Alternate-Daten und liefert pro Sprache die passenden Inhalte aus.
Das Modell besteht aus drei stabilen Page-Werten:
| Feld | Aufgabe | Regel |
|---|---|---|
variant.translationKey | Verbindet alle Sprachversionen derselben fachlichen Page. | Für alle Varianten gleich lassen. Nicht übersetzen. |
variant.locale | Setzt die Sprache der konkreten Variante. | Pro Variante passend setzen, zum Beispiel de, en oder de-DE. |
variant.slug | Setzt den öffentlichen Pfad der konkreten Variante. | Sprachlich passend und dauerhaft planen. Veröffentlichte Slugs nur mit Redirect-Konzept ändern. |
Sprachversion einer Page anlegen
Nutzen Sie diesen Ablauf, wenn eine bestehende öffentliche Page in einer weiteren Sprache erscheinen soll.
- Klären Sie zuerst, ob die Sprachversion fachlich dieselbe Page ist. Wenn Zielgruppe, Zweck, Layout und Conversion-Ziel gleich bleiben, verwenden Sie denselben
translationKey. - Legen Sie eine neue Page-Datei unter
pages/an oder kopieren Sie die bestehende Page-Datei als Arbeitsgrundlage. - Übernehmen Sie
type, wiederkehrende Container-Struktur, technische Navigations-ID und benötigte Assets, wenn die Seite denselben PageType und dasselbe Layout nutzt. - Lassen Sie
variant.translationKeyunverändert. - Setzen Sie
variant.localeauf die neue Sprache. - Setzen Sie
variant.slugauf den öffentlichen Pfad dieser Sprache. - Übersetzen Sie
title,description, Navigationslabels und sichtbare Page-Inhalte. - Ergänzen oder prüfen Sie
translationScopes, wenn Templates oder Scripts wiederverwendbare Texte ausi18n/<locale>/brauchen. - Prüfen Sie lokale
translations, wenn die Page kleine eigene Textbausteine an das Template übergibt. - Prüfen Sie den Template-Head auf Canonical- und Alternate-Ausgabe.
- Prüfen Sie Vorschau,
validate, Build und fachlichen Review vor der Veröffentlichung.
Beispiel für zwei Sprachversionen derselben Page:
# pages/about.de.yaml
type: default
variant:
translationKey: about
locale: de
slug: ueber-uns
title: Über uns
description: Lernen Sie unser Unternehmen kennen.
navigation:
main:
id: about
label: Über uns
ranking: 20
containers:
mainContent:
- type: markdown
content: |
Wir entwickeln Workspace für klare Geschäftsprozesse.# pages/about.en.yaml
type: default
variant:
translationKey: about
locale: en
slug: about-us
title: About us
description: Learn more about our company.
navigation:
main:
id: about
label: About us
ranking: 20
containers:
mainContent:
- type: markdown
content: |
We build Workspace for clear business processes.Die technische Navigations-ID about bleibt gleich, weil sie den Navigationseintrag identifiziert. Das sichtbare label wird übersetzt.
Metadaten im Template ausgeben
Workspace stellt .CanonicalURL und .AlternateLinks beim Rendern bereit. Das Template muss diese Werte im <head> ausgeben, damit Browser, Suchmaschinen und Prüftools die Sprachversionen sehen.
<link rel="canonical" href="{{ .CanonicalURL }}">
{{ range .AlternateLinks }}
<link rel="alternate" hreflang="{{ .Lang }}" href="{{ .URL }}">
{{ end }}Der Block erzeugt keine Sprachversionen. Er gibt nur die Varianten aus, die über denselben translationKey im Site-Projekt vorhanden sind. Wenn eine Variante fehlt oder einen anderen translationKey nutzt, kann das Template sie nicht als Sprachalternative anzeigen.
x-default entsteht aus der konfigurierten defaultPage.Locale. Prüfen Sie die Default-Sprache der Site, bevor Sie die erste Sprachversion veröffentlichen. Die öffentliche Root-URL kommt aus defaultPage.Page; codieren Sie den Root- Slug nicht im Template.
Texte und Übersetzungsbündel trennen
Pflegen Sie Übersetzungen an der Stelle, an der sie fachlich hingehören:
| Inhalt | Ablage |
|---|---|
| Seitentitel, Meta-Beschreibung, Navigation und sichtbarer Seiteninhalt | Direkt in der jeweiligen Page-Variante. |
| Wiederverwendbare UI- oder Template-Texte | i18n/<locale>/<scope>.yaml. |
| Page-spezifische kleine Template-Werte | Lokale translations in der Page. |
| Produktnamen, Produkttexte, SEO-Produktdaten und Snippets | PIM-Inhalte pro Locale und Sales Channel, nicht statisch in der Site-Page. |
Nutzen Sie translationScopes, wenn eine Page bestimmte i18n-Bundles braucht:
translationScopes:
- common
- checkoutTemplates können übersetzte Werte über die freigegebenen i18n-Funktionen lesen. Halten Sie technische IDs, Navigations-IDs und Translation Keys stabil. Übersetzen Sie sichtbare Labels, nicht die Identität des Eintrags.
Sprachversionen prüfen
Eine Sprachversion ist fertig, wenn diese Prüfungen bestanden sind:
| Prüfung | Erwartung |
|---|---|
| Vorschau | Jede Sprache ist unter ihrem Slug erreichbar und zeigt passende Inhalte. |
| HTML-Head | Die Seite enthält genau eine Canonical-URL und Alternate-Links für die zusammengehörigen Varianten. |
| Navigation | Sichtbare Labels sind übersetzt, technische IDs bleiben stabil, aktive Navigation passt zur aktuellen Page. |
| SEO | title, description, Slug, Sitemap-Eintrag und Canonical-Policy passen pro Sprache. |
| Build | nucli --tenant <tenant> sites validate <site-id> und der Release-Build melden keine Blocker. |
| Review | Fachliche Verantwortliche prüfen, dass die Sprachversion gleichwertig und freigegeben ist. |
Typische Fehlerbilder:
| Symptom | Bedeutung | Prüfung |
|---|---|---|
| Eine Sprache erscheint nicht als Alternate Link. | Die Page fehlt, hat einen anderen translationKey oder wurde nicht geladen. | translationKey, locale, Dateipfad und validate prüfen. |
x-default zeigt auf die falsche Sprache. | defaultPage.Locale passt nicht zur gewünschten Standardsprache. | Site-Konfiguration prüfen, danach Build wiederholen. |
| Beide Sprachen zeigen denselben Text. | Inhalte wurden kopiert, aber nicht lokalisiert oder das Template liest nur ein globales Bundle. | Page-Inhalte, translationScopes und lokale translations prüfen. |
| Canonical zeigt auf den internen Startseiten-Slug. | defaultPage.Page oder Template-Root-Logik ist falsch geplant. | Root-Seite über defaultPage führen, keine Root-Sonderlogik im Template bauen. |
| Veröffentlichtes URL-Schema ist uneinheitlich. | Slash-Policy oder Slug-Konzept wurde pro Sprache unterschiedlich gesetzt. | Canonical-Path-Policy und Redirect-Konzept gemeinsam prüfen. |
Assets und öffentliche Dateien
Referenzieren Sie Styles und Scripts über PageTypes oder Pages. Der Build bündelt referenzierte Assets und stellt sie dem Template über .Assets bereit. Wenn ein Script sichtbare Texte rendert, lesen Sie diese Texte aus den freigegebenen i18n-Daten oder aus der Page-Konfiguration, nicht aus hart codierten deutschen oder englischen Strings.
Dateien unter public/ werden unverändert veröffentlicht. Nutzen Sie public/ für statische Dateien wie robots.txt, security.txt, Web-Manifeste, SVGs, PDFs oder JSON-Dateien. Verwenden Sie dort keine Template-Platzhalter, keine Secrets und keine unfertigen Entwürfe. Wenn öffentliche Dateien sprachabhängig sind, planen Sie die Pfade bewusst, zum Beispiel downloads/de/ und downloads/en/, und verlinken Sie sie aus der passenden Page-Variante.
SEO und Auffindbarkeit planen
SEO entsteht nicht erst am Ende. Planen Sie Suchmaschinen, interne Suche und teilbare Links zusammen mit der Seitenstruktur.
| Thema | Umsetzung |
|---|---|
| Slugs | Verwenden Sie lesbare, stabile Pfade. Ändern Sie veröffentlichte Slugs nur mit geplantem Redirect-Konzept. |
| Titel und Beschreibung | Pflegen Sie pro Page einen präzisen title und eine klare description. |
| Sitemap | Nutzen Sie PageTypes und Page-Einstellungen, damit nur freigegebene öffentliche Seiten in die Sitemap kommen. |
| Canonical und Sprache | Führen Sie Sprachvarianten über translationKey, locale und passende Slugs zusammen. |
| Sprachversionen | Prüfen Sie pro Sprache eigene Inhalte, Navigation, Canonical-URL, Alternate Links und x-default. |
| Öffentliche Dateien | Prüfen Sie robots.txt, security.txt, Web-Manifeste und Downloads auf korrekte Inhalte und fehlende Interna. |
| Produktseiten | Nutzen Sie gepflegte Produktinhalte für Beschreibung, Vorteile und SEO-Texte. Dynamische Produktdetailseiten lesen SEO-Metadaten aus dem konfigurierten SEO-Zweck und geben strukturierte Produktdaten serverseitig aus, wenn Produkt, Route, Medien und öffentliche Preis-/Verfügbarkeitsdaten dafür belastbar sind. Die Pflege steht in Produktdaten veröffentlichen. |
| Kampagnen | Verwenden Sie Tracking-Links und Auswertungen nur mit fachlich freigegebenen Datenschutz- und Consent-Grundlagen. Details stehen in Website-Analytics und Marketing-Attribution. |
Kanonische Pfadform konfigurieren
Legen Sie pro Site fest, ob öffentliche HTML-Seiten mit oder ohne abschließenden Slash erreichbar sein sollen. Ohne Konfiguration bleibt Workspace bei preserve: Die Site normalisiert Slash-Varianten nicht automatisch.
Setzen Sie die site-weite Policy in config/defaults.yaml:
CanonicalPath:
mode: no_trailing_slash
redirectCode: 308Nutzen Sie diese Modi:
| Modus | Wirkung |
|---|---|
preserve | Keine automatische Slash-Normalisierung. |
no_trailing_slash | Öffentliche HTML-Seiten leiten von /pfad/ nach /pfad um. |
trailing_slash | Öffentliche HTML-Seiten leiten von /pfad nach /pfad/ um. |
redirectCode darf 301 oder 308 sein. Wenn Sie bei einer redirectenden Policy keinen Code setzen, verwendet Workspace 308.
Überschreiben Sie die Policy nur dann in einer Page-Datei, wenn diese Seite fachlich abweichen muss:
canonicalPath:
mode: trailing_slashEine Page kann mit canonicalPath.mode: inherit ausdrücklich die Site-Policy übernehmen. Verwenden Sie inherit nicht in config/defaults.yaml; Site- Defaults sind der Ursprung der Vererbung und normalisieren inherit zu preserve.
Canonical-Redirects gelten nur für öffentliche HTML-Seiten und dynamische Produktdetailseiten, nachdem der Seitenzugriff erlaubt wurde. Sie gelten nicht für geschützte Tenant-, Self- oder System-Seiten, Assets, Dateien unter public/, API-Pfade oder technische Runtime-Pfade.
Browser-Header explizit härten
Ohne Konfiguration verwendet Workspace das Profil compatibility. Bestehende Sites behalten damit ihre bisherigen Browser-Header. Aktivieren Sie strengere Header nur nach einem Test Ihrer Site, eingebetteter Inhalte und Authentifizierungsabläufe:
SecurityHeaders:
Profile: hardenedhardened setzt zentral Schutzheader gegen Content-Type-Sniffing, fremdes Framing, unnötige Referrer-Daten und den Zugriff auf Kamera, Standort und Mikrofon. Das Profil setzt weder HSTS noch eine globale Content Security Policy. Konfigurieren Sie HSTS am TLS-Edge. Definieren Sie eine CSP passend zur Site, wenn Sie eine benötigen.
Behandeln Sie Site-Authoring als Code-Publikation: Templates, HTML und Scripts können im Browser ausgeführt werden. Erteilen Sie Authoring- und Publish-Rechte nur Rollen, die diesen Code prüfen und verantworten dürfen. Preview-Zugriff ersetzt keine Authoring- oder Publish-Berechtigung.
Dev- und Release-Previews sowie Preview-Handoffs sind nicht öffentlich cachebar. Der Server kennzeichnet diese Antworten als privat und speichert sie nicht in gemeinsam genutzten Caches.
Website-Typen wählen
| Typ | Zweck | Typische Verträge und Doku | SEO-Fokus | Hinweis |
|---|---|---|---|---|
| Company- oder Corporate-Site | Unternehmen, Leistungen, Kontakt und rechtliche Seiten darstellen | Site, PageTypes, Templates, Navigation, Kontaktformulare, Website Chat | Startseite, Leistungsseiten, lokale oder branchenspezifische Begriffe | Meist reicht eine normale Site mit Formularen und Chat. |
| Blog, News oder Magazin | Artikel, Neuigkeiten und redaktionelle Themen veröffentlichen | Site, Artikel-PageTypes, Navigation, Kategorien als Site-Struktur | Artikel-Slugs, Titel, Beschreibung, Archivseiten | Beschreiben Sie Blog-Strukturen nur als Site-Archetyp, solange kein eigener Blog-Vertrag veröffentlicht ist. |
| Produktkatalog ohne Checkout | Produkte zeigen, aber nicht direkt verkaufen | Public Catalog, Produktdarstellung, Produktinhalte, Kontakt- oder Anfrageformular | Produktdetailseiten, strukturierte Produkttexte, Medien | Nutzen Sie keine Cart- oder Checkout-Logik, wenn die Site nur anfragen oder informieren soll. |
| Landingpage oder Kampagnenseite | Zielgerichtete Conversion für Kampagnen, Downloads oder Anfragen | Site, eigene PageTypes, Formulare, Tracking-Links | Kampagnen-Slug, klares Snippet, schnelle Indexierbarkeit | Halten Sie die Seite schlank und prüfen Sie Consent, Tracking und rechtliche Texte vor Veröffentlichung. |
| Help Center oder Knowledge Base | Hilfeartikel, Anleitungen und Supportinhalte bereitstellen | Site, Artikel-PageTypes, Navigation, Suche nur über veröffentlichte Verträge | Frageorientierte Titel, stabile Artikelpfade | Verwenden Sie diesen Typ nur für öffentlich freigegebene Inhalte. |
| Kundenportal oder Self-Service | Geschützte Kundenfunktionen anbieten | Headless-Login, Account-Kontext, veröffentlichte Ressourcen, Backend-Integration | Öffentliche Einstiegsseiten, private Inhalte nicht indexieren | Bauen Sie private Funktionen als eigenen Client gegen veröffentlichte Verträge, nicht als statische Website. |
| B2B- oder Partnerportal | Firmenkontext, kundenspezifische Inhalte, Preise oder Anfragen abbilden | Account, Firmenzugang, Customer Groups, Public Catalog, Pricing, Quote | Öffentliche Einstiegsseiten, geschützte Bereiche getrennt halten | Prüfen Sie Firmenzugang und Preislogik über den Serverkontext. |
| Karriere- oder Jobseite | Stellen, Arbeitgeberprofil und Bewerbungen veröffentlichen | Site, PageTypes, Bewerbungs- oder Kontaktformular, Datenschutztexte | Jobtitel, Standort, Berufsbereich | Verwenden Sie nur freigegebene Formulare und geben Sie Bewerberdaten nicht in öffentliche Dateien aus. |
| Event- oder Anmeldeseite | Veranstaltungen, Termine und Anmeldungen kommunizieren | Site, Landingpage, Formular, Bestätigungsseite | Eventname, Datum, Ort, Anmeldung | Wenn Buchung, Zahlung oder Teilnehmerverwaltung nötig sind, braucht der Client passende veröffentlichte Verträge. |
| Onlineshop | Produkte suchen, Preise zeigen, Warenkorb und Checkout ausführen | Storefront Context, Public Catalog, Pricing, Cart, Checkout, Payment, Account, B2B, Quote | Produktlisten, Produktdetailseiten, Kategorie- und Suchseiten | Nutzen Sie den Onlineshop-Leitfaden als eigene große Lösung. |
Was immer gleich bleibt
- Der Server entscheidet über Tenant, Site, Domain, Veröffentlichung und bei Storefronts über Sales Channel, Preise, Verfügbarkeit, Checkout und Zahlarten.
- Der Client liest veröffentlichte Verträge und rendert deren Ergebnis. Er baut keinen lokalen Ersatz für fehlende Daten, fehlende Domainbindung oder blockierte Readiness.
- Öffentliche Seiten zeigen keine Admin-Navigation, keine internen IDs ohne fachlichen Zweck, keine Secrets und keine unfertigen Entwürfe.
- Templates, PageTypes und Snippets reduzieren Wiederholung. Sie ersetzen keine fachliche Freigabe für Inhalte, Datenschutz, Tracking oder rechtliche Texte.
- Fehler- und Diagnoseausgaben bleiben public-safe. Geben Sie keine Tokens, Sessions, Rohdaten, vollständigen Payloads oder internen Pfade an Besucher weiter.
Onlineshop als eigene Lösung
Ein Onlineshop ist mehr als eine Website mit Produktseiten. Er braucht einen serverseitig aufgelösten Storefront-Kontext, veröffentlichte Produkte, Preise, Verfügbarkeit, Warenkorb, Versand, Checkout, Payment, Account-Flows, Firmenzugang und Angebotsanfragen. Starten Sie deshalb mit Onlineshop, wenn Besucher kaufen, Preise im Kontext sehen oder einen Warenkorb führen sollen.
Nutzen Sie die Onlineshop-Detailseiten für die technische Umsetzung:
- Katalog, Preise und Produktdarstellung
- Warenkorb, Checkout und Payment
- Login, Gastkauf und B2B
- Storefront-Erweiterungen
Verwenden Sie keine internen PIM-, Commerce-, Inventory-, Admin- oder CRUD-Endpunkte als Storefront-Fallback. Wenn ein öffentliches Ergebnis leer oder blockiert ist, klären Sie Site, Veröffentlichung, Sales Channel, Readiness, Preise oder Berechtigungen.
Nächste Schritte
- Allgemeine Site-Verwaltung, Domain, Dev-Mode, Build und Publish: Sites und CMS
- API- und CLI-Integration für eigene Clients: Integration
- Backend-Verträge für eigene Oberflächen: Backend-Integration für eigene Clients
- Onlineshop als Commerce-Storefront: B2B-Onlineshop bauen