Technik
Unser Stack. Modern, offen, selbst betrieben.
Payload CMS als Redaktionssystem, Puck als visueller Baukasten, Next.js für die Ausspielung – ergänzt um bewährte Open-Source-Bausteine für Suche, Anmeldung, Statistik und automatische Qualitätsprüfung. Alles läuft dort, wo Sie es entscheiden.
Architektur
Einmal pflegen, überall ausspielen
Die Redaktion arbeitet im Baukasten, Payload verwaltet Inhalte, Rechte und Versionen. Über eine offene Schnittstelle werden Website, Micropages, Stadt-App, Infoscreens, KI-Assistenten und Open-Data-Portale aus derselben Quelle versorgt.
flowchart TB
R["Redaktion im Baukasten Puck<br/>Single Sign-on: Entra ID · Keycloak"] --> P["Payload CMS<br/>Inhalte · Rechte · Versionen"]
P <--> DB[("PostgreSQL")]
P <--> S3[("Medien")]
P <--> SU["Suche<br/>Meilisearch"]
P -. jede Änderung .-> Q["Qualitätsprüfung<br/>axe · Lighthouse · veraPDF"]
P --> API{{"Offene API<br/>REST · GraphQL"}}
API --> W["Website &<br/>Micropages"]
API --> A["Stadt-App<br/>& Push"]
API --> I["Infoscreens"]
API --> M["KI-Assistenten<br/>MCP-Server"]
API --> O["Open Data<br/>DCAT-AP.de"]
P --> X["Exchange Online<br/>Mails · Tickets"]
classDef blau fill:#4678A0,stroke:#2F2F2F,color:#ffffff,stroke-width:1.5px
classDef gruen fill:#96A532,stroke:#2F2F2F,color:#000000,stroke-width:1.5px
classDef weiss fill:#ffffff,stroke:#BBBCBC,color:#000000
classDef grau fill:#F3F3F1,stroke:#BBBCBC,color:#000000
classDef signal fill:#BEF500,stroke:#2F2F2F,color:#000000
classDef dunkel fill:#2F2F2F,stroke:#2F2F2F,color:#ffffff
class R gruen
class P blau
class DB,S3,SU grau
class Q signal
class API dunkel
class W,A,I,M,O weiss
class X grau
Bausteine
Was wir einsetzen – und warum
Jeder Baustein ist Open Source, verbreitet und selbst betreibbar. So bleiben Sie unabhängig – von Lizenzen, von Herstellern und auch von uns.
| Baustein | Wofür | Warum | Lizenz |
|---|---|---|---|
| Payload CMS | Redaktionssystem und API | Rechte, Entwürfe, Versionen, Mehrsprachigkeit – typsicher in TypeScript | MIT |
| Puck | Visueller Baukasten | Drag-and-Drop, aber nur mit freigegebenen, barrierefreien Bausteinen | MIT |
| Next.js | Website und Micropages | Schnelle Seiten, gut für Suchmaschinen, statisch und dynamisch | MIT |
| PostgreSQL | Datenbank | Bewährt, robust, in Rechenzentren der Verwaltung verbreitet | PostgreSQL-Lizenz |
| Meilisearch | Suche | Tippfehler-tolerant, Synonyme, schnell – selbst betrieben | MIT |
| Microsoft Entra ID oder Keycloak | Anmeldung (Single Sign-on) | Redaktion meldet sich mit dem Verwaltungskonto an. Entra ID nutzt Ihre M365-Umgebung, Keycloak betreiben Sie selbst und koppeln es auf Wunsch mit Entra ID oder Active Directory. Gruppen werden zu Rollen. Standards: OpenID Connect, SAML, OAuth 2.0 | Ihre M365-Lizenz bzw. Apache 2.0 |
| Exchange Online (Microsoft Graph) | Mailversand & Tickets | Formulare und Benachrichtigungen gehen aus Postfächern der Verwaltung, Anfragen landen als Tickets in Ihrem System | Ihre M365-Lizenz |
| sharp | Bildverarbeitung | Erzeugt beim Upload WebP und AVIF in passenden Größen, entfernt Metadaten | Apache 2.0 |
| KI-Modelle nach Wahl | Vorschläge für Texte | Alternativtexte, SEO-Titel, Meta-Beschreibungen – Verarbeitung in der EU oder auf eigenen Servern | je nach Modell |
| Matomo | Statistik | Auswertung ohne einwilligungspflichtige Cookies | GPL |
| axe-core, Playwright, veraPDF | Qualitätsprüfung | Jede Änderung wird automatisch auf Barrierefreiheit und PDF-Standards geprüft | MPL 2.0, Apache 2.0, GPL/MPL |
Qualität
Jede Änderung wird geprüft, bevor sie online geht
Barrierefreiheit und Qualität dürfen nicht vom Zufall abhängen. Deshalb laufen bei jeder Änderung an Code, Vorlagen oder Bausteinen automatische Prüfungen – erst wenn alles bestanden ist, wird veröffentlicht.
- axe-core & Playwright prüfen Seiten automatisch auf Barrieren
- Lighthouse misst Ladezeit und technische Qualität
- veraPDF prüft hochgeladene PDFs nach PDF/UA
- Weiterleitungs-Test stellt sicher, dass keine alte Adresse ins Leere führt
flowchart TB
A["Änderung<br/>Code · Vorlage · Baustein"] --> P{"Automatische<br/>Prüfungen"}
P --> B1["Barrierefreiheit<br/>axe · Playwright"]
P --> B2["Ladezeit<br/>Lighthouse"]
P --> B3["PDFs<br/>veraPDF"]
P --> B4["Weiterleitungen<br/>0 × 404"]
B1 & B2 & B3 & B4 --> E{"Alles bestanden?"}
E -->|ja| L["Veröffentlichen"]
E -->|nein| R["Bericht an das Team<br/>Korrektur"] --> A
classDef blau fill:#4678A0,stroke:#2F2F2F,color:#ffffff,stroke-width:1.5px
classDef gruen fill:#96A532,stroke:#2F2F2F,color:#000000,stroke-width:1.5px
classDef weiss fill:#ffffff,stroke:#BBBCBC,color:#000000
classDef signal fill:#BEF500,stroke:#2F2F2F,color:#000000
class A,B1,B2,B3,B4 weiss
class P,E blau
class L gruen
class R signal