# OSPO Developer Portal > Entwicklerdokumentation des OSPO E-Commerce Hub SH: Onlineshops und ihre Randsysteme mit Open-Source-Bausteinen selbst betreiben --- # OSPO Developer Portal Willkommen im Developer Portal des **OSPO E-Commerce Hub SH**. Im OSPO-Projekt, gefördert vom Land Schleswig-Holstein und umgesetzt von der Splendid Internet GmbH, untersuchen wir eine praktische Frage: Mit welchen Open-Source-Bausteinen lässt sich ein Onlineshop samt Randsystemen betreiben, ohne sich an einen Hersteller oder eine Cloud zu binden? Die Ergebnisse fließen in den **Konfigurations-Assistenten**, der daraus fertige, selbst betreibbare Shop-Pakete erzeugt. Hier steht, was Entwicklerinnen und Entwickler dafür wissen müssen: wie die Stacks aufgebaut sind, warum welche Komponente gewählt wurde und wo die Fallstricke liegen. Erprobt ist bisher der Stack mit **WooCommerce**. Shopware 6 und Mage-OS werden noch evaluiert. Was hier zu Randsystemen steht, gilt deshalb vorerst für WooCommerce. ## Wegweiser | Bereich | Inhalt | | :--- | :--- | | [Architektur und Grundsätze](https://ecommerce-hub.sh/developer-portal/allgemein/) | Aufbau aus Shopsystem und Randsystemen, Lizenzkriterien, verworfene Kandidaten | | [Konfigurations-Assistent](https://ecommerce-hub.sh/developer-portal/konfigurator/) | Was der Assistent fragt, was er erzeugt und wie man das Paket startet | | [WooCommerce](https://ecommerce-hub.sh/developer-portal/woocommerce/) | Referenz-Stack mit Erweiterungen, Rechtlichem, Randsystemen, KI, Theme, Barrierefreiheit und Betrieb | | [Shopware 6](https://ecommerce-hub.sh/developer-portal/shopware/) | in Vorbereitung | | [Mage-OS](https://ecommerce-hub.sh/developer-portal/mageos/) | in Vorbereitung | | [Glossar](https://ecommerce-hub.sh/developer-portal/allgemein/glossar/) | Begriffe und Komponenten auf einen Blick | ## Für KI-Werkzeuge Jede Seite lässt sich über „Seite kopieren“ oben rechts als Markdown übernehmen. Für das ganze Portal gibt es zwei Dateien nach dem Vorschlag [llms.txt](https://llmstxt.org/): [llms.txt](llms.txt) ist ein Verzeichnis aller Seiten mit je einem Satz dazu, [llms-full.txt](llms-full.txt) enthält den gesamten Inhalt am Stück. Links darin sind vollständige Adressen, das Prüfdatum einer Seite steht unter ihrem Titel. ## Mitmachen Hinweise, Korrekturen und Vorschläge für neue Seiten sind willkommen. Unter jeder Seite stehen dafür Knöpfe: ohne Konto über ein kurzes Formular, mit Codeberg-Konto als Issue oder als eigene Änderung im [öffentlichen Repository](https://codeberg.org/OSPO/OSPO-Developer-Portal). Wie das im Einzelnen läuft, steht unter [Inhalte pflegen](https://ecommerce-hub.sh/developer-portal/allgemein/inhalte-pflegen/#beitraege). --- # Architektur und Grundsätze ## Aufbau eines OSPO-Stacks Jeder Stack besteht aus einem **Shopsystem** und optionalen **Randsystemen**, die jeweils eine Aufgabe übernehmen. Shop und Randsysteme laufen als Docker-Container, die Verbindung zwischen ihnen steckt nicht in der Container-Definition, sondern in der Konfiguration der Anwendungen: ein Plugin im Shop, ein Konnektor im PIM, ein Flow in der Automatisierung. !!! info "Stand der Evaluierung" Erprobt ist bisher nur der Stack mit **WooCommerce**. Alles in der Tabelle unten wurde mit einer WooCommerce-Instanz aufgebaut und getestet. Ob und wie sich die Randsysteme an **Shopware 6** und **Mage-OS** anbinden lassen, ist noch offen. Die Evaluierung dieser beiden Shopsysteme läuft. **Randsysteme, wie sie mit WooCommerce erprobt sind:** | Bereich | Gewählte Komponente | Lizenz | Anbindung an WooCommerce | | :--- | :--- | :--- | :--- | | Zahlung | Mollie | GPLv2 (Plugin) | Plugin im Shop, API-Schlüssel des Händlers | | Newsletter | Newsletter (Stefano Lissa) | GPLv2+ | läuft im Shop selbst | | Produktdaten (PIM) | LibrePIM | OSL-3.0 | Akeneo Connector (GPLv3), nur PIM → Shop | | Web-Analyse | Matomo | GPLv3 | Connect Matomo (`wp-piwik`) | | Automatisierung | Activepieces | MIT | REST-API und Webhooks von WooCommerce, kein Plugin | | Zusammenarbeit | Nextcloud | AGPLv3 | nicht gekoppelt, Arbeitsumgebung fürs Team | | KI | Ollama mit offenem Modell | MIT, Modell Apache-2.0 | serverseitig umgeleitet, siehe [KI-Produkttexte](https://ecommerce-hub.sh/developer-portal/woocommerce/ki/) | Die Details stehen unter [WooCommerce: Randsysteme anbinden](https://ecommerce-hub.sh/developer-portal/woocommerce/randsysteme/). **Shopware 6 und Mage-OS:** Für Matomo sind Konnektoren gefunden (`tinect/matomo` für Shopware 6, `fnogatz/magento2-matomo` für Mage-OS), aber noch nicht erprobt. Für die übrigen Randsysteme ist die Anbindung an diese beiden Shopsysteme noch nicht untersucht. ## Auswahlkriterien Eine Komponente kommt nur in den Stack, wenn sie alle vier Punkte erfüllt: 1. **OSI-anerkannte Open-Source-Lizenz**, möglichst verträglich mit der GPL des übrigen Stacks. „Fair Code" oder Freemium mit gesperrten Kernfunktionen zählt nicht. 2. **Selbst betreibbar.** Kein Pflicht-Clouddienst, keine Kontingente, ab denen es kostet. 3. **Kein Abfluss von Daten** an Dritte ohne Not, insbesondere nicht außerhalb der EU. 4. **Tatsächlich anbindbar.** Ein offener Konnektor muss existieren und funktionieren. Ein kostenpflichtiger Konnektor für ein freies System hilft nicht. !!! note "Werbung ist kein Beleg" Mehrfach hat sich ein Plugin im Code anders verhalten, als es beworben wird. Beispiele: Ein KI-Plugin nennt sich anbieterunabhängig, ist aber fest auf drei Cloud-Anbieter verdrahtet. Ein Matomo-Plugin bringt eine eigene Matomo-Kopie mit, statt die vorhandene Instanz anzusprechen. Vor einer Entscheidung lohnt der Blick in den Quelltext. ## Geprüft und verworfen | Kandidat | Wofür | Warum verworfen | | :--- | :--- | :--- | | n8n | Automatisierung | Sustainable Use License, keine OSI-Lizenz, Betrieb als bezahlter Dienst untersagt | | Node-RED | Automatisierung | lizenzrechtlich sauber, aber eher Flow-Programmierung für IoT als App-Automatisierung | | Odoo, Pimcore | ERP, PIM | WooCommerce-Konnektoren nur kostenpflichtig | | Tinify | Bildoptimierung | Clouddienst mit Freikontingent, danach kostenpflichtig | | Akismet | Spamschutz | schickt Formulardaten an Server in den USA | | Google reCAPTCHA | Spamschutz | ersetzt durch EU-Captcha (Hosting in Deutschland) | | WPForms, Ninja Forms, Forminator | Formulare | Freemium, Kernfunktionen gesperrt | | „Matomo Analytics" (`matomo`) | Analyse | bettet eine eigene Matomo-Kopie ein, statt eine zentrale Instanz anzubinden | | PayOne | Zahlung | technisch geeignet, MIT-Lizenz; Mollie (GPLv2) passt besser zum GPL-Stack | !!! tip "ERP und PIM" Für ERP- und PIM-Anbindungen an WooCommerce bleibt mit strengen Open-Source-Vorgaben oft nur die eigene Entwicklung über die REST-API. Odoo und Pimcore bieten ihre WooCommerce-Konnektoren nur kostenpflichtig an. LibrePIM ist die Ausnahme, weil der Akeneo Connector frei ist. Wie es bei Shopware 6 und Mage-OS aussieht, ist noch nicht untersucht. ## Gemeinsame Muster Diese Erkenntnisse stammen aus dem Betrieb der WooCommerce-Instanz. **Reverse Proxy mit TLS.** Shop und Randsysteme laufen hinter einem Reverse Proxy (bei uns Traefik), der TLS terminiert. Die Anwendungen müssen dem Proxy vertrauen, sonst erzeugen sie `http://`-Adressen statt `https://`. Das betrifft Nextcloud (`OVERWRITEPROTOCOL`), Symfony-Anwendungen wie LibrePIM (`TRUSTED_PROXY_IPS`) und Matomo. **Basic-Auth auf Testinstanzen.** Sandboxen liegen hinter HTTP-Basic-Auth. Alles, was Server miteinander oder Besucher mit einem Tracker sprechen, braucht dann eine Ausnahme mit eigener Authentifizierung: die REST-API des Shops (`/wp-json`), die API von LibrePIM (`/api`), der Matomo-Tracker. Anwendungen mit viel Hintergrundverkehr wie Activepieces gehören gar nicht hinter Basic-Auth, sie bleiben sonst in einer Anmeldeschleife hängen. **Projekteigene Anpassungen als Must-Use-Plugin.** In WordPress liegen alle eigenen Anpassungen unter `wp-content/mu-plugins/`, nie im Code eines fremden Plugins. So überstehen sie jedes Update. --- # Glossar | Begriff | Beschreibung | | :--- | :--- | | **Activepieces** | Selbst gehostete Workflow-Automatisierung (MIT), Ersatz für n8n oder Zapier. Spricht den Shop über dessen REST-API und Webhooks an. | | **AI Content Generator for WooCommerce** | WordPress-Plugin (WebToffee) für KI-generierte Produkttexte. Trotz beworbener offener Connector-Architektur fest auf OpenAI, Google und Anthropic verdrahtet, siehe [KI-Produkttexte](https://ecommerce-hub.sh/developer-portal/woocommerce/ki/). | | **Akeneo Connector** | WordPress-Plugin (GPLv3), das WooCommerce mit LibrePIM bzw. dem Akeneo-Protokoll verbindet. Importiert nur, schreibt nichts zurück. | | **BFSG** | Barrierefreiheitsstärkungsgesetz. Gilt seit dem 28.06.2025 auch für den elektronischen Geschäftsverkehr, praktischer Maßstab ist WCAG 2.1 AA. | | **Complianz** | Cookie-Consent- und DSGVO-Plugin (GPLv2), ohne Cloud-Anbindung. | | **Connect Matomo (`wp-piwik`)** | WordPress-Plugin, das den Shop mit einer **externen** Matomo-Instanz verbindet. Nicht zu verwechseln mit „Matomo Analytics", das eine eigene Kopie einbettet. | | **Elasticsearch / ElasticPress** | Suchmaschine bzw. das WordPress-Plugin, das die Shopsuche statt über MySQL-Volltext über Elasticsearch abwickelt. | | **EU-Captcha** | Bot-Schutz der Myra Security GmbH, in Deutschland gehostet, DSGVO-konforme Alternative zu reCAPTCHA. | | **EU-Gewährleistungshinweis** | Harmonisierte Mitteilung der EU über das gesetzliche Gewährleistungsrecht (Durchführungsverordnung (EU) 2025/1960), die Shops mit Verbrauchern seit dem 27.09.2026 vor Vertragsschluss zeigen müssen. Bei WooCommerce über Germanized, siehe [Rechtliches](https://ecommerce-hub.sh/developer-portal/woocommerce/rechtliches/#gewaehrleistung). | | **EWWW Image Optimizer** | Bildoptimierung, die vollständig lokal arbeitet, ohne Clouddienst. | | **Germanized for WooCommerce** | Plugin (GPLv3), das WooCommerce um die in Deutschland vorgeschriebenen Funktionen ergänzt: Rechtstexte, Checkboxen, Grundpreise, Widerrufsbutton. | | **Konfigurations-Assistent** | Web-Assistent des OSPO-Projekts, der aus wenigen Fragen ein startfertiges Shop-Paket erzeugt, siehe [Konfigurations-Assistent](https://ecommerce-hub.sh/developer-portal/konfigurator/). | | **LibrePIM** | Aktiv gepflegter Fork von Akeneo Community Edition (OSL-3.0), seit Akeneo CE nicht mehr weiterentwickelt wird. | | **Matomo** | Selbst gehostete Web-Analyse (GPLv3) als Alternative zu Google Analytics. | | **Mollie** | Zahlungsdienstleister, WooCommerce-Plugin unter GPLv2. | | **mu-plugin** | Must-Use-Plugin: WordPress lädt alles unter `wp-content/mu-plugins/` automatisch, ohne Aktivierung und unabhängig von Plugin-Updates. | | **Nextcloud** | Selbst gehostete Plattform für Dateien, Kalender und Zusammenarbeit (AGPLv3). | | **Ollama** | Werkzeug zum lokalen Betrieb offener Sprachmodelle mit OpenAI-kompatibler API. | | **OSPO** | Das vom Land Schleswig-Holstein geförderte Projekt, in dem die Splendid Internet GmbH Open-Source-Stacks für den E-Commerce evaluiert. | | **`pre_http_request`** | WordPress-Filter, mit dem sich ausgehende HTTP-Anfragen abfangen und durch eine eigene Antwort ersetzen lassen. | | **Qwen3.6 35B-A3B** | Offenes Sprachmodell (Apache-2.0) mit Mixture-of-Experts-Aufbau: 35 Milliarden Parameter, 3 Milliarden davon pro Token aktiv. Dadurch auch ohne GPU nutzbar. | | **Randsystem** | Jedes System neben dem Shop, das eine Aufgabe übernimmt: Zahlung, Newsletter, PIM, Analyse, Automatisierung, Zusammenarbeit. | | **Storefront** | Offizielles Standard-Theme von WooCommerce (GPLv3). | | **Traefik** | Reverse Proxy, der für alle Container das Routing und die TLS-Terminierung übernimmt. | --- # Inhalte pflegen Das Portal entsteht aus Markdown-Dateien im GitLab-Repository `splendidinternet/ospo/devportal`. Jeder Push auf `main` baut die Seite mit [MkDocs](https://www.mkdocs.org/) und dem Theme [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) neu und stellt sie automatisch in die Vorschau. Live unter `ecommerce-hub.sh` geht ein Stand erst, wenn jemand den Job `deploy-live` der Pipeline von Hand startet. ``` docs/*.md bearbeiten ↓ git push origin main GitLab-Pipeline: Prüfungen, mkdocs build ↓ automatisch Vorschau: https://devportal.ospo.splendid-sandbox.de (mit Passwortschutz) ↓ von Hand: Job deploy-live https://ecommerce-hub.sh/developer-portal/ ``` ## Repository klonen Von außen über den öffentlichen Spiegel auf Codeberg, intern über unser GitLab: ```bash git clone https://codeberg.org/OSPO/OSPO-Developer-Portal.git # von außen git clone https://gitlab.splendid-dev.de/splendidinternet/ospo/devportal.git # intern ``` Wie Beiträge von außen ins Portal kommen, steht unter [Beiträge von außen](https://ecommerce-hub.sh/developer-portal/allgemein/inhalte-pflegen/#beitraege). ## Aufbau ``` devportal/ ├── mkdocs.yml Konfiguration und Navigation, baut die Vorschau ├── mkdocs-live.yml Abweichungen für ecommerce-hub.sh ├── hooks/ Markdown für „Seite kopieren“, Prüfdatum, llms.txt ├── overrides/ Ergänzungen am Theme, Navigation und Footer des Hubs ├── tools/ Prüfungen für die Pipeline └── docs/ ├── index.md Startseite ├── allgemein/ Architektur, Glossar, diese Anleitung ├── konfigurator/ Konfigurations-Assistent ├── woocommerce/ je Thema eine Seite ├── shopware/ └── mageos/ ``` ## Neue Seite anlegen 1. Markdown-Datei unter `docs/` anlegen, zum Beispiel `docs/shopware/api.md`. 2. In `mkdocs.yml` unter `nav:` eintragen. Seiten, die dort fehlen, erscheinen nicht im Menü. ```yaml nav: - Shopware: - Übersicht: shopware/index.md - API: shopware/api.md ``` 3. Committen und pushen, die Pipeline stellt den Stand in die Vorschau: ```bash git add . git commit -m "Add Shopware API docs" git push ``` Interne Links immer relativ auf die Markdown-Datei setzen (`[Betrieb](../woocommerce/betrieb.md)`), nicht auf die fertige URL. MkDocs rechnet sie um und meldet beim Bauen, wenn ein Ziel fehlt. ## Lokal ansehen ```bash python3 -m venv .venv .venv/bin/pip install -r requirements.txt .venv/bin/mkdocs serve # → http://127.0.0.1:8000, Änderungen erscheinen sofort ``` `requirements.txt` legt die Versionen fest, mit denen auch die Pipeline baut. Wer aktualisieren will, ändert sie dort. MkDocs bleibt auf 1.x: Material verlangt `mkdocs<2`, und MkDocs 2.0 schafft das System für Plugins und Theme-Anpassungen ab. Die Pipeline baut mit `--strict`. Ein toter interner Link oder ein fehlender Anker bricht den Build ab, statt eine fehlerhafte Seite zu veröffentlichen. Lokal prüft man das genauso mit `.venv/bin/mkdocs build --strict`. ## Automatische Prüfungen Vor dem Veröffentlichen laufen in der Pipeline vier Prüfungen, auch bei Merge Requests: | Prüfung | Was sie findet | Bei einem Treffer | | :--- | :--- | :--- | | `mkdocs build --strict` | tote interne Links, Seiten außerhalb der Navigation, Fehler in der Prüfangabe | nichts wird veröffentlicht | | `tools/vollstaendig_pruefen.py` | Seiten, auf denen nach dem Bauen Abschnitte fehlen. Python-Markdown hält etwa `<` vor einem Buchstaben für ein HTML-Tag, auch in Backticks, und verschluckt dann den Rest der Seite | nichts wird veröffentlicht | | `tools/inhalt_pruefen.py` | Zugangsdaten, Schlüssel und Tokens, Server-Adressen, SSH-Ports, interne Pfade, HTML außerhalb von Code sowie Links auf `javascript:` und `data:` | nichts wird veröffentlicht | | `tools/links_pruefen.py` | externe Links, die ins Leere führen (`404`, `410`, Serverfehler, keine Verbindung) | nur eine Warnung, weil fremde Seiten auch einmal ausfallen | Lokal laufen sie genauso: ```bash .venv/bin/mkdocs build --strict python3 tools/vollstaendig_pruefen.py docs site python3 tools/inhalt_pruefen.py docs python3 tools/links_pruefen.py site ``` Die Inhaltsprüfung kennt keine Ausnahmen. Für Beispiele deshalb Adressen nehmen, die dafür reserviert sind: `example.org` und seine Subdomains, `127.0.0.1` und für IP-Adressen die Bereiche `192.0.2.0/24`, `198.51.100.0/24` und `203.0.113.0/24`. Namen von Kunden findet sie nicht, darauf bleibt beim Schreiben selbst zu achten. Eingebettetes HTML ist gesperrt, weil Markdown es unverändert in die Seite übernimmt: Ein Beitrag könnte sonst ein Skript mitbringen, das nach dem Zusammenführen bei jedem Besucher läuft. HTML-Beispiele gehören deshalb in Backticks oder einen Codeblock. Automatische Links wie `` sind erlaubt. ## Geprüft am Eine Seite kann angeben, wann sie zuletzt gegen eine laufende Instanz geprüft wurde und mit welchen Versionen. Das Datum steht dann oben rechts neben „Seite kopieren“, die Versionen im Tooltip und in der kopierten Fassung unter dem Titel. ```markdown --- geprueft: am: 2026-10-08 mit: WordPress 7.1.3, WooCommerce 11.2.0 und PHP 8.4.26 --- # WooCommerce ``` Davon getrennt steht unter dem Titel jeder Seite klein „Zuletzt geändert am …“. Das Datum kommt aus dem letzten Commit an der Markdown-Datei (`hooks/geaendert.py`) und zieht bei jeder Änderung von selbst nach, auch wenn nur ein Satz dazukommt. Es sagt also nichts darüber, ob die Seite geprüft ist. Das Prüfdatum nur setzen, wenn die Aussagen der Seite wirklich an einer laufenden Instanz nachvollzogen sind, und dabei `mit` auf die Versionen bringen, die dort liefen. Wer eine Seite nur umformuliert, lässt die Angabe stehen, wie sie ist. Eine unvollständige Angabe, etwa ohne `mit`, bricht den Build ab. ## Was hier hingehört und was nicht Das Portal richtet sich an Entwicklerinnen und Entwickler, auch außerhalb von Splendid, und ist öffentlich. Deshalb: - **Hinein:** Aufbau, Entscheidungen mit Begründung, Fallstricke, wiederverwendbare Lösungen. - **Nicht hinein:** Zugangsdaten, Server-Adressen und SSH-Ports, interne Pfade einzelner Instanzen, Namen von Kunden. Das gehört in die Projektdoku des jeweiligen Repositories. ## Beiträge von außen Führend ist das interne Repository. Die Pipeline spiegelt jeden Stand von `main` nach dem Deploy in die Vorschau auf [Codeberg](https://codeberg.org/OSPO/OSPO-Developer-Portal), mit eigener Historie und ohne Pipeline und Spiegel-Skript. Wie Externe beitragen, beschreibt dort die `CONTRIBUTING.md`. Unter jeder Seite stehen dafür diese Wege, auf der Startseite nur die beiden für neue Seiten: | Weg | Wer | Wo es landet | | :--- | :--- | :--- | | „Feedback geben“ | alle, ohne Konto | vertrauliches Issue mit dem Label `Feedback` im internen Repository | | „Auf Codeberg bearbeiten“ | mit Codeberg-Konto | Pull Request auf Codeberg | | „Als Issue melden“ | mit Codeberg-Konto | öffentliches Issue auf Codeberg | | „Neue Seite vorschlagen“ | alle, ohne Konto | vertrauliches Issue mit dem Label `Seitenvorschlag` im internen Repository | | „Auf Codeberg schreiben“ | mit Codeberg-Konto | neue Datei im Bereich der aktuellen Seite, als Pull Request auf Codeberg | „Auf Codeberg bearbeiten“ und „Auf Codeberg schreiben“ führen auf die Ansicht der Datei beziehungsweise des Ordners, nicht in den Editor. Den Editor öffnet Codeberg nur für Mitglieder der Organisation, alle anderen bekommen dort eine 404. Externe forken deshalb zuerst, ändern in ihrer Kopie und stellen von dort den Pull Request. Mitglied der Organisation muss dafür niemand sein. Bei einer neuen Seite den Eintrag unter `nav:` in `mkdocs.yml` beim Übernehmen ergänzen, falls er fehlt, sonst bricht der strikte Build ab. **Beide Formulare** senden an den Activepieces-Flow „Developer Portal: Feedback“, dessen Adresse in `mkdocs.yml` unter `extra.feedback_url` steht. Der Flow unterscheidet sie am Feld `art` (`hinweis` oder `seite`), prüft die Angaben (Länge, Thema, Köderfeld, Mindestdauer, nur Seiten des Portals) und legt das Issue mit einem Projekt-Token an, das nur Issues anlegen darf. Vertraulich ist es, weil eine E-Mail-Adresse darin stehen kann. Das Token läuft nach einem Jahr ab. Danach meldet das Formular einen Fehler, bis ein neues Token im Flow eingetragen ist. **Pull Requests kommen automatisch herüber:** 1. Codeberg meldet jeden neuen oder aktualisierten Pull Request über einen Webhook an den Pipeline-Trigger dieses Projekts. 2. Der Job `codeberg-pr` (`tools/codeberg_pr.py`) übernimmt ihn mit `git am` auf einen Zweig `codeberg/pr-`. Die Commits behalten ihre Autorin oder ihren Autor, fehlende Navigationseinträge für neue Seiten ergänzt der Job selbst. Dann öffnet er einen Merge Request mit dem Label `Codeberg`. 3. Auf dem Merge Request laufen die Prüfungen. Zusammenführen geht nur, wenn sie grün sind. 4. Nach dem Zusammenführen stellt die Pipeline den Stand in die Vorschau, und der Spiegel schreibt ihn nach Codeberg, mit der Autorin des Beitrags. Dann markiert er den Pull Request dort als zusammengeführt und bedankt sich im Kommentar. Wird der Pull Request auf Codeberg ohne Übernahme geschlossen, schließt der Job auch den Merge Request. **Nur Markdown unter `docs/` geht automatisch.** Die Pipeline eines Merge Requests läuft mit dem Inhalt seines Zweigs. Ein Beitrag, der Hooks, Skripte, die Pipeline oder `mkdocs.yml` ändert, würde fremden Code auf unserem Runner ausführen. Für solche Pull Requests legt der Job stattdessen ein Issue „braucht Handprüfung“ an. Übernehmen lässt er sich dann von Hand: ```bash curl -sL https://codeberg.org/OSPO/OSPO-Developer-Portal/pulls/.patch | git am git push origin main ``` Danach im Pull Request „Als manuell zusammengeführt markieren“ wählen und den Commit aus dem Spiegel angeben. Live geht ein übernommener Beitrag wie jede andere Änderung erst mit dem Job `deploy-live`. **Was dafür eingerichtet ist:** ein Webhook auf Codeberg mit dem Pipeline-Trigger-Token dieses Projekts, die CI-Variable `GITLAB_PR_TOKEN` (Projekt-Token, Rolle Developer, Bereiche `api` und `write_repository`) und die CI-Variable `CODEBERG_TOKEN` (Codeberg-Token mit Schreibrecht für Repository und Issues). Beide Tokens laufen nach spätestens einem Jahr ab. !!! warning "Auf Codeberg nicht zusammenführen" Der Spiegel legt bei jedem Lauf den internen Stand ab. Was nur auf Codeberg zusammengeführt würde, wäre nach dem nächsten Lauf wieder verschwunden. Deshalb ist dort als einzige Art „Manually merged“ erlaubt. ## Anker für den Konfigurations-Assistenten Der Assistent verlinkt auf das Portal. Die Abschnitte der Seite [Konfigurations-Assistent](https://ecommerce-hub.sh/developer-portal/konfigurator/) tragen deshalb feste Anker, die den Schritt-Schlüsseln im Assistenten entsprechen, etwa `#modell` oder `#stammdaten`. Diese Anker beim Überarbeiten bitte nicht umbenennen. Gesetzt werden sie so: ```markdown ## Geschäftsmodell {#modell} ``` ## Markdown-Hilfen Code mit Hervorhebung: ````markdown ```php # Konfigurations-Assistent > Geprüft am 08.10.2026 mit dem Konfigurator-Stand 175fc24 und einem WooCommerce-Paket auf PHP 8.4. Der Konfigurations-Assistent führt in elf Schritten zu einem **startfertigen Shop-Paket**: einem ZIP-Archiv mit Docker-Compose-Datei, vorbereiteter Umgebung und einem Einrichtungsskript. Wer das Paket auf einem Rechner mit Docker auspackt und zwei Befehle ausführt, hat einen eingerichteten Shop samt der gewählten Randsysteme. Der Assistent öffnet sich auf dem E-Commerce Hub unter im Modal. Der Quellcode liegt in GitLab unter `splendidinternet/ospo/konfigurator` (Symfony). !!! info "Was der Assistent nicht speichert" Auf dem Server wird nichts abgelegt und es wird kein Cookie gesetzt. Die Auswahl liegt nur im Browser (`localStorage`) und wird nach dem Download, bei „Neu beginnen" oder beim nächsten Aufruf der Startseite gelöscht, spätestens nach 24 Stunden. Zugangsdaten fragt der Assistent grundsätzlich nicht ab. ## Die Schritte ### Geschäftsmodell B2C, B2B oder beides. Die Auswahl bestimmt, welche Shopsysteme im nächsten Schritt wählbar sind. WooCommerce wird nur für B2C angeboten: Im freien Standard fehlen Staffelpreise, Kundengruppen und ein Feld für die Umsatzsteuer-ID, die Voraussetzung für Reverse Charge ist. ### Shopsystem WooCommerce, Shopware 6 oder Mage-OS. Ein System, das noch nicht ausgeliefert werden kann, steht mit „Bald verfügbar" in der Liste, lässt sich aber noch nicht wählen. Der Grund steht sichtbar auf der Karte. Derzeit ist auf ecommerce-hub.sh nur WooCommerce wählbar: Mage-OS lässt sich noch nicht ausliefern, und Shopware 6 ist nur in unserer internen Testumgebung wählbar, solange die Auslieferung entsteht. ### Aussehen und Inhalte - **Theme:** bei WooCommerce Storefront, das offizielle Shop-Theme, oder das mitgelieferte WordPress-Theme. - **Sortimentsgröße:** bis 100, bis 1.000, bis 10.000 oder mehr als 10.000 Produkte. Davon hängt ab, welche Erweiterungen im nächsten Schritt empfohlen werden. - **Beispielprodukte:** auf Wunsch werden Demo-Produkte importiert, um den Shop auszuprobieren. Der Import läuft nur, solange der Shop noch leer ist. ### Erweiterungen Die rechtlich nötigen Grundbausteine sind immer dabei, bei WooCommerce sind das WooCommerce selbst, Germanized und die eigene Erweiterung „Gewährleistungshinweis“ (`ospo-gewaehrleistung`). `setup.sh` schaltet in Germanized den seit 27.09.2026 vorgeschriebenen EU-Gewährleistungshinweis ein, ab Werk ist er aus. Die Erweiterung macht ihn mit jedem Theme barrierefrei und zeigt ihn auch auf Kategorie- und Suchseiten, Einzelheiten unter [Rechtliches mit Germanized](https://ecommerce-hub.sh/developer-portal/woocommerce/rechtliches/#gewaehrleistung). Dazu kommen wählbare Erweiterungen, die empfohlenen sind vorausgewählt: | Erweiterung | Zweck | Empfohlen | | :--- | :--- | :--- | | Yoast SEO | Suchmaschinenoptimierung | ja | | Complianz | Cookie-Einwilligung, DSGVO | ja | | WP Mail SMTP | zuverlässiger Mailversand über einen SMTP-Dienst | ja | | EU-Captcha | Spamschutz, Hosting in Deutschland | ja | | Two Factor | Zwei-Faktor-Anmeldung | ja | | Contact Form 7 | Kontaktformulare | | | EWWW Image Optimizer | lokale Bildoptimierung | | | ElasticPress | schnelle Suche über Elasticsearch | ab 10.000 Produkten | | KI-Produkttexte | Produkttexte per KI | | Wer bei einem großen Sortiment die Suche abwählt, bekommt auf der Abschlussseite einen Hinweis, mit dem sie sich per Klick nachtragen lässt. Begründungen zu den einzelnen Erweiterungen stehen unter [WooCommerce: Erweiterungen](https://ecommerce-hub.sh/developer-portal/woocommerce/erweiterungen/). **Aktualisierung.** Unter den Erweiterungen steht die Karte „Automatisch aktualisieren“, vorausgewählt und als empfohlen markiert. Sie erscheint nur bei Shopsystemen, deren Katalog dafür Befehle mitbringt, derzeit bei WooCommerce. Mit Haken schaltet `setup.sh` ganz am Ende, wenn auch die Erweiterungen der Randsysteme installiert sind, die automatischen Updates für WordPress, alle Erweiterungen und alle Themes ein. Ohne Haken setzt es `auto_update_core_major` ausdrücklich auf `disabled`, denn WordPress schaltet das bei der Installation selbst ein. Dann kommen nur die Sicherheitsupdates des Kerns automatisch, alles andere aktualisiert der Händler im Backend. Die Wahl steht als `automatische_updates` in der `konfiguration.json`; fehlt der Schlüssel, etwa in älteren Dateien, gilt der Haken als gesetzt. **Erweiterungen, die nicht aus dem WordPress-Verzeichnis kommen.** Zwei Erweiterungen installiert `setup.sh` aus einer Datei statt aus dem Verzeichnis: EU-Captcha, das dort nicht steht, und die eigene Pflicht-Erweiterung „Gewährleistungshinweis“ (`ospo-gewaehrleistung`). EU-Captcha holt `setup.sh` beim Einrichten direkt bei Myra Security, aus dem fertigen ZIP im GitHub-Repository des Herstellers (`Myra-Security-GmbH/eu-captcha-wordpress`, Zweig `main`). Jeder neue Shop bekommt damit die neueste Fassung. Das ist bewusst so gewählt: immer aktuell, dafür ohne Prüfung durch uns. Scheitert der Download, etwa ohne Netz, installiert `setup.sh` die Fassung, die im Paket unter `plugins/` liegt. Der Gewährleistungshinweis kommt immer aus dem Paket. Für beide kennt WordPress keine Update-Quelle. Sie melden nie eine neue Fassung und aktualisieren sich auch mit Haken bei „Automatisch aktualisieren“ nicht. Die Karte sagt das, die `README.md` im Paket nennt beide mit der Anleitung: neue Fassung als ZIP-Datei im Backend unter `Plugins` → `Neues Plugin hinzufügen` → `Plugin hochladen` einspielen. Die `AGENTS.md` nennt den Befehl dafür, mit einer ZIP-Datei oder einer URL: ```bash wp plugin install https://raw.githubusercontent.com/Myra-Security-GmbH/eu-captcha-wordpress/main/eu-captcha.zip --force ``` ### Zahlungsanbieter Mollie wird an der Kasse eingebunden. Die API-Schlüssel trägt der Händler selbst in die `.env` ein. ### Newsletter Das Newsletter-Plugin läuft im Shop selbst. Für eine verlässliche Zustellung sollte der Shop über einen SMTP-Dienst versenden (WP Mail SMTP). ### Ihr Shop Öffentliche Angaben, wie sie später im Impressum stehen: Shopname, Domain, Firma, Anschrift, Land (derzeit nur Deutschland), Währung (Euro), Kleinunternehmerregelung nach § 19 UStG, Teilnahme an Verbraucherstreitbeilegung und die Preisauszeichnung. Bei der Preisauszeichnung gibt es zwei Vorlagen statt Einzelfragen: „Standard" zeigt alle Pflichtangaben, „Minimal" nur das gesetzliche Minimum. Germanized kennt rund 280 Einzeloptionen dafür, siehe [Rechtliches mit Germanized](https://ecommerce-hub.sh/developer-portal/woocommerce/rechtliches/). Aus der Domain schlägt der Assistent in den folgenden Schritten die Adressen der Randsysteme vor, deshalb kommt „Ihr Shop“ vor ihnen. Wer keine weiteren Randsysteme braucht, nimmt statt „Weiter“ den zweiten Knopf **„Ohne weitere Randsysteme fertigstellen“**. Er prüft die Angaben wie „Weiter“, verwirft eine Auswahl in den späteren Schritten Produktdaten, Web-Analyse, Automatisierung und Zusammenarbeit und führt direkt zum Abschluss. Zahlungsanbieter und Newsletter kommen davor und bleiben erhalten. Mit der Eingabetaste geht es weiter wie bisher. ### Produktdaten LibrePIM als zentrale Quelle für Produktdaten. Sinnvoll, sobald Produkte in mehreren Kanälen oder Sprachen gepflegt werden. Wählbar ist derzeit nur, eine bestehende Instanz anzubinden, mit einer vorgeschlagenen Adresse wie bei den übrigen Randsystemen (siehe [unten](https://ecommerce-hub.sh/developer-portal/konfigurator/#adressen)). „Mitinstallieren“ steht als „Bald verfügbar“ da, weil es noch kein Docker-Image gibt, das den Code von LibrePIM enthält. Das verfügbare Image ist eine reine Entwicklungsumgebung, im Paket startete der Container ohne Code immer wieder neu. Hintergründe zur Anbindung unter [Randsysteme anbinden](https://ecommerce-hub.sh/developer-portal/woocommerce/randsysteme/#librepim). ### Web-Analyse Matomo, selbst gehostet, als Ersatz für Google Analytics. Siehe [Randsysteme anbinden](https://ecommerce-hub.sh/developer-portal/woocommerce/randsysteme/#matomo). **Mitinstalliert** kommt Matomo fertig eingerichtet, ohne Installationsassistent. Der Einmal-Dienst `matomo-einrichtung` läuft vor `setup.sh` und legt den Administrator aus `MATOMO_ADMIN_USER` und `MATOMO_ADMIN_PASSWORD` an, den Shop als E-Commerce-Website und den Token, mit dem sich der Shop anmeldet. Man meldet sich also direkt mit den Angaben aus der `.env` an. Das Image steht fest auf `matomo:5`, weil die Einrichtung Matomos interne Klassen nutzt wie der Installationsassistent. Gezählt wird über den Shop selbst: Der Browser schickt die Besuche an den Shop, WordPress reicht sie intern an Matomo weiter, ohne Cookies. Matomo muss dafür für Besucher nicht öffentlich erreichbar sein. `MATOMO_URL_OEFFENTLICH` ist nur die Adresse, unter der man Matomo selbst im Browser aufruft. Sie kommt aus dem Adressfeld des Schritts. **Anbinden** fragt die Adresse und die Website-ID ab. Den Token legt man in der vorhandenen Instanz an und trägt ihn in die `.env` ein. ### Automatisierung Activepieces verbindet Shop und Randsysteme ohne Programmierung, als selbst gehostete Alternative zu Zapier oder n8n. Siehe [Randsysteme anbinden](https://ecommerce-hub.sh/developer-portal/woocommerce/randsysteme/#activepieces). **Mitinstalliert** legt `setup.sh` den ersten Benutzer an. Man meldet sich mit `ADMIN_EMAIL` und `ACTIVEPIECES_ADMIN_PASSWORD` aus der `.env` an, eine Registrierung entfällt. Danach lässt Activepieces neue Benutzer nur noch per Einladung zu. Den Schlüssel für die REST-API des Shops legt man weiter selbst an, damit er nicht im Klartext in der Konfiguration landet. ### Zusammenarbeit Nextcloud als Plattform für Dateien, Kalender und Teamarbeit. Nextcloud ist nicht mit dem Shop gekoppelt, sondern steht dem Team als Arbeitsumgebung zur Verfügung. **Mitinstalliert** richtet sich Nextcloud beim ersten Start selbst ein, ohne Assistenten. Man meldet sich mit `NEXTCLOUD_ADMIN_USER` und `NEXTCLOUD_ADMIN_PASSWORD` aus der `.env` an. `NEXTCLOUD_TRUSTED_DOMAINS` bekommt den Hostnamen aus dem Adressfeld des Schritts. Die Liste wirkt nur beim ersten Start, danach lässt sie sich nur noch in Nextcloud selbst ändern. ### Abschluss und Download Die Abschlussseite fasst die Auswahl zusammen, nennt die nötige Hardware und listet die Dateien im Paket. Von hier aus gibt es das ZIP und die Datei `konfiguration.json`. ## Randsysteme: mitinstallieren oder verbinden Für jedes Randsystem gibt es bis zu drei Möglichkeiten: | Modus | Was passiert | | :--- | :--- | | **Installieren** | Das System kommt als eigene Container ins Paket, die Zugangsdaten werden beim Download frisch erzeugt. Matomo, Activepieces und Nextcloud sind nach der Einrichtung fertig eingerichtet, ohne Installationsassistent und ohne Registrierung. | | **Verbinden** | Ein vorhandenes System wird angebunden. Abgefragt werden nur nicht geheime Angaben wie die URL, Geheimnisse trägt man selbst in die `.env` ein. | | **Keines** | Das System taucht im Paket nicht auf, auch kein Plugin im Shop. | Ein Modus, der noch nicht funktioniert, steht ausgegraut mit „Bald verfügbar“ da und lässt sich nicht wählen, derzeit „Mitinstallieren“ bei LibrePIM. ### Adressen der Randsysteme Jedes Randsystem, das mitinstalliert oder angebunden wird, hat ein Adressfeld. Darunter steht ein Vorschlag aus der Domain des Schritts „Ihr Shop“, den man mit „Übernehmen“ einträgt oder im Feld ändert: | System | Vorschlag | | :--- | :--- | | LibrePIM | `https://librepim.example.org`, nur beim Anbinden | | Matomo | `https://matomo.example.org` | | Activepieces | `https://activepieces.example.org` | | Nextcloud | `https://nextcloud.example.org` | Steht vor der Domain `www.` oder `shop.`, fällt das für den Vorschlag weg: Aus `shop.example.org` wird `https://matomo.example.org`. Der Server prüft jede Adresse, beim Schritt und noch einmal beim Download. Feste `localhost`-Adressen gibt es im Assistenten und in der `.env` nicht mehr. !!! warning "Erprobt ist bisher nur WooCommerce" Der Assistent bietet die Randsysteme auch für Shopware 6 und Mage-OS an. Aufgebaut und getestet ist die Anbindung aber bisher nur mit WooCommerce. Für die beiden anderen Shopsysteme läuft die Evaluierung noch, siehe [Architektur und Grundsätze](https://ecommerce-hub.sh/developer-portal/allgemein/). ## Das Paket | Datei | Inhalt | | :--- | :--- | | `docker-compose.yml` | alle Dienste: Shop, Datenbank, gewählte Randsysteme, Einrichtungsdienst | | `.env` | Ports, Adressen für den Server und Zugangsdaten. Was sich erzeugen lässt, ist bereits erzeugt; was nur der Händler kennt, bleibt leer und ist beschriftet. | | `.env.local` | nur die Adressen auf `localhost` mit den Ports aus der `.env`, zum Ausprobieren auf dem eigenen Rechner | | `setup.sh` | richtet den Shop ein: Installation, Sprache, Erweiterungen, Rechtsseiten, Stammdaten, Anbindung der Randsysteme. Lässt sich gefahrlos wiederholen. | | `README.md` | Anleitung für Menschen | | `AGENTS.md` | Anleitung für KI-Werkzeuge, die das Paket selbstständig aufsetzen sollen | | `konfiguration.json` | die Auswahl selbst, maschinenlesbar | | `plugins/` | Erweiterungen, die es nicht im WordPress-Verzeichnis gibt | | Beilagen | Skripte, mit denen sich mitinstallierte Randsysteme einrichten, etwa `matomo-einrichten.php` und `activepieces-einrichten.php` | ### Paket starten Ein Paket lässt sich auf zwei Wegen starten, ohne etwas umzuschreiben: auf dem eigenen Rechner zum Ausprobieren oder auf dem Server. Die `.env` enthält die Adressen für den Server, abgeleitet aus der Domain und den Adressfeldern im Assistenten. Die `.env.local` ersetzt beim Ausprobieren nur diese Adressen durch `http://localhost` mit den Ports aus der `.env`. Zugangsdaten stehen nur in der `.env`, die beiden Dateien können also nicht auseinanderlaufen. In beiden Fällen zuerst das Archiv auspacken und in der `.env` mindestens `ADMIN_EMAIL` eintragen. **Auf dem eigenen Rechner ausprobieren.** Beide Dateien laden und einen eigenen Projektnamen setzen. Der Name besteht aus dem Shopnamen und `-test`, im README des Pakets steht er fertig im Befehl: ```bash docker compose --env-file .env --env-file .env.local -p meinshop-test up -d docker compose --env-file .env --env-file .env.local -p meinshop-test --profile setup run --rm wpcli ``` Der eigene Projektname ist Pflicht. WordPress und Matomo schreiben ihre Adresse bei der Einrichtung in die Datenbank, ein Test unter `localhost` wäre sonst im Betrieb nicht mehr loszuwerden. So bekommt er eigene Volumes und ist hinterher spurlos weg: ```bash docker compose -p meinshop-test down -v ``` Damit auch die Einrichtungsdienste die lokale Datei lesen, steht in der `docker-compose.yml` bei ihnen `env_file: [.env, '${ENV_LOCAL:-.env}']`, und die `.env.local` setzt `ENV_LOCAL`. Ein solcher Test gehört nicht ins offene Netz: Es gibt keine Verschlüsselung, und die Rechtstexte sind Platzhalter. **Auf dem Server betreiben.** Ohne `.env.local`: 1. Für die Shop-Adresse (`SITE_URL`) und jede Adresse eines Randsystems einen DNS-Eintrag auf den Server setzen. Das README des Pakets listet sie einzeln auf. 2. `HTTP_PORT` und die übrigen Ports auf freie Werte setzen. 3. Starten und einmalig einrichten: ```bash docker compose up -d docker compose --profile setup run --rm wpcli ``` 4. Einen Reverse Proxy mit TLS davorsetzen, etwa Traefik, Caddy oder nginx. Er leitet jede Adresse auf den Port ihres Dienstes auf `127.0.0.1` weiter, die Zuordnung steht ebenfalls im README des Pakets. Der Name des Einrichtungsdienstes (`wpcli` bei WooCommerce) steht im README des Pakets. Die `AGENTS.md` beschreibt dieselben zwei Wege für KI-Werkzeuge und fragt zuerst, welcher gemeint ist. Danach ist die Verwaltung unter der Shop-Adresse plus `/wp-admin` erreichbar, Benutzer `admin`, das Passwort steht in der `.env`. Dort stehen auch die Zugänge der mitinstallierten Randsysteme. Der Shop ist zunächst für Besucher gesperrt. Das ist Absicht: Impressum, AGB, Datenschutzerklärung und Widerrufsbelehrung sind als Entwürfe mit Platzhaltern angelegt und müssen vor dem Livegang ergänzt und rechtlich geprüft werden. ### Randsysteme erreichen Auf dem Server sind die Randsysteme unter ihren Adressen aus der `.env` erreichbar, sobald DNS und Reverse Proxy stehen. Beim Ausprobieren gelten die Ports, die Voreinstellungen stehen in der `.env`: | System | Port beim Ausprobieren | | :--- | :--- | | Shop | 8090 (`HTTP_PORT`) | | Matomo | 8081 (`MATOMO_PORT`) | | Activepieces | 8083 (`ACTIVEPIECES_PORT`) | | Nextcloud | 8084 (`NEXTCLOUD_PORT`) | Ändert man einen Port in der `.env`, zieht die `.env.local` mit, weil sie die Adressen aus den Port-Werten bildet. Die Adressen fürs Ausprobieren stehen im README des Pakets. !!! warning "Ports nicht direkt ins Netz" Docker veröffentlicht Ports standardmäßig auf allen Schnittstellen und umgeht dabei Firewalls wie `ufw`. Auf einem Server die Ports per Firewall vor dem Rechner sperren oder in der `docker-compose.yml` an `127.0.0.1` binden (`127.0.0.1:8081:80`), damit nur der Reverse Proxy sie erreicht. ## Eine Konfiguration weitergeben Die `konfiguration.json` aus einem früheren Download lässt sich am Anfang des Assistenten oder auf der Abschlussseite wieder hochladen. Übernommen wird nur, was der Katalog kennt. Unbekannte Systeme, Erweiterungen oder Felder fallen stillschweigend weg, eingelesene Werte landen nie ungeprüft in einem Shell-Befehl. ## Den Assistenten erweitern Die Auswahl steckt nicht im PHP-Code, sondern in einem Katalog: eine YAML-Datei je System unter `config/katalog/`. Eine Datei beschreibt, was das System im Paket ausmacht: - Bezeichnung, Beschreibung, Kategorie und für welche Shopsysteme es passt, - je Modus die Container (`compose`), die Umgebungsvariablen (`env`, erzeugt, vorgegeben oder geheim) und die abgefragten Felder, - die Einrichtungsbefehle je Shopsystem (`setup`), die in die `setup.sh` übernommen werden, - Beilagen, die mit ins Paket gehen (`beilagen`), und Dienste, auf die `setup.sh` warten muss (`einrichtung_wartet_auf`), etwa der Einmal-Dienst von Matomo, - Adressen: `vorschlag` gibt den Namen der vorgeschlagenen Subdomain vor, `lokal` den Wert für die `.env.local`, `nur_host` macht aus der Adresse einen reinen Hostnamen wie bei `NEXTCLOUD_TRUSTED_DOMAINS`, - Sperren: `gesperrt` an einem Modus zeigt ihn als „Bald verfügbar“, `nur_sandbox` an einem Shopsystem lässt es nur in der internen Testumgebung wählen. Beides prüft auch der Server, bis zum Download. Ein neues Randsystem heißt also: eine neue YAML-Datei. Nur eine neue **Kategorie** braucht zusätzlich eine Zeile in `src/Configurator/StepRegistry.php`. ## Barrierefreiheit Der Assistent folgt dem BFSG, also WCAG 2.1 AA: vollständig per Tastatur bedienbar, Auswahlkarten mit sichtbarem Fokus, Hinweise nicht nur beim Überfahren mit der Maus. Das Repository enthält dafür eine automatische Prüfung (`tests/barrierefrei_pruefen.py`). --- # WooCommerce > Geprüft am 08.10.2026 mit WordPress 7.1.3, WooCommerce 11.2.0, PHP 8.4.26, MariaDB 11.8.8, Elasticsearch 7.17.24 und Storefront 4.6.2. Der WooCommerce-Stack ist im OSPO-Projekt am weitesten ausgebaut. Er dient als Referenzinstanz: Hier wurden Plugins und Randsysteme ausprobiert, angebunden und bewertet, bevor sie in den [Konfigurations-Assistenten](https://ecommerce-hub.sh/developer-portal/konfigurator/) übernommen wurden. ## Stack | Komponente | Version | Woher die Version kommt | Zweck | | :--- | :--- | :--- | :--- | | WordPress | jeweils aktuell | automatische Updates auf der Sandbox, Aktualisierung beim Einrichten eines Pakets, danach nach Wahl im Assistenten | CMS | | WooCommerce und Erweiterungen | jeweils aktuell | ebenso; Sprünge über eine Hauptversion lässt WooCommerce nicht automatisch zu, siehe [Betrieb](https://ecommerce-hub.sh/developer-portal/woocommerce/betrieb/#wp-cron) | Shopfunktionen | | PHP | 8.4.x | fest über den Image-Tag `php8.4`, Patches kommen mit dem Image. 8.4 ist die neueste Version, gegen die WooCommerce getestet ist | Laufzeit, mit Apache | | MariaDB | 11.x | Image `mariadb:11`, immer die neueste 11er-Version | Datenbank | | Elasticsearch | 7.17.24 | exakt festgelegt | Suche über ElasticPress | | Storefront | jeweils aktuell | wie die Erweiterungen; auf der Sandbox ergänzt um das Child Theme `ospo-storefront` | Theme | !!! note "Pakete aus dem Konfigurations-Assistenten" Beim Einrichten holt `setup.sh` die neuesten Versionen von WordPress, WooCommerce, allen Erweiterungen, Themes und Übersetzungen. Ob das Paket danach weiter von selbst aktualisiert, entscheidet der Interessent im Schritt [Erweiterungen](https://ecommerce-hub.sh/developer-portal/konfigurator/#plugins) mit der Karte „Automatisch aktualisieren“, die vorausgewählt ist. Mit Haken schaltet `setup.sh` am Ende die automatischen Updates für WordPress, Erweiterungen und Themes ein, ohne Haken laufen nur die Sicherheitsupdates des Kerns. Was dafür auf dem Server nötig ist, steht unter [Betrieb](https://ecommerce-hub.sh/developer-portal/woocommerce/betrieb/#wp-cron). Ausnahmen sind EU-Captcha und der Gewährleistungshinweis: Sie stehen nicht im WordPress-Verzeichnis. EU-Captcha holt `setup.sh` beim Einrichten in der neuesten Fassung direkt bei Myra, der Gewährleistungshinweis kommt aus dem Paket. Automatisch aktualisieren sich beide danach nicht, siehe [Erweiterungen](https://ecommerce-hub.sh/developer-portal/konfigurator/#plugins). Alles läuft als Docker-Container hinter einem Reverse Proxy, der TLS terminiert. Das eigene Image erweitert `wordpress:php8.4-apache` nur um WP-CLI und die Werkzeuge für die lokale Bildoptimierung (`jpegoptim`, `optipng`, `gifsicle`, `pngquant`, `webp`). | Container | Image | Aufgabe | | :--- | :--- | :--- | | `web` | eigenes Image auf Basis `wordpress:php8.4-apache` | WordPress, PHP, Apache | | `db` | `mariadb:11` | Datenbank | | `elasticsearch` | `docker.elastic.co/elasticsearch/elasticsearch:7.17.24` | Suchindex | ## Themen | Seite | Worum es geht | | :--- | :--- | | [Erweiterungen](https://ecommerce-hub.sh/developer-portal/woocommerce/erweiterungen/) | welche Plugins im Einsatz sind, mit Lizenz und Begründung, und welche verworfen wurden | | [Rechtliches mit Germanized](https://ecommerce-hub.sh/developer-portal/woocommerce/rechtliches/) | Rechtstexte, Checkboxen, Widerrufsbutton, Einstellungs-Referenz | | [Randsysteme anbinden](https://ecommerce-hub.sh/developer-portal/woocommerce/randsysteme/) | Matomo, LibrePIM, Activepieces, Mollie, Newsletter | | [KI-Produkttexte](https://ecommerce-hub.sh/developer-portal/woocommerce/ki/) | KI-Texte mit lokalem Sprachmodell statt Cloud | | [Theme und Frontend](https://ecommerce-hub.sh/developer-portal/woocommerce/theme/) | Child Theme, Storefront-Hooks, CSS-Fallstricke, Ladeverhalten | | [Barrierefreiheit](https://ecommerce-hub.sh/developer-portal/woocommerce/barrierefreiheit/) | BFSG, WCAG 2.1 AA, geprüfte und behobene Punkte | | [Betrieb](https://ecommerce-hub.sh/developer-portal/woocommerce/betrieb/) | Zugangsdaten, Docker-Fallstricke, Cron und automatische Updates, Mailversand | | [Fehlersuche](https://ecommerce-hub.sh/developer-portal/woocommerce/fehlersuche/) | was schiefgehen kann, nach Symptom sortiert, mit Ursache und Abhilfe | ## In Kürze: was wir gelernt haben - **Ohne Germanized ist WooCommerce in Deutschland nicht betreibbar.** Rechtstexte, Pflicht-Checkboxen und Grundpreise fehlen im Kern. - **B2B geht mit freiem WooCommerce nicht sinnvoll.** Staffelpreise, Kundengruppen und ein Feld für die Umsatzsteuer-ID fehlen im Standard und sind nur über kostenpflichtige Erweiterungen zu haben. - **Plugin-Beschreibungen prüfen.** Mehrere Plugins verhielten sich im Code anders als beworben. - **Eigene Anpassungen gehören in Must-Use-Plugins** unter `wp-content/mu-plugins/`, nicht in fremden Plugin-Code. - **WP-Cron braucht einen System-Cron**, sobald `DISABLE_WP_CRON` gesetzt ist. Sonst laufen weder automatische Updates noch Webhooks. --- # Erweiterungen > Geprüft am 08.10.2026 mit WooCommerce 11.2.0 und den aktiven Erweiterungen, darunter Germanized 4.1.4, ElasticPress 5.3.5, Yoast SEO 28.6 und Complianz 7.5.5. ## Im Einsatz | Plugin | Zweck | Lizenz | Warum dieses | | :--- | :--- | :--- | :--- | | WooCommerce | Shopkern | GPLv3 | | | Germanized for WooCommerce | deutsche Rechtskonformität | GPLv3 | kostenlose Kernversion deckt das Nötige ab, siehe [Rechtliches](https://ecommerce-hub.sh/developer-portal/woocommerce/rechtliches/) | | Gewährleistungshinweis (`ospo-gewaehrleistung`) | EU-Gewährleistungshinweis von Germanized als barrierefreier Dialog, auch auf Produktlisten | GPL-2.0-or-later | eigene Erweiterung, nur im Paket des Assistenten; im Referenzshop übernimmt das Child Theme dasselbe, siehe [Rechtliches](https://ecommerce-hub.sh/developer-portal/woocommerce/rechtliches/#gewaehrleistung) | | ElasticPress | Suche über Elasticsearch | GPLv2+ | Facetten, Autovervollständigung, „Meinten Sie", lohnt ab großen Sortimenten | | Yoast SEO | Suchmaschinenoptimierung | GPL | | | Complianz | Cookie-Einwilligung, DSGVO | GPLv2 | läuft ohne Cloud, anders als die meisten Konkurrenten | | Mollie Payments for WooCommerce | Zahlung | GPLv2 | gewählt statt PayOne (MIT) wegen der Nähe zur GPL | | EWWW Image Optimizer | Bildoptimierung | GPL | arbeitet lokal, statt Bilder an einen Clouddienst zu schicken | | Newsletter (Stefano Lissa) | Newsletter | GPLv2+ | ersetzt MailPoet | | Contact Form 7 | Kontaktformular | GPLv2 | vollständig kostenlos, keine gesperrten Funktionen | | EU-Captcha | Spamschutz | GPL-2.0-or-later | Myra Security, Hosting in Deutschland, statt reCAPTCHA. Nicht im WordPress-Verzeichnis: „captcha-eu" dort ist ein anderes Produkt eines anderen Anbieters, das Myra-Plugin kommt aus eigener Quelle. Ohne Update-Quelle in WordPress, neue Fassungen von Hand, siehe [Betrieb](https://ecommerce-hub.sh/developer-portal/woocommerce/betrieb/#ohne-update-quelle) | | WP Mail SMTP | Mailversand über SMTP | GPLv3 | Zugangsdaten als PHP-Konstanten statt in der Datenbank, siehe [Betrieb](https://ecommerce-hub.sh/developer-portal/woocommerce/betrieb/#zugangsdaten) | | Connect Matomo (`wp-piwik`) | Anbindung an Matomo | im WordPress-Verzeichnis | spricht eine externe Instanz an, siehe [Randsysteme](https://ecommerce-hub.sh/developer-portal/woocommerce/randsysteme/#matomo) | | Akeneo Connector | Anbindung an LibrePIM | GPLv3 | siehe [Randsysteme](https://ecommerce-hub.sh/developer-portal/woocommerce/randsysteme/#librepim) | | AI Content Generator for WooCommerce | KI-Produkttexte | im WordPress-Verzeichnis | mit lokalem Modell betrieben, siehe [KI-Produkttexte](https://ecommerce-hub.sh/developer-portal/woocommerce/ki/) | | AI Provider for Ollama | Ollama als Anbieter im KI-Framework von WordPress | GPL-2.0-or-later | erscheint in der Auswahl des AI Content Generator, wird von ihm aber nicht benutzt. Die Texte laufen über eine Umleitung, siehe [KI-Produkttexte](https://ecommerce-hub.sh/developer-portal/woocommerce/ki/#das-plugin-und-sein-haken) | | Two Factor | Zwei-Faktor-Anmeldung | GPL-2.0-or-later | vom WordPress-Core-Team, TOTP und Backup-Codes ohne Clouddienst | | Health Check & Troubleshooting | Fehlersuche ohne Plugins abzuschalten | GPLv2 | offizielles Plugin des WordPress-Teams | | WP Crontrol | WP-Cron einsehen und anstoßen | GPLv2 | unverzichtbar bei Cron-Problemen, siehe [Betrieb](https://ecommerce-hub.sh/developer-portal/woocommerce/betrieb/#wp-cron) | | Classic Editor | klassischer Editor | GPLv2 | offizielles Plugin des WordPress-Teams | Im [Konfigurations-Assistenten](https://ecommerce-hub.sh/developer-portal/konfigurator/#plugins) ist eine Auswahl davon wählbar, WooCommerce, Germanized und der Gewährleistungshinweis sind immer dabei. ## Geprüft und verworfen | Plugin | Grund | | :--- | :--- | | „Matomo Analytics" (`matomo`) | bringt eine eigene, in WordPress eingebettete Matomo-Kopie mit eigenen Tabellen mit, statt eine vorhandene Instanz anzubinden | | Odoo- und Pimcore-Konnektoren | nur kostenpflichtig | | WPForms, Ninja Forms, Forminator | Freemium, Kernfunktionen gesperrt | | Tinify | Clouddienst mit Freikontingent von 500 Bildern, danach kostenpflichtig | | Akismet | schickt IP-Adresse, E-Mail und Inhalt von Kommentaren und Formularen zur Prüfung an Server in den USA | | MailPoet | durch das Newsletter-Plugin ersetzt | | User Switching | im Projekt kein Bedarf | !!! tip "Erst den Code lesen" Der Name eines Plugins sagt wenig darüber, was es tut. „Matomo Analytics" klingt nach Anbindung und ist eine eingebettete Kopie. Der „AI Content Generator" nennt sich anbieterunabhängig und kennt im Code genau drei Cloud-Anbieter. Beides fiel erst beim Blick in den Quelltext auf. --- # Rechtliches mit Germanized WooCommerce bringt die Funktionen nicht mit, die für einen Onlineshop in Deutschland vorgeschrieben sind. Diese Lücke schließt **Germanized for WooCommerce** (vendidero, GPLv3). Die kostenlose Kernversion reicht. Die Pro-Version braucht man nur für PDF-Rechnungen, eine mehrstufige Kasse, eigene Checkboxen, Rechtstext-Generatoren und Lebensmittelkennzeichnung. ## Was eingerichtet wird - **Rechtliche Checkboxen an der Kasse:** Pflicht-Checkbox für AGB und Widerrufsbelehrung, je nach Produkt weitere für Altersprüfung, Gebrauchtware oder Mängelexemplare. - **Grundpreise** nach Preisangabenverordnung sowie Liefer- und Versandkostenhinweise auf der Produktseite. - **Rechtstexte als eigene Seiten:** Impressum, AGB, Widerrufsbelehrung und Datenschutzerklärung, verknüpft mit den Seiteneinstellungen von WooCommerce und Germanized. - **Erreichbarkeit:** ein Menü „Rechtliches" mit allen vier Seiten im Footer. Rechtlich gefordert ist, dass die Texte von jeder Seite aus ohne Suchen erreichbar sind. - **Streitbeilegung:** Link zur OS-Plattform in Impressum und AGB. Die Angabe „nicht bereit oder verpflichtet" ist für kleinere Shops zulässig, muss aber offengelegt werden. - **Widerrufsbutton** nach EU-Richtlinie 2023/2673. - **EU-Gewährleistungshinweis**, Pflicht seit 27.09.2026, siehe [unten](https://ecommerce-hub.sh/developer-portal/woocommerce/rechtliches/#gewaehrleistung). !!! warning "Platzhalter in den Rechtstexten" Die angelegten Texte enthalten markierte Platzhalter für Handelsregister, Umsatzsteuer-ID und vertretungsberechtigte Personen. Vor dem Livegang müssen sie durch echte, rechtlich geprüfte Angaben ersetzt werden. Der Konfigurations-Assistent sperrt den Shop deshalb zunächst für Besucher. ## Einrichtung per WP-CLI Germanized startet nach der Aktivierung einen eigenen Einrichtungsassistenten. Dessen Schritte lassen sich auch ohne Oberfläche ausführen, so macht es die `setup.sh` des Konfigurations-Assistenten: ```bash wp eval 'WC_GZD_Install::set_default_settings();' wp eval 'WC_GZD_Install::create_pages();' wp eval 'WC_GZD_Install::create_tax_rates();' # Der Assistent wurde beim Aktivieren vorgemerkt, weil es da noch keine # Widerrufsseite gab. Jetzt gibt es sie, die Vormerkung kann weg. wp transient delete _wc_gzd_setup_wizard_redirect wp transient delete _wc_gzd_activation_redirect ``` Ohne das Löschen der beiden Transienten landet man beim ersten Aufruf des Backends im Assistenten, obwohl alles eingerichtet ist. !!! note "Assistent nach Updates" Nach einem Major-Update von Germanized erscheint der Assistent erneut. Auf einem eingerichteten Shop **nicht** durchlaufen, er kann Rechtsseiten doppelt anlegen. „Zurück zu WP Admin" wählen. ## EU-Gewährleistungshinweis Seit dem 27.09.2026 müssen Onlineshops, die an Verbraucher verkaufen, vor Vertragsschluss hervorgehoben auf das gesetzliche Gewährleistungsrecht hinweisen, und zwar mit der harmonisierten Mitteilung der EU (Richtlinie (EU) 2024/825, Durchführungsverordnung (EU) 2025/1960 Anhang I, in Deutschland Art. 246a § 1 Abs. 1 Nr. 11 EGBGB). Die Mitteilung ist eine amtliche Grafik, deren Elemente nicht verändert werden dürfen. Online ist die farbige Fassung zu verwenden, lesbar in Standardgröße und mit einem klickbaren Link auf dasselbe Ziel wie der QR-Code, für Deutsch `https://europa.eu/youreurope/garantien`. **Germanized bringt die Mitteilung mit, schaltet sie aber nicht ein.** Die Funktion liegt unter `WooCommerce` → `Einstellungen` → `Germanized` → `Preisauszeichnung` → `EU Gewährleistung`. Die mitgelieferte Grafik ist byte-gleich mit der Datei der Kommission, eine eigene Erweiterung für die Grafik ist also nicht nötig. In einer frischen Installation ist die Funktion aus, und die Einstellungen stehen nur in der Datenbank. Eingeschaltet wird sie so, wie es auch die `setup.sh` des Konfigurations-Assistenten tut: ```bash wp option update woocommerce_gzd_legal_guarantee_enabled yes wp option update woocommerce_gzd_legal_guarantee_display_locations '["footer","cart","checkout"]' --format=json wp option update woocommerce_gzd_legal_guarantee_default_display_variant link wp option update woocommerce_gzd_mail_attach_eu_guarantees '["customer_processing_order","customer_on_hold_order"]' --format=json ``` | Option | Wert | Bedeutung | | :--- | :--- | :--- | | `woocommerce_gzd_legal_guarantee_enabled` | `yes` | Funktion an, ab Werk aus | | `woocommerce_gzd_legal_guarantee_display_locations` | `footer`, `cart`, `checkout` | Anzeige im Footer, im Warenkorb und in der Kasse | | `woocommerce_gzd_legal_guarantee_default_display_variant` | `link` | Link „Ihre gesetzlichen Gewährleistungsrechte“, der erste Klick öffnet die Mitteilung | | `woocommerce_gzd_mail_attach_eu_guarantees` | `customer_processing_order`, `customer_on_hold_order` | Mitteilung als PDF-Anhang der Bestellbestätigung | | `woocommerce_gzd_garan_label_enabled` | `no` | GARAN-Kennzeichnung für Herstellergarantien über zwei Jahre, nur je Produkt mit Herstellerangaben sinnvoll | Die Darstellung als Link folgt den praktischen Leitlinien der Kommission vom April 2026. Der Hinweis im Backend von Germanized, diese Variante sei „aus rechtlicher Sicht derzeit nicht empfohlen“, stammt aus der Zeit davor. Germanized verschickt auch bei Vorkasse die Bestellbestätigung als `customer_processing_order`, `customer_on_hold_order` steht nur vorsorglich in der Liste. **Wo der Hinweis erscheint:** im Footer jeder Seite, im Warenkorb, in der Kasse und als PDF-Anhang der Bestellbestätigung. In Warenkorb und Kasse nur, wenn mindestens ein nicht virtuelles Produkt darin liegt, bei gemischten Warenkörben mit „Für körperliche Produkte:“ davor. Kategorie-, Such- und Shopseiten bietet Germanized nicht an, die Leitlinien nennen sie aber. **Was Germanized allein nicht leistet:** - Der Auslöser ist ein Link auf die PNG-Datei, das Popover ist als `role="tooltip"` ausgezeichnet und öffnet schon nach einer Sekunde Überfahren mit der Maus. Das widerspricht WCAG 1.4.13, siehe [Barrierefreiheit](https://ecommerce-hub.sh/developer-portal/woocommerce/barrierefreiheit/#hinweise-und-tooltips). - Der Linktext duzt, der Rest eines gesiezten Shops nicht. - Für Screenreader fehlt der Wortlaut der Mitteilung als Alternativtext. - Germanized zwingt die Grafik mit `width:100% !important` in den Bildschirm. Auf 390 px Breite ist die Mitteilung dann nicht mehr lesbar. - Auf Produktlisten erscheint nichts. **Ergänzungen dafür:** Im Referenzshop stecken sie im Child Theme `ospo-storefront`, siehe [Theme und Frontend](https://ecommerce-hub.sh/developer-portal/woocommerce/theme/). Das Paket des [Konfigurations-Assistenten](https://ecommerce-hub.sh/developer-portal/konfigurator/#plugins) bringt sie stattdessen als eigene Erweiterung „Gewährleistungshinweis“ (`ospo-gewaehrleistung`, GPL-2.0-or-later) mit, damit sie mit jedem Theme funktionieren. Beide machen dasselbe: - Der Auslöser ist ein `