{
"event": "PreToolUse",
"tool_name": "mcp__mcp-db__db_insert",
"tool_input": {
"table": "contracts",
"database": "ki_dev",
"data": {
"uuid": "a1b2c3d4-htmx-1234-5678-abcdef123456",
"name": "htmx-patterns-contract",
"version": "1.0",
"status": "active",
"scope_description": "HTMX-Nutzung in View-Templates - einheitliche Patterns, CSRF, Confirmations",
"created_by": "claude",
"yaml_content": "contract:\n name: htmx-patterns\n version: \"1.0\"\n status: active\n description: |\n Contract für konsistente HTMX-Nutzung in View-Templates.\n Definiert Pflicht-Patterns, Best-Practices und verbotene Anti-Patterns.\n \n Erstellt basierend auf Meta-Analyse vom 2025-12-27.\n Referenz-Implementierungen: content\/show.php, docs\/code.php, chat\/index.php\n\n created: \"2025-12-27\"\n author: claude\n\n scope:\n paths:\n - \"\/src\/View\/**\/*.php\"\n excludes:\n - \"\/src\/View\/layout.php\"\n - \"\/src\/View\/partials\/form\/**\"\n\n principles:\n - PROGRESSIVE_ENHANCEMENT # HTMX als Enhancement, nicht Ersatz\n - CONSISTENCY # Einheitliche Patterns über alle Views\n - SECURITY_FIRST # CSRF-Token immer mitschicken\n - USER_FEEDBACK # Loading-States und Confirmations\n\n # ==========================================================================\n # KRITISCHE REGELN (müssen erfüllt sein)\n # ==========================================================================\n \n rules:\n # --- CSRF Security ---\n - id: csrf-on-post\n check_type: conditional_required\n condition: \"hx-post=\"\n requires: \"hx-headers=.*X-CSRF-TOKEN\"\n in_files: \"View\/**\/*.php\"\n severity: critical\n description: |\n hx-post MUSS X-CSRF-TOKEN Header haben.\n Pattern: hx-headers='{\"X-CSRF-TOKEN\": \"<?= $csrfToken ?>\"}'\n\n - id: csrf-on-delete\n check_type: conditional_required\n condition: \"hx-delete=\"\n requires: \"hx-headers=.*X-CSRF-TOKEN\"\n in_files: \"View\/**\/*.php\"\n severity: critical\n description: |\n hx-delete MUSS X-CSRF-TOKEN Header haben.\n Pattern: hx-headers='{\"X-CSRF-TOKEN\": \"<?= $csrfToken ?>\"}'\n\n - id: csrf-on-patch\n check_type: conditional_required\n condition: \"hx-patch=\"\n requires: \"hx-headers=.*X-CSRF-TOKEN\"\n in_files: \"View\/**\/*.php\"\n severity: critical\n description: |\n hx-patch MUSS X-CSRF-TOKEN Header haben.\n\n # --- Delete Confirmation ---\n - id: delete-requires-confirm\n check_type: conditional_required\n condition: \"hx-delete=\"\n requires: \"hx-confirm=\"\n in_files: \"View\/**\/*.php\"\n severity: critical\n description: |\n hx-delete MUSS hx-confirm haben.\n Pattern: hx-confirm=\"Wirklich löschen?\"\n\n # --- Anti-Patterns ---\n - id: no-fetch-for-simple-post\n check_type: forbidden_pattern\n patterns:\n - \"fetch.*method.*POST\"\n - \"fetch.*POST\"\n in_files: \"View\/**\/*.php\"\n exclude_files:\n - \"**\/chat\/index.php\" # Streaming erfordert fetch\n severity: major\n description: |\n Kein fetch() für einfache POST-Aktionen - verwende hx-post.\n Ausnahme: Streaming-Responses (SSE) erfordern fetch().\n\n - id: no-inline-onclick-for-ajax\n check_type: forbidden_pattern\n patterns:\n - \"onclick=.*fetch\"\n - \"onclick=.*XMLHttpRequest\"\n in_files: \"View\/**\/*.php\"\n severity: major\n description: |\n Kein onclick mit fetch\/XHR - verwende HTMX-Attribute.\n\n # ==========================================================================\n # EMPFOHLENE REGELN (sollten erfüllt sein)\n # ==========================================================================\n\n - id: use-hx-indicator\n check_type: recommended_pattern\n condition: \"hx-post=\"\n recommends: \"hx-indicator=\"\n in_files: \"View\/**\/*.php\"\n severity: minor\n description: |\n hx-post SOLLTE hx-indicator für Loading-Feedback haben.\n Pattern: hx-indicator=\"#spinner\" oder hx-indicator=\"closest .btn\"\n\n - id: use-hx-disabled-elt\n check_type: recommended_pattern\n condition: \"hx-post=.*form\"\n recommends: \"hx-disabled-elt=\"\n in_files: \"View\/**\/*.php\"\n severity: minor\n description: |\n Form-Submits SOLLTEN hx-disabled-elt haben.\n Pattern: hx-disabled-elt=\"find button\" (verhindert Doppel-Submit)\n\n - id: prefer-hx-swap-innerhtml\n check_type: recommended_pattern\n condition: \"hx-target=\"\n recommends: \"hx-swap=\"\n in_files: \"View\/**\/*.php\"\n severity: info\n description: |\n Bei hx-target SOLLTE hx-swap explizit gesetzt sein.\n Default ist innerHTML, aber explizit ist besser.\n\n # ==========================================================================\n # STANDARD-PATTERNS (Referenz-Implementierungen)\n # ==========================================================================\n\n patterns:\n # Pattern 1: Form-Submit mit Partial-Update\n form_partial_update:\n description: \"Form-Submit ersetzt Teil der Seite\"\n example: |\n <form hx-post=\"\/endpoint\"\n hx-target=\"#result-container\"\n hx-swap=\"innerHTML\"\n hx-disabled-elt=\"find button\"\n hx-headers='{\"X-CSRF-TOKEN\": \"<?= $csrfToken ?>\"}'\n hx-indicator=\"#spinner\">\n reference: \"content\/show.php:61-65\"\n use_when: \"Ergebnis soll inline angezeigt werden\"\n\n # Pattern 2: Action mit Page-Reload\n action_with_reload:\n description: \"Aktion ausführen, dann Seite neu laden\"\n example: |\n <button hx-post=\"\/action\"\n hx-swap=\"none\"\n hx-on::after-request=\"location.reload()\"\n hx-headers='{\"X-CSRF-TOKEN\": \"<?= $csrfToken ?>\"}'>\n reference: \"content\/show.php:163\"\n use_when: \"Gesamte Seite muss nach Aktion aktualisiert werden\"\n\n # Pattern 3: Delete mit Confirmation\n delete_with_confirm:\n description: \"Löschen mit Bestätigung\"\n example: |\n <button hx-delete=\"\/resource\/{id}\"\n hx-confirm=\"Wirklich löschen?\"\n hx-swap=\"outerHTML\"\n hx-headers='{\"X-CSRF-TOKEN\": \"<?= $csrfToken ?>\"}'>\n reference: \"chat\/partials\/session-list.php:35-37\"\n use_when: \"Destruktive Aktion mit Bestätigung\"\n\n # Pattern 4: Polling für Live-Updates\n polling_live_update:\n description: \"Periodisches Polling für Status-Updates\"\n example: |\n <div hx-get=\"\/status\/{id}\"\n hx-trigger=\"load delay:1s\"\n hx-swap=\"outerHTML\">\n reference: \"content\/partials\/generating.php:12-15\"\n use_when: \"Live-Status während langer Operationen\"\n\n # Pattern 5: Lazy-Load\n lazy_load:\n description: \"Content erst bei Sichtbarkeit laden\"\n example: |\n <div hx-get=\"\/content\/{id}\"\n hx-trigger=\"revealed\"\n hx-swap=\"innerHTML\">\n <span class=\"loading\">Lade...<\/span>\n <\/div>\n use_when: \"Schwere Inhalte erst bei Bedarf laden\"\n\n # ==========================================================================\n # ENFORCEMENT\n # ==========================================================================\n\n enforcement:\n on_violation: warn\n block_on_critical: true\n\n pass_threshold:\n critical_max: 0\n major_max: 2\n minor_max: 5\n\n # ==========================================================================\n # MIGRATION GUIDE\n # ==========================================================================\n\n migration:\n from_traditional_form:\n before: |\n <form method=\"post\" action=\"\/endpoint\">\n <?= $csrfField ?>\n <button type=\"submit\">Submit<\/button>\n <\/form>\n after: |\n <button hx-post=\"\/endpoint\"\n hx-headers='{\"X-CSRF-TOKEN\": \"<?= $csrfToken ?>\"}'\n hx-swap=\"none\"\n hx-on::after-request=\"location.reload()\">\n Submit\n <\/button>\n notes: |\n - csrfField → hx-headers mit csrfToken\n - Backend muss isHtmxRequest() prüfen\n - Non-JS Fallback bedenken\n\n from_fetch:\n before: |\n <button onclick=\"fetch('\/api', {method:'POST'}).then(...)\">\n after: |\n <button hx-post=\"\/api\"\n hx-target=\"#result\"\n hx-swap=\"innerHTML\">\n notes: |\n - Nur für einfache Requests\n - Streaming (SSE) weiterhin mit fetch()\n"
}
}
}
{
"tool_response": [
{
"type": "text",
"text": "{\n \"status\": \"success\",\n \"table\": \"contracts\",\n \"inserted_id\": 14,\n \"execution_ms\": 1\n}"
}
]
}