Vom Prompt zum CSP-konformen phtml-Template
Claude Code kann ein neues Hyvä-Template in Sekunden skizzieren, doch nur mit den passenden Projektkonventionen als Kontext entsteht wirklich brauchbarer Code. Dieser Artikel zeigt, wie man ein phtml-Template mit ViewModel scaffoldet, Alpine.js-Komponenten CSP-konform generieren lässt und KI-vorgeschlagene Tailwind-Klassen gegen das tatsächliche Design-System prüft, bevor sie in Produktion landen.
Inhaltsverzeichnis
- 1. Was Hyvä-Templates mit KI-Unterstützung wirklich bedeutet
- 2. Projektkonventionen als Kontext für Claude Code
- 3. Praxisbeispiel: Ein neues Template scaffolden
- 4. Alpine.js-Komponenten generieren lassen
- 5. CSP-Konformität sicherstellen
- 6. Tailwind-Klassen verifizieren statt erfinden
- 7. Typische Fehler von KI-generierten Hyvä-Templates
- 8. Sicherer Workflow: Kontext-Dateien und Prompting
- 9. Hyvä-Templates im Vergleich: KI-Vorschlag gegen Projektkonvention
- 10. Zusammenfassung
- 11. FAQ
1. Was Hyvä-Templates mit KI-Unterstützung wirklich bedeutet
Hyvä-Templates mit KI-Unterstützung zu bauen bedeutet nicht, dass Claude Code aus einer kurzen Beschreibung ein produktionsreifes phtml-Template erzeugt. Es bedeutet, ein Sprachmodell gezielt für die Teile der Arbeit einzusetzen, die klar strukturiert sind: das Anlegen der Grunddatei nach bestehendem Muster, das Verdrahten eines ViewModels über die Layout-XML und das Formulieren einer ersten Alpine.js-Komponente. Der Unterschied zwischen einem brauchbaren und einem unbrauchbaren Ergebnis liegt fast immer im Kontext, den Claude Code vor der Generierung erhält, nicht im Modell selbst.
Ohne Kontext greift ein Sprachmodell auf generisches Wissen über Tailwind, Alpine.js und PHP zurück, das mit den tatsächlichen Konventionen eines konkreten Hyvä-Projekts oft nur teilweise übereinstimmt. Das zeigt sich besonders deutlich an drei Stellen: der Struktur eines phtml-Templates mit ViewModel-Zugriff, der Art, wie Alpine.js-Komponenten CSP-konform eingebunden werden, und der Frage, welche Tailwind-Klassen im Projekt tatsächlich existieren. Die folgenden Abschnitte behandeln genau diese drei Bereiche im Detail, jeweils mit einem praktischen Beispiel aus einem laufenden Magento-2-Projekt.
2. Projektkonventionen als Kontext für Claude Code
Ein Hyvä-Theme erbt typischerweise von einem Parent-Theme wie hyva-themes/magento2-default-theme-csp und überschreibt gezielt einzelne Templates. Diese Vererbungsstruktur ist für ein Sprachmodell ohne zusätzlichen Kontext nicht sichtbar. Wer Claude Code lediglich bittet, ein neues Produktkarten-Template zu erzeugen, bekommt in der Regel ein technisch funktionierendes, aber stilistisch fremdes Ergebnis, weil weder die im Projekt üblichen Escaper-Aufrufe noch die Namenskonvention für ViewModels noch die tatsächlich genutzten Tailwind-Klassen bekannt sind.
Der zuverlässigste Weg, diesen Kontext bereitzustellen, ist, Claude Code zwei oder drei bestehende, ähnliche Templates aus dem eigenen Theme direkt lesen zu lassen, bevor eine neue Datei entsteht. Ergänzend hilft eine CLAUDE.md mit klaren Regeln zu Block-Iteration, CSP-Registrierung und Escaping-Pflicht, wie sie in diesem Projekt bereits gepflegt wird. Diese Kombination aus konkreten Beispieldateien und expliziten Regeln liefert deutlich konsistentere Ergebnisse als eine rein textuelle Beschreibung der gewünschten Konventionen.
3. Praxisbeispiel: Ein neues Template scaffolden
Als Beispiel dient ein neues Template für eine Produktbewertungs-Zusammenfassung, die auf der Produktdetailseite oberhalb der Beschreibung erscheinen soll. Der Auftrag an Claude Code umfasste drei Teile: ein ViewModel-Interface für die Bewertungsdaten, ein passendes Layout-XML-Fragment und das eigentliche phtml-Template. Wichtig war, dass Claude Code vor der Generierung zunächst vergleichbare Templates im Verzeichnis Magento_Catalog/templates/product/view durchsucht hat, um die tatsächliche Struktur von ViewModel-Zugriffen und Escaper-Aufrufen zu übernehmen.
Das Ergebnis war ein Template, das die Block-Child-Iteration nicht ersetzt, sondern respektiert, konsequent den Escaper für Ausgabedaten verwendet und dieselbe Einrückung und PHPDoc-Struktur wie die Nachbardateien nutzt. Entscheidend war dabei weniger die Geschwindigkeit der Generierung als die Tatsache, dass ein manueller Review kaum Anpassungen an Konventionen mehr nötig hatte, weil die Konventionen bereits im Prompt-Kontext vorhanden waren.
#!/usr/bin/env bash
# scaffold-context.sh - collect project conventions before asking
# Claude Code to scaffold a new Hyva template
set -euo pipefail
THEME_DIR="app/design/frontend/Mironsoft/default"
TARGET_DIR="$THEME_DIR/Magento_Catalog/templates/product/view"
echo "[1/3] Listing existing sibling templates for style reference..."
find "$TARGET_DIR" -maxdepth 1 -name "*.phtml" -print
echo "[2/3] Extracting ViewModel access pattern from an existing template..."
grep -n "viewModels\|escapeHtml\|getChildNames" "$TARGET_DIR/description.phtml"
echo "[3/3] Writing the new template following the same structure..."
mkdir -p "$TARGET_DIR"
cat <<'PHTML' > "$TARGET_DIR/review-summary.phtml"
<?php
/** @var \Magento\Framework\View\Block\Template $block */
/** @var \Magento\Framework\Escaper $escaper */
/** @var \Mironsoft\ReviewSummary\ViewModel\ReviewSummary $viewModel */
$viewModel = $viewModels->require(\Mironsoft\ReviewSummary\ViewModel\ReviewSummary::class);
?>
<div class="mb-6" x-data="reviewSummary()">
<h3 class="text-lg font-semibold text-gray-900">
<?= $escaper->escapeHtml(__('Customer Ratings')) ?>
</h3>
<?php foreach ($block->getChildNames() as $childName): ?>
<?= $block->getChildHtml($childName) ?>
<?php endforeach; ?>
</div>
PHTML
echo "Template scaffolded, run bin/phpcs on the new file next."
4. Alpine.js-Komponenten generieren lassen
Für die Interaktivität der Bewertungs-Zusammenfassung, ein aufklappbarer Bereich mit Sterne-Filter, sollte Claude Code eine Alpine.js-Komponente nach dem im Projekt üblichen Muster erzeugen. Hyvä-Themes registrieren Komponenten typischerweise über Alpine.data() in einer separaten JavaScript-Datei, nicht als Inline-Objekt direkt im x-data-Attribut, sobald die Logik mehr als ein paar Zeilen umfasst. Dieses Muster hält phtml-Templates lesbar und macht die Komponente wiederverwendbar.
Claude Code kann diese Trennung zuverlässig umsetzen, wenn der Prompt explizit danach fragt und ein bestehendes Beispiel wie die Mobile-Footer-Collapse-Komponente aus footer.phtml als Referenz mitgegeben wird. Ohne diesen Hinweis neigt das Modell dazu, die gesamte Logik als Inline-Objekt in x-data zu formulieren, was bei einfachen Komponenten unproblematisch ist, bei komplexeren Filtern aber schnell unübersichtlich wird und die Testbarkeit erschwert.
// web/js/review-summary.js
// Alpine.js component for the collapsible review summary block.
// Registered via Alpine.data() so the phtml template only references
// the component name, keeping markup and logic separated.
document.addEventListener('alpine:init', () => {
Alpine.data('reviewSummary', () => ({
expanded: false,
activeStarFilter: null,
toggleExpanded() {
this.expanded = !this.expanded;
},
setStarFilter(stars) {
this.activeStarFilter = this.activeStarFilter === stars ? null : stars;
this.$dispatch('review-filter-changed', { stars: this.activeStarFilter });
},
isFilterActive(stars) {
return this.activeStarFilter === stars;
}
}));
});
5. CSP-Konformität sicherstellen
Hyvä-Themes mit aktivierter Content Security Policy verbieten Inline-Event-Handler wie onclick und erfordern, dass jeder Inline-Script-Block explizit über registerInlineScript() der Hyvä-CSP-Komponente freigegeben wird. Ein KI-Modell, das primär mit allgemeinem Alpine.js-Code trainiert wurde, schlägt gelegentlich Muster vor, die in einer Standard-Webanwendung unproblematisch wären, in einem CSP-strikten Hyvä-Theme aber von der Browser-Policy blockiert werden, etwa ein onclick-Attribut statt x-on:click oder ein Inline-Skript ohne begleitenden PHP-Aufruf.
Der zuverlässigste Schutz gegen solche Fehler ist eine automatisierte Prüfung nach jeder KI-gestützten Template-Generierung, die gezielt nach verbotenen Mustern sucht, statt sich auf die Sorgfalt des Prompts allein zu verlassen. Ein einfaches Shell-Skript, das mit ripgrep nach on-Attributen und nicht registrierten Skript-Blöcken sucht, deckt die häufigsten Verstöße zuverlässig auf, bevor die Änderung in den Review-Prozess geht.
#!/usr/bin/env bash
# csp-audit.sh - detect common CSP violations in a freshly
# AI-generated Hyva template before it enters code review
set -euo pipefail
TEMPLATE="$1"
echo "[1/3] Checking for forbidden inline event handler attributes..."
if grep -nE 'on(click|load|change|submit)=' "$TEMPLATE"; then
echo "[FAIL] Inline event handler found, use x-on:event instead" >&2
exit 1
fi
echo "[2/3] Checking every inline <script> block is CSP-registered..."
script_count=$(grep -c '<script type="text/plain">' "$TEMPLATE" || true)
register_count=$(grep -c 'registerInlineScript' "$TEMPLATE" || true)
if [[ "$script_count" -gt "$register_count" ]]; then
echo "[FAIL] Inline script without matching registerInlineScript() call" >&2
exit 1
fi
echo "[3/3] Checking for eval or new Function usage..."
grep -nE 'eval\(|new Function\(' "$TEMPLATE" && exit 1
echo "[OK] No obvious CSP violations found in $TEMPLATE"
6. Tailwind-Klassen verifizieren statt erfinden
Ein wiederkehrendes Problem bei KI-generierten Hyvä-Templates sind Tailwind-Klassen, die syntaktisch korrekt aussehen, aber im Projekt gar nicht existieren, weil sie nicht in tailwind.config.js definiert oder durch die verwendeten Utility-Klassen im restlichen Theme abgedeckt sind. Ein typisches Beispiel ist bg-primary-500, wenn das Projekt tatsächlich eine benutzerdefinierte Farbpalette mit Namen wie brand-orange oder einer numerischen Skala wie orange-600 verwendet. Da Tailwind im CSS-first-Ansatz von Version 4 nur Klassen erzeugt, die tatsächlich im Quellcode vorkommen und mit der Konfiguration übereinstimmen, führt eine erfundene Klasse nicht zu einem Fehler, sondern schlicht zu fehlendem Styling.
Diese Fehlerart ist besonders tückisch, weil sie erst beim visuellen Review auffällt und nicht durch PHPStan oder einen PHP-Lint-Lauf abgefangen wird. Ein kleines Python-Skript, das alle im generierten Template verwendeten Klassen extrahiert und gegen eine Liste tatsächlich im Projekt genutzter Klassen abgleicht, macht diese Prüfung reproduzierbar und lässt sich problemlos in den Build-Schritt integrieren, direkt nach dem Tailwind-Build und vor dem Static-Content-Deploy.
#!/usr/bin/env python3
# verify_tailwind_classes.py - flag Tailwind classes suggested by an
# AI model that do not exist anywhere else in the project design system
import re
import sys
from pathlib import Path
CLASS_ATTR = re.compile(r'class="([^"]+)"')
def extract_classes(file_path: Path) -> set[str]:
text = file_path.read_text(encoding="utf-8")
found: set[str] = set()
for match in CLASS_ATTR.finditer(text):
found.update(match.group(1).split())
return found
def load_known_classes(theme_dir: Path) -> set[str]:
known: set[str] = set()
for phtml_file in theme_dir.rglob("*.phtml"):
known.update(extract_classes(phtml_file))
return known
if __name__ == "__main__":
new_template = Path(sys.argv[1])
theme_root = Path("app/design/frontend/Mironsoft/default")
known_classes = load_known_classes(theme_root)
new_classes = extract_classes(new_template)
unknown = sorted(new_classes - known_classes)
if unknown:
print(f"Unverified Tailwind classes in {new_template}:")
for class_name in unknown:
print(f" - {class_name}")
sys.exit(1)
print(f"All classes in {new_template} match existing project usage.")
7. Typische Fehler von KI-generierten Hyvä-Templates
Neben erfundenen Tailwind-Klassen und CSP-Verstößen tauchen bei KI-generierten Hyvä-Templates einige weitere Muster wiederholt auf. Das häufigste: jQuery-Reste oder Knockout-Bindings aus generischem Magento-2-Trainingsmaterial, obwohl das Projekt konsequent auf Alpine.js setzt und weder jQuery noch UI-Components lädt. Ein zweites Muster ist das Ersetzen der getChildNames()-Iteration durch fest verdrahtete Kindblock-Aufrufe, was das Hyvä-Block-System faktisch aushebelt und spätere Layout-Erweiterungen über XML erschwert.
Ein drittes, subtileres Problem betrifft fehlendes Escaping. Claude Code escaped Ausgaben zuverlässig, wenn im Kontext bereits erkennbar ist, dass escapeHtml() oder escapeHtmlAttr() Projektstandard sind, vergisst es aber gelegentlich bei neu eingeführten Variablen wie einem aus einer externen API geladenen Bewertungstext. Ein manueller Blick auf jede unescaped ausgegebene Variable bleibt deshalb Pflicht, unabhängig davon, wie zuverlässig das Modell in anderen Bereichen war.
8. Sicherer Workflow: Kontext-Dateien und Prompting
Ein wiederholbarer Workflow für KI-gestütztes Hyvä-Templating beginnt nicht mit dem Prompt für das neue Template, sondern mit der Zusammenstellung des Kontexts: zwei bis drei strukturell ähnliche Bestandstemplates, die relevanten Abschnitte der CLAUDE.md, ein Ausschnitt aus tailwind.config.js und, falls vorhanden, die bestehende Alpine.js-Referenzkomponente. Erst danach folgt die eigentliche Aufgabenbeschreibung mit klar formulierten Anforderungen wie CSP-Konformität, Verwendung ausschließlich vorhandener Design-Tokens und Beibehaltung der Block-Iteration.
Nach der Generierung folgt derselbe Review-Rhythmus wie bei jeder anderen KI-gestützten Änderung: Diff vollständig lesen, CSP-Audit-Skript ausführen, Tailwind-Klassen gegen das Design-System prüfen und das Template im Browser visuell kontrollieren, bevor es in den Deploy-Prozess geht. Dieser Rhythmus kostet bei einem einzelnen Template wenige Minuten zusätzlich, verhindert aber zuverlässig, dass CSP-Verstöße oder unstyled Bereiche erst in der Produktion auffallen.
{
"task": "scaffold-hyva-template",
"target_directory": "app/design/frontend/Mironsoft/default/Magento_Catalog/templates/product/view",
"new_file": "review-summary.phtml",
"context_files": [
"Magento_Catalog/templates/product/view/description.phtml",
"Magento_Theme/templates/page/js/sticky-header.phtml",
"CLAUDE.md#coding-standards",
"web/tailwind/tailwind.config.js"
],
"requirements": {
"csp_compliant": true,
"no_jquery": true,
"no_knockout": true,
"preserve_block_iteration": true,
"escaper_required_for_all_output": true,
"tailwind_classes": "existing project classes only, no invented utility values"
},
"verification": {
"csp_audit": "bin/bash csp-audit.sh review-summary.phtml",
"tailwind_check": "python3 verify_tailwind_classes.py review-summary.phtml",
"static_analysis": "bin/analyse app/code/Mironsoft/ReviewSummary --level=5"
}
}
9. Hyvä-Templates im Vergleich: KI-Vorschlag gegen Projektkonvention
Die folgende Übersicht fasst die häufigsten Abweichungen zwischen einem ungeprüften KI-Vorschlag und der tatsächlichen Projektkonvention zusammen. Sie basiert auf wiederholt beobachteten Mustern aus mehreren Hyvä-Scaffolding-Aufträgen und dient als Checkliste für den Review nach jeder KI-gestützten Template-Generierung.
| Bereich | Ungeprüfter KI-Vorschlag | Projektkonvention | Warum es wichtig ist |
|---|---|---|---|
| Interaktivität | jQuery-Selektor oder Knockout-Binding | Alpine.data()-Komponente | Theme lädt bewusst weder jQuery noch UI-Components |
| Event-Handling | onclick="..." Attribut | x-on:click mit registrierter Funktion | Inline-Handler werden von der CSP blockiert |
| Block-Struktur | Fest verdrahteter Kindblock-Aufruf | $block->getChildNames()-Iteration | Layout-Erweiterbarkeit über XML bleibt erhalten |
| Farbklassen | bg-primary-500 (existiert nicht) | bg-orange-600 (definierte Palette) | Erfundene Klassen erzeugen kein CSS-Output |
| Ausgabe | <?= $data['title'] ?> ohne Escaper | $escaper->escapeHtml($title) | Verhindert XSS über extern geladene Daten |
Auffällig ist, dass fast alle Abweichungen in der Tabelle nicht durch einen fehlerhaften Prompt entstehen, sondern durch fehlenden Kontext über das jeweilige Projekt. Ein Modell, das keine Beispieldatei mit getChildNames() gesehen hat, kann diese Konvention nicht zuverlässig anwenden, egal wie präzise die textuelle Beschreibung formuliert ist.
Mironsoft
Hyvä-Frontend-Entwicklung mit strukturiertem KI-Einsatz
Hyvä-Templates, die zur Codebasis passen?
Wir setzen Claude Code gezielt für das Scaffolding neuer Hyvä-Templates ein und sichern jedes Ergebnis mit CSP-Audit, Tailwind-Klassen-Verifikation und vollständigem Diff-Review ab, damit euer Frontend konsistent und CSP-konform bleibt.
Template-Scaffolding
Neue phtml-Templates nach euren bestehenden Konventionen erstellen
CSP-Audit
Alpine.js-Komponenten auf verbotene Inline-Muster prüfen
Design-System-Check
Tailwind-Klassen gegen euer tatsächliches Theme abgleichen
10. Zusammenfassung
Hyvä-Templates mit KI-Unterstützung zu bauen funktioniert zuverlässig für das Scaffolding neuer Dateien, das Ableiten von ViewModel-Strukturen aus bestehenden Beispielen und das Formulieren erster Alpine.js-Komponenten, solange Claude Code vor der Generierung ausreichend Kontext über die tatsächlichen Projektkonventionen erhält. Ohne diesen Kontext entstehen technisch lauffähige, aber stilistisch und teilweise funktional abweichende Templates, insbesondere bei CSP-Konformität und bei der Verwendung tatsächlich existierender Tailwind-Klassen.
Drei Prüfungen sollten nach jeder KI-gestützten Template-Generierung feststehender Bestandteil des Reviews sein: ein CSP-Audit auf verbotene Inline-Muster, ein Abgleich verwendeter Tailwind-Klassen gegen das Design-System und ein manueller Blick auf Escaping sowie Block-Iteration. Wer diese drei Punkte konsequent prüft, kann Claude Code produktiv für Hyvä-Frontend-Arbeit einsetzen, ohne stilistische oder sicherheitsrelevante Regressionen in Kauf zu nehmen.
Hyvä-Templates mit KI-Unterstützung bauen - Das Wichtigste auf einen Blick
Kontext vor Prompt
Bestehende Templates, CLAUDE.md und Tailwind-Config vor der Generierung mitgeben, nicht nur beschreiben.
CSP-Audit
Jedes generierte Template auf Inline-Handler und fehlende registerInlineScript()-Aufrufe prüfen.
Tailwind-Verifikation
Vorgeschlagene Klassen gegen tatsächlich im Projekt genutzte Klassen abgleichen, nicht blind übernehmen.
Block-System bewahren
getChildNames()-Iteration und Escaper-Pflicht dürfen durch KI-Vorschläge nicht ersetzt werden.