KuroCMS DevLog Vol.5: Implementierung des Rezepttyps
Wir haben eine neue Rezeptkarten-Funktion in KuroCMS basierend auf Feedback implementiert. Erfahren Sie mehr über die Architektur, JSON-LD-Generierung und Editor-Integration.
In „KuroCMS“ und „KuroEditor“, die als headless CMS der nächsten Generation für den Betrieb am Edge entwickelt wurden, wurde in der neuesten Version offiziell eine neue „Rezeptkarte“ implementiert. Während sich frühere Versionen von KuroCMS auf die allgemeine Dokumentdarstellung mittels Markdown und Standard-HTML konzentrierten, ermöglicht die Einführung dieser Rezeptkarte eine strikte Handhabung von Metadaten wie Kochzeit, Zutatenlisten, Portionen und Schritten, was eine konsistente Ausgabe als strukturierte Daten garantiert, die Suchmaschinen wie Google leicht verstehen können (Schema.org Recipe). In diesem Artikel beschreiben wir das technische Design dieser Rezeptkarte und zeigen, wie die Validierung über die Editor-, API- und Frontend-Ebenen hinweg erzwungen wird.
Designphilosophie und Basisdesign: Intelligentes Datenmodell, beschränkt auf 1 Dokument = 1 Rezept
Bei der Implementierung der Rezeptkarte bestand die größte Herausforderung für das Entwicklungsteam in der „Datenkonsistenz und der Vermeidung von Redundanz“. Während allgemeine Rezept-Websites oft mehrere Rezeptkarten verstreut in einem einzigen Artikel enthalten, führt dies tendenziell zu einer fehlerhaften Struktur aus der Perspektive der strukturierten Daten von Suchmaschinen (JSON-LD). Wenn mehrere verschiedene Gerichte oder Schritte parallel für eine einzige URL (Artikel) ausgegeben werden, wird die Zuordnung zwischen gemeinsamen Eigenschaften (wie Gerichtsname, fertiges Bild, Beschreibung und Veröffentlichungsdatum) und einzelnen Rezeptkarten unklar.
Daher erzwingt KuroCMS eine regelbasierte Einschränkung von „1 Dokument = 1 Rezept“. Die RecipeCard ist nur für die „rezeptspezifischen variablen Teile“ (Portionen, Kochzeit, Zutaten und Schritte) verantwortlich, während gemeinsame Informationen wie Gerichtsname, Beschreibung, fertiges Bild und Veröffentlichungsdatum aus den Dokumenteigenschaften (Titel, Zusammenfassung, Cover-Bild, Erstellungsdatum usw.) wiederverwendet werden. Dies vermeidet redundante Eingaben und verhindert Probleme, bei denen identische Rezeptnamen in einem fehlerhaften Format innerhalb derselben strukturierten Daten zirkulieren.
Ehrlich gesagt wollten wir aus Sicht des Designs von KuroEditor die Einschränkung 1 Dokument = 1 Rezept nicht akzeptieren, da sie die Flexibilität des Layouts einschränkt. Da die Rezeptseiten der Benutzer jedoch bessere SEO-Bewertungen erhalten und einfacher zu lesen und zu referenzieren sind, erzwingen wir in der aktuellen Version strikt die Regel von einer Rezeptkarte pro Artikel.
Konsistenzgarantie durch gemeinsam genutzte reine Funktionen
In einem headless CMS ist es nicht einfach, eine identische Strukturvalidierung im Rich-Editor (KuroEditor), der Speicher-API und dem statischen Build-Prozess öffentlicher Seiten durchzuführen. Wenn Sie die Validierungslogik separat unter Verwendung verschiedener Sprachen oder Frameworks auf jeder Ebene schreiben, führen Implementierungsunterschiede unweigerlich zu Problemen wie „im Editor gespeichert, aber beim API-Server fehlgeschlagen“ oder „in der Datenbank gespeichert, aber beim Frontend-Build fehlgeschlagen, wodurch die Website beschädigt wird“.
Um dies grundlegend zu lösen, hat KuroCMS ein Designmuster mit einer „gemeinsam genutzten reinen Funktion“ (Shared Pure Function) eingeführt. Konkret integrieren wir „dist/kuro-recipe.js“ (erstellt im Upstream-KuroEditor-Repository) in den KuroCMS-Kern als „src/kuro-recipe.js“, zusammen mit der Typdefinitionsdatei „kuro-recipe.d.ts“. Dies stellt sicher, dass exakt derselbe JavaScript-Code die Rezeptdaten im Body-HTML während der Bearbeitung im Editor, bei API-Speicheraufrufen und statischen Builds überprüft. Dieses Single-Source-of-Truth-Design minimiert Fehler.
*Da sowohl KuroEditor als auch KuroCMS von Kuroboo entwickelte „Open-Source-Software“ sind, erleichtert die gemeinsame Bezugnahme auf den GitHub-Verlauf das Verständnis.
Strikte Validierung in der Speicher-API: Spezifikationen von recipe-guard.ts
Wenn ein Artikel in KuroCMS gespeichert (PUT) wird, speichert die serverseitige API nicht nur den String. Sie überprüft strikt, ob die Rezeptdaten korrekt in das gesendete Body-HTML eingebettet sind. Diese Rolle wird von der Funktion „checkRecipeCards(bodyHtml, isRecipeType)“ in „src/recipe-guard.ts“ im Backend übernommen.
Der kritischste Aspekt dieser Validierung ist der Zeitpunkt. KuroCMS berücksichtigt die gemeinsame Bearbeitung durch mehrere Benutzer, und die endgültig gespeicherten Daten werden nach einem „3-Wege-Merge“ (3-way merge) mehrerer Versionen in die Datenbank geschrieben. Wenn die Validierung vor der Zusammenführung ausgeführt wird, können wir Fälle nicht verhindern, in denen die Zusammenführung versehentlich Rezeptkarten dupliziert oder beschädigte Daten einfügt. Daher wird die Prüfung immer auf dem endgültigen Text nach der Zusammenführung ausgeführt. Schlägt die Validierung fehl, gibt die API einen klaren Fehler an den Client zurück und blockiert den Speichervorgang.
| Prüfelement | Details und Sicherheitsmaßnahmen |
|---|---|
| Anzahl der Karten | Bestätigen Sie, dass in einem Rezeptartikel genau 1 Karte existiert und in Nicht-Rezeptartikeln genau 0 Karten existieren. |
| data-recipe Entschlüsselung | Entschlüsseln Sie die codierten Rezept-JSON-Daten, die im HTML-Tag eingebettet sind, und prüfen Sie, ob sie dem Schema entsprechen. |
| Attribut-Erlaubnisliste (allowlist) | Prüfen Sie streng auf unbekannte HTML-Attribute. Dies eliminiert Schwachstellen, bei denen böswillige Benutzer XSS-Skripte wie „onclick“ über den HTML-Text einschleusen. |
| Versionsprüfung | Überprüfen Sie die Versionskompatibilität des Rezeptschemas, um das Speichern alter Kartenversionen oder beschädigter Formate zu verhindern. |
JSON-LD-Ausgabe: Automatische Generierung der Rezeptstruktur für SEO
Dies ist der Kernwert des Hinzufügens der Rezeptkarte. Normalerweise gibt KuroCMS „Article“ als strukturierte Daten für die Seite aus, aber wenn ein Dokument eine Rezeptkarte enthält, wird diese automatisch ersetzt und „Recipe“ als primäre strukturierte Daten ausgegeben.
Es liest das Attribut „data-recipe“ aus dem gespeicherten HTML und übergibt die analysierten Daten als „article.recipe“ und „page.isRecipe“ an das HTML-Template. Um eine „Typprüfung durch String-Vergleich“ im Template zu vermeiden, wird eine einfache boolesche Verzweigung (#if page.isRecipe) verwendet, um zwischen Templates zu wechseln. Zeitdaten werden intern automatisch in das internationale Standard-ISO-8601-Dauerformat (z. B. „PT25M“ für 25 Minuten) konvertiert. Da die HTML-Anzeige und die strukturierten JSON-LD-Daten aus exakt derselben Datenquelle generiert werden, besteht kein Risiko abweichender Informationen für Suchmaschinen.
Admin-Integration: Dynamische Editor-Reorganisationslogik
In den Editorbereich des Admin-Panels wurde ebenfalls eine Integrationslogik integriert. In KuroEditor wird das Aktivieren oder Deaktivieren der „Topf-Schaltfläche“ für die Rezepterstellung über die bei der Initialisierung übergebene Option „recipeUi“ gesteuert. Da das Standardverhalten von KuroEditor darin besteht, die Schaltfläche anzuzeigen (true), muss KuroCMS dies normalerweise nicht angeben. Wenn es jedoch auf false gesetzt wird, sieht es für Benutzer, die KuroEditor nicht für die Rezeptbearbeitung verwenden, unverändert aus, was die Auswirkungen der Änderung minimiert.
Darüber hinaus sind Rezeptkarten auf KuroEditor-Ebene jetzt auf 1 Rezept pro Artikel beschränkt (die zweite Schaltfläche ist ausgegraut und kann nicht angeklickt werden). Dies bewahrt die Kernregel von Rezeptartikeln. KuroCMS führt beim Speichern außerdem eine Doppelprüfung durch, um sicherzustellen, dass rezeptspezifische Prüfungen für Rezeptartikel korrekt ausgeführt werden.
Auf dieser Grundlage wurde eine rezeptbezogene Testsuite „npm run test:recipe“ (src/recipe-guard.test.ts, insgesamt 12 Testfälle) hinzugefügt, die alles von der Kartenanzahl bis zum Maskieren von Zeichen in Attributen überprüft.
Verbleibende Probleme und zukünftige Roadmap
Mit diesem Update sind das Rezeptartikel-„Kernsystem“ und die „Speicher-Validierung“ voll funktionsfähig. KuroCMS bietet jedoch noch kein umfassendes Rezeptseiten-Layout wie große Portale. Unser Ziel war es, das einfache Posten von Rezepten auf persönlichen Websites zu ermöglichen, wobei SEO-Daten automatisch generiert werden, ohne dass der Benutzer sie schreiben muss. Jetzt kann jeder ganz einfach eine Kochseite erstellen.
Da KuroCMS über ein Template-System verfügt, können Benutzer das Design selbst weiter verfeinern (Details siehe Quelle 3). Um KuroCMS noch einfacher nutzbar zu machen, wird das Entwicklungsteam weiterhin Updates basierend auf Ihrem Feedback implementieren. Vielen Dank für Ihre Unterstützung!