{"total":788,"items":[{"id":2,"slug":"mcp-demo","title":"MCP Demo","meta_description":"Erstellt vom MCP-Smoketest","content":"<h1>MCP funktioniert</h1><p>Diese Seite wurde via Python <strong>MCP-Server</strong> erzeugt.</p><ol><li>list_pages</li><li>create_page</li><li>get_page</li></ol>","created_at":"2026-05-21T02:38:19+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":48,"konversionen":25},{"id":1185,"slug":"slug-liste","title":"Slug-Liste","meta_description":"Vollständige alphabetische Liste der aktuell in ki-web vorhandenen Slugs.","content":"<h1>Slug-Liste</h1><p>Vollständige alphabetische Liste der aktuell in ki-web vorhandenen Slugs. Anzahl: <strong>773</strong>.</p><ul><li><a href=\"/api-referenz\">api-referenz</a></li><li><a href=\"/code\">code</a></li><li><a href=\"/code/css\">code/css</a></li><li><a href=\"/code/css/rules\">code/css/rules</a></li><li><a href=\"/code/css/rules/css-001-external-css-only\">code/css/rules/css-001-external-css-only</a></li><li><a href=\"/code/css/rules/css-002-no-css-frameworks-for-first-party-ui\">code/css/rules/css-002-no-css-frameworks-for-first-party-ui</a></li><li><a href=\"/code/css/rules/css-003-css-is-presentation-adapter\">code/css/rules/css-003-css-is-presentation-adapter</a></li><li><a href=\"/code/css/rules/css-004-no-authorization-by-display-none\">code/css/rules/css-004-no-authorization-by-display-none</a></li><li><a href=\"/code/css/rules/css-005-file-role-single-responsibility\">code/css/rules/css-005-file-role-single-responsibility</a></li><li><a href=\"/code/css/rules/css-006-maxloc-file\">code/css/rules/css-006-maxloc-file</a></li><li><a href=\"/code/css/rules/css-007-maxloc-rule-block\">code/css/rules/css-007-maxloc-rule-block</a></li><li><a href=\"/code/css/rules/css-008-cascade-layers-for-new-global-css\">code/css/rules/css-008-cascade-layers-for-new-global-css</a></li><li><a href=\"/code/css/rules/css-009-imports-avoided-at-runtime\">code/css/rules/css-009-imports-avoided-at-runtime</a></li><li><a href=\"/code/css/rules/css-010-low-specificity-by-default\">code/css/rules/css-010-low-specificity-by-default</a></li><li><a href=\"/code/css/rules/css-011-no-id-selectors-for-style\">code/css/rules/css-011-no-id-selectors-for-style</a></li><li><a href=\"/code/css/rules/css-012-no-important-except-accessibility-override\">code/css/rules/css-012-no-important-except-accessibility-override</a></li><li><a href=\"/code/css/rules/css-013-nesting-depth-limit\">code/css/rules/css-013-nesting-depth-limit</a></li><li><a href=\"/code/css/rules/css-014-scope-components-by-root\">code/css/rules/css-014-scope-components-by-root</a></li><li><a href=\"/code/css/rules/css-015-component-state-matrix-complete\">code/css/rules/css-015-component-state-matrix-complete</a></li><li><a href=\"/code/css/rules/css-016-design-tokens-semantic\">code/css/rules/css-016-design-tokens-semantic</a></li><li><a href=\"/code/css/rules/css-017-token-names-not-visual-only\">code/css/rules/css-017-token-names-not-visual-only</a></li><li><a href=\"/code/css/rules/css-018-token-fallbacks-for-cross-project-reuse\">code/css/rules/css-018-token-fallbacks-for-cross-project-reuse</a></li><li><a href=\"/code/css/rules/css-019-no-style-as-data-source\">code/css/rules/css-019-no-style-as-data-source</a></li><li><a href=\"/code/css/rules/css-020-js-toggles-state-not-style\">code/css/rules/css-020-js-toggles-state-not-style</a></li><li><a href=\"/code/css/rules/css-021-no-modals-or-modal-tokens\">code/css/rules/css-021-no-modals-or-modal-tokens</a></li><li><a href=\"/code/css/rules/css-022-overlay-only-for-non-modal-system-states\">code/css/rules/css-022-overlay-only-for-non-modal-system-states</a></li><li><a href=\"/code/css/rules/css-023-focus-visible-never-removed\">code/css/rules/css-023-focus-visible-never-removed</a></li><li><a href=\"/code/css/rules/css-024-text-contrast-light-dark\">code/css/rules/css-024-text-contrast-light-dark</a></li><li><a href=\"/code/css/rules/css-025-non-text-contrast\">code/css/rules/css-025-non-text-contrast</a></li><li><a href=\"/code/css/rules/css-026-not-color-only\">code/css/rules/css-026-not-color-only</a></li><li><a href=\"/code/css/rules/css-027-visually-hidden-pattern-safe\">code/css/rules/css-027-visually-hidden-pattern-safe</a></li><li><a href=\"/code/css/rules/css-028-hidden-state-matches-semantics\">code/css/rules/css-028-hidden-state-matches-semantics</a></li><li><a href=\"/code/css/rules/css-029-reduced-motion\">code/css/rules/css-029-reduced-motion</a></li><li><a href=\"/code/css/rules/css-030-forced-colors-compatible\">code/css/rules/css-030-forced-colors-compatible</a></li><li><a href=\"/code/css/rules/css-031-light-dark-system-theme\">code/css/rules/css-031-light-dark-system-theme</a></li><li><a href=\"/code/css/rules/css-032-no-flash-wrong-theme-css-support\">code/css/rules/css-032-no-flash-wrong-theme-css-support</a></li><li><a href=\"/code/css/rules/css-033-responsive-by-component\">code/css/rules/css-033-responsive-by-component</a></li><li><a href=\"/code/css/rules/css-034-reflow-320px\">code/css/rules/css-034-reflow-320px</a></li><li><a href=\"/code/css/rules/css-035-logical-properties-for-new-layout\">code/css/rules/css-035-logical-properties-for-new-layout</a></li><li><a href=\"/code/css/rules/css-036-touch-targets-and-pointer-media\">code/css/rules/css-036-touch-targets-and-pointer-media</a></li><li><a href=\"/code/css/rules/css-037-tables-keep-semantic-reachability\">code/css/rules/css-037-tables-keep-semantic-reachability</a></li><li><a href=\"/code/css/rules/css-038-live-filter-visual-status\">code/css/rules/css-038-live-filter-visual-status</a></li><li><a href=\"/code/css/rules/css-039-form-states-inline\">code/css/rules/css-039-form-states-inline</a></li><li><a href=\"/code/css/rules/css-040-print-and-export-styles\">code/css/rules/css-040-print-and-export-styles</a></li><li><a href=\"/code/css/rules/css-041-page-scoped-css\">code/css/rules/css-041-page-scoped-css</a></li><li><a href=\"/code/css/rules/css-042-unused-css-budget\">code/css/rules/css-042-unused-css-budget</a></li><li><a href=\"/code/css/rules/css-043-content-visibility-for-long-independent-sections\">code/css/rules/css-043-content-visibility-for-long-independent-sections</a></li><li><a href=\"/code/css/rules/css-044-no-layout-shift-from-late-styles\">code/css/rules/css-044-no-layout-shift-from-late-styles</a></li><li><a href=\"/code/css/rules/css-045-z-index-scale\">code/css/rules/css-045-z-index-scale</a></li><li><a href=\"/code/css/rules/css-046-no-text-clipping-or-viewport-font-scaling\">code/css/rules/css-046-no-text-clipping-or-viewport-font-scaling</a></li><li><a href=\"/code/css/rules/css-047-no-one-note-palette\">code/css/rules/css-047-no-one-note-palette</a></li><li><a href=\"/code/css/rules/css-048-stylelint-or-static-scan\">code/css/rules/css-048-stylelint-or-static-scan</a></li><li><a href=\"/code/css/rules/css-049-history-diff-states\">code/css/rules/css-049-history-diff-states</a></li><li><a href=\"/code/css/rules/css-050-history-layout-no-modal\">code/css/rules/css-050-history-layout-no-modal</a></li><li><a href=\"/code/css/rules/css-051-history-table-responsive-stable\">code/css/rules/css-051-history-table-responsive-stable</a></li><li><a href=\"/code/css/sources\">code/css/sources</a></li><li><a href=\"/code/deployment-config\">code/deployment-config</a></li><li><a href=\"/code/deployment-config/reflection-model\">code/deployment-config/reflection-model</a></li><li><a href=\"/code/deployment-config/rules\">code/deployment-config/rules</a></li><li><a href=\"/code/deployment-config/rules/deploy-001-config-outside-code\">code/deployment-config/rules/deploy-001-config-outside-code</a></li><li><a href=\"/code/deployment-config/rules/deploy-002-config-validation-at-boot\">code/deployment-config/rules/deploy-002-config-validation-at-boot</a></li><li><a href=\"/code/deployment-config/rules/deploy-003-secrets-not-versioned\">code/deployment-config/rules/deploy-003-secrets-not-versioned</a></li><li><a href=\"/code/deployment-config/rules/deploy-004-secret-rotation\">code/deployment-config/rules/deploy-004-secret-rotation</a></li><li><a href=\"/code/deployment-config/rules/deploy-005-ordered-deployment-steps\">code/deployment-config/rules/deploy-005-ordered-deployment-steps</a></li><li><a href=\"/code/deployment-config/rules/deploy-006-migration-deploy-plan\">code/deployment-config/rules/deploy-006-migration-deploy-plan</a></li><li><a href=\"/code/deployment-config/rules/deploy-007-backups-and-restore-tests\">code/deployment-config/rules/deploy-007-backups-and-restore-tests</a></li><li><a href=\"/code/deployment-config/rules/deploy-008-feature-flags-with-expiry\">code/deployment-config/rules/deploy-008-feature-flags-with-expiry</a></li><li><a href=\"/code/deployment-config/rules/deploy-009-runtime-process-supervision\">code/deployment-config/rules/deploy-009-runtime-process-supervision</a></li><li><a href=\"/code/deployment-config/rules/deploy-010-opcache-deploy-invalidation\">code/deployment-config/rules/deploy-010-opcache-deploy-invalidation</a></li><li><a href=\"/code/deployment-config/rules/deploy-011-security-headers-by-environment\">code/deployment-config/rules/deploy-011-security-headers-by-environment</a></li><li><a href=\"/code/deployment-config/rules/deploy-012-asset-versioning\">code/deployment-config/rules/deploy-012-asset-versioning</a></li><li><a href=\"/code/deployment-config/rules/deploy-013-no-client-exposed-internal-config\">code/deployment-config/rules/deploy-013-no-client-exposed-internal-config</a></li><li><a href=\"/code/deployment-config/rules/deploy-014-rollback-with-data-compatibility\">code/deployment-config/rules/deploy-014-rollback-with-data-compatibility</a></li><li><a href=\"/code/deployment-config/rules/deploy-015-target-schema-drift-blocks-migration\">code/deployment-config/rules/deploy-015-target-schema-drift-blocks-migration</a></li><li><a href=\"/code/deployment-config/rules/deploy-016-production-migration-requires-explicit-target-approva\">code/deployment-config/rules/deploy-016-production-migration-requires-explicit-target-approva</a></li><li><a href=\"/code/deployment-config/sources\">code/deployment-config/sources</a></li><li><a href=\"/code/gui\">code/gui</a></li><li><a href=\"/code/gui/auth-magic-code-session\">code/gui/auth-magic-code-session</a></li><li><a href=\"/code/gui/auth-magic-code-session/reflection-model\">code/gui/auth-magic-code-session/reflection-model</a></li><li><a href=\"/code/gui/auth-magic-code-session/rules\">code/gui/auth-magic-code-session/rules</a></li><li><a href=\"/code/gui/auth-magic-code-session/rules/auth-001-magic-code-not-cognitive-barrier\">code/gui/auth-magic-code-session/rules/auth-001-magic-code-not-cognitive-barrier</a></li><li><a href=\"/code/gui/auth-magic-code-session/rules/auth-002-code-input-label-and-purpose\">code/gui/auth-magic-code-session/rules/auth-002-code-input-label-and-purpose</a></li><li><a href=\"/code/gui/auth-magic-code-session/rules/auth-003-accept-paste-and-autocomplete\">code/gui/auth-magic-code-session/rules/auth-003-accept-paste-and-autocomplete</a></li><li><a href=\"/code/gui/auth-magic-code-session/rules/auth-004-no-redundant-reentry\">code/gui/auth-magic-code-session/rules/auth-004-no-redundant-reentry</a></li><li><a href=\"/code/gui/auth-magic-code-session/rules/auth-005-resend-and-expiry-are-clear\">code/gui/auth-magic-code-session/rules/auth-005-resend-and-expiry-are-clear</a></li><li><a href=\"/code/gui/auth-magic-code-session/rules/auth-006-error-messages-specific\">code/gui/auth-magic-code-session/rules/auth-006-error-messages-specific</a></li><li><a href=\"/code/gui/auth-magic-code-session/rules/auth-007-timeout-warning-before-expiry\">code/gui/auth-magic-code-session/rules/auth-007-timeout-warning-before-expiry</a></li><li><a href=\"/code/gui/auth-magic-code-session/rules/auth-008-session-extension-control\">code/gui/auth-magic-code-session/rules/auth-008-session-extension-control</a></li><li><a href=\"/code/gui/auth-magic-code-session/rules/auth-009-reauth-preserves-data\">code/gui/auth-magic-code-session/rules/auth-009-reauth-preserves-data</a></li><li><a href=\"/code/gui/auth-magic-code-session/rules/auth-010-no-modal-auth-or-timeout\">code/gui/auth-magic-code-session/rules/auth-010-no-modal-auth-or-timeout</a></li><li><a href=\"/code/gui/auth-magic-code-session/rules/auth-011-status-messages-for-auth-state\">code/gui/auth-magic-code-session/rules/auth-011-status-messages-for-auth-state</a></li><li><a href=\"/code/gui/auth-magic-code-session/rules/auth-012-focus-after-auth-events\">code/gui/auth-magic-code-session/rules/auth-012-focus-after-auth-events</a></li><li><a href=\"/code/gui/auth-magic-code-session/rules/auth-013-security-copy-is-actionable\">code/gui/auth-magic-code-session/rules/auth-013-security-copy-is-actionable</a></li><li><a href=\"/code/gui/auth-magic-code-session/rules/auth-014-pending-auth-state-not-in-url\">code/gui/auth-magic-code-session/rules/auth-014-pending-auth-state-not-in-url</a></li><li><a href=\"/code/gui/auth-magic-code-session/sources\">code/gui/auth-magic-code-session/sources</a></li><li><a href=\"/code/gui/bulk-aktionen\">code/gui/bulk-aktionen</a></li><li><a href=\"/code/gui/bulk-aktionen/rules\">code/gui/bulk-aktionen/rules</a></li><li><a href=\"/code/gui/bulk-aktionen/rules/bulk-001-real-checkboxes\">code/gui/bulk-aktionen/rules/bulk-001-real-checkboxes</a></li><li><a href=\"/code/gui/bulk-aktionen/rules/bulk-002-selected-count-status\">code/gui/bulk-aktionen/rules/bulk-002-selected-count-status</a></li><li><a href=\"/code/gui/bulk-aktionen/rules/bulk-003-scope-page-vs-results\">code/gui/bulk-aktionen/rules/bulk-003-scope-page-vs-results</a></li><li><a href=\"/code/gui/bulk-aktionen/rules/bulk-004-action-bar-visible\">code/gui/bulk-aktionen/rules/bulk-004-action-bar-visible</a></li><li><a href=\"/code/gui/bulk-aktionen/rules/bulk-005-no-modal-confirm\">code/gui/bulk-aktionen/rules/bulk-005-no-modal-confirm</a></li><li><a href=\"/code/gui/bulk-aktionen/rules/bulk-006-destructive-protection\">code/gui/bulk-aktionen/rules/bulk-006-destructive-protection</a></li><li><a href=\"/code/gui/bulk-aktionen/rules/bulk-007-keyboard-operable\">code/gui/bulk-aktionen/rules/bulk-007-keyboard-operable</a></li><li><a href=\"/code/gui/bulk-aktionen/rules/bulk-008-preserve-context\">code/gui/bulk-aktionen/rules/bulk-008-preserve-context</a></li><li><a href=\"/code/gui/bulk-aktionen/rules/bulk-009-partial-failures\">code/gui/bulk-aktionen/rules/bulk-009-partial-failures</a></li><li><a href=\"/code/gui/bulk-aktionen/sources\">code/gui/bulk-aktionen/sources</a></li><li><a href=\"/code/gui/charts-visualisierungen\">code/gui/charts-visualisierungen</a></li><li><a href=\"/code/gui/charts-visualisierungen/reflection-model\">code/gui/charts-visualisierungen/reflection-model</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules\">code/gui/charts-visualisierungen/rules</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules/chart-001-text-alternative-required\">code/gui/charts-visualisierungen/rules/chart-001-text-alternative-required</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules/chart-002-complex-description-or-data\">code/gui/charts-visualisierungen/rules/chart-002-complex-description-or-data</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules/chart-003-data-table-available\">code/gui/charts-visualisierungen/rules/chart-003-data-table-available</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules/chart-004-not-color-only\">code/gui/charts-visualisierungen/rules/chart-004-not-color-only</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules/chart-005-contrast-for-marks-and-text\">code/gui/charts-visualisierungen/rules/chart-005-contrast-for-marks-and-text</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules/chart-006-axes-legend-and-units\">code/gui/charts-visualisierungen/rules/chart-006-axes-legend-and-units</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules/chart-007-tooltip-not-hover-only\">code/gui/charts-visualisierungen/rules/chart-007-tooltip-not-hover-only</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules/chart-008-keyboard-drilldown\">code/gui/charts-visualisierungen/rules/chart-008-keyboard-drilldown</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules/chart-009-reduced-motion\">code/gui/charts-visualisierungen/rules/chart-009-reduced-motion</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules/chart-010-responsive-reflow\">code/gui/charts-visualisierungen/rules/chart-010-responsive-reflow</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules/chart-011-dynamic-updates-status\">code/gui/charts-visualisierungen/rules/chart-011-dynamic-updates-status</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules/chart-012-export-or-data-access\">code/gui/charts-visualisierungen/rules/chart-012-export-or-data-access</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules/chart-013-empty-loading-error-states\">code/gui/charts-visualisierungen/rules/chart-013-empty-loading-error-states</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules/chart-014-no-auto-refresh-without-control\">code/gui/charts-visualisierungen/rules/chart-014-no-auto-refresh-without-control</a></li><li><a href=\"/code/gui/charts-visualisierungen/rules/chart-015-no-modal-chart-details\">code/gui/charts-visualisierungen/rules/chart-015-no-modal-chart-details</a></li><li><a href=\"/code/gui/charts-visualisierungen/sources\">code/gui/charts-visualisierungen/sources</a></li><li><a href=\"/code/gui/chat-ai-composer\">code/gui/chat-ai-composer</a></li><li><a href=\"/code/gui/chat-ai-composer/reflection-model\">code/gui/chat-ai-composer/reflection-model</a></li><li><a href=\"/code/gui/chat-ai-composer/rules\">code/gui/chat-ai-composer/rules</a></li><li><a href=\"/code/gui/chat-ai-composer/rules/chat-001-composer-label-and-submit\">code/gui/chat-ai-composer/rules/chat-001-composer-label-and-submit</a></li><li><a href=\"/code/gui/chat-ai-composer/rules/chat-002-streaming-does-not-steal-focus\">code/gui/chat-ai-composer/rules/chat-002-streaming-does-not-steal-focus</a></li><li><a href=\"/code/gui/chat-ai-composer/rules/chat-003-status-for-generation\">code/gui/chat-ai-composer/rules/chat-003-status-for-generation</a></li><li><a href=\"/code/gui/chat-ai-composer/rules/chat-004-feed-or-list-structure\">code/gui/chat-ai-composer/rules/chat-004-feed-or-list-structure</a></li><li><a href=\"/code/gui/chat-ai-composer/rules/chat-005-source-citations-actionable\">code/gui/chat-ai-composer/rules/chat-005-source-citations-actionable</a></li><li><a href=\"/code/gui/chat-ai-composer/rules/chat-006-retry-stop-and-error-recovery\">code/gui/chat-ai-composer/rules/chat-006-retry-stop-and-error-recovery</a></li><li><a href=\"/code/gui/chat-ai-composer/rules/chat-007-thread-switch-preserves-draft\">code/gui/chat-ai-composer/rules/chat-007-thread-switch-preserves-draft</a></li><li><a href=\"/code/gui/chat-ai-composer/rules/chat-008-streaming-animation-reducible\">code/gui/chat-ai-composer/rules/chat-008-streaming-animation-reducible</a></li><li><a href=\"/code/gui/chat-ai-composer/rules/chat-009-authoring-support-for-ai-output\">code/gui/chat-ai-composer/rules/chat-009-authoring-support-for-ai-output</a></li><li><a href=\"/code/gui/chat-ai-composer/rules/chat-010-no-modal-chat-flow\">code/gui/chat-ai-composer/rules/chat-010-no-modal-chat-flow</a></li><li><a href=\"/code/gui/chat-ai-composer/sources\">code/gui/chat-ai-composer/sources</a></li><li><a href=\"/code/gui/checkout-finanzfluesse\">code/gui/checkout-finanzfluesse</a></li><li><a href=\"/code/gui/checkout-finanzfluesse/reflection-model\">code/gui/checkout-finanzfluesse/reflection-model</a></li><li><a href=\"/code/gui/checkout-finanzfluesse/rules\">code/gui/checkout-finanzfluesse/rules</a></li><li><a href=\"/code/gui/checkout-finanzfluesse/rules/checkout-001-costs-visible-before-payment\">code/gui/checkout-finanzfluesse/rules/checkout-001-costs-visible-before-payment</a></li><li><a href=\"/code/gui/checkout-finanzfluesse/rules/checkout-002-review-correct-or-cancel\">code/gui/checkout-finanzfluesse/rules/checkout-002-review-correct-or-cancel</a></li><li><a href=\"/code/gui/checkout-finanzfluesse/rules/checkout-003-provider-status-visible\">code/gui/checkout-finanzfluesse/rules/checkout-003-provider-status-visible</a></li><li><a href=\"/code/gui/checkout-finanzfluesse/rules/checkout-004-preserve-form-on-provider-return\">code/gui/checkout-finanzfluesse/rules/checkout-004-preserve-form-on-provider-return</a></li><li><a href=\"/code/gui/checkout-finanzfluesse/rules/checkout-005-tax-fields-contextual-and-explained\">code/gui/checkout-finanzfluesse/rules/checkout-005-tax-fields-contextual-and-explained</a></li><li><a href=\"/code/gui/checkout-finanzfluesse/rules/checkout-006-idempotent-submit-and-no-double-charge\">code/gui/checkout-finanzfluesse/rules/checkout-006-idempotent-submit-and-no-double-charge</a></li><li><a href=\"/code/gui/checkout-finanzfluesse/rules/checkout-007-no-modal-financial-flow\">code/gui/checkout-finanzfluesse/rules/checkout-007-no-modal-financial-flow</a></li><li><a href=\"/code/gui/checkout-finanzfluesse/rules/checkout-008-external-provider-handoff-disclosed\">code/gui/checkout-finanzfluesse/rules/checkout-008-external-provider-handoff-disclosed</a></li><li><a href=\"/code/gui/checkout-finanzfluesse/rules/checkout-009-receipt-and-next-step\">code/gui/checkout-finanzfluesse/rules/checkout-009-receipt-and-next-step</a></li><li><a href=\"/code/gui/checkout-finanzfluesse/rules/checkout-010-accessible-trust-and-legal-copy\">code/gui/checkout-finanzfluesse/rules/checkout-010-accessible-trust-and-legal-copy</a></li><li><a href=\"/code/gui/checkout-finanzfluesse/sources\">code/gui/checkout-finanzfluesse/sources</a></li><li><a href=\"/code/gui/consent-signatur-fragebogen\">code/gui/consent-signatur-fragebogen</a></li><li><a href=\"/code/gui/consent-signatur-fragebogen/reflection-model\">code/gui/consent-signatur-fragebogen/reflection-model</a></li><li><a href=\"/code/gui/consent-signatur-fragebogen/rules\">code/gui/consent-signatur-fragebogen/rules</a></li><li><a href=\"/code/gui/consent-signatur-fragebogen/rules/consent-001-explicit-unchecked-consent\">code/gui/consent-signatur-fragebogen/rules/consent-001-explicit-unchecked-consent</a></li><li><a href=\"/code/gui/consent-signatur-fragebogen/rules/consent-002-labels-groups-and-required-state\">code/gui/consent-signatur-fragebogen/rules/consent-002-labels-groups-and-required-state</a></li><li><a href=\"/code/gui/consent-signatur-fragebogen/rules/consent-003-review-before-final-submit\">code/gui/consent-signatur-fragebogen/rules/consent-003-review-before-final-submit</a></li><li><a href=\"/code/gui/consent-signatur-fragebogen/rules/consent-004-signature-has-accessible-alternative\">code/gui/consent-signatur-fragebogen/rules/consent-004-signature-has-accessible-alternative</a></li><li><a href=\"/code/gui/consent-signatur-fragebogen/rules/consent-005-pointer-cancellation-for-signature\">code/gui/consent-signatur-fragebogen/rules/consent-005-pointer-cancellation-for-signature</a></li><li><a href=\"/code/gui/consent-signatur-fragebogen/rules/consent-006-draft-and-error-preservation\">code/gui/consent-signatur-fragebogen/rules/consent-006-draft-and-error-preservation</a></li><li><a href=\"/code/gui/consent-signatur-fragebogen/rules/consent-007-status-for-submit-and-pdf\">code/gui/consent-signatur-fragebogen/rules/consent-007-status-for-submit-and-pdf</a></li><li><a href=\"/code/gui/consent-signatur-fragebogen/rules/consent-008-read-only-after-submit-clear\">code/gui/consent-signatur-fragebogen/rules/consent-008-read-only-after-submit-clear</a></li><li><a href=\"/code/gui/consent-signatur-fragebogen/rules/consent-009-no-modal-consent-signature-flow\">code/gui/consent-signatur-fragebogen/rules/consent-009-no-modal-consent-signature-flow</a></li><li><a href=\"/code/gui/consent-signatur-fragebogen/sources\">code/gui/consent-signatur-fragebogen/sources</a></li><li><a href=\"/code/gui/datentabellen-crud\">code/gui/datentabellen-crud</a></li><li><a href=\"/code/gui/datentabellen-crud/rules\">code/gui/datentabellen-crud/rules</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/action-001-create-visible\">code/gui/datentabellen-crud/rules/action-001-create-visible</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/action-002-row-actions-named\">code/gui/datentabellen-crud/rules/action-002-row-actions-named</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/action-003-destructive-confirm-or-undo\">code/gui/datentabellen-crud/rules/action-003-destructive-confirm-or-undo</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/action-004-actions-available-on-focus-and-touch\">code/gui/datentabellen-crud/rules/action-004-actions-available-on-focus-and-touch</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/consistency-001-crud-labels\">code/gui/datentabellen-crud/rules/consistency-001-crud-labels</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/data-001-formats-units-and-alignment\">code/gui/datentabellen-crud/rules/data-001-formats-units-and-alignment</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/data-002-truncation-recoverable\">code/gui/datentabellen-crud/rules/data-002-truncation-recoverable</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/data-003-column-priority\">code/gui/datentabellen-crud/rules/data-003-column-priority</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/empty-001-actionable-empty-state\">code/gui/datentabellen-crud/rules/empty-001-actionable-empty-state</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/filter-001-filters-labelled\">code/gui/datentabellen-crud/rules/filter-001-filters-labelled</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/filter-002-clear-filters\">code/gui/datentabellen-crud/rules/filter-002-clear-filters</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/filter-003-result-count-status\">code/gui/datentabellen-crud/rules/filter-003-result-count-status</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/filter-004-table-search-filters-live-sync\">code/gui/datentabellen-crud/rules/filter-004-table-search-filters-live-sync</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/filter-005-live-filtering-without-context-jump\">code/gui/datentabellen-crud/rules/filter-005-live-filtering-without-context-jump</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/focus-001-visible-focus\">code/gui/datentabellen-crud/rules/focus-001-visible-focus</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/focus-002-enhanced-focus-appearance\">code/gui/datentabellen-crud/rules/focus-002-enhanced-focus-appearance</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/grid-001-only-for-interactive-grids\">code/gui/datentabellen-crud/rules/grid-001-only-for-interactive-grids</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/grid-002-apg-keyboard-model\">code/gui/datentabellen-crud/rules/grid-002-apg-keyboard-model</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/grid-003-grid-cells-focusable-or-labelled\">code/gui/datentabellen-crud/rules/grid-003-grid-cells-focusable-or-labelled</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/header-001-th-for-headers\">code/gui/datentabellen-crud/rules/header-001-th-for-headers</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/header-002-scope-simple-tables\">code/gui/datentabellen-crud/rules/header-002-scope-simple-tables</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/header-003-id-headers-complex-tables\">code/gui/datentabellen-crud/rules/header-003-id-headers-complex-tables</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/pagination-001-discoverable-controls\">code/gui/datentabellen-crud/rules/pagination-001-discoverable-controls</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/pagination-002-state-in-url\">code/gui/datentabellen-crud/rules/pagination-002-state-in-url</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/pagination-003-focus-after-page-change\">code/gui/datentabellen-crud/rules/pagination-003-focus-after-page-change</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/policy-001-no-modal-crud-table-actions\">code/gui/datentabellen-crud/rules/policy-001-no-modal-crud-table-actions</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/responsive-001-keep-grid-structure\">code/gui/datentabellen-crud/rules/responsive-001-keep-grid-structure</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/responsive-002-scroll-region-labelled\">code/gui/datentabellen-crud/rules/responsive-002-scroll-region-labelled</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/responsive-003-no-critical-actions-hidden\">code/gui/datentabellen-crud/rules/responsive-003-no-critical-actions-hidden</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/route-001-defined-entry-is-link\">code/gui/datentabellen-crud/rules/route-001-defined-entry-is-link</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/route-002-canonical-slug-href\">code/gui/datentabellen-crud/rules/route-002-canonical-slug-href</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/route-003-slug-valid-and-stable\">code/gui/datentabellen-crud/rules/route-003-slug-valid-and-stable</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/route-004-link-purpose-context\">code/gui/datentabellen-crud/rules/route-004-link-purpose-context</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/route-005-row-click-duplicates-link-only\">code/gui/datentabellen-crud/rules/route-005-row-click-duplicates-link-only</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/route-006-no-nested-interactive-row-links\">code/gui/datentabellen-crud/rules/route-006-no-nested-interactive-row-links</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/search-001-search-covers-visible-data\">code/gui/datentabellen-crud/rules/search-001-search-covers-visible-data</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/search-002-search-scope-visible\">code/gui/datentabellen-crud/rules/search-002-search-scope-visible</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/selection-001-checkboxes-for-bulk\">code/gui/datentabellen-crud/rules/selection-001-checkboxes-for-bulk</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/sort-001-sort-buttons-in-headers\">code/gui/datentabellen-crud/rules/sort-001-sort-buttons-in-headers</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/sort-002-aria-sort-state\">code/gui/datentabellen-crud/rules/sort-002-aria-sort-state</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/status-001-loading-busy\">code/gui/datentabellen-crud/rules/status-001-loading-busy</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/status-002-crud-result-messages\">code/gui/datentabellen-crud/rules/status-002-crud-result-messages</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/table-001-native-data-table\">code/gui/datentabellen-crud/rules/table-001-native-data-table</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/table-002-no-layout-table\">code/gui/datentabellen-crud/rules/table-002-no-layout-table</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/table-003-caption-or-label\">code/gui/datentabellen-crud/rules/table-003-caption-or-label</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/table-004-summary-for-complex-tables\">code/gui/datentabellen-crud/rules/table-004-summary-for-complex-tables</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/target-001-wcag-aa-minimum\">code/gui/datentabellen-crud/rules/target-001-wcag-aa-minimum</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/target-002-enhanced-44px-primary\">code/gui/datentabellen-crud/rules/target-002-enhanced-44px-primary</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/visual-001-text-contrast\">code/gui/datentabellen-crud/rules/visual-001-text-contrast</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/visual-002-non-text-contrast\">code/gui/datentabellen-crud/rules/visual-002-non-text-contrast</a></li><li><a href=\"/code/gui/datentabellen-crud/rules/visual-003-not-color-only\">code/gui/datentabellen-crud/rules/visual-003-not-color-only</a></li><li><a href=\"/code/gui/datentabellen-crud/sources\">code/gui/datentabellen-crud/sources</a></li><li><a href=\"/code/gui/detailseiten-crud\">code/gui/detailseiten-crud</a></li><li><a href=\"/code/gui/detailseiten-crud/rules\">code/gui/detailseiten-crud/rules</a></li><li><a href=\"/code/gui/detailseiten-crud/rules/detail-001-canonical-slug-route\">code/gui/detailseiten-crud/rules/detail-001-canonical-slug-route</a></li><li><a href=\"/code/gui/detailseiten-crud/rules/detail-002-page-title-and-h1\">code/gui/detailseiten-crud/rules/detail-002-page-title-and-h1</a></li><li><a href=\"/code/gui/detailseiten-crud/rules/detail-003-breadcrumb-or-back\">code/gui/detailseiten-crud/rules/detail-003-breadcrumb-or-back</a></li><li><a href=\"/code/gui/detailseiten-crud/rules/detail-004-action-hierarchy\">code/gui/detailseiten-crud/rules/detail-004-action-hierarchy</a></li><li><a href=\"/code/gui/detailseiten-crud/rules/detail-005-no-modal-actions\">code/gui/detailseiten-crud/rules/detail-005-no-modal-actions</a></li><li><a href=\"/code/gui/detailseiten-crud/rules/detail-006-destructive-confirm-or-undo\">code/gui/detailseiten-crud/rules/detail-006-destructive-confirm-or-undo</a></li><li><a href=\"/code/gui/detailseiten-crud/rules/detail-007-status-visible\">code/gui/detailseiten-crud/rules/detail-007-status-visible</a></li><li><a href=\"/code/gui/detailseiten-crud/rules/detail-008-metadata-and-audit\">code/gui/detailseiten-crud/rules/detail-008-metadata-and-audit</a></li><li><a href=\"/code/gui/detailseiten-crud/rules/detail-009-save-feedback\">code/gui/detailseiten-crud/rules/detail-009-save-feedback</a></li><li><a href=\"/code/gui/detailseiten-crud/rules/detail-010-unsaved-changes-no-modal\">code/gui/detailseiten-crud/rules/detail-010-unsaved-changes-no-modal</a></li><li><a href=\"/code/gui/detailseiten-crud/sources\">code/gui/detailseiten-crud/sources</a></li><li><a href=\"/code/gui/dialoge-modals\">code/gui/dialoge-modals</a></li><li><a href=\"/code/gui/dialoge-modals/rules\">code/gui/dialoge-modals/rules</a></li><li><a href=\"/code/gui/dialoge-modals/rules/modal-001-no-modal-dialogs\">code/gui/dialoge-modals/rules/modal-001-no-modal-dialogs</a></li><li><a href=\"/code/gui/dialoge-modals/rules/modal-002-no-blocking-overlays\">code/gui/dialoge-modals/rules/modal-002-no-blocking-overlays</a></li><li><a href=\"/code/gui/dialoge-modals/rules/modal-003-no-js-confirm-alert-prompt\">code/gui/dialoge-modals/rules/modal-003-no-js-confirm-alert-prompt</a></li><li><a href=\"/code/gui/dialoge-modals/rules/modal-004-inline-confirm-for-destructive-actions\">code/gui/dialoge-modals/rules/modal-004-inline-confirm-for-destructive-actions</a></li><li><a href=\"/code/gui/dialoge-modals/rules/modal-005-dedicated-page-for-complex-tasks\">code/gui/dialoge-modals/rules/modal-005-dedicated-page-for-complex-tasks</a></li><li><a href=\"/code/gui/dialoge-modals/rules/modal-006-undo-for-reversible-mutations\">code/gui/dialoge-modals/rules/modal-006-undo-for-reversible-mutations</a></li><li><a href=\"/code/gui/dialoge-modals/rules/modal-007-disclosure-not-overlay\">code/gui/dialoge-modals/rules/modal-007-disclosure-not-overlay</a></li><li><a href=\"/code/gui/dialoge-modals/rules/modal-008-status-not-modal\">code/gui/dialoge-modals/rules/modal-008-status-not-modal</a></li><li><a href=\"/code/gui/dialoge-modals/rules/modal-009-focus-stays-in-page-flow\">code/gui/dialoge-modals/rules/modal-009-focus-stays-in-page-flow</a></li><li><a href=\"/code/gui/dialoge-modals/rules/modal-010-no-popover-for-required-input\">code/gui/dialoge-modals/rules/modal-010-no-popover-for-required-input</a></li><li><a href=\"/code/gui/dialoge-modals/sources\">code/gui/dialoge-modals/sources</a></li><li><a href=\"/code/gui/dokumentenbaum-viewer-dragdrop\">code/gui/dokumentenbaum-viewer-dragdrop</a></li><li><a href=\"/code/gui/dokumentenbaum-viewer-dragdrop/reflection-model\">code/gui/dokumentenbaum-viewer-dragdrop/reflection-model</a></li><li><a href=\"/code/gui/dokumentenbaum-viewer-dragdrop/rules\">code/gui/dokumentenbaum-viewer-dragdrop/rules</a></li><li><a href=\"/code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-001-treeview-apg-or-native-list\">code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-001-treeview-apg-or-native-list</a></li><li><a href=\"/code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-002-drag-drop-has-non-drag-alternative\">code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-002-drag-drop-has-non-drag-alternative</a></li><li><a href=\"/code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-003-selected-context-visible\">code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-003-selected-context-visible</a></li><li><a href=\"/code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-004-viewer-has-accessible-text\">code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-004-viewer-has-accessible-text</a></li><li><a href=\"/code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-005-page-and-chunk-navigation\">code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-005-page-and-chunk-navigation</a></li><li><a href=\"/code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-006-delete-move-share-inline-confirm\">code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-006-delete-move-share-inline-confirm</a></li><li><a href=\"/code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-007-async-operations-status\">code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-007-async-operations-status</a></li><li><a href=\"/code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-008-permissions-and-sharing-clear\">code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-008-permissions-and-sharing-clear</a></li><li><a href=\"/code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-009-no-modal-document-flow\">code/gui/dokumentenbaum-viewer-dragdrop/rules/docs-009-no-modal-document-flow</a></li><li><a href=\"/code/gui/dokumentenbaum-viewer-dragdrop/sources\">code/gui/dokumentenbaum-viewer-dragdrop/sources</a></li><li><a href=\"/code/gui/dropdowns-menues\">code/gui/dropdowns-menues</a></li><li><a href=\"/code/gui/dropdowns-menues/rules\">code/gui/dropdowns-menues/rules</a></li><li><a href=\"/code/gui/dropdowns-menues/rules/menu-001-native-select-for-value-choice\">code/gui/dropdowns-menues/rules/menu-001-native-select-for-value-choice</a></li><li><a href=\"/code/gui/dropdowns-menues/rules/menu-002-button-trigger\">code/gui/dropdowns-menues/rules/menu-002-button-trigger</a></li><li><a href=\"/code/gui/dropdowns-menues/rules/menu-003-menu-button-state\">code/gui/dropdowns-menues/rules/menu-003-menu-button-state</a></li><li><a href=\"/code/gui/dropdowns-menues/rules/menu-004-keyboard-model\">code/gui/dropdowns-menues/rules/menu-004-keyboard-model</a></li><li><a href=\"/code/gui/dropdowns-menues/rules/menu-005-no-nav-menu-role-for-simple-nav\">code/gui/dropdowns-menues/rules/menu-005-no-nav-menu-role-for-simple-nav</a></li><li><a href=\"/code/gui/dropdowns-menues/rules/menu-006-item-names\">code/gui/dropdowns-menues/rules/menu-006-item-names</a></li><li><a href=\"/code/gui/dropdowns-menues/rules/menu-007-destructive-separation\">code/gui/dropdowns-menues/rules/menu-007-destructive-separation</a></li><li><a href=\"/code/gui/dropdowns-menues/rules/menu-008-no-modal-from-menu\">code/gui/dropdowns-menues/rules/menu-008-no-modal-from-menu</a></li><li><a href=\"/code/gui/dropdowns-menues/rules/menu-009-disabled-items\">code/gui/dropdowns-menues/rules/menu-009-disabled-items</a></li><li><a href=\"/code/gui/dropdowns-menues/rules/menu-010-target-size\">code/gui/dropdowns-menues/rules/menu-010-target-size</a></li><li><a href=\"/code/gui/dropdowns-menues/sources\">code/gui/dropdowns-menues/sources</a></li><li><a href=\"/code/gui/editoren-versionierung\">code/gui/editoren-versionierung</a></li><li><a href=\"/code/gui/editoren-versionierung/reflection-model\">code/gui/editoren-versionierung/reflection-model</a></li><li><a href=\"/code/gui/editoren-versionierung/rules\">code/gui/editoren-versionierung/rules</a></li><li><a href=\"/code/gui/editoren-versionierung/rules/editor-001-textarea-or-accessible-editor\">code/gui/editoren-versionierung/rules/editor-001-textarea-or-accessible-editor</a></li><li><a href=\"/code/gui/editoren-versionierung/rules/editor-002-dirty-state-and-unsaved-changes\">code/gui/editoren-versionierung/rules/editor-002-dirty-state-and-unsaved-changes</a></li><li><a href=\"/code/gui/editoren-versionierung/rules/editor-003-autosave-status\">code/gui/editoren-versionierung/rules/editor-003-autosave-status</a></li><li><a href=\"/code/gui/editoren-versionierung/rules/editor-004-placeholder-insert-accessible\">code/gui/editoren-versionierung/rules/editor-004-placeholder-insert-accessible</a></li><li><a href=\"/code/gui/editoren-versionierung/rules/editor-005-preview-inline-and-accessible\">code/gui/editoren-versionierung/rules/editor-005-preview-inline-and-accessible</a></li><li><a href=\"/code/gui/editoren-versionierung/rules/editor-006-version-history-identifiable\">code/gui/editoren-versionierung/rules/editor-006-version-history-identifiable</a></li><li><a href=\"/code/gui/editoren-versionierung/rules/editor-007-publish-archive-review\">code/gui/editoren-versionierung/rules/editor-007-publish-archive-review</a></li><li><a href=\"/code/gui/editoren-versionierung/rules/editor-008-ai-draft-requires-human-review\">code/gui/editoren-versionierung/rules/editor-008-ai-draft-requires-human-review</a></li><li><a href=\"/code/gui/editoren-versionierung/rules/editor-009-no-modal-editor-flow\">code/gui/editoren-versionierung/rules/editor-009-no-modal-editor-flow</a></li><li><a href=\"/code/gui/editoren-versionierung/rules/editor-010-history-gui-for-restore\">code/gui/editoren-versionierung/rules/editor-010-history-gui-for-restore</a></li><li><a href=\"/code/gui/editoren-versionierung/rules/editor-011-history-live-filter-and-sort\">code/gui/editoren-versionierung/rules/editor-011-history-live-filter-and-sort</a></li><li><a href=\"/code/gui/editoren-versionierung/rules/editor-012-restore-requires-review-no-modal\">code/gui/editoren-versionierung/rules/editor-012-restore-requires-review-no-modal</a></li><li><a href=\"/code/gui/editoren-versionierung/sources\">code/gui/editoren-versionierung/sources</a></li><li><a href=\"/code/gui/feedback-statusmeldungen\">code/gui/feedback-statusmeldungen</a></li><li><a href=\"/code/gui/feedback-statusmeldungen/rules\">code/gui/feedback-statusmeldungen/rules</a></li><li><a href=\"/code/gui/feedback-statusmeldungen/rules/feedback-001-status-role\">code/gui/feedback-statusmeldungen/rules/feedback-001-status-role</a></li><li><a href=\"/code/gui/feedback-statusmeldungen/rules/feedback-002-no-modal-feedback\">code/gui/feedback-statusmeldungen/rules/feedback-002-no-modal-feedback</a></li><li><a href=\"/code/gui/feedback-statusmeldungen/rules/feedback-003-error-summary\">code/gui/feedback-statusmeldungen/rules/feedback-003-error-summary</a></li><li><a href=\"/code/gui/feedback-statusmeldungen/rules/feedback-004-inline-association\">code/gui/feedback-statusmeldungen/rules/feedback-004-inline-association</a></li><li><a href=\"/code/gui/feedback-statusmeldungen/rules/feedback-005-success-next-step\">code/gui/feedback-statusmeldungen/rules/feedback-005-success-next-step</a></li><li><a href=\"/code/gui/feedback-statusmeldungen/rules/feedback-006-loading-busy\">code/gui/feedback-statusmeldungen/rules/feedback-006-loading-busy</a></li><li><a href=\"/code/gui/feedback-statusmeldungen/rules/feedback-007-timeout-control\">code/gui/feedback-statusmeldungen/rules/feedback-007-timeout-control</a></li><li><a href=\"/code/gui/feedback-statusmeldungen/rules/feedback-008-dismissible\">code/gui/feedback-statusmeldungen/rules/feedback-008-dismissible</a></li><li><a href=\"/code/gui/feedback-statusmeldungen/rules/feedback-009-not-color-only\">code/gui/feedback-statusmeldungen/rules/feedback-009-not-color-only</a></li><li><a href=\"/code/gui/feedback-statusmeldungen/rules/feedback-010-contrast\">code/gui/feedback-statusmeldungen/rules/feedback-010-contrast</a></li><li><a href=\"/code/gui/feedback-statusmeldungen/sources\">code/gui/feedback-statusmeldungen/sources</a></li><li><a href=\"/code/gui/formulare\">code/gui/formulare</a></li><li><a href=\"/code/gui/formulare/rules\">code/gui/formulare/rules</a></li><li><a href=\"/code/gui/formulare/rules/action-001-destructive-confirm-or-undo\">code/gui/formulare/rules/action-001-destructive-confirm-or-undo</a></li><li><a href=\"/code/gui/formulare/rules/change-001-no-unexpected-context-change\">code/gui/formulare/rules/change-001-no-unexpected-context-change</a></li><li><a href=\"/code/gui/formulare/rules/color-001-not-color-only\">code/gui/formulare/rules/color-001-not-color-only</a></li><li><a href=\"/code/gui/formulare/rules/consistency-001-help-and-actions\">code/gui/formulare/rules/consistency-001-help-and-actions</a></li><li><a href=\"/code/gui/formulare/rules/contrast-001-text\">code/gui/formulare/rules/contrast-001-text</a></li><li><a href=\"/code/gui/formulare/rules/contrast-002-non-text-ui\">code/gui/formulare/rules/contrast-002-non-text-ui</a></li><li><a href=\"/code/gui/formulare/rules/custom-001-native-before-aria\">code/gui/formulare/rules/custom-001-native-before-aria</a></li><li><a href=\"/code/gui/formulare/rules/disclosure-001-accessible-conditional-fields\">code/gui/formulare/rules/disclosure-001-accessible-conditional-fields</a></li><li><a href=\"/code/gui/formulare/rules/error-001-error-summary\">code/gui/formulare/rules/error-001-error-summary</a></li><li><a href=\"/code/gui/formulare/rules/error-002-inline-error-association\">code/gui/formulare/rules/error-002-inline-error-association</a></li><li><a href=\"/code/gui/formulare/rules/error-003-preserve-values\">code/gui/formulare/rules/error-003-preserve-values</a></li><li><a href=\"/code/gui/formulare/rules/error-004-no-reset-button\">code/gui/formulare/rules/error-004-no-reset-button</a></li><li><a href=\"/code/gui/formulare/rules/feedback-001-status-messages\">code/gui/formulare/rules/feedback-001-status-messages</a></li><li><a href=\"/code/gui/formulare/rules/focus-001-visible-focus\">code/gui/formulare/rules/focus-001-visible-focus</a></li><li><a href=\"/code/gui/formulare/rules/focus-002-enhanced-focus-appearance\">code/gui/formulare/rules/focus-002-enhanced-focus-appearance</a></li><li><a href=\"/code/gui/formulare/rules/form-001-minimal-fields\">code/gui/formulare/rules/form-001-minimal-fields</a></li><li><a href=\"/code/gui/formulare/rules/form-002-progress-for-long-forms\">code/gui/formulare/rules/form-002-progress-for-long-forms</a></li><li><a href=\"/code/gui/formulare/rules/group-001-fieldset-legend\">code/gui/formulare/rules/group-001-fieldset-legend</a></li><li><a href=\"/code/gui/formulare/rules/hint-001-associated-instructions\">code/gui/formulare/rules/hint-001-associated-instructions</a></li><li><a href=\"/code/gui/formulare/rules/hint-002-placeholder-not-label\">code/gui/formulare/rules/hint-002-placeholder-not-label</a></li><li><a href=\"/code/gui/formulare/rules/input-001-semantic-input-metadata\">code/gui/formulare/rules/input-001-semantic-input-metadata</a></li><li><a href=\"/code/gui/formulare/rules/input-002-forgiving-formats\">code/gui/formulare/rules/input-002-forgiving-formats</a></li><li><a href=\"/code/gui/formulare/rules/keyboard-001-operable\">code/gui/formulare/rules/keyboard-001-operable</a></li><li><a href=\"/code/gui/formulare/rules/label-001-visible-label\">code/gui/formulare/rules/label-001-visible-label</a></li><li><a href=\"/code/gui/formulare/rules/label-002-programmatic-label\">code/gui/formulare/rules/label-002-programmatic-label</a></li><li><a href=\"/code/gui/formulare/rules/label-003-label-in-name\">code/gui/formulare/rules/label-003-label-in-name</a></li><li><a href=\"/code/gui/formulare/rules/layout-001-single-column-default\">code/gui/formulare/rules/layout-001-single-column-default</a></li><li><a href=\"/code/gui/formulare/rules/layout-002-top-labels-for-text-inputs\">code/gui/formulare/rules/layout-002-top-labels-for-text-inputs</a></li><li><a href=\"/code/gui/formulare/rules/policy-001-no-modal-form-flows\">code/gui/formulare/rules/policy-001-no-modal-form-flows</a></li><li><a href=\"/code/gui/formulare/rules/required-001-visible-and-programmatic\">code/gui/formulare/rules/required-001-visible-and-programmatic</a></li><li><a href=\"/code/gui/formulare/rules/target-001-wcag-aa-minimum\">code/gui/formulare/rules/target-001-wcag-aa-minimum</a></li><li><a href=\"/code/gui/formulare/rules/target-002-enhanced-44px\">code/gui/formulare/rules/target-002-enhanced-44px</a></li><li><a href=\"/code/gui/formulare/rules/time-001-timeouts-and-data-loss\">code/gui/formulare/rules/time-001-timeouts-and-data-loss</a></li><li><a href=\"/code/gui/formulare/rules/validation-001-server-and-client\">code/gui/formulare/rules/validation-001-server-and-client</a></li><li><a href=\"/code/gui/formulare/rules/validation-002-no-premature-punishment\">code/gui/formulare/rules/validation-002-no-premature-punishment</a></li><li><a href=\"/code/gui/formulare/sources\">code/gui/formulare/sources</a></li><li><a href=\"/code/gui/interactive-graph-3d\">code/gui/interactive-graph-3d</a></li><li><a href=\"/code/gui/interactive-graph-3d/reflection-model\">code/gui/interactive-graph-3d/reflection-model</a></li><li><a href=\"/code/gui/interactive-graph-3d/rules\">code/gui/interactive-graph-3d/rules</a></li><li><a href=\"/code/gui/interactive-graph-3d/rules/graph3d-001-data-alternative-required\">code/gui/interactive-graph-3d/rules/graph3d-001-data-alternative-required</a></li><li><a href=\"/code/gui/interactive-graph-3d/rules/graph3d-002-keyboard-select-and-details\">code/gui/interactive-graph-3d/rules/graph3d-002-keyboard-select-and-details</a></li><li><a href=\"/code/gui/interactive-graph-3d/rules/graph3d-003-simple-pointer-alternatives\">code/gui/interactive-graph-3d/rules/graph3d-003-simple-pointer-alternatives</a></li><li><a href=\"/code/gui/interactive-graph-3d/rules/graph3d-004-reduced-motion-and-pause\">code/gui/interactive-graph-3d/rules/graph3d-004-reduced-motion-and-pause</a></li><li><a href=\"/code/gui/interactive-graph-3d/rules/graph3d-005-not-color-only-heatmap\">code/gui/interactive-graph-3d/rules/graph3d-005-not-color-only-heatmap</a></li><li><a href=\"/code/gui/interactive-graph-3d/rules/graph3d-006-search-filter-status\">code/gui/interactive-graph-3d/rules/graph3d-006-search-filter-status</a></li><li><a href=\"/code/gui/interactive-graph-3d/rules/graph3d-007-detail-panel-not-modal\">code/gui/interactive-graph-3d/rules/graph3d-007-detail-panel-not-modal</a></li><li><a href=\"/code/gui/interactive-graph-3d/rules/graph3d-008-reset-and-orientation\">code/gui/interactive-graph-3d/rules/graph3d-008-reset-and-orientation</a></li><li><a href=\"/code/gui/interactive-graph-3d/rules/graph3d-009-no-modal-graph-flow\">code/gui/interactive-graph-3d/rules/graph3d-009-no-modal-graph-flow</a></li><li><a href=\"/code/gui/interactive-graph-3d/sources\">code/gui/interactive-graph-3d/sources</a></li><li><a href=\"/code/gui/navigation\">code/gui/navigation</a></li><li><a href=\"/code/gui/navigation/rules\">code/gui/navigation/rules</a></li><li><a href=\"/code/gui/navigation/rules/nav-001-nav-landmark\">code/gui/navigation/rules/nav-001-nav-landmark</a></li><li><a href=\"/code/gui/navigation/rules/nav-002-skip-link\">code/gui/navigation/rules/nav-002-skip-link</a></li><li><a href=\"/code/gui/navigation/rules/nav-003-links-are-real-links\">code/gui/navigation/rules/nav-003-links-are-real-links</a></li><li><a href=\"/code/gui/navigation/rules/nav-004-current-page\">code/gui/navigation/rules/nav-004-current-page</a></li><li><a href=\"/code/gui/navigation/rules/nav-005-consistent-order\">code/gui/navigation/rules/nav-005-consistent-order</a></li><li><a href=\"/code/gui/navigation/rules/nav-006-disclosure-for-dropdown-nav\">code/gui/navigation/rules/nav-006-disclosure-for-dropdown-nav</a></li><li><a href=\"/code/gui/navigation/rules/nav-007-no-modal-navigation\">code/gui/navigation/rules/nav-007-no-modal-navigation</a></li><li><a href=\"/code/gui/navigation/rules/nav-008-toggle-state\">code/gui/navigation/rules/nav-008-toggle-state</a></li><li><a href=\"/code/gui/navigation/rules/nav-009-keyboard-operable\">code/gui/navigation/rules/nav-009-keyboard-operable</a></li><li><a href=\"/code/gui/navigation/rules/nav-010-focus-visible\">code/gui/navigation/rules/nav-010-focus-visible</a></li><li><a href=\"/code/gui/navigation/rules/nav-011-breadcrumb\">code/gui/navigation/rules/nav-011-breadcrumb</a></li><li><a href=\"/code/gui/navigation/rules/nav-012-link-purpose\">code/gui/navigation/rules/nav-012-link-purpose</a></li><li><a href=\"/code/gui/navigation/sources\">code/gui/navigation/sources</a></li><li><a href=\"/code/gui/realtime-video-audio-recording\">code/gui/realtime-video-audio-recording</a></li><li><a href=\"/code/gui/realtime-video-audio-recording/reflection-model\">code/gui/realtime-video-audio-recording/reflection-model</a></li><li><a href=\"/code/gui/realtime-video-audio-recording/rules\">code/gui/realtime-video-audio-recording/rules</a></li><li><a href=\"/code/gui/realtime-video-audio-recording/rules/rtc-001-toolbar-semantics-and-keyboard\">code/gui/realtime-video-audio-recording/rules/rtc-001-toolbar-semantics-and-keyboard</a></li><li><a href=\"/code/gui/realtime-video-audio-recording/rules/rtc-002-toggle-state-programmatic\">code/gui/realtime-video-audio-recording/rules/rtc-002-toggle-state-programmatic</a></li><li><a href=\"/code/gui/realtime-video-audio-recording/rules/rtc-003-recording-state-explicit\">code/gui/realtime-video-audio-recording/rules/rtc-003-recording-state-explicit</a></li><li><a href=\"/code/gui/realtime-video-audio-recording/rules/rtc-004-media-device-selects-labelled\">code/gui/realtime-video-audio-recording/rules/rtc-004-media-device-selects-labelled</a></li><li><a href=\"/code/gui/realtime-video-audio-recording/rules/rtc-005-reconnect-and-degraded-status\">code/gui/realtime-video-audio-recording/rules/rtc-005-reconnect-and-degraded-status</a></li><li><a href=\"/code/gui/realtime-video-audio-recording/rules/rtc-006-no-hover-only-controls\">code/gui/realtime-video-audio-recording/rules/rtc-006-no-hover-only-controls</a></li><li><a href=\"/code/gui/realtime-video-audio-recording/rules/rtc-007-media-alternatives-for-recordings\">code/gui/realtime-video-audio-recording/rules/rtc-007-media-alternatives-for-recordings</a></li><li><a href=\"/code/gui/realtime-video-audio-recording/rules/rtc-008-sliders-for-timeline-or-volume\">code/gui/realtime-video-audio-recording/rules/rtc-008-sliders-for-timeline-or-volume</a></li><li><a href=\"/code/gui/realtime-video-audio-recording/rules/rtc-009-admin-actions-require-inline-confirm\">code/gui/realtime-video-audio-recording/rules/rtc-009-admin-actions-require-inline-confirm</a></li><li><a href=\"/code/gui/realtime-video-audio-recording/rules/rtc-010-no-modal-realtime-flow\">code/gui/realtime-video-audio-recording/rules/rtc-010-no-modal-realtime-flow</a></li><li><a href=\"/code/gui/realtime-video-audio-recording/rules/rtc-011-simple-pointer-alternatives\">code/gui/realtime-video-audio-recording/rules/rtc-011-simple-pointer-alternatives</a></li><li><a href=\"/code/gui/realtime-video-audio-recording/sources\">code/gui/realtime-video-audio-recording/sources</a></li><li><a href=\"/code/gui/suche-filter\">code/gui/suche-filter</a></li><li><a href=\"/code/gui/suche-filter/rules\">code/gui/suche-filter/rules</a></li><li><a href=\"/code/gui/suche-filter/rules/filter-001-active-filters-visible\">code/gui/suche-filter/rules/filter-001-active-filters-visible</a></li><li><a href=\"/code/gui/suche-filter/rules/filter-002-clear-all\">code/gui/suche-filter/rules/filter-002-clear-all</a></li><li><a href=\"/code/gui/suche-filter/rules/filter-003-url-state\">code/gui/suche-filter/rules/filter-003-url-state</a></li><li><a href=\"/code/gui/suche-filter/rules/filter-004-no-unexpected-context-change\">code/gui/suche-filter/rules/filter-004-no-unexpected-context-change</a></li><li><a href=\"/code/gui/suche-filter/rules/filter-005-empty-state\">code/gui/suche-filter/rules/filter-005-empty-state</a></li><li><a href=\"/code/gui/suche-filter/rules/filter-006-keyboard-operable\">code/gui/suche-filter/rules/filter-006-keyboard-operable</a></li><li><a href=\"/code/gui/suche-filter/rules/filter-007-no-modal-search-or-filters\">code/gui/suche-filter/rules/filter-007-no-modal-search-or-filters</a></li><li><a href=\"/code/gui/suche-filter/rules/search-001-visible-label\">code/gui/suche-filter/rules/search-001-visible-label</a></li><li><a href=\"/code/gui/suche-filter/rules/search-002-real-form-or-button\">code/gui/suche-filter/rules/search-002-real-form-or-button</a></li><li><a href=\"/code/gui/suche-filter/rules/search-003-combobox-only-for-suggestions\">code/gui/suche-filter/rules/search-003-combobox-only-for-suggestions</a></li><li><a href=\"/code/gui/suche-filter/rules/search-004-no-combobox-for-simple-search\">code/gui/suche-filter/rules/search-004-no-combobox-for-simple-search</a></li><li><a href=\"/code/gui/suche-filter/rules/search-005-result-count-status\">code/gui/suche-filter/rules/search-005-result-count-status</a></li><li><a href=\"/code/gui/suche-filter/rules/search-006-table-search-filters-live-sync\">code/gui/suche-filter/rules/search-006-table-search-filters-live-sync</a></li><li><a href=\"/code/gui/suche-filter/rules/search-007-live-sync-keeps-focus\">code/gui/suche-filter/rules/search-007-live-sync-keeps-focus</a></li><li><a href=\"/code/gui/suche-filter/sources\">code/gui/suche-filter/sources</a></li><li><a href=\"/code/gui/tabs-accordions-disclosure\">code/gui/tabs-accordions-disclosure</a></li><li><a href=\"/code/gui/tabs-accordions-disclosure/rules\">code/gui/tabs-accordions-disclosure/rules</a></li><li><a href=\"/code/gui/tabs-accordions-disclosure/rules/accordion-001-header-button\">code/gui/tabs-accordions-disclosure/rules/accordion-001-header-button</a></li><li><a href=\"/code/gui/tabs-accordions-disclosure/rules/accordion-002-panel-label\">code/gui/tabs-accordions-disclosure/rules/accordion-002-panel-label</a></li><li><a href=\"/code/gui/tabs-accordions-disclosure/rules/common-001-no-modal-panel\">code/gui/tabs-accordions-disclosure/rules/common-001-no-modal-panel</a></li><li><a href=\"/code/gui/tabs-accordions-disclosure/rules/common-002-required-content-visible-by-default\">code/gui/tabs-accordions-disclosure/rules/common-002-required-content-visible-by-default</a></li><li><a href=\"/code/gui/tabs-accordions-disclosure/rules/common-003-state-persistence\">code/gui/tabs-accordions-disclosure/rules/common-003-state-persistence</a></li><li><a href=\"/code/gui/tabs-accordions-disclosure/rules/common-004-focus-visible\">code/gui/tabs-accordions-disclosure/rules/common-004-focus-visible</a></li><li><a href=\"/code/gui/tabs-accordions-disclosure/rules/disclosure-001-button-and-expanded\">code/gui/tabs-accordions-disclosure/rules/disclosure-001-button-and-expanded</a></li><li><a href=\"/code/gui/tabs-accordions-disclosure/rules/disclosure-002-controls-relationship\">code/gui/tabs-accordions-disclosure/rules/disclosure-002-controls-relationship</a></li><li><a href=\"/code/gui/tabs-accordions-disclosure/rules/tabs-001-tab-roles\">code/gui/tabs-accordions-disclosure/rules/tabs-001-tab-roles</a></li><li><a href=\"/code/gui/tabs-accordions-disclosure/rules/tabs-002-keyboard-model\">code/gui/tabs-accordions-disclosure/rules/tabs-002-keyboard-model</a></li><li><a href=\"/code/gui/tabs-accordions-disclosure/sources\">code/gui/tabs-accordions-disclosure/sources</a></li><li><a href=\"/code/gui/termine-kalender-slotpicker\">code/gui/termine-kalender-slotpicker</a></li><li><a href=\"/code/gui/termine-kalender-slotpicker/reflection-model\">code/gui/termine-kalender-slotpicker/reflection-model</a></li><li><a href=\"/code/gui/termine-kalender-slotpicker/rules\">code/gui/termine-kalender-slotpicker/rules</a></li><li><a href=\"/code/gui/termine-kalender-slotpicker/rules/appt-001-slot-has-date-time-timezone-location\">code/gui/termine-kalender-slotpicker/rules/appt-001-slot-has-date-time-timezone-location</a></li><li><a href=\"/code/gui/termine-kalender-slotpicker/rules/appt-002-slot-selection-reversible-before-submit\">code/gui/termine-kalender-slotpicker/rules/appt-002-slot-selection-reversible-before-submit</a></li><li><a href=\"/code/gui/termine-kalender-slotpicker/rules/appt-003-keyboard-and-touch-slot-selection\">code/gui/termine-kalender-slotpicker/rules/appt-003-keyboard-and-touch-slot-selection</a></li><li><a href=\"/code/gui/termine-kalender-slotpicker/rules/appt-004-grid-only-with-apg-model\">code/gui/termine-kalender-slotpicker/rules/appt-004-grid-only-with-apg-model</a></li><li><a href=\"/code/gui/termine-kalender-slotpicker/rules/appt-005-live-filters-keep-context\">code/gui/termine-kalender-slotpicker/rules/appt-005-live-filters-keep-context</a></li><li><a href=\"/code/gui/termine-kalender-slotpicker/rules/appt-006-waitlist-reorder-not-drag-only\">code/gui/termine-kalender-slotpicker/rules/appt-006-waitlist-reorder-not-drag-only</a></li><li><a href=\"/code/gui/termine-kalender-slotpicker/rules/appt-007-reschedule-and-cancel-inline-confirm\">code/gui/termine-kalender-slotpicker/rules/appt-007-reschedule-and-cancel-inline-confirm</a></li><li><a href=\"/code/gui/termine-kalender-slotpicker/rules/appt-008-async-status-visible\">code/gui/termine-kalender-slotpicker/rules/appt-008-async-status-visible</a></li><li><a href=\"/code/gui/termine-kalender-slotpicker/rules/appt-009-no-modal-appointment-flow\">code/gui/termine-kalender-slotpicker/rules/appt-009-no-modal-appointment-flow</a></li><li><a href=\"/code/gui/termine-kalender-slotpicker/rules/appt-010-empty-and-unavailable-states\">code/gui/termine-kalender-slotpicker/rules/appt-010-empty-and-unavailable-states</a></li><li><a href=\"/code/gui/termine-kalender-slotpicker/sources\">code/gui/termine-kalender-slotpicker/sources</a></li><li><a href=\"/code/gui/theme-dark-light-mode\">code/gui/theme-dark-light-mode</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules\">code/gui/theme-dark-light-mode/rules</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-001-light-dark-system-available\">code/gui/theme-dark-light-mode/rules/theme-001-light-dark-system-available</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-002-user-preference-persisted\">code/gui/theme-dark-light-mode/rules/theme-002-user-preference-persisted</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-003-no-flash-wrong-theme\">code/gui/theme-dark-light-mode/rules/theme-003-no-flash-wrong-theme</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-004-text-contrast-each-theme\">code/gui/theme-dark-light-mode/rules/theme-004-text-contrast-each-theme</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-005-non-text-contrast-each-theme\">code/gui/theme-dark-light-mode/rules/theme-005-non-text-contrast-each-theme</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-006-focus-visible-each-theme\">code/gui/theme-dark-light-mode/rules/theme-006-focus-visible-each-theme</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-007-not-color-only\">code/gui/theme-dark-light-mode/rules/theme-007-not-color-only</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-008-state-set-complete-in-both-themes\">code/gui/theme-dark-light-mode/rules/theme-008-state-set-complete-in-both-themes</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-009-disabled-not-critical-only\">code/gui/theme-dark-light-mode/rules/theme-009-disabled-not-critical-only</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-010-forced-colors-and-high-contrast\">code/gui/theme-dark-light-mode/rules/theme-010-forced-colors-and-high-contrast</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-011-theme-control-accessible\">code/gui/theme-dark-light-mode/rules/theme-011-theme-control-accessible</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-012-no-modal-theme-picker\">code/gui/theme-dark-light-mode/rules/theme-012-no-modal-theme-picker</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-013-switch-preserves-context-and-data\">code/gui/theme-dark-light-mode/rules/theme-013-switch-preserves-context-and-data</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-014-status-on-async-theme-save\">code/gui/theme-dark-light-mode/rules/theme-014-status-on-async-theme-save</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-015-themed-assets-and-charts\">code/gui/theme-dark-light-mode/rules/theme-015-themed-assets-and-charts</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-016-browser-ui-and-pwa-colors\">code/gui/theme-dark-light-mode/rules/theme-016-browser-ui-and-pwa-colors</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-017-print-and-export-readable\">code/gui/theme-dark-light-mode/rules/theme-017-print-and-export-readable</a></li><li><a href=\"/code/gui/theme-dark-light-mode/rules/theme-018-complete-component-coverage\">code/gui/theme-dark-light-mode/rules/theme-018-complete-component-coverage</a></li><li><a href=\"/code/gui/theme-dark-light-mode/sources\">code/gui/theme-dark-light-mode/sources</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung\">code/gui/uploads-dateiverwaltung</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung/reflection-model\">code/gui/uploads-dateiverwaltung/reflection-model</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung/rules\">code/gui/uploads-dateiverwaltung/rules</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung/rules/upload-001-labelled-native-file-input\">code/gui/uploads-dateiverwaltung/rules/upload-001-labelled-native-file-input</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung/rules/upload-002-drag-drop-has-alternatives\">code/gui/uploads-dateiverwaltung/rules/upload-002-drag-drop-has-alternatives</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung/rules/upload-003-constraints-visible-before-selection\">code/gui/uploads-dateiverwaltung/rules/upload-003-constraints-visible-before-selection</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung/rules/upload-004-validate-client-and-server\">code/gui/uploads-dateiverwaltung/rules/upload-004-validate-client-and-server</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung/rules/upload-005-progress-and-processing-status\">code/gui/uploads-dateiverwaltung/rules/upload-005-progress-and-processing-status</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung/rules/upload-006-per-file-errors\">code/gui/uploads-dateiverwaltung/rules/upload-006-per-file-errors</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung/rules/upload-007-file-list-review-and-remove\">code/gui/uploads-dateiverwaltung/rules/upload-007-file-list-review-and-remove</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung/rules/upload-008-no-modal-upload-ui\">code/gui/uploads-dateiverwaltung/rules/upload-008-no-modal-upload-ui</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung/rules/upload-009-action-target-size\">code/gui/uploads-dateiverwaltung/rules/upload-009-action-target-size</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung/rules/upload-010-preserve-on-error-reauth\">code/gui/uploads-dateiverwaltung/rules/upload-010-preserve-on-error-reauth</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung/rules/upload-011-dangerous-file-actions-confirm-inline\">code/gui/uploads-dateiverwaltung/rules/upload-011-dangerous-file-actions-confirm-inline</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung/rules/upload-012-stable-multi-file-order\">code/gui/uploads-dateiverwaltung/rules/upload-012-stable-multi-file-order</a></li><li><a href=\"/code/gui/uploads-dateiverwaltung/sources\">code/gui/uploads-dateiverwaltung/sources</a></li><li><a href=\"/code/html-templates\">code/html-templates</a></li><li><a href=\"/code/html-templates/reflection-model\">code/html-templates/reflection-model</a></li><li><a href=\"/code/html-templates/rules\">code/html-templates/rules</a></li><li><a href=\"/code/html-templates/rules/html-001-valid-document-structure\">code/html-templates/rules/html-001-valid-document-structure</a></li><li><a href=\"/code/html-templates/rules/html-002-landmarks-and-headings\">code/html-templates/rules/html-002-landmarks-and-headings</a></li><li><a href=\"/code/html-templates/rules/html-003-native-controls-first\">code/html-templates/rules/html-003-native-controls-first</a></li><li><a href=\"/code/html-templates/rules/html-004-forms-labels-errors\">code/html-templates/rules/html-004-forms-labels-errors</a></li><li><a href=\"/code/html-templates/rules/html-005-table-semantics-sort-filter-pagination\">code/html-templates/rules/html-005-table-semantics-sort-filter-pagination</a></li><li><a href=\"/code/html-templates/rules/html-006-links-vs-buttons\">code/html-templates/rules/html-006-links-vs-buttons</a></li><li><a href=\"/code/html-templates/rules/html-007-no-inline-handlers-or-styles\">code/html-templates/rules/html-007-no-inline-handlers-or-styles</a></li><li><a href=\"/code/html-templates/rules/html-008-data-and-aria-state-contract\">code/html-templates/rules/html-008-data-and-aria-state-contract</a></li><li><a href=\"/code/html-templates/rules/html-009-no-modals-dialogs\">code/html-templates/rules/html-009-no-modals-dialogs</a></li><li><a href=\"/code/html-templates/rules/html-010-progressive-enhancement\">code/html-templates/rules/html-010-progressive-enhancement</a></li><li><a href=\"/code/html-templates/rules/html-011-media-alt-text\">code/html-templates/rules/html-011-media-alt-text</a></li><li><a href=\"/code/html-templates/rules/html-012-hide-visually-not-semantically\">code/html-templates/rules/html-012-hide-visually-not-semantically</a></li><li><a href=\"/code/html-templates/rules/html-013-metadata-lang-viewport\">code/html-templates/rules/html-013-metadata-lang-viewport</a></li><li><a href=\"/code/html-templates/rules/html-014-html-escaping-boundaries\">code/html-templates/rules/html-014-html-escaping-boundaries</a></li><li><a href=\"/code/html-templates/sources\">code/html-templates/sources</a></li><li><a href=\"/code/http-api\">code/http-api</a></li><li><a href=\"/code/http-api/reflection-model\">code/http-api/reflection-model</a></li><li><a href=\"/code/http-api/rules\">code/http-api/rules</a></li><li><a href=\"/code/http-api/rules/http-001-resource-routes\">code/http-api/rules/http-001-resource-routes</a></li><li><a href=\"/code/http-api/rules/http-002-method-semantics\">code/http-api/rules/http-002-method-semantics</a></li><li><a href=\"/code/http-api/rules/http-003-status-codes\">code/http-api/rules/http-003-status-codes</a></li><li><a href=\"/code/http-api/rules/http-004-problem-details\">code/http-api/rules/http-004-problem-details</a></li><li><a href=\"/code/http-api/rules/http-005-query-contract-for-tables\">code/http-api/rules/http-005-query-contract-for-tables</a></li><li><a href=\"/code/http-api/rules/http-006-live-search-support\">code/http-api/rules/http-006-live-search-support</a></li><li><a href=\"/code/http-api/rules/http-007-link-headers-for-pagination\">code/http-api/rules/http-007-link-headers-for-pagination</a></li><li><a href=\"/code/http-api/rules/http-008-cache-validators\">code/http-api/rules/http-008-cache-validators</a></li><li><a href=\"/code/http-api/rules/http-009-server-side-authz\">code/http-api/rules/http-009-server-side-authz</a></li><li><a href=\"/code/http-api/rules/http-010-content-negotiation\">code/http-api/rules/http-010-content-negotiation</a></li><li><a href=\"/code/http-api/rules/http-011-schema-documentation\">code/http-api/rules/http-011-schema-documentation</a></li><li><a href=\"/code/http-api/rules/http-012-idempotency-for-risky-mutations\">code/http-api/rules/http-012-idempotency-for-risky-mutations</a></li><li><a href=\"/code/http-api/rules/http-013-rate-limit-and-resource-limits\">code/http-api/rules/http-013-rate-limit-and-resource-limits</a></li><li><a href=\"/code/http-api/rules/http-014-no-modal-error-flows\">code/http-api/rules/http-014-no-modal-error-flows</a></li><li><a href=\"/code/http-api/rules/http-015-no-sensitive-values-in-query-or-redirect\">code/http-api/rules/http-015-no-sensitive-values-in-query-or-redirect</a></li><li><a href=\"/code/http-api/sources\">code/http-api/sources</a></li><li><a href=\"/code/js\">code/js</a></li><li><a href=\"/code/js/rules\">code/js/rules</a></li><li><a href=\"/code/js/rules/js-001-vanilla-only-no-frameworks\">code/js/rules/js-001-vanilla-only-no-frameworks</a></li><li><a href=\"/code/js/rules/js-002-js-is-presentation-adapter-only\">code/js/rules/js-002-js-is-presentation-adapter-only</a></li><li><a href=\"/code/js/rules/js-003-no-domain-invariant-duplication\">code/js/rules/js-003-no-domain-invariant-duplication</a></li><li><a href=\"/code/js/rules/js-004-api-client-as-port-adapter\">code/js/rules/js-004-api-client-as-port-adapter</a></li><li><a href=\"/code/js/rules/js-005-mvc-controller-thin\">code/js/rules/js-005-mvc-controller-thin</a></li><li><a href=\"/code/js/rules/js-006-php-contract-explicit\">code/js/rules/js-006-php-contract-explicit</a></li><li><a href=\"/code/js/rules/js-007-server-authoritative-for-mutations\">code/js/rules/js-007-server-authoritative-for-mutations</a></li><li><a href=\"/code/js/rules/js-008-page-bootstrap-single-entry\">code/js/rules/js-008-page-bootstrap-single-entry</a></li><li><a href=\"/code/js/rules/js-009-srp-module-role\">code/js/rules/js-009-srp-module-role</a></li><li><a href=\"/code/js/rules/js-010-maxloc-module\">code/js/rules/js-010-maxloc-module</a></li><li><a href=\"/code/js/rules/js-011-maxloc-function\">code/js/rules/js-011-maxloc-function</a></li><li><a href=\"/code/js/rules/js-012-dry-after-second-duplication\">code/js/rules/js-012-dry-after-second-duplication</a></li><li><a href=\"/code/js/rules/js-013-no-god-state\">code/js/rules/js-013-no-god-state</a></li><li><a href=\"/code/js/rules/js-014-classes-only-for-lifecycle-or-adapters\">code/js/rules/js-014-classes-only-for-lifecycle-or-adapters</a></li><li><a href=\"/code/js/rules/js-015-new-code-es-modules\">code/js/rules/js-015-new-code-es-modules</a></li><li><a href=\"/code/js/rules/js-016-legacy-script-iife-strict\">code/js/rules/js-016-legacy-script-iife-strict</a></li><li><a href=\"/code/js/rules/js-017-no-inline-scripts-or-handlers\">code/js/rules/js-017-no-inline-scripts-or-handlers</a></li><li><a href=\"/code/js/rules/js-018-bootstrap-dom-ready-correct\">code/js/rules/js-018-bootstrap-dom-ready-correct</a></li><li><a href=\"/code/js/rules/js-019-feature-detection-over-browser-sniffing\">code/js/rules/js-019-feature-detection-over-browser-sniffing</a></li><li><a href=\"/code/js/rules/js-020-add-event-listener-only\">code/js/rules/js-020-add-event-listener-only</a></li><li><a href=\"/code/js/rules/js-021-delegate-dynamic-collection-events\">code/js/rules/js-021-delegate-dynamic-collection-events</a></li><li><a href=\"/code/js/rules/js-022-abort-controller-for-cleanup\">code/js/rules/js-022-abort-controller-for-cleanup</a></li><li><a href=\"/code/js/rules/js-023-fetch-wrapper-standard\">code/js/rules/js-023-fetch-wrapper-standard</a></li><li><a href=\"/code/js/rules/js-024-abort-stale-requests\">code/js/rules/js-024-abort-stale-requests</a></li><li><a href=\"/code/js/rules/js-025-same-origin-csrf-for-mutations\">code/js/rules/js-025-same-origin-csrf-for-mutations</a></li><li><a href=\"/code/js/rules/js-026-safe-dom-text-by-default\">code/js/rules/js-026-safe-dom-text-by-default</a></li><li><a href=\"/code/js/rules/js-027-html-sinks-central-and-sanitized\">code/js/rules/js-027-html-sinks-central-and-sanitized</a></li><li><a href=\"/code/js/rules/js-028-no-eval-or-string-code\">code/js/rules/js-028-no-eval-or-string-code</a></li><li><a href=\"/code/js/rules/js-029-progressive-enhancement-baseline\">code/js/rules/js-029-progressive-enhancement-baseline</a></li><li><a href=\"/code/js/rules/js-030-no-modals\">code/js/rules/js-030-no-modals</a></li><li><a href=\"/code/js/rules/js-031-table-search-filters-live-sync\">code/js/rules/js-031-table-search-filters-live-sync</a></li><li><a href=\"/code/js/rules/js-032-live-update-preserves-context\">code/js/rules/js-032-live-update-preserves-context</a></li><li><a href=\"/code/js/rules/js-033-status-messages-programmatic\">code/js/rules/js-033-status-messages-programmatic</a></li><li><a href=\"/code/js/rules/js-034-focus-and-data-preserved\">code/js/rules/js-034-focus-and-data-preserved</a></li><li><a href=\"/code/js/rules/js-035-native-controls-first\">code/js/rules/js-035-native-controls-first</a></li><li><a href=\"/code/js/rules/js-036-pointer-drag-has-alternative\">code/js/rules/js-036-pointer-drag-has-alternative</a></li><li><a href=\"/code/js/rules/js-037-theme-dark-light-compatible\">code/js/rules/js-037-theme-dark-light-compatible</a></li><li><a href=\"/code/js/rules/js-038-reduced-motion-and-timing\">code/js/rules/js-038-reduced-motion-and-timing</a></li><li><a href=\"/code/js/rules/js-039-page-scoped-loading\">code/js/rules/js-039-page-scoped-loading</a></li><li><a href=\"/code/js/rules/js-040-third-party-containment\">code/js/rules/js-040-third-party-containment</a></li><li><a href=\"/code/js/rules/js-041-no-layout-thrash-in-loops\">code/js/rules/js-041-no-layout-thrash-in-loops</a></li><li><a href=\"/code/js/rules/js-042-test-pure-helpers-and-api-adapters\">code/js/rules/js-042-test-pure-helpers-and-api-adapters</a></li><li><a href=\"/code/js/rules/js-043-browser-a11y-regression-for-gui-rules\">code/js/rules/js-043-browser-a11y-regression-for-gui-rules</a></li><li><a href=\"/code/js/rules/js-044-lint-baseline\">code/js/rules/js-044-lint-baseline</a></li><li><a href=\"/code/js/rules/js-045-observable-errors-not-console-only\">code/js/rules/js-045-observable-errors-not-console-only</a></li><li><a href=\"/code/js/rules/js-046-history-ui-as-presentation-adapter\">code/js/rules/js-046-history-ui-as-presentation-adapter</a></li><li><a href=\"/code/js/rules/js-047-history-live-filter-and-stale-requests\">code/js/rules/js-047-history-live-filter-and-stale-requests</a></li><li><a href=\"/code/js/rules/js-048-restore-errors-inline\">code/js/rules/js-048-restore-errors-inline</a></li><li><a href=\"/code/js/sources\">code/js/sources</a></li><li><a href=\"/code/kc\">code/kc</a></li><li><a href=\"/code/kc/reflection-model\">code/kc/reflection-model</a></li><li><a href=\"/code/kc/rules\">code/kc/rules</a></li><li><a href=\"/code/kc/rules/kc-001-use-kc-for-file-mutations\">code/kc/rules/kc-001-use-kc-for-file-mutations</a></li><li><a href=\"/code/kc/rules/kc-002-task-required-for-code-mutations\">code/kc/rules/kc-002-task-required-for-code-mutations</a></li><li><a href=\"/code/kc/rules/kc-003-no-composer-for-projects\">code/kc/rules/kc-003-no-composer-for-projects</a></li><li><a href=\"/code/kc/rules/kc-004-node-npm-qa-only\">code/kc/rules/kc-004-node-npm-qa-only</a></li><li><a href=\"/code/kc/rules/kc-005-prefer-read-only-first\">code/kc/rules/kc-005-prefer-read-only-first</a></li><li><a href=\"/code/kc/rules/kc-006-destructive-requires-reason\">code/kc/rules/kc-006-destructive-requires-reason</a></li><li><a href=\"/code/kc/rules/kc-007-db-query-execute-split\">code/kc/rules/kc-007-db-query-execute-split</a></li><li><a href=\"/code/kc/rules/kc-008-grep-is-substring\">code/kc/rules/kc-008-grep-is-substring</a></li><li><a href=\"/code/kc/rules/kc-009-supervise-before-finish\">code/kc/rules/kc-009-supervise-before-finish</a></li><li><a href=\"/code/kc/rules/kc-010-browser-for-gui\">code/kc/rules/kc-010-browser-for-gui</a></li><li><a href=\"/code/kc/rules/kc-011-ops-tools-are-not-dev-shortcuts\">code/kc/rules/kc-011-ops-tools-are-not-dev-shortcuts</a></li><li><a href=\"/code/kc/rules/kc-012-no-git-assumption\">code/kc/rules/kc-012-no-git-assumption</a></li><li><a href=\"/code/kc/rules/kc-013-package-managers-not-for-app-architecture\">code/kc/rules/kc-013-package-managers-not-for-app-architecture</a></li><li><a href=\"/code/kc/rules/kc-014-record-evidence-for-claims\">code/kc/rules/kc-014-record-evidence-for-claims</a></li><li><a href=\"/code/kc/rules/kc-015-db-history-audit-before-restore-work\">code/kc/rules/kc-015-db-history-audit-before-restore-work</a></li><li><a href=\"/code/kc/sources\">code/kc/sources</a></li><li><a href=\"/code/observability-audit\">code/observability-audit</a></li><li><a href=\"/code/observability-audit/reflection-model\">code/observability-audit/reflection-model</a></li><li><a href=\"/code/observability-audit/rules\">code/observability-audit/rules</a></li><li><a href=\"/code/observability-audit/rules/obs-001-structured-logs\">code/observability-audit/rules/obs-001-structured-logs</a></li><li><a href=\"/code/observability-audit/rules/obs-002-no-secrets-or-raw-pii-in-logs\">code/observability-audit/rules/obs-002-no-secrets-or-raw-pii-in-logs</a></li><li><a href=\"/code/observability-audit/rules/obs-003-trace-context-propagation\">code/observability-audit/rules/obs-003-trace-context-propagation</a></li><li><a href=\"/code/observability-audit/rules/obs-004-audit-sensitive-actions\">code/observability-audit/rules/obs-004-audit-sensitive-actions</a></li><li><a href=\"/code/observability-audit/rules/obs-005-audit-events-are-append-only\">code/observability-audit/rules/obs-005-audit-events-are-append-only</a></li><li><a href=\"/code/observability-audit/rules/obs-006-error-messages-have-correlation\">code/observability-audit/rules/obs-006-error-messages-have-correlation</a></li><li><a href=\"/code/observability-audit/rules/obs-007-metrics-with-cardinality-review\">code/observability-audit/rules/obs-007-metrics-with-cardinality-review</a></li><li><a href=\"/code/observability-audit/rules/obs-008-health-checks-are-safe\">code/observability-audit/rules/obs-008-health-checks-are-safe</a></li><li><a href=\"/code/observability-audit/rules/obs-009-admin-audit-tables-support-live-filter\">code/observability-audit/rules/obs-009-admin-audit-tables-support-live-filter</a></li><li><a href=\"/code/observability-audit/rules/obs-010-no-modal-audit-details\">code/observability-audit/rules/obs-010-no-modal-audit-details</a></li><li><a href=\"/code/observability-audit/rules/obs-011-retention-is-defined\">code/observability-audit/rules/obs-011-retention-is-defined</a></li><li><a href=\"/code/observability-audit/rules/obs-012-jobs-and-outbox-are-traceable\">code/observability-audit/rules/obs-012-jobs-and-outbox-are-traceable</a></li><li><a href=\"/code/observability-audit/rules/obs-013-log-levels-are-consistent\">code/observability-audit/rules/obs-013-log-levels-are-consistent</a></li><li><a href=\"/code/observability-audit/rules/obs-014-user-visible-status-is-accessible\">code/observability-audit/rules/obs-014-user-visible-status-is-accessible</a></li><li><a href=\"/code/observability-audit/rules/obs-015-no-raw-urls-with-pii-in-logs\">code/observability-audit/rules/obs-015-no-raw-urls-with-pii-in-logs</a></li><li><a href=\"/code/observability-audit/rules/obs-016-db-history-context\">code/observability-audit/rules/obs-016-db-history-context</a></li><li><a href=\"/code/observability-audit/rules/obs-017-row-history-is-not-just-audit-log\">code/observability-audit/rules/obs-017-row-history-is-not-just-audit-log</a></li><li><a href=\"/code/observability-audit/rules/obs-018-audit-sufficiency-is-decided-per-question\">code/observability-audit/rules/obs-018-audit-sufficiency-is-decided-per-question</a></li><li><a href=\"/code/observability-audit/rules/obs-019-before-after-event-logs-declare-limits\">code/observability-audit/rules/obs-019-before-after-event-logs-declare-limits</a></li><li><a href=\"/code/observability-audit/rules/obs-020-audit-gaps-are-table-specific\">code/observability-audit/rules/obs-020-audit-gaps-are-table-specific</a></li><li><a href=\"/code/observability-audit/sources\">code/observability-audit/sources</a></li><li><a href=\"/code/performance\">code/performance</a></li><li><a href=\"/code/performance/reflection-model\">code/performance/reflection-model</a></li><li><a href=\"/code/performance/rules\">code/performance/rules</a></li><li><a href=\"/code/performance/rules/perf-001-route-budgets\">code/performance/rules/perf-001-route-budgets</a></li><li><a href=\"/code/performance/rules/perf-002-core-web-vitals-targets\">code/performance/rules/perf-002-core-web-vitals-targets</a></li><li><a href=\"/code/performance/rules/perf-003-page-scoped-assets\">code/performance/rules/perf-003-page-scoped-assets</a></li><li><a href=\"/code/performance/rules/perf-004-http-caching\">code/performance/rules/perf-004-http-caching</a></li><li><a href=\"/code/performance/rules/perf-005-no-layout-shift\">code/performance/rules/perf-005-no-layout-shift</a></li><li><a href=\"/code/performance/rules/perf-006-table-queries-explained\">code/performance/rules/perf-006-table-queries-explained</a></li><li><a href=\"/code/performance/rules/perf-007-pagination-for-large-lists\">code/performance/rules/perf-007-pagination-for-large-lists</a></li><li><a href=\"/code/performance/rules/perf-008-live-search-debounce-abort\">code/performance/rules/perf-008-live-search-debounce-abort</a></li><li><a href=\"/code/performance/rules/perf-009-no-blocking-third-party\">code/performance/rules/perf-009-no-blocking-third-party</a></li><li><a href=\"/code/performance/rules/perf-010-media-dimensions-and-priority\">code/performance/rules/perf-010-media-dimensions-and-priority</a></li><li><a href=\"/code/performance/rules/perf-011-php-opcache-enabled\">code/performance/rules/perf-011-php-opcache-enabled</a></li><li><a href=\"/code/performance/rules/perf-012-external-call-timeouts\">code/performance/rules/perf-012-external-call-timeouts</a></li><li><a href=\"/code/performance/rules/perf-013-accessible-loading-states\">code/performance/rules/perf-013-accessible-loading-states</a></li><li><a href=\"/code/performance/rules/perf-014-measure-before-optimizing-shared-paths\">code/performance/rules/perf-014-measure-before-optimizing-shared-paths</a></li><li><a href=\"/code/performance/sources\">code/performance/sources</a></li><li><a href=\"/code/php\">code/php</a></li><li><a href=\"/code/projektcharakteristika\">code/projektcharakteristika</a></li><li><a href=\"/code/projektcharakteristika/reflection-model\">code/projektcharakteristika/reflection-model</a></li><li><a href=\"/code/projektcharakteristika/rules\">code/projektcharakteristika/rules</a></li><li><a href=\"/code/projektcharakteristika/rules/char-001-no-composer-vendor\">code/projektcharakteristika/rules/char-001-no-composer-vendor</a></li><li><a href=\"/code/projektcharakteristika/rules/char-002-own-autoloader-required\">code/projektcharakteristika/rules/char-002-own-autoloader-required</a></li><li><a href=\"/code/projektcharakteristika/rules/char-003-no-application-frameworks\">code/projektcharakteristika/rules/char-003-no-application-frameworks</a></li><li><a href=\"/code/projektcharakteristika/rules/char-004-ddd-hexagonal-clean-architecture\">code/projektcharakteristika/rules/char-004-ddd-hexagonal-clean-architecture</a></li><li><a href=\"/code/projektcharakteristika/rules/char-005-domain-is-framework-free\">code/projektcharakteristika/rules/char-005-domain-is-framework-free</a></li><li><a href=\"/code/projektcharakteristika/rules/char-006-application-usecases-orchestrate\">code/projektcharakteristika/rules/char-006-application-usecases-orchestrate</a></li><li><a href=\"/code/projektcharakteristika/rules/char-007-infrastructure-is-adapter-boundary\">code/projektcharakteristika/rules/char-007-infrastructure-is-adapter-boundary</a></li><li><a href=\"/code/projektcharakteristika/rules/char-008-presentation-has-no-business-truth\">code/projektcharakteristika/rules/char-008-presentation-has-no-business-truth</a></li><li><a href=\"/code/projektcharakteristika/rules/char-009-no-template-engines\">code/projektcharakteristika/rules/char-009-no-template-engines</a></li><li><a href=\"/code/projektcharakteristika/rules/char-010-vanilla-js-only\">code/projektcharakteristika/rules/char-010-vanilla-js-only</a></li><li><a href=\"/code/projektcharakteristika/rules/char-011-plain-css-only\">code/projektcharakteristika/rules/char-011-plain-css-only</a></li><li><a href=\"/code/projektcharakteristika/rules/char-012-html5-wcag-w3c-baseline\">code/projektcharakteristika/rules/char-012-html5-wcag-w3c-baseline</a></li><li><a href=\"/code/projektcharakteristika/rules/char-013-progressive-enhancement\">code/projektcharakteristika/rules/char-013-progressive-enhancement</a></li><li><a href=\"/code/projektcharakteristika/rules/char-014-no-modals\">code/projektcharakteristika/rules/char-014-no-modals</a></li><li><a href=\"/code/projektcharakteristika/rules/char-015-node-qa-only\">code/projektcharakteristika/rules/char-015-node-qa-only</a></li><li><a href=\"/code/projektcharakteristika/rules/char-016-no-git-dependency\">code/projektcharakteristika/rules/char-016-no-git-dependency</a></li><li><a href=\"/code/projektcharakteristika/rules/char-017-maxloc-is-enforced\">code/projektcharakteristika/rules/char-017-maxloc-is-enforced</a></li><li><a href=\"/code/projektcharakteristika/rules/char-018-clean-code-solid-srp-soc-dry\">code/projektcharakteristika/rules/char-018-clean-code-solid-srp-soc-dry</a></li><li><a href=\"/code/projektcharakteristika/sources\">code/projektcharakteristika/sources</a></li><li><a href=\"/code/python-mcp\">code/python-mcp</a></li><li><a href=\"/code/python-mcp/reflection-model\">code/python-mcp/reflection-model</a></li><li><a href=\"/code/python-mcp/rules\">code/python-mcp/rules</a></li><li><a href=\"/code/python-mcp/rules/pymcp-001-official-sdk-required\">code/python-mcp/rules/pymcp-001-official-sdk-required</a></li><li><a href=\"/code/python-mcp/rules/pymcp-002-stdio-default-transport\">code/python-mcp/rules/pymcp-002-stdio-default-transport</a></li><li><a href=\"/code/python-mcp/rules/pymcp-003-stdout-reserved-for-jsonrpc\">code/python-mcp/rules/pymcp-003-stdout-reserved-for-jsonrpc</a></li><li><a href=\"/code/python-mcp/rules/pymcp-004-logging-to-stderr-before-deps\">code/python-mcp/rules/pymcp-004-logging-to-stderr-before-deps</a></li><li><a href=\"/code/python-mcp/rules/pymcp-005-wrapper-unbuffered\">code/python-mcp/rules/pymcp-005-wrapper-unbuffered</a></li><li><a href=\"/code/python-mcp/rules/pymcp-006-tool-signature-discipline\">code/python-mcp/rules/pymcp-006-tool-signature-discipline</a></li><li><a href=\"/code/python-mcp/rules/pymcp-007-literal-for-enum-parameters\">code/python-mcp/rules/pymcp-007-literal-for-enum-parameters</a></li><li><a href=\"/code/python-mcp/rules/pymcp-008-bounds-for-numeric-parameters\">code/python-mcp/rules/pymcp-008-bounds-for-numeric-parameters</a></li><li><a href=\"/code/python-mcp/rules/pymcp-009-typed-dict-return\">code/python-mcp/rules/pymcp-009-typed-dict-return</a></li><li><a href=\"/code/python-mcp/rules/pymcp-010-layered-architecture\">code/python-mcp/rules/pymcp-010-layered-architecture</a></li><li><a href=\"/code/python-mcp/rules/pymcp-011-domain-framework-free\">code/python-mcp/rules/pymcp-011-domain-framework-free</a></li><li><a href=\"/code/python-mcp/rules/pymcp-012-application-uses-ports\">code/python-mcp/rules/pymcp-012-application-uses-ports</a></li><li><a href=\"/code/python-mcp/rules/pymcp-013-infrastructure-is-io-boundary\">code/python-mcp/rules/pymcp-013-infrastructure-is-io-boundary</a></li><li><a href=\"/code/python-mcp/rules/pymcp-014-maxloc-hard-limits\">code/python-mcp/rules/pymcp-014-maxloc-hard-limits</a></li><li><a href=\"/code/python-mcp/rules/pymcp-015-no-framework-as-mcp-driver\">code/python-mcp/rules/pymcp-015-no-framework-as-mcp-driver</a></li><li><a href=\"/code/python-mcp/rules/pymcp-016-no-module-level-singletons\">code/python-mcp/rules/pymcp-016-no-module-level-singletons</a></li><li><a href=\"/code/python-mcp/rules/pymcp-017-secrets-from-files-or-env\">code/python-mcp/rules/pymcp-017-secrets-from-files-or-env</a></li><li><a href=\"/code/python-mcp/rules/pymcp-018-sandbox-tool-inputs\">code/python-mcp/rules/pymcp-018-sandbox-tool-inputs</a></li><li><a href=\"/code/python-mcp/rules/pymcp-019-error-mapping-and-traceback-hygiene\">code/python-mcp/rules/pymcp-019-error-mapping-and-traceback-hygiene</a></li><li><a href=\"/code/python-mcp/rules/pymcp-020-no-raw-backend-body-in-tool-error\">code/python-mcp/rules/pymcp-020-no-raw-backend-body-in-tool-error</a></li><li><a href=\"/code/python-mcp/rules/pymcp-021-http-retries-and-lifecycle\">code/python-mcp/rules/pymcp-021-http-retries-and-lifecycle</a></li><li><a href=\"/code/python-mcp/rules/pymcp-022-backend-is-validation-source-of-truth\">code/python-mcp/rules/pymcp-022-backend-is-validation-source-of-truth</a></li><li><a href=\"/code/python-mcp/rules/pymcp-023-pyproject-and-lockfile\">code/python-mcp/rules/pymcp-023-pyproject-and-lockfile</a></li><li><a href=\"/code/python-mcp/rules/pymcp-024-tests-three-layers\">code/python-mcp/rules/pymcp-024-tests-three-layers</a></li><li><a href=\"/code/python-mcp/rules/pymcp-025-health-subcommand\">code/python-mcp/rules/pymcp-025-health-subcommand</a></li><li><a href=\"/code/python-mcp/sources\">code/python-mcp/sources</a></li><li><a href=\"/code/rust\">code/rust</a></li><li><a href=\"/code/rust/kc-cli-quality\">code/rust/kc-cli-quality</a></li><li><a href=\"/code/rust/kc-cli-quality/rules\">code/rust/kc-cli-quality/rules</a></li><li><a href=\"/code/rust/kc-cli-quality/rules/rust-cli-001-test-pattern\">code/rust/kc-cli-quality/rules/rust-cli-001-test-pattern</a></li><li><a href=\"/code/rust/kc-cli-quality/rules/rust-cli-002-release-binary-acceptance\">code/rust/kc-cli-quality/rules/rust-cli-002-release-binary-acceptance</a></li><li><a href=\"/code/rust/kc-cli-quality/rules/rust-cli-003-keep-modules-small\">code/rust/kc-cli-quality/rules/rust-cli-003-keep-modules-small</a></li><li><a href=\"/code/rust/kc-cli-quality/rules/rust-cli-004-warnings-are-tech-debt\">code/rust/kc-cli-quality/rules/rust-cli-004-warnings-are-tech-debt</a></li><li><a href=\"/code/rust/kc-cli-quality/rules/rust-cli-005-atomic-install\">code/rust/kc-cli-quality/rules/rust-cli-005-atomic-install</a></li><li><a href=\"/code/rust/kc-cli-quality/rules/rust-cli-006-data-driven-rules-need-engine-boundaries\">code/rust/kc-cli-quality/rules/rust-cli-006-data-driven-rules-need-engine-boundaries</a></li><li><a href=\"/code/rust/kc-cli-quality/rules/rust-cli-007-config-query-errors-are-not-empty-results\">code/rust/kc-cli-quality/rules/rust-cli-007-config-query-errors-are-not-empty-results</a></li><li><a href=\"/code/rust/kc-cli-quality/rules/rust-cli-008-cargo-project-argv-standardprofile\">code/rust/kc-cli-quality/rules/rust-cli-008-cargo-project-argv-standardprofile</a></li><li><a href=\"/code/rust/kc-cli-quality/rules/rust-cli-009-deduplicate-cargo-project-checks\">code/rust/kc-cli-quality/rules/rust-cli-009-deduplicate-cargo-project-checks</a></li><li><a href=\"/code/schreibstil\">code/schreibstil</a></li><li><a href=\"/code/schreibstil/reflection-model\">code/schreibstil/reflection-model</a></li><li><a href=\"/code/schreibstil/rules\">code/schreibstil/rules</a></li><li><a href=\"/code/schreibstil/rules/stil-001-umlauts-as-utf8\">code/schreibstil/rules/stil-001-umlauts-as-utf8</a></li><li><a href=\"/code/schreibstil/rules/stil-002-no-em-or-en-dash\">code/schreibstil/rules/stil-002-no-em-or-en-dash</a></li><li><a href=\"/code/schreibstil/rules/stil-003-legacy-transliterations-frozen\">code/schreibstil/rules/stil-003-legacy-transliterations-frozen</a></li><li><a href=\"/code/schreibstil/rules/stil-004-ssot-in-var-www-code\">code/schreibstil/rules/stil-004-ssot-in-var-www-code</a></li><li><a href=\"/code/schreibstil/rules/stil-005-prose-markup-respects-whitelist\">code/schreibstil/rules/stil-005-prose-markup-respects-whitelist</a></li><li><a href=\"/code/schreibstil/rules/stil-006-no-pseudo-dramatic-phrasing\">code/schreibstil/rules/stil-006-no-pseudo-dramatic-phrasing</a></li><li><a href=\"/code/schreibstil/sources\">code/schreibstil/sources</a></li><li><a href=\"/code/security\">code/security</a></li><li><a href=\"/code/security/reflection-model\">code/security/reflection-model</a></li><li><a href=\"/code/security/rules\">code/security/rules</a></li><li><a href=\"/code/security/rules/sec-001-server-side-authorization\">code/security/rules/sec-001-server-side-authorization</a></li><li><a href=\"/code/security/rules/sec-002-csrf-for-state-change\">code/security/rules/sec-002-csrf-for-state-change</a></li><li><a href=\"/code/security/rules/sec-003-contextual-output-encoding\">code/security/rules/sec-003-contextual-output-encoding</a></li><li><a href=\"/code/security/rules/sec-004-csp-without-inline-defaults\">code/security/rules/sec-004-csp-without-inline-defaults</a></li><li><a href=\"/code/security/rules/sec-005-session-cookie-hardening\">code/security/rules/sec-005-session-cookie-hardening</a></li><li><a href=\"/code/security/rules/sec-006-timeout-reauth-no-data-loss\">code/security/rules/sec-006-timeout-reauth-no-data-loss</a></li><li><a href=\"/code/security/rules/sec-007-no-modal-security-flows\">code/security/rules/sec-007-no-modal-security-flows</a></li><li><a href=\"/code/security/rules/sec-008-rate-limit-auth-and-search\">code/security/rules/sec-008-rate-limit-auth-and-search</a></li><li><a href=\"/code/security/rules/sec-009-uploads-are-isolated\">code/security/rules/sec-009-uploads-are-isolated</a></li><li><a href=\"/code/security/rules/sec-010-secrets-never-in-repo-or-client\">code/security/rules/sec-010-secrets-never-in-repo-or-client</a></li><li><a href=\"/code/security/rules/sec-011-security-headers-baseline\">code/security/rules/sec-011-security-headers-baseline</a></li><li><a href=\"/code/security/rules/sec-012-audit-security-events\">code/security/rules/sec-012-audit-security-events</a></li><li><a href=\"/code/security/rules/sec-013-no-security-by-ui-state\">code/security/rules/sec-013-no-security-by-ui-state</a></li><li><a href=\"/code/security/rules/sec-014-error-messages-do-not-leak\">code/security/rules/sec-014-error-messages-do-not-leak</a></li><li><a href=\"/code/security/rules/sec-015-no-pii-or-auth-state-in-urls\">code/security/rules/sec-015-no-pii-or-auth-state-in-urls</a></li><li><a href=\"/code/security/rules/sec-016-history-pii-retention-and-erasure\">code/security/rules/sec-016-history-pii-retention-and-erasure</a></li><li><a href=\"/code/security/rules/sec-017-no-secret-history-payloads\">code/security/rules/sec-017-no-secret-history-payloads</a></li><li><a href=\"/code/security/rules/sec-018-db-session-context-is-transaction-local\">code/security/rules/sec-018-db-session-context-is-transaction-local</a></li><li><a href=\"/code/security/rules/sec-019-audit-context-is-server-authored\">code/security/rules/sec-019-audit-context-is-server-authored</a></li><li><a href=\"/code/security/sources\">code/security/sources</a></li><li><a href=\"/code/sql-db-migrations\">code/sql-db-migrations</a></li><li><a href=\"/code/sql-db-migrations/reflection-model\">code/sql-db-migrations/reflection-model</a></li><li><a href=\"/code/sql-db-migrations/rules\">code/sql-db-migrations/rules</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-001-constraints-for-integrity\">code/sql-db-migrations/rules/sql-001-constraints-for-integrity</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-002-prepared-statements\">code/sql-db-migrations/rules/sql-002-prepared-statements</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-003-tenant-scope\">code/sql-db-migrations/rules/sql-003-tenant-scope</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-004-index-for-filter-sort-search\">code/sql-db-migrations/rules/sql-004-index-for-filter-sort-search</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-005-stable-pagination-order\">code/sql-db-migrations/rules/sql-005-stable-pagination-order</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-006-no-select-star-in-app-queries\">code/sql-db-migrations/rules/sql-006-no-select-star-in-app-queries</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-007-transactions-for-multi-step-changes\">code/sql-db-migrations/rules/sql-007-transactions-for-multi-step-changes</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-008-migrations-are-reviewable\">code/sql-db-migrations/rules/sql-008-migrations-are-reviewable</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-009-backfill-without-long-locks\">code/sql-db-migrations/rules/sql-009-backfill-without-long-locks</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-010-soft-delete-uniqueness\">code/sql-db-migrations/rules/sql-010-soft-delete-uniqueness</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-011-auditable-timestamps\">code/sql-db-migrations/rules/sql-011-auditable-timestamps</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-012-explain-for-slow-or-shared-queries\">code/sql-db-migrations/rules/sql-012-explain-for-slow-or-shared-queries</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-013-deterministic-fixtures\">code/sql-db-migrations/rules/sql-013-deterministic-fixtures</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-014-no-gui-only-data-rules\">code/sql-db-migrations/rules/sql-014-no-gui-only-data-rules</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-015-mutable-ssot-requires-row-history\">code/sql-db-migrations/rules/sql-015-mutable-ssot-requires-row-history</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-016-history-trigger-covers-insert-update-delete\">code/sql-db-migrations/rules/sql-016-history-trigger-covers-insert-update-delete</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-017-history-baseline-backfill-required\">code/sql-db-migrations/rules/sql-017-history-baseline-backfill-required</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-018-history-exclusions-are-explicit\">code/sql-db-migrations/rules/sql-018-history-exclusions-are-explicit</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-019-dynamic-schemas-include-history\">code/sql-db-migrations/rules/sql-019-dynamic-schemas-include-history</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-020-history-pii-and-secret-boundaries\">code/sql-db-migrations/rules/sql-020-history-pii-and-secret-boundaries</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-021-restore-contract-required\">code/sql-db-migrations/rules/sql-021-restore-contract-required</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-022-history-gui-contract\">code/sql-db-migrations/rules/sql-022-history-gui-contract</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-023-history-tables-append-only\">code/sql-db-migrations/rules/sql-023-history-tables-append-only</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-024-audit-question-before-history-layer\">code/sql-db-migrations/rules/sql-024-audit-question-before-history-layer</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-025-target-schema-preflight-required\">code/sql-db-migrations/rules/sql-025-target-schema-preflight-required</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-026-history-ignores-technical-timestamp-only-changes\">code/sql-db-migrations/rules/sql-026-history-ignores-technical-timestamp-only-changes</a></li><li><a href=\"/code/sql-db-migrations/rules/sql-027-history-scope-is-proportional\">code/sql-db-migrations/rules/sql-027-history-scope-is-proportional</a></li><li><a href=\"/code/sql-db-migrations/sources\">code/sql-db-migrations/sources</a></li><li><a href=\"/code/testing-qa\">code/testing-qa</a></li><li><a href=\"/code/testing-qa/reflection-model\">code/testing-qa/reflection-model</a></li><li><a href=\"/code/testing-qa/rules\">code/testing-qa/rules</a></li><li><a href=\"/code/testing-qa/rules/test-001-domain-unit-tests\">code/testing-qa/rules/test-001-domain-unit-tests</a></li><li><a href=\"/code/testing-qa/rules/test-002-repository-integration-tests\">code/testing-qa/rules/test-002-repository-integration-tests</a></li><li><a href=\"/code/testing-qa/rules/test-003-controller-and-http-contracts\">code/testing-qa/rules/test-003-controller-and-http-contracts</a></li><li><a href=\"/code/testing-qa/rules/test-004-browser-smoke-for-critical-flows\">code/testing-qa/rules/test-004-browser-smoke-for-critical-flows</a></li><li><a href=\"/code/testing-qa/rules/test-005-accessibility-baseline\">code/testing-qa/rules/test-005-accessibility-baseline</a></li><li><a href=\"/code/testing-qa/rules/test-006-no-modal-regression\">code/testing-qa/rules/test-006-no-modal-regression</a></li><li><a href=\"/code/testing-qa/rules/test-007-live-filter-regression\">code/testing-qa/rules/test-007-live-filter-regression</a></li><li><a href=\"/code/testing-qa/rules/test-008-js-disabled-baseline\">code/testing-qa/rules/test-008-js-disabled-baseline</a></li><li><a href=\"/code/testing-qa/rules/test-009-static-analysis-gate\">code/testing-qa/rules/test-009-static-analysis-gate</a></li><li><a href=\"/code/testing-qa/rules/test-010-mutation-for-high-value-rules\">code/testing-qa/rules/test-010-mutation-for-high-value-rules</a></li><li><a href=\"/code/testing-qa/rules/test-011-deterministic-fixtures\">code/testing-qa/rules/test-011-deterministic-fixtures</a></li><li><a href=\"/code/testing-qa/rules/test-012-regression-for-bug-fixes\">code/testing-qa/rules/test-012-regression-for-bug-fixes</a></li><li><a href=\"/code/testing-qa/rules/test-013-ci-commands-are-explicit\">code/testing-qa/rules/test-013-ci-commands-are-explicit</a></li><li><a href=\"/code/testing-qa/rules/test-014-evidence-artifacts\">code/testing-qa/rules/test-014-evidence-artifacts</a></li><li><a href=\"/code/testing-qa/rules/test-015-no-pii-in-auth-urls-regression\">code/testing-qa/rules/test-015-no-pii-in-auth-urls-regression</a></li><li><a href=\"/code/testing-qa/rules/test-016-db-history-trigger-regression\">code/testing-qa/rules/test-016-db-history-trigger-regression</a></li><li><a href=\"/code/testing-qa/rules/test-017-history-gui-and-restore-regression\">code/testing-qa/rules/test-017-history-gui-and-restore-regression</a></li><li><a href=\"/code/testing-qa/sources\">code/testing-qa/sources</a></li><li><a href=\"/db\">db</a></li><li><a href=\"/hallo-welt\">hallo-welt</a></li><li><a href=\"/kw-scrape\">kw-scrape</a></li><li><a href=\"/mcp-anleitung\">mcp-anleitung</a></li><li><a href=\"/mcp-demo\">mcp-demo</a></li><li><a href=\"/mcp-ki-web\">mcp-ki-web</a></li><li><a href=\"/mcp-qwen\">mcp-qwen</a></li><li><a href=\"/mcp-server-erstellen-regeln\">mcp-server-erstellen-regeln</a></li><li><a href=\"/mcp-vs-api-vs-cli\">mcp-vs-api-vs-cli</a></li><li><a href=\"/slug-liste\">slug-liste</a></li><li><a href=\"/web-scraping\">web-scraping</a></li></ul>","created_at":"2026-05-21T14:50:04+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":38,"konversionen":94},{"id":4,"slug":"mcp-qwen","title":"Konfiguration eines MCP-Servers in Qwen","meta_description":"Schritt-für-Schritt-Anleitung zur Konfiguration eines MCP-Servers innerhalb der Qwen-Plattform","content":"<h2>Einführung</h2>\n<p>Der MCP-Server (Multi-Cloud Platform) ist ein zentraler Bestandteil der Qwen-Infrastruktur, der die Kommunikation zwischen verschiedenen Cloud-Diensten und -Ressourcen verwaltet. Diese Anleitung erklärt, wie Sie einen MCP-Server in Qwen konfigurieren.</p>\n\n<h3>Schritt 1: Umgebung vorbereiten</h3>\n<ul>\n<li>Stellen Sie sicher, dass der Qwen-Server mit der neuesten Version von MCP kompatibel ist.</li>\n<li>Erstellen Sie eine Konfigurationsdatei  im Verzeichnis .</li>\n</ul>\n\n<h3>Schritt 2: MCP-Server konfigurieren</h3>\n\n\n<h3>Schritt 3: Server starten</h3>\n<p>Führen Sie den folgenden Befehl aus, um den MCP-Server zu starten:</p>\n\n\n<h3>Schritt 4: Überprüfung</h3>\n<p>Prüfen Sie den Status des MCP-Servers mit:</p>\n\n\n<h3>Häufige Probleme</h3>\n<ul>\n<li><strong>Fehler: Port 8080 belegt</strong> – Ändern Sie den Port in der Konfigurationsdatei.</li>\n<li><strong>Authentifizierung fehlschlägt</strong> – Stellen Sie sicher, dass der Token-Expiry-Wert korrekt ist.</li>\n</ul>","created_at":"2026-05-21T02:48:47+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":36,"konversionen":2},{"id":57,"slug":"code/schreibstil/rules/stil-006-no-pseudo-dramatic-phrasing","title":"STIL_006_NO_PSEUDO_DRAMATIC_PHRASING: Keine pseudo-dramatischen KI-Formulierungen","meta_description":"STIL_006_NO_PSEUDO_DRAMATIC_PHRASING (must): Keine pseudo-dramatischen KI-Formulierungen. Texte DÜRFEN keine rhetorischen Antithesen oder Steigerungs-Schablonen enthalten, deren Funktion Dramatik stat","content":"<h1>STIL_006_NO_PSEUDO_DRAMATIC_PHRASING: Keine pseudo-dramatischen KI-Formulierungen</h1><p>Severity: <strong>must</strong>. Bereich: <a href=\"/code/schreibstil\">schreibstil</a>.</p><h2>Regel</h2><p>Texte DÜRFEN keine rhetorischen Antithesen oder Steigerungs-Schablonen enthalten, deren Funktion Dramatik statt Präzision ist. Diese Muster sind klassische LLM-Floskeln und werden ausnahmslos entfernt oder umformuliert. Detektion erfolgt über die unten gelisteten Patterns, Korrektur durch nüchterne, direkte Aussage. . VERBOTEN (Beispiel-Patterns, keine vollständige Liste): . 1. Antithese-Schablone:   \"Das ist kein X, das ist (ein) Y.\"   \"Das ist nicht X, sondern Y.\"   \"Es ist nicht nur X, es ist Y.\"   \"Mehr als nur X.\". 2. Steigerungs-Triplets:   \"Schnell. Einfach. Mächtig.\"   \"Klein. Robust. Universell.\"   \"X. Y. Z.\" als rhetorische Schluss-Salve.. 3. Theatralische Eröffnung oder Abschluss:   \"Willkommen zu X.\"   \"Hier beginnt der eigentliche Weg.\"   \"Das ändert alles.\"   \"Lang lebe Y.\"   \"Eine Wahrheit, drei Hüllen.\". 4. Marketing-Verstärker ohne Inhalt:   \"Genau hier glänzt X.\"   \"Bestechend einfach.\"   \"Der eigentliche Trick ist Y.\"   \"Genau dort, wo X aufhört, beginnt Y.\". ERLAUBT bleibt die nüchterne Sachaussage:   \"X macht A. Y macht B. Beides zusammen ergibt C.\"   \"Wir nutzen X, weil Y.\". Antithesen sind nur dann zulässig, wenn sie eine echte fachliche Unterscheidung treffen (\"PUT ersetzt, PATCH ändert teilweise.\") und nicht der Steigerung dienen.</p><h2>Reflection-Check</h2><pre><code>check:\n  reflect:\n    fields:\n    - contains_antithesis_template\n    - contains_dramatic_triplet\n    - contains_theatrical_opener_or_closer\n    - contains_empty_marketing_intensifier\n    object: text_artifact</code></pre><h2>Evidence</h2><ul><li><strong>LOCAL_KARL_DIRECTIVE_2026_05_21</strong>, Karls direkte Anweisung am 2026-05-21</li></ul><p><a href=\"/code/schreibstil/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:39:43+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":90,"konversionen":95},{"id":1186,"slug":"torsten","title":"Hallo Torsten","meta_description":"Hallo Torsten","content":"<p>hallo Torsten</p>","created_at":"2026-05-21T14:54:32+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":4,"konversionen":4},{"id":63,"slug":"code/css/rules","title":"Regeln, css","meta_description":"Liste der 51 Regeln im Bereich css, sortiert nach ID.","content":"<h1>Regeln, css</h1><p>51 Regeln in /var/www/code/css/rules.yaml.</p><table><thead><tr><th>ID</th><th>Titel</th><th>Severity</th></tr></thead><tbody><tr><td><a href=\"/code/css/rules/css-001-external-css-only\">CSS_001_EXTERNAL_CSS_ONLY</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/css/rules/css-002-no-css-frameworks-for-first-party-ui\">CSS_002_NO_CSS_FRAMEWORKS_FOR_FIRST_PARTY_UI</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-003-css-is-presentation-adapter\">CSS_003_CSS_IS_PRESENTATION_ADAPTER</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/css/rules/css-004-no-authorization-by-display-none\">CSS_004_NO_AUTHORIZATION_BY_DISPLAY_NONE</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/css/rules/css-005-file-role-single-responsibility\">CSS_005_FILE_ROLE_SINGLE_RESPONSIBILITY</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-006-maxloc-file\">CSS_006_MAXLOC_FILE</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-007-maxloc-rule-block\">CSS_007_MAXLOC_RULE_BLOCK</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-008-cascade-layers-for-new-global-css\">CSS_008_CASCADE_LAYERS_FOR_NEW_GLOBAL_CSS</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-009-imports-avoided-at-runtime\">CSS_009_IMPORTS_AVOIDED_AT_RUNTIME</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-010-low-specificity-by-default\">CSS_010_LOW_SPECIFICITY_BY_DEFAULT</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-011-no-id-selectors-for-style\">CSS_011_NO_ID_SELECTORS_FOR_STYLE</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-012-no-important-except-accessibility-override\">CSS_012_NO_IMPORTANT_EXCEPT_ACCESSIBILITY_OVERRIDE</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-013-nesting-depth-limit\">CSS_013_NESTING_DEPTH_LIMIT</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-014-scope-components-by-root\">CSS_014_SCOPE_COMPONENTS_BY_ROOT</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-015-component-state-matrix-complete\">CSS_015_COMPONENT_STATE_MATRIX_COMPLETE</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-016-design-tokens-semantic\">CSS_016_DESIGN_TOKENS_SEMANTIC</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-017-token-names-not-visual-only\">CSS_017_TOKEN_NAMES_NOT_VISUAL_ONLY</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-018-token-fallbacks-for-cross-project-reuse\">CSS_018_TOKEN_FALLBACKS_FOR_CROSS_PROJECT_REUSE</a></td><td></td><td><strong>minor</strong></td></tr><tr><td><a href=\"/code/css/rules/css-019-no-style-as-data-source\">CSS_019_NO_STYLE_AS_DATA_SOURCE</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/css/rules/css-020-js-toggles-state-not-style\">CSS_020_JS_TOGGLES_STATE_NOT_STYLE</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-021-no-modals-or-modal-tokens\">CSS_021_NO_MODALS_OR_MODAL_TOKENS</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/css/rules/css-022-overlay-only-for-non-modal-system-states\">CSS_022_OVERLAY_ONLY_FOR_NON_MODAL_SYSTEM_STATES</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-023-focus-visible-never-removed\">CSS_023_FOCUS_VISIBLE_NEVER_REMOVED</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/css/rules/css-024-text-contrast-light-dark\">CSS_024_TEXT_CONTRAST_LIGHT_DARK</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/css/rules/css-025-non-text-contrast\">CSS_025_NON_TEXT_CONTRAST</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/css/rules/css-026-not-color-only\">CSS_026_NOT_COLOR_ONLY</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/css/rules/css-027-visually-hidden-pattern-safe\">CSS_027_VISUALLY_HIDDEN_PATTERN_SAFE</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-028-hidden-state-matches-semantics\">CSS_028_HIDDEN_STATE_MATCHES_SEMANTICS</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-029-reduced-motion\">CSS_029_REDUCED_MOTION</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-030-forced-colors-compatible\">CSS_030_FORCED_COLORS_COMPATIBLE</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-031-light-dark-system-theme\">CSS_031_LIGHT_DARK_SYSTEM_THEME</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-032-no-flash-wrong-theme-css-support\">CSS_032_NO_FLASH_WRONG_THEME_CSS_SUPPORT</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-033-responsive-by-component\">CSS_033_RESPONSIVE_BY_COMPONENT</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-034-reflow-320px\">CSS_034_REFLOW_320PX</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/css/rules/css-035-logical-properties-for-new-layout\">CSS_035_LOGICAL_PROPERTIES_FOR_NEW_LAYOUT</a></td><td></td><td><strong>minor</strong></td></tr><tr><td><a href=\"/code/css/rules/css-036-touch-targets-and-pointer-media\">CSS_036_TOUCH_TARGETS_AND_POINTER_MEDIA</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-037-tables-keep-semantic-reachability\">CSS_037_TABLES_KEEP_SEMANTIC_REACHABILITY</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-038-live-filter-visual-status\">CSS_038_LIVE_FILTER_VISUAL_STATUS</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-039-form-states-inline\">CSS_039_FORM_STATES_INLINE</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/css/rules/css-040-print-and-export-styles\">CSS_040_PRINT_AND_EXPORT_STYLES</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-041-page-scoped-css\">CSS_041_PAGE_SCOPED_CSS</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-042-unused-css-budget\">CSS_042_UNUSED_CSS_BUDGET</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-043-content-visibility-for-long-independent-sections\">CSS_043_CONTENT_VISIBILITY_FOR_LONG_INDEPENDENT_SECTIONS</a></td><td></td><td><strong>minor</strong></td></tr><tr><td><a href=\"/code/css/rules/css-044-no-layout-shift-from-late-styles\">CSS_044_NO_LAYOUT_SHIFT_FROM_LATE_STYLES</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-045-z-index-scale\">CSS_045_Z_INDEX_SCALE</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-046-no-text-clipping-or-viewport-font-scaling\">CSS_046_NO_TEXT_CLIPPING_OR_VIEWPORT_FONT_SCALING</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-047-no-one-note-palette\">CSS_047_NO_ONE_NOTE_PALETTE</a></td><td></td><td><strong>minor</strong></td></tr><tr><td><a href=\"/code/css/rules/css-048-stylelint-or-static-scan\">CSS_048_STYLELINT_OR_STATIC_SCAN</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-049-history-diff-states\">CSS_049_HISTORY_DIFF_STATES</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/css/rules/css-050-history-layout-no-modal\">CSS_050_HISTORY_LAYOUT_NO_MODAL</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/css/rules/css-051-history-table-responsive-stable\">CSS_051_HISTORY_TABLE_RESPONSIVE_STABLE</a></td><td></td><td><strong>major</strong></td></tr></tbody></table><p><a href=\"/code/css\">Zurück zum Bereich</a></p>","created_at":"2026-05-21T12:39:59+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":34,"konversionen":56},{"id":1187,"slug":"tim","title":"Tim","meta_description":"hallo Tim","content":"<p>hallo Tim</p>","created_at":"2026-05-21T14:55:00+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":69,"konversionen":11},{"id":1188,"slug":"sascha","title":"Hallo Sascha","meta_description":"Hallo Sascha","content":"<p>hallo Sascha</p>","created_at":"2026-05-21T14:55:50+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":89,"konversionen":22},{"id":70,"slug":"code/css/rules/css-007-maxloc-rule-block","title":"CSS_007_MAXLOC_RULE_BLOCK:","meta_description":"CSS_007_MAXLOC_RULE_BLOCK (major): .","content":"<h1>CSS_007_MAXLOC_RULE_BLOCK: </h1><p>Severity: <strong>major</strong>. Bereich: <a href=\"/code/css\">css</a>.</p><h2>Regel</h2><p>(kein Regeltext)</p><h2>Reflection-Check</h2><pre><code>check:\n  fail: Ein Selectorblock enthaelt viele Layout-, Typografie-, Farb-, State- und Responsive-Deklarationen\n    zugleich.\n  pass: Ein Rule Block bleibt bei &lt;= 20 LOC Zielwert, &lt;= 35 LOC Hard Limit und &lt;=\n    16 Deklarationen.\n  remediation: Basis, Variante, State, Responsive und Theme-Regeln trennen; Tokens\n    statt Wiederholung nutzen.\n  type: css_rule</code></pre><h2>Evidence</h2><ul><li><strong>MDN_CSS_PERFORMANCE</strong>, MDN: CSS performance optimization</li></ul><p><a href=\"/code/css/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:39:59+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":67,"konversionen":27},{"id":223,"slug":"code/js/sources","title":"Quellen, js","meta_description":"Quellen des Bereichs js, 20 Eintraege.","content":"<h1>Quellen, js</h1><p>20 Quellen in /var/www/code/js/sources.yaml.</p><table><thead><tr><th>ID</th><th>Titel</th><th>URL / Referenz</th><th>Publisher</th><th>Typ</th><th>Relevanz</th></tr></thead><tbody><tr><td><strong>MDN_JS_MODULES</strong></td><td>MDN: JavaScript modules</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules\">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules</a></td><td></td><td></td><td>Native ES-Module, import/export, type=module und Import Maps fuer moderne Vanilla-JS-Struktur.</td></tr><tr><td><strong>MDN_STRICT_MODE</strong></td><td>MDN: Strict mode</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode\">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode</a></td><td></td><td></td><td>Striktere JavaScript-Ausfuehrung; Module sind automatisch strict, Legacy-Skripte brauchen explizites strict/IIFE.</td></tr><tr><td><strong>MDN_ADD_EVENT_LISTENER</strong></td><td>MDN: EventTarget.addEventListener</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener\">https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener</a></td><td></td><td></td><td>Standard-API fuer Event-Binding, Optionen und AbortSignal-basierte Listener-Verwaltung.</td></tr><tr><td><strong>MDN_ABORT_CONTROLLER</strong></td><td>MDN: AbortController</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/AbortController\">https://developer.mozilla.org/en-US/docs/Web/API/AbortController</a></td><td></td><td></td><td>Abbruch von Fetches und Event-Listenern fuer stale Requests und Komponenten-Cleanup.</td></tr><tr><td><strong>MDN_FETCH</strong></td><td>MDN: Using the Fetch API</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch\">https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch</a></td><td></td><td></td><td>Fetch-Requests, Response-Handling, Fehlerbehandlung und Request-Abbruch.</td></tr><tr><td><strong>MDN_DOMCONTENTLOADED</strong></td><td>MDN: DOMContentLoaded event</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document/DOMContentLoaded_event\">https://developer.mozilla.org/en-US/docs/Web/API/Document/DOMContentLoaded_event</a></td><td></td><td></td><td>Korrektes Bootstrapping abhaengig von classic/defer/module scripts und Dokumentzustand.</td></tr><tr><td><strong>MDN_PROGRESSIVE_ENHANCEMENT</strong></td><td>MDN Glossary: Progressive Enhancement</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement\">https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement</a></td><td></td><td></td><td>Baseline-Funktion zuerst; moderne Browser erhalten zusaetzliche Verbesserung per Feature Detection.</td></tr><tr><td><strong>MDN_JS_ACCESSIBILITY</strong></td><td>MDN: CSS and JavaScript accessibility best practices</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Accessibility/CSS_and_JavaScript\">https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Accessibility/CSS_and_JavaScript</a></td><td></td><td></td><td>Unobtrusive JavaScript, Semantik, native Controls und zugaengliche dynamische Inhalte.</td></tr><tr><td><strong>WEBDEV_RESOURCE_LOADING</strong></td><td>web.dev: Optimize resource loading</td><td><a href=\"https://web.dev/learn/performance/optimize-resource-loading\">https://web.dev/learn/performance/optimize-resource-loading</a></td><td></td><td></td><td>Script-Loading, Parser-Blocking, Async/Defer/Module und Page-Performance.</td></tr><tr><td><strong>WEBDEV_THIRD_PARTY_JS</strong></td><td>web.dev: Efficiently load third-party JavaScript</td><td><a href=\"https://web.dev/articles/efficiently-load-third-party-javascript\">https://web.dev/articles/efficiently-load-third-party-javascript</a></td><td></td><td></td><td>Drittanbieter-Skripte begrenzen, asynchron/deferred laden und Performance-Kosten sichtbar machen.</td></tr><tr><td><strong>OWASP_DOM_XSS</strong></td><td>OWASP DOM based XSS Prevention Cheat Sheet</td><td><a href=\"https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html\">https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html</a></td><td></td><td></td><td>Untrusted Data nicht als Markup/Code behandeln; sichere DOM-Erzeugung mit createElement, setAttribute und appendChild.</td></tr><tr><td><strong>OWASP_XSS</strong></td><td>OWASP Cross Site Scripting Prevention Cheat Sheet</td><td><a href=\"https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\">https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html</a></td><td></td><td></td><td>Unsafe sinks wie innerHTML minimieren; textContent/value bevorzugen und kontextgerecht encoden.</td></tr><tr><td><strong>WCAG22</strong></td><td>Web Content Accessibility Guidelines 2.2</td><td><a href=\"https://www.w3.org/TR/WCAG22/\">https://www.w3.org/TR/WCAG22/</a></td><td></td><td></td><td>Keyboard, Fokus, Statusmeldungen, Kontrast, Name/Role/Value, Eingabe und Vorhersagbarkeit.</td></tr><tr><td><strong>WAI_STATUS</strong></td><td>Understanding WCAG 4.1.3 Status Messages</td><td><a href=\"https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html\">https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html</a></td><td></td><td></td><td>Dynamische Statusmeldungen duerfen ohne Fokuswechsel erscheinen, muessen aber programmatisch bestimmbar sein.</td></tr><tr><td><strong>COCKBURN_HEXAGONAL</strong></td><td>Alistair Cockburn: Hexagonal Architecture</td><td><a href=\"https://alistair.cockburn.us/hexagonal-architecture\">https://alistair.cockburn.us/hexagonal-architecture</a></td><td></td><td></td><td>Ports and Adapters: UI ist Adapter; Application bleibt unabhaengig von UI, Datenbank und externen Technologien.</td></tr><tr><td><strong>FOWLER_PRESENTATION_DOMAIN</strong></td><td>Martin Fowler: Presentation Domain Separation</td><td><a href=\"https://martinfowler.com/bliki/PresentationDomainSeparation.html\">https://martinfowler.com/bliki/PresentationDomainSeparation.html</a></td><td></td><td></td><td>Domainlogik und Praesentationslogik muessen getrennt bleiben.</td></tr><tr><td><strong>FOWLER_SEPARATED_PRESENTATION</strong></td><td>Martin Fowler: Separated Presentation</td><td><a href=\"https://martinfowler.com/eaaDev/SeparatedPresentation.html\">https://martinfowler.com/eaaDev/SeparatedPresentation.html</a></td><td></td><td></td><td>Praesentationscode manipuliert Praesentation; Domain- und Datenquellenlogik liegen getrennt.</td></tr><tr><td><strong>FOWLER_MVC</strong></td><td>Martin Fowler: Model View Controller</td><td><a href=\"https://martinfowler.com/eaaCatalog/modelViewController.html\">https://martinfowler.com/eaaCatalog/modelViewController.html</a></td><td></td><td></td><td>MVC als Muster zur Trennung von Input Controller, Model und View.</td></tr><tr><td><strong>DDD_REFERENCE</strong></td><td>Domain Language: Domain-Driven Design Reference</td><td><a href=\"https://www.domainlanguage.com/ddd/reference/\">https://www.domainlanguage.com/ddd/reference/</a></td><td></td><td></td><td>DDD-Bausteine wie Entity, Value Object, Aggregate, Repository, Domain Service und Bounded Context.</td></tr><tr><td><strong>LOCAL_GUI_RULES</strong></td><td>Lokale GUI-YAML-Libraries</td><td>file:/var/www/code/gui</td><td></td><td></td><td>Projektinterne GUI-Regeln fuer Formulare, Tabellen, Suche, Feedback, Theme, Drag/Drop, Uploads, Auth und Modal-Verbot.</td></tr></tbody></table><p><a href=\"/code/js\">Zurück zum Bereich</a></p>","created_at":"2026-05-21T12:40:03+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":51,"konversionen":100},{"id":1189,"slug":"heiko","title":"Heiko","meta_description":"hallo Heiko","content":"<p>hallo Heiko</p>","created_at":"2026-05-21T14:57:05+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":45,"konversionen":11},{"id":79,"slug":"code/css/rules/css-016-design-tokens-semantic","title":"CSS_016_DESIGN_TOKENS_SEMANTIC:","meta_description":"CSS_016_DESIGN_TOKENS_SEMANTIC (major): .","content":"<h1>CSS_016_DESIGN_TOKENS_SEMANTIC: </h1><p>Severity: <strong>major</strong>. Bereich: <a href=\"/code/css\">css</a>.</p><h2>Regel</h2><p>(kein Regeltext)</p><h2>Reflection-Check</h2><pre><code>check:\n  fail: Raw Hex-, px-, shadow- oder z-index-Werte werden in vielen Komponenten wiederholt.\n  pass: Farben, Abstaende, Radii, Schatten, Fontgroessen, Motion und Z-Indices nutzen\n    semantische Custom Properties.\n  remediation: Semantische Tokens definieren, z.B. --color-surface, --color-danger-text,\n    --space-3, --focus-ring.\n  type: design_token</code></pre><h2>Evidence</h2><ul><li><strong>MDN_CUSTOM_PROPERTIES</strong>, MDN: Using CSS custom properties</li><li><strong>LOCAL_GUI_RULES</strong>, Lokale GUI-YAML-Libraries</li></ul><p><a href=\"/code/css/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:39:59+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":60,"konversionen":33},{"id":1190,"slug":"andreas","title":"Andreas","meta_description":"hallo Andreas","content":"<p>hallo Andreas</p>","created_at":"2026-05-21T14:57:48+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":84,"konversionen":95},{"id":86,"slug":"code/css/rules/css-023-focus-visible-never-removed","title":"CSS_023_FOCUS_VISIBLE_NEVER_REMOVED:","meta_description":"CSS_023_FOCUS_VISIBLE_NEVER_REMOVED (blocker): .","content":"<h1>CSS_023_FOCUS_VISIBLE_NEVER_REMOVED: </h1><p>Severity: <strong>blocker</strong>. Bereich: <a href=\"/code/css\">css</a>.</p><h2>Regel</h2><p>(kein Regeltext)</p><h2>Reflection-Check</h2><pre><code>check:\n  fail: 'outline: none ohne gleichwertigen Ersatz oder Fokus nur durch schwachen Schatten.'\n  pass: Fokus ist per :focus-visible sichtbar, ausreichend gross und kontrastreich.\n  remediation: Token fuer Focus-Ring definieren; outline/box-shadow mit &gt;= 3:1 Zustandskontrast\n    pruefen.\n  type: accessibility_style</code></pre><h2>Evidence</h2><ul><li><strong>WCAG_FOCUS_APPEARANCE</strong>, Understanding WCAG 2.4.13 Focus Appearance</li><li><strong>WCAG22</strong>, Web Content Accessibility Guidelines 2.2</li></ul><p><a href=\"/code/css/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:40:00+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":60,"konversionen":65},{"id":94,"slug":"code/css/rules/css-031-light-dark-system-theme","title":"CSS_031_LIGHT_DARK_SYSTEM_THEME:","meta_description":"CSS_031_LIGHT_DARK_SYSTEM_THEME (major): .","content":"<h1>CSS_031_LIGHT_DARK_SYSTEM_THEME: </h1><p>Severity: <strong>major</strong>. Bereich: <a href=\"/code/css\">css</a>.</p><h2>Regel</h2><p>(kein Regeltext)</p><h2>Reflection-Check</h2><pre><code>check:\n  fail: Komponente hat feste Farben oder nur Dark/Light ohne Systempfad.\n  pass: Styles funktionieren fuer Light, Dark und System; color-scheme/meta-Vertrag\n    wird nicht durch CSS unterlaufen.\n  remediation: Theme-Tokens mit prefers-color-scheme und [data-theme] kombinieren;\n    beide Modi messen.\n  type: component_style</code></pre><h2>Evidence</h2><ul><li><strong>MDN_PREFERS_COLOR_SCHEME</strong>, MDN: prefers-color-scheme</li><li><strong>MDN_COLOR_SCHEME</strong>, MDN: color-scheme</li><li><strong>LOCAL_GUI_RULES</strong>, Lokale GUI-YAML-Libraries</li></ul><p><a href=\"/code/css/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:40:00+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":39,"konversionen":99},{"id":102,"slug":"code/css/rules/css-039-form-states-inline","title":"CSS_039_FORM_STATES_INLINE:","meta_description":"CSS_039_FORM_STATES_INLINE (blocker): .","content":"<h1>CSS_039_FORM_STATES_INLINE: </h1><p>Severity: <strong>blocker</strong>. Bereich: <a href=\"/code/css\">css</a>.</p><h2>Regel</h2><p>(kein Regeltext)</p><h2>Reflection-Check</h2><pre><code>check:\n  fail: CSS zeigt Fehler nur als rote Border oder Placeholder ersetzt Label.\n  pass: Fehler, Hinweise, Pflichtstatus, disabled/readonly und success sind inline\n    sichtbar und nicht nur farblich.\n  remediation: Fehlertext, aria-invalid, describedby und semantische Icons/Text visuell\n    unterstuetzen.\n  type: component_style</code></pre><h2>Evidence</h2><ul><li><strong>LOCAL_GUI_RULES</strong>, Lokale GUI-YAML-Libraries</li><li><strong>WCAG22</strong>, Web Content Accessibility Guidelines 2.2</li></ul><p><a href=\"/code/css/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:40:00+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":27,"konversionen":24},{"id":1193,"slug":"logistikberatung","title":"Logistikberatung","meta_description":"Durchgaengige IT-gestuetzte Logistikprozesse von Auftragseingang bis Versand.","content":"<h1>Logistikberatung</h1><p>Als Zulieferer, Komponentenfertiger oder Logistikdienstleister haengt Ihre Wettbewerbsfaehigkeit wesentlich von exzellenten Logistikprozessen ab: zuverlaessige, termingerechte Lieferung in exakter Menge, vereinbarter Qualitaet und vorgeschriebener Verpackung an die richtige Abladestelle.</p><p>Unternehmen, die ihre Prozesse vom Auftragseingang ueber Kommissionierung, Verpackung, Transportzusammenstellung und Etikettierung bis zum Versand durchgaengig IT-gestuetzt steuern, haben die Nase vorn. Bei komplexen Ablaeufen wie Streckenabwicklung, Lohnbearbeitung oder Just-in-Sequence (JIS) zahlt sich diese Durchgaengigkeit besonders aus.</p><p>WSW Software plant und realisiert gemeinsam mit Ihnen eine massgeschneiderte Loesung mit mehr als 30 Jahren Logistikerfahrung, die sich rasch amortisiert und Effizienz, Flexibilitaet und Transparenz Ihrer Logistik nachhaltig erhoeht.</p>","created_at":"2026-05-21T15:06:15+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":22,"konversionen":73},{"id":115,"slug":"code/css/sources","title":"Quellen, css","meta_description":"Quellen des Bereichs css, 27 Eintraege.","content":"<h1>Quellen, css</h1><p>27 Quellen in /var/www/code/css/sources.yaml.</p><table><thead><tr><th>ID</th><th>Titel</th><th>URL / Referenz</th><th>Publisher</th><th>Typ</th><th>Relevanz</th></tr></thead><tbody><tr><td><strong>W3C_CSS_CASCADE_6</strong></td><td>CSS Cascading and Inheritance Level 6</td><td><a href=\"https://www.w3.org/TR/css-cascade-6/\">https://www.w3.org/TR/css-cascade-6/</a></td><td></td><td></td><td>Cascade, origins, importance, cascade layers und @scope als Grundlage fuer wartbare CSS-Architektur.</td></tr><tr><td><strong>MDN_LAYER</strong></td><td>MDN: @layer</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/@layer\">https://developer.mozilla.org/en-US/docs/Web/CSS/@layer</a></td><td></td><td></td><td>Cascade Layers zur Steuerung von Prioritaet ohne Spezifitaetskaempfe.</td></tr><tr><td><strong>MDN_CUSTOM_PROPERTIES</strong></td><td>MDN: Using CSS custom properties</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_cascading_variables/Using_CSS_custom_properties\">https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_cascading_variables/Using_CSS_custom_properties</a></td><td></td><td></td><td>CSS Custom Properties fuer semantische Design Tokens, DRY und Theme-Faehigkeit.</td></tr><tr><td><strong>MDN_CONTAINER_QUERIES</strong></td><td>MDN: CSS container queries</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_container_queries\">https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_container_queries</a></td><td></td><td></td><td>Komponenten koennen sich an ihre Container statt nur an Viewport-Breakpoints anpassen.</td></tr><tr><td><strong>MDN_NESTING</strong></td><td>MDN: Using CSS nesting</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting/Using_CSS_nesting\">https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting/Using_CSS_nesting</a></td><td></td><td></td><td>Native CSS Nesting kann Wartbarkeit verbessern, erhoeht aber Spezifitaets- und Tiefenrisiko.</td></tr><tr><td><strong>MDN_WHERE</strong></td><td>MDN: :where()</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/:where\">https://developer.mozilla.org/en-US/docs/Web/CSS/:where</a></td><td></td><td></td><td>Niedrige Spezifitaet fuer Basis-/Reset-/Layout-Selektoren.</td></tr><tr><td><strong>MDN_HAS</strong></td><td>MDN: :has()</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/:has\">https://developer.mozilla.org/en-US/docs/Web/CSS/:has</a></td><td></td><td></td><td>Relationale Selektoren koennen JS reduzieren, muessen aber bewusst und performant eingesetzt werden.</td></tr><tr><td><strong>MDN_SUPPORTS</strong></td><td>MDN: @supports</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/@supports\">https://developer.mozilla.org/en-US/docs/Web/CSS/@supports</a></td><td></td><td></td><td>Feature Detection und progressive CSS-Verbesserung ohne Browser-Sniffing.</td></tr><tr><td><strong>MDN_LOGICAL_PROPERTIES</strong></td><td>MDN: CSS logical properties and values</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values\">https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values</a></td><td></td><td></td><td>Richtungsunabhaengige Layouts fuer Internationalisierung und robuste Schreibmodi.</td></tr><tr><td><strong>MDN_PREFERS_COLOR_SCHEME</strong></td><td>MDN: prefers-color-scheme</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme\">https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme</a></td><td></td><td></td><td>Systempraeferenz fuer Light/Dark Mode.</td></tr><tr><td><strong>MDN_COLOR_SCHEME</strong></td><td>MDN: color-scheme</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme\">https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme</a></td><td></td><td></td><td>UA-Controls und initiale Farbschema-Verhandlung, inkl. Vermeidung falscher Erstfarben.</td></tr><tr><td><strong>MDN_PREFERS_REDUCED_MOTION</strong></td><td>MDN: prefers-reduced-motion</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion\">https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion</a></td><td></td><td></td><td>Nutzerpraeferenz fuer reduzierte Bewegung.</td></tr><tr><td><strong>MDN_FORCED_COLORS</strong></td><td>MDN: forced-colors</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/@media/forced-colors\">https://developer.mozilla.org/en-US/docs/Web/CSS/@media/forced-colors</a></td><td></td><td></td><td>High-Contrast/Forced-Colors-Kompatibilitaet.</td></tr><tr><td><strong>MDN_HOVER</strong></td><td>MDN: hover media feature</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/@media/hover\">https://developer.mozilla.org/en-US/docs/Web/CSS/@media/hover</a></td><td></td><td></td><td>Hover-Styles nur einsetzen, wenn Hover-Eingabe tatsaechlich verfuegbar ist.</td></tr><tr><td><strong>MDN_POINTER</strong></td><td>MDN: pointer media feature</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer\">https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer</a></td><td></td><td></td><td>Touch-/Pointer-Zielgroessen und Eingabemodalitaeten.</td></tr><tr><td><strong>MDN_CSS_CONTAINMENT</strong></td><td>MDN: Using CSS containment</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Using_CSS_containment\">https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Using_CSS_containment</a></td><td></td><td></td><td>Containment und content-visibility fuer Performance bei grossen Seiten.</td></tr><tr><td><strong>MDN_CSS_PERFORMANCE</strong></td><td>MDN: CSS performance optimization</td><td><a href=\"https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance/CSS\">https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance/CSS</a></td><td></td><td></td><td>CSS-Dateigroessen, ungenutzte Regeln, render-blocking CSS und optimierte Auslieferung.</td></tr><tr><td><strong>WEBDEV_RENDER_BLOCKING_CSS</strong></td><td>web.dev: Render-blocking CSS</td><td><a href=\"https://web.dev/critical-rendering-path-render-blocking-css/\">https://web.dev/critical-rendering-path-render-blocking-css/</a></td><td></td><td></td><td>CSS ist render-blocking; kritisches CSS klein halten und Auslieferung bewusst planen.</td></tr><tr><td><strong>WCAG22</strong></td><td>Web Content Accessibility Guidelines 2.2</td><td><a href=\"https://www.w3.org/TR/WCAG22/\">https://www.w3.org/TR/WCAG22/</a></td><td></td><td></td><td>Kontrast, Fokus, Reflow, Text Spacing, Motion, Pointer, Status und Name/Role/Value.</td></tr><tr><td><strong>WCAG_CONTRAST_MINIMUM</strong></td><td>Understanding WCAG 1.4.3 Contrast (Minimum)</td><td><a href=\"https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html\">https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html</a></td><td></td><td></td><td>Textkontrast fuer alle Theme- und State-Farbpaare.</td></tr><tr><td><strong>WCAG_NON_TEXT_CONTRAST</strong></td><td>Understanding WCAG 1.4.11 Non-text Contrast</td><td><a href=\"https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html\">https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html</a></td><td></td><td></td><td>Fokus, Borders, Icons, Controls und Zustandsmarker brauchen ausreichenden Kontrast.</td></tr><tr><td><strong>WCAG_USE_OF_COLOR</strong></td><td>Understanding WCAG 1.4.1 Use of Color</td><td><a href=\"https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html\">https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html</a></td><td></td><td></td><td>Farbe darf nicht einzige Informationsquelle sein.</td></tr><tr><td><strong>WCAG_FOCUS_APPEARANCE</strong></td><td>Understanding WCAG 2.4.13 Focus Appearance</td><td><a href=\"https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance.html\">https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance.html</a></td><td></td><td></td><td>Fokusindikatoren muessen ausreichend sichtbar und kontrastreich sein.</td></tr><tr><td><strong>COCKBURN_HEXAGONAL</strong></td><td>Alistair Cockburn: Hexagonal Architecture</td><td><a href=\"https://alistair.cockburn.us/hexagonal-architecture\">https://alistair.cockburn.us/hexagonal-architecture</a></td><td></td><td></td><td>UI und Styling sind Adapter an der Aussenseite; Application bleibt unabhaengig von Praesentation.</td></tr><tr><td><strong>FOWLER_PRESENTATION_DOMAIN</strong></td><td>Martin Fowler: Presentation Domain Separation</td><td><a href=\"https://martinfowler.com/bliki/PresentationDomainSeparation.html\">https://martinfowler.com/bliki/PresentationDomainSeparation.html</a></td><td></td><td></td><td>Praesentations- und Domainlogik getrennt halten.</td></tr><tr><td><strong>LOCAL_GUI_RULES</strong></td><td>Lokale GUI-YAML-Libraries</td><td>file:/var/www/code/gui</td><td></td><td></td><td>Projektinterne GUI-Regeln fuer Formulare, Tabellen, Suche, Feedback, Theme, Uploads, Auth und Modal-Verbot.</td></tr><tr><td><strong>LOCAL_JS_RULES</strong></td><td>Lokale Vanilla-JS-YAML-Library</td><td>file:/var/www/code/js</td><td></td><td></td><td>JS setzt State/Verhalten; CSS reagiert auf Klassen, data-state, aria-* und Tokens.</td></tr></tbody></table><p><a href=\"/code/css\">Zurück zum Bereich</a></p>","created_at":"2026-05-21T12:40:00+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":49,"konversionen":49},{"id":1191,"slug":"sap-beratung","title":"SAP-Beratung","meta_description":"Ganzheitliche SAP-Beratung für ERP und S/4HANA mit über 30 Jahren Erfahrung.","content":"<h1>SAP-Beratung</h1><p>In der dynamischen Geschäftswelt von heute hängt Ihre Wettbewerbsfähigkeit davon ab, dass alle Geschäftsprozesse durchgängig und reibungslos ablaufen. Weil sich die Anforderungen ständig ändern, müssen Prozesse laufend optimiert, weiterentwickelt und modernisiert werden.</p><p>Unternehmen mit SAP-Lösungen profitieren besonders dann von unserer Beratung, wenn sie als Zulieferer oder Komponentenfertiger im Just-in-Sequence-Verfahren beliefern, Prozessabbildungen jenseits des SAP-Standards benötigen oder konkrete Vorhaben in Business Analytics oder SAP Global Trade Services umsetzen wollen.</p><p>Egal ob SAP ERP oder SAP S/4HANA: WSW Software begleitet Sie mit betriebswirtschaftlicher, prozessorientierter und technologischer Beratungskompetenz aus mehr als 30 Jahren Erfahrung, ergänzt um eigene Add-ons wie SPEEDI und JUNIQ, die den SAP-Standard modifikationsfrei erweitern.</p>","created_at":"2026-05-21T14:59:27+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":52,"konversionen":7},{"id":121,"slug":"code/deployment-config/rules/deploy-004-secret-rotation","title":"DEPLOY_004_SECRET_ROTATION: Secrets haben Rotation und Fallback","meta_description":"DEPLOY_004_SECRET_ROTATION (should): Secrets haben Rotation und Fallback. Kritische Secrets SOLLTEN Rotation, Verbraucheruebersicht und Fallback-Policy definieren, bevor sie produktiv genutzt we","content":"<h1>DEPLOY_004_SECRET_ROTATION: Secrets haben Rotation und Fallback</h1><p>Severity: <strong>should</strong>. Bereich: <a href=\"/code/deployment-config\">deployment-config</a>.</p><h2>Regel</h2><p>Kritische Secrets SOLLTEN Rotation, Verbraucheruebersicht und Fallback-Policy definieren, bevor sie produktiv genutzt werden.</p><h2>Reflection-Check</h2><pre><code>check:\n  reflect:\n    fields:\n    - rotation_policy\n    - fallback_policy\n    object: secret_config</code></pre><h2>Evidence</h2><ul><li><strong>OWASP_SECRETS</strong>, OWASP Secrets Management Cheat Sheet</li></ul><p><a href=\"/code/deployment-config/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:40:00+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":5,"konversionen":3},{"id":1195,"slug":"jis-komponenten","title":"JIS-Beratung – Komponenten-Modell","meta_description":"Analyse der WSW-Landingpage zur JIS-Beratung entlang des Komponenten-Modells nach Karl Kratz.","content":"<h1>JIS-Beratung – Komponenten-Modell</h1><p>Analyse der Landingpage <a href=\"https://www.wsw.de/leistungen/jis-beratung/\">wsw.de/leistungen/jis-beratung</a> entlang des Komponenten-Modells nach Karl Kratz (Quelle: <strong>komponenten-modell_gesamt.pdf</strong>). Aufgeführt sind alle für eine Konversion relevanten Komponenten und ihre jeweilige Ausprägung auf der untersuchten Seite.</p><table><thead><tr><th>Komponente</th><th>Ausprägung auf der WSW JIS-Beratungs-Seite</th></tr></thead><tbody><tr><td>Logo</td><td>WSW Software im Header</td></tr><tr><td>Überschrift</td><td><strong>Just-in-Sequence (JIS)-Beratung</strong> mit Sub-Headline „Gebündelte Kompetenz für Ihren JIS-Erfolg\"</td></tr><tr><td>Bild</td><td>Keyvisual sowie Bebilderung der einzelnen Beratungsphasen-Module</td></tr><tr><td>Einleitungs-Text</td><td>Kontext für Zulieferer: Menge, Zeit, Ort und Reihenfolge exakt einhalten; interne Prozessoptimierung als Voraussetzung</td></tr><tr><td>Informations-Text</td><td>Was ist JIS, Abgrenzung zu Just-in-Time, größte Probleme intern und extern, FAQ-Abschnitt</td></tr><tr><td>Aufzählungs-Liste</td><td>Externe Faktoren (Materialknappheit, Supply-Chain-Störungen, Produktionsausfälle, Fachkräftemangel) und interne Probleme (EDI-Kommunikation, sequenzgerechte Produktion, Systemausfälle, fehlende Ressourcen)</td></tr><tr><td>Handlungsaufforderung</td><td>„Lassen Sie sich beraten!\", „Lernen Sie unsere Experten persönlich kennen\", „Terminanfrage\"</td></tr><tr><td>Konversion-Element</td><td>Terminanfrage-Formular für 60-minütiges Kennenlerngespräch</td></tr><tr><td>Referenzen</td><td>Case Eurofit/Radsystem Mosel (JIS-Serienbelieferung Reifen-Rad-Baugruppen), Kundenauszug der WSW</td></tr><tr><td>Vertrauensbildende Elemente</td><td>30+ Jahre JIS-Erfahrung, JIS Competence Center, ITIL-konformer Support, „Partner auf Augenhöhe\", technologieoffen mit und ohne SAP</td></tr><tr><td>Konditionen</td><td>Implizit über Leistungspakete von OEM-Ausschreibung über Strategieberatung, Planung, Softwareauswahl, Implementierung bis Betrieb und Update</td></tr><tr><td>AGB</td><td>Footer-Verlinkung</td></tr><tr><td>Social-Media-Elemente</td><td>Footer-Verlinkung</td></tr><tr><td>Impressum</td><td>Footer-Verlinkung</td></tr><tr><td>Datenschutz</td><td>Footer-Verlinkung</td></tr></tbody></table><h2>Beobachtungen</h2><ul><li>Alle für eine B2B-Beratungs-Landingpage typischen Pflicht-Komponenten sind vorhanden.</li><li>Stark ausgeprägt sind <strong>Informations-Text</strong>, <strong>vertrauensbildende Elemente</strong> und <strong>Referenzen</strong> – passend zum erklärungsbedürftigen, risikoreichen Produkt.</li><li>Die <strong>Handlungsaufforderung</strong> ist auf ein unverbindliches Erstgespräch fokussiert, nicht auf direkten Vertragsabschluss – konsistent mit dem langen B2B-Sales-Cycle.</li></ul>","created_at":"2026-05-21T15:30:29+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":26,"konversionen":80},{"id":124,"slug":"code/deployment-config/rules/deploy-007-backups-and-restore-tests","title":"DEPLOY_007_BACKUPS_AND_RESTORE_TESTS: Backups werden restore-getestet","meta_description":"DEPLOY_007_BACKUPS_AND_RESTORE_TESTS (must): Backups werden restore-getestet. Produktive Datenbanken MUESSEN Backup-Frequenz, Retention, Verschluesselung und regelmaessig getestete Wiederherstellung","content":"<h1>DEPLOY_007_BACKUPS_AND_RESTORE_TESTS: Backups werden restore-getestet</h1><p>Severity: <strong>must</strong>. Bereich: <a href=\"/code/deployment-config\">deployment-config</a>.</p><h2>Regel</h2><p>Produktive Datenbanken MUESSEN Backup-Frequenz, Retention, Verschluesselung und regelmaessig getestete Wiederherstellung dokumentieren.</p><h2>Reflection-Check</h2><pre><code>check:\n  reflect:\n    object: backup_policy</code></pre><h2>Evidence</h2><ul><li><strong>POSTGRES_BACKUP</strong>, PostgreSQL Documentation: Backup and Restore</li></ul><p><a href=\"/code/deployment-config/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:40:01+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":72,"konversionen":55},{"id":1196,"slug":"jis-ebenen","title":"JIS-Beratung – Dominante Perspektiven (Ebenen-Modell)","meta_description":"Anwendung des Ebenen-Modells auf das Thema Just-in-Sequence: dominante Perspektiven mit Leitfragen und Resonanzpunkten.","content":"<h1>JIS-Beratung – Dominante Perspektiven (Ebenen-Modell)</h1><p>Anwendung des <a href=\"https://karlkratz.de/ebenen-modell\">Ebenen-Modells nach Karl Kratz</a> auf das Thema Just-in-Sequence-Belieferung. Grundlage ist die öffentliche Darstellung auf <a href=\"https://www.wsw.de/leistungen/jis-beratung/\">wsw.de/leistungen/jis-beratung</a>. Aufgeführt sind die <strong>dominanten Perspektiven</strong>, jeweils mit Leitfrage und beobachteten Resonanzpunkten.</p><table><thead><tr><th>Ebene / Perspektive</th><th>Leitfrage</th><th>Resonanzpunkte aus der Quelle</th></tr></thead><tbody><tr><td>Strategisch-wettbewerblich</td><td>Wie sichert JIS-Kompetenz langfristig den Marktzugang zum OEM?</td><td>Liefertreue, Lieferantenbewertung, Risiko des Lieferantenwechsels</td></tr><tr><td>OEM- und Kunden-Perspektive</td><td>Welche Erwartungen hat der OEM an Menge, Zeit, Ort und Reihenfolge?</td><td>Montagereihenfolge am Band, minutengenaue Anlieferung, OEM-spezifische Sonderanforderungen</td></tr><tr><td>Prozess- und Logistik-Perspektive</td><td>Wie bilden wir Sequenzbelieferung intern reibungslos ab?</td><td>Sequenzgerechte Produktion, Monitoring, Streckenabwicklung, Abgrenzung zu Just-in-Time</td></tr><tr><td>Technologisch (SAP / IT)</td><td>Mit welcher Software setzen wir die Logik um?</td><td>SAP-JIT-Modul, User Exits und BADIs, EDI-Datenempfang, SAP- und Non-SAP-Pfade</td></tr><tr><td>Risiko- und Krisen-Perspektive</td><td>Was passiert beim Bandstillstand des Kunden?</td><td>Produktionsstillstand beim OEM, Reputationsverlust, Vertragsstrafen</td></tr><tr><td>Wirtschaftlich-finanziell</td><td>Was kosten Sonderfahrten, Zusatzschichten und externe Dienstleister?</td><td>Sonderfahrten, Zusatzschichten, externe Sequenzierer als teure Alternative</td></tr><tr><td>Organisation und Menschen</td><td>Wer trägt im Unternehmen die JIS-Last, mit welchen Ressourcen?</td><td>Supply-Chain-Manager als „Feuerwehr\", Fachkräftemangel, Schulungsbedarf</td></tr><tr><td>Supply-Chain / externe Faktoren</td><td>Wie reagieren wir auf Störungen jenseits des eigenen Werks?</td><td>Materialknappheit, Supply-Chain-Störungen, Produktionsausfälle vorgelagerter Stufen</td></tr><tr><td>Daten- und Informations-Perspektive</td><td>Welche Datenflüsse machen den Prozess transparent?</td><td>EDI-Empfang, Lieferavise, Feinabrufe, Monitoring-Dashboards</td></tr><tr><td>Service- und Betriebs-Perspektive</td><td>Wie bleibt die Lösung über Jahre stabil und konform?</td><td>ITIL-konformer Support, Wartung, Updates, langfristige Partnerschaft</td></tr><tr><td>Methodisch-Beratungs-Perspektive</td><td>In welcher Projektphase steigen wir ein?</td><td>OEM-Ausschreibung, Strategieberatung, Projektplanung, Softwareauswahl, Implementierung, Betrieb</td></tr></tbody></table><h2>Beobachtungen</h2><ul><li>Die Quelle adressiert vor allem <strong>Risiko</strong>, <strong>Wirtschaftlichkeit</strong> und <strong>Prozesskompetenz</strong> – emotional aufgeladene, harte Resonanzpunkte für Entscheider.</li><li>Die <strong>technologische Perspektive</strong> bleibt bewusst zweistufig (mit und ohne SAP) und damit anschlussfähig für unterschiedliche IT-Landschaften.</li><li>Eine Perspektive, die <strong>fehlt</strong> oder nur implizit auftaucht: Nachhaltigkeit (CO₂-Bilanz von Sonderfahrten) und die Sicht der Werker am Band – beides potenzielle Differenzierungs-Ebenen für Folgeinhalte.</li></ul>","created_at":"2026-05-21T15:30:48+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":61,"konversionen":99},{"id":131,"slug":"code/deployment-config/rules/deploy-014-rollback-with-data-compatibility","title":"DEPLOY_014_ROLLBACK_WITH_DATA_COMPATIBILITY: Rollback beachtet Datenkompatibilitaet","meta_description":"DEPLOY_014_ROLLBACK_WITH_DATA_COMPATIBILITY (must): Rollback beachtet Datenkompatibilitaet. Rollbacks MUESSEN mit Datenbankmigrationen, Feature Flags, Cache und laufenden Jobs kompatibel geplant werde","content":"<h1>DEPLOY_014_ROLLBACK_WITH_DATA_COMPATIBILITY: Rollback beachtet Datenkompatibilitaet</h1><p>Severity: <strong>must</strong>. Bereich: <a href=\"/code/deployment-config\">deployment-config</a>.</p><h2>Regel</h2><p>Rollbacks MUESSEN mit Datenbankmigrationen, Feature Flags, Cache und laufenden Jobs kompatibel geplant werden; reine Code-Rollbacks reichen bei Schemaaenderungen nicht aus.</p><h2>Reflection-Check</h2><pre><code>check:\n  reflect:\n    objects:\n    - deployment_step\n    - migration_deploy</code></pre><h2>Evidence</h2><ul><li><strong>POSTGRES_ALTER_TABLE</strong>, PostgreSQL Documentation: ALTER TABLE</li><li><strong>POSTGRES_BACKUP</strong>, PostgreSQL Documentation: Backup and Restore</li></ul><p><a href=\"/code/deployment-config/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:40:01+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":79,"konversionen":51},{"id":164,"slug":"code/http-api/rules/http-009-server-side-authz","title":"HTTP_009_SERVER_SIDE_AUTHZ: Autorisierung bleibt serverseitig","meta_description":"HTTP_009_SERVER_SIDE_AUTHZ (must): Autorisierung bleibt serverseitig. Jeder Endpunkt MUSS Zugriff, Tenant-Scope und Objektberechtigung serverseitig pruefen; ausgeblendete UI-Elemente ersetze","content":"<h1>HTTP_009_SERVER_SIDE_AUTHZ: Autorisierung bleibt serverseitig</h1><p>Severity: <strong>must</strong>. Bereich: <a href=\"/code/http-api\">http-api</a>.</p><h2>Regel</h2><p>Jeder Endpunkt MUSS Zugriff, Tenant-Scope und Objektberechtigung serverseitig pruefen; ausgeblendete UI-Elemente ersetzen niemals Autorisierung.</p><h2>Reflection-Check</h2><pre><code>check:\n  reflect:\n    fields:\n    - auth_required\n    - tenant_scope\n    object: endpoint</code></pre><h2>Evidence</h2><ul><li><strong>OWASP_API_TOP10</strong>, OWASP API Security Top 10 2023</li></ul><p><a href=\"/code/http-api/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:40:02+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":94,"konversionen":54},{"id":1197,"slug":"jis-marktbegleiter","title":"JIS – Marktbegleiter mit Detailseiten","meta_description":"Fünf konkrete Marktbegleiter im Just-in-Sequence-Umfeld mit ihren JIS-spezifischen Detailseiten.","content":"<h1>JIS – Marktbegleiter mit Detailseiten</h1><p>Sieben konkrete Marktbegleiter und thematisch verwandte Anbieter im Just-in-Sequence-Umfeld. Jeder Eintrag verlinkt nicht auf die generische Startseite, sondern auf die <strong>JIS-spezifische Detail-, Produkt- oder Lexikon-Seite</strong>. Alle URLs wurden gegen den Live-Status geprüft (HTTP 200). Sprachvarianten der URLs sind bevorzugt deutsch.</p><table><thead><tr><th>Marktbegleiter</th><th>Sitz</th><th>Schwerpunkt im JIS-Umfeld</th><th>JIS-Detailseite</th></tr></thead><tbody><tr><td><strong>amotIQ automotive GmbH</strong></td><td>Heilbronn</td><td>JIT/JIS-Produkt <strong>JITplant</strong>: modulares Sequenzsystem für Montagesteuerung in Automotive und Manufacturing</td><td><a href=\"https://www.amotiq.de/kompetenzen-leistungen/jit-jis/\">amotiq.de/kompetenzen-leistungen/jit-jis/</a></td></tr><tr><td><strong>nemetris GmbH</strong></td><td>Bietigheim-Bissingen</td><td>JIS Software Solutions für die Automobilbranche; Produktübersicht über alle JIS-Varianten (Produktion, Montage, Logistik, SaaS); 20+ Jahre JIS-Erfahrung</td><td><a href=\"https://nemetris.com/de/jis-software-loesungen/\">nemetris.com/de/jis-software-loesungen/</a></td></tr><tr><td><strong>JITpro GmbH</strong></td><td>Leipzig</td><td>Individualprogrammierung von Lager- und Dispositionssoftware für JIS-Zulieferer; wickelt rund 5.000 Modulmontagen pro Tag ab</td><td><a href=\"https://jitpro.de/leistungen/automotive\">jitpro.de/leistungen/automotive</a></td></tr><tr><td><strong>Prisma Software Engineering GmbH</strong></td><td>Papenburg</td><td>Eigenes <strong>JIS-System</strong> mit EDI-Schnittstellen zu OEMs zur Organisation und Steuerung der Produktion</td><td><a href=\"https://www.prisma-software.de/?menu=jis-system\">prisma-software.de/?menu=jis-system</a></td></tr><tr><td><strong>Aimtec a.s.</strong></td><td>Pilsen (CZ)</td><td>JIS/JIT-Plattform mit automatischer EDI-Nachrichtenverarbeitung, Sequenzierung, Versand und Abrechnungskontrolle</td><td><a href=\"https://www.aimtecglobal.com/de/just-in-sequence\">aimtecglobal.com/de/just-in-sequence</a></td></tr><tr><td><strong>LIS AG</strong></td><td>Greven</td><td>Transportmanagement-Software; JIS-Lexikoneintrag mit Begriffsklärung, Herausforderungen und Anbieterperspektive</td><td><a href=\"https://www.lis.eu/lexikon/just-in-sequence/\">lis.eu/lexikon/just-in-sequence/</a></td></tr><tr><td><strong>Symestic GmbH</strong></td><td>Bremen</td><td>MES-Anbieter; thematisiert JIS als Anwendungsfall: Unterschied zu JIT, EDI-Ablauf vom OEM-Abruf bis zur Linie und IT-Anforderungen</td><td><a href=\"https://www.symestic.com/de-de/was-ist/jis\">symestic.com/de-de/was-ist/jis</a></td></tr></tbody></table><h2>Letzte Änderungen</h2><ul><li><strong>amotIQ</strong>: URL umgestellt von der EN-Variante auf <a href=\"https://www.amotiq.de/kompetenzen-leistungen/jit-jis/\">amotiq.de/kompetenzen-leistungen/jit-jis/</a> (DE).</li><li><strong>nemetris</strong>: URL umgestellt von der Logistik-Detailseite auf die übergeordnete Produktübersicht <a href=\"https://nemetris.com/de/jis-software-loesungen/\">nemetris.com/de/jis-software-loesungen/</a>; Schwerpunkt entsprechend von „Logistik-Variante\" auf „JIS Software Solutions Übersicht\" angepasst.</li><li><strong>Aimtec</strong>: bereits auf <a href=\"https://www.aimtecglobal.com/de/just-in-sequence\">aimtecglobal.com/de/just-in-sequence</a> – keine Änderung.</li></ul><h2>Hinweis zur Vergleichbarkeit</h2><p><strong>amotIQ</strong>, <strong>nemetris</strong>, <strong>Prisma</strong> und <strong>JITpro</strong> sind direkte Wettbewerber von WSW Software mit eigenem JIS-Produkt oder Individualentwicklung. <strong>Aimtec</strong> deckt eine breitere JIT/JIS-Plattform inklusive EDI-Stack ab. <strong>LIS</strong> und <strong>Symestic</strong> sind nicht im engen Sinne JIS-Beratungswettbewerber, sondern angrenzende Anbieter (Transportmanagement bzw. MES), deren öffentliche Lexikon-/Themenseiten den JIS-Diskurs prägen.</p>","created_at":"2026-05-21T15:38:39+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":56,"konversionen":22},{"id":1201,"slug":"marktbegleiter-komponenten","title":"JIS-Marktbegleiter + WSW – Komponenten-Matrix (0/1)","meta_description":"Binäre Komponenten-Analyse von 5 JIS-Marktbegleitern: Vereinigungsmenge aller gefundenen Komponenten als Zeilen, Anbieter-URLs als Spalten, Zellwerte 0/1, Zeilen- und Spaltensummen.","content":"<h1>JIS-Marktbegleiter + WSW – Komponenten-Matrix (0/1)</h1><p>Binäre Komponenten-Analyse von fünf Just-in-Sequence-Marktbegleitern, ergänzt um <strong>WSW Software</strong> als Referenz-Anker. <strong>Spalten</strong> = Anbieter-Detailseiten (5 Marktbegleiter + WSW als 6. Spalte). <strong>Zeilen</strong> = Vereinigungsmenge aller auf mindestens einer der 6 Seiten tatsächlich identifizierten Komponenten (datengetrieben). <strong>Zellwerte</strong>: <code>1</code> = vorhanden, <code>0</code> = nicht vorhanden. <strong>Ausgeschlossen</strong>: LIS und Symestic (Lexikon-Seiten, keine Konversion) sowie AGB / Impressum / Datenschutz (Footer-Pflicht, analytisch irrelevant).</p><h2>Matrix</h2><table><thead><tr><th>Komponente</th><th><a href=\"https://www.amotiq.de/kompetenzen-leistungen/jit-jis/\">amotIQ</a></th><th><a href=\"https://nemetris.com/de/jis-software-loesungen/\">nemetris</a></th><th><a href=\"https://jitpro.de/leistungen/automotive\">JITpro</a></th><th><a href=\"https://www.prisma-software.de/?menu=jis-system\">Prisma</a></th><th><a href=\"https://www.aimtecglobal.com/de/just-in-sequence\">Aimtec</a></th><th><a href=\"https://www.wsw.de/leistungen/jis-beratung/\">WSW</a></th><th>Σ_row</th></tr></thead><tbody><tr><td>Logo (Header-Marke)</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td><strong>6</strong></td></tr><tr><td>Hauptüberschrift</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td><strong>6</strong></td></tr><tr><td>Einleitungs-Text</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td><strong>6</strong></td></tr><tr><td>Informations-Text</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td><strong>6</strong></td></tr><tr><td>Aufzählungs-Liste</td><td>1</td><td>0</td><td>1</td><td>1</td><td>1</td><td>1</td><td><strong>5</strong></td></tr><tr><td>Sub-Headline / Claim</td><td>1</td><td>0</td><td>0</td><td>1</td><td>1</td><td>1</td><td><strong>4</strong></td></tr><tr><td>Handlungsaufforderung (textueller CTA)</td><td>1</td><td>1</td><td>0</td><td>1</td><td>0</td><td>1</td><td><strong>4</strong></td></tr><tr><td>Vertrauensbildende Elemente (Erfahrung / Kennzahlen)</td><td>1</td><td>0</td><td>1</td><td>0</td><td>1</td><td>1</td><td><strong>4</strong></td></tr><tr><td>Konversion-Element (Kontakt-Link / -Formular)</td><td>0</td><td>1</td><td>0</td><td>1</td><td>0</td><td>1</td><td><strong>3</strong></td></tr><tr><td>Referenzen / Kundenliste</td><td>0</td><td>0</td><td>0</td><td>1</td><td>1</td><td>1</td><td><strong>3</strong></td></tr><tr><td>Fallstudie / Case-Study</td><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td><td>1</td><td><strong>2</strong></td></tr><tr><td>24/7-Support-Hinweis</td><td>1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td><strong>1</strong></td></tr><tr><td><strong>Σ_col</strong></td><td><strong>9</strong></td><td><strong>6</strong></td><td><strong>6</strong></td><td><strong>9</strong></td><td><strong>9</strong></td><td><strong>11</strong></td><td><strong>Σ_total = 50</strong></td></tr></tbody></table><h2>Konsistenzcheck</h2><p>Σ aller Zeilensummen = 6+6+6+6+5+4+4+4+3+3+2+1 = <strong>50</strong>. Σ aller Spaltensummen = 9+6+6+9+9+11 = <strong>50</strong>. Beide Wege liefern denselben Σ_total → Matrix konsistent.</p><h2>Operationale Belege je Zeile (inkl. WSW)</h2><ul><li><strong>Logo / Hauptüberschrift / Einleitungs-Text / Informations-Text</strong>: Pflicht-Bausteine, auf allen 6 Seiten klar identifizierbar.</li><li><strong>Aufzählungs-Liste</strong>: amotIQ („Vorteile auf einen Blick\"), JITpro (Lösungs-Liste), Prisma (Funktionsübersicht), Aimtec (Feature-Collapses), WSW (Externe Faktoren / Interne Probleme).</li><li><strong>Sub-Headline / Claim</strong>: amotIQ („Maximale Effizienz – null Lagerbestand\"), Prisma („Software zur Just-in-Sequence Produktion und Belieferung\"), Aimtec („Steuern Sie Versand, Palettierung und Montage…\"), WSW („Gebündelte Kompetenz für Ihren JIS-Erfolg\").</li><li><strong>Handlungsaufforderung</strong>: amotIQ („Was ist JIT für Sie? Finden wir es gemeinsam heraus\"), nemetris („Vereinbaren Sie einen Expertentermin\"), Prisma („Vereinbaren Sie einen Termin\"), WSW („Lassen Sie sich beraten!\" / „Terminanfrage\").</li><li><strong>Vertrauensbildende Elemente</strong>: amotIQ („seit über 20 Jahren\"), JITpro („seit mehr als 10 Jahren\", „täglich 5.000 Modulmontagen\"), Aimtec (OEM-Markenliste), WSW („30+ Jahre Erfahrung\", „JIS Competence Center\", „ITIL-konformer Support\").</li><li><strong>Konversion-Element</strong>: nemetris (Expertentermin-Buchung), Prisma („Klicken Sie hier zur Kontaktaufnahme!\"), WSW (Terminanfrage-Formular für 60-Min-Kennenlerngespräch).</li><li><strong>Referenzen / Kundenliste</strong>: Prisma („Unsere Referenzen\"-Block), Aimtec („Unsere Kunden\"-OEM-Block), WSW („Ein Auszug unserer Kunden\").</li><li><strong>Fallstudie</strong>: Aimtec (ŠKODA-CEDL-Case), WSW (Eurofit / Radsystem Mosel – JIS-Serienbelieferung Reifen-Rad-Baugruppen).</li><li><strong>24/7-Support-Hinweis</strong>: nur amotIQ („Hotline International 24/7 Support\"). WSW erwähnt zwar ITIL-konformen Support, aber kein explizites 24/7.</li></ul><h2>Lesarten</h2><ul><li><strong>Reichste Komponenten-Abdeckung</strong>: <strong>WSW mit 11 von 12</strong> – klar vor allen Marktbegleitern. Einzige fehlende Komponente: expliziter 24/7-Support-Hinweis.</li><li><strong>Verfolgerfeld</strong>: amotIQ, Prisma und Aimtec gleichauf bei 9 von 12.</li><li><strong>Schmalste Seiten</strong>: nemetris und JITpro mit 6 von 12 – beide stark text- und produkt-orientiert, ohne Trust-Block, Referenzen oder Fallstudie.</li><li><strong>Universelle Pflicht-Komponenten</strong> (Σ_row = 6): Logo, Hauptüberschrift, Einleitungs-Text, Informations-Text – auf jeder der 6 Seiten vorhanden.</li><li><strong>Differenzierende Komponenten</strong> (Σ_row ≤ 2): Fallstudie und 24/7-Support – die beiden echten Unterscheidungsmerkmale, an denen sich Anbieter klar voneinander absetzen.</li><li><strong>WSW-Lücke</strong>: Ein expliziter 24/7-Support-Hinweis fehlt auf der WSW-JIS-Beratungs-Seite – im Vergleich zu amotIQ ein potenzieller Trust-Hebel, wenn WSW einen entsprechenden Service tatsächlich anbietet.</li><li><strong>Methodische Grenze</strong>: Erhebung erfolgt auf statisch gescraptem Markdown. JS-spät geladene Komponenten (Chat-Widget, Live-Trust-Banner, Hero-Bilder ohne <code>alt</code>-Text) können fälschlich als 0 gezählt sein.</li></ul>","created_at":"2026-05-21T15:54:08+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":89,"konversionen":28},{"id":1203,"slug":"marktbegleiter-ebenen","title":"JIS-Marktbegleiter + WSW – Ebenen-Matrix (0/1)","meta_description":"Binäre Ebenen-Analyse von 5 JIS-Marktbegleitern plus WSW: Vereinigungsmenge aller auf mindestens einer Seite eigenständig adressierten Perspektiven als Zeilen, Anbieter als Spalten.","content":"<h1>JIS-Marktbegleiter + WSW – Ebenen-Matrix (0/1)</h1><p>Binäre Ebenen-Analyse nach dem <a href=\"https://karlkratz.de/ebenen-modell\">Ebenen-Modell</a> von fünf Just-in-Sequence-Marktbegleitern plus <strong>WSW Software</strong> als Referenz-Anker. <strong>Spalten</strong> = Anbieter-Detailseiten (5 Marktbegleiter + WSW). <strong>Zeilen</strong> = datengetriebene Vereinigungsmenge aller Ebenen, die auf mindestens einer der 6 Seiten <strong>mit eigenem Abschnitt oder mehreren Sätzen</strong> explizit adressiert werden (Sharp-Kriterium). <strong>Zellwerte</strong>: <code>1</code> = Ebene auf der Seite eigenständig adressiert, <code>0</code> = nicht oder nur beiläufig. <strong>Ausgeschlossen</strong>: LIS und Symestic (Lexikon-Seiten, keine Anbieter-Frame).</p><h2>Matrix</h2><table><thead><tr><th>Ebene / Perspektive</th><th><a href=\"https://www.amotiq.de/kompetenzen-leistungen/jit-jis/\">amotIQ</a></th><th><a href=\"https://nemetris.com/de/jis-software-loesungen/\">nemetris</a></th><th><a href=\"https://jitpro.de/leistungen/automotive\">JITpro</a></th><th><a href=\"https://www.prisma-software.de/?menu=jis-system\">Prisma</a></th><th><a href=\"https://www.aimtecglobal.com/de/just-in-sequence\">Aimtec</a></th><th><a href=\"https://www.wsw.de/leistungen/jis-beratung/\">WSW</a></th><th>Σ_row</th></tr></thead><tbody><tr><td>Technologisch / Produkt</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td><strong>6</strong></td></tr><tr><td>Prozess- und Logistik-Perspektive</td><td>1</td><td>0</td><td>1</td><td>1</td><td>1</td><td>1</td><td><strong>5</strong></td></tr><tr><td>Daten- und Informations-Perspektive (EDI / Schnittstellen)</td><td>0</td><td>0</td><td>0</td><td>1</td><td>1</td><td>1</td><td><strong>3</strong></td></tr><tr><td>Risiko- und Kontroll-Perspektive (Sicherheits-/Audit-Mechanismen)</td><td>0</td><td>0</td><td>0</td><td>1</td><td>1</td><td>1</td><td><strong>3</strong></td></tr><tr><td>OEM- und Kunden-Perspektive</td><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td><td>1</td><td><strong>2</strong></td></tr><tr><td>Service- und Betriebs-Perspektive (Support / Wartung)</td><td>1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td><td><strong>2</strong></td></tr><tr><td>Wirtschaftlich-finanzielle Perspektive</td><td>1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td><strong>1</strong></td></tr><tr><td>Methodisch-Beratungs-Perspektive (Phasenmodell)</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td><td><strong>1</strong></td></tr><tr><td>Strategisch-wettbewerbliche Perspektive</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td><td><strong>1</strong></td></tr><tr><td>Supply-Chain / externe Faktoren</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td><td><strong>1</strong></td></tr><tr><td>Organisation und Menschen</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td><td><strong>1</strong></td></tr><tr><td>Branchen- / Marktumfeld-Perspektive</td><td>0</td><td>0</td><td>1</td><td>0</td><td>0</td><td>0</td><td><strong>1</strong></td></tr><tr><td>Integrations- / Vernetzungs-Perspektive (SAP / Drittsysteme)</td><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td><td>0</td><td><strong>1</strong></td></tr><tr><td><strong>Σ_col</strong></td><td><strong>4</strong></td><td><strong>1</strong></td><td><strong>3</strong></td><td><strong>4</strong></td><td><strong>6</strong></td><td><strong>10</strong></td><td><strong>Σ_total = 28</strong></td></tr></tbody></table><h2>Konsistenzcheck</h2><p>Σ aller Zeilensummen = 6+5+3+3+2+2+1+1+1+1+1+1+1 = <strong>28</strong>. Σ aller Spaltensummen = 4+1+3+4+6+10 = <strong>28</strong>. Beide Wege liefern denselben Σ_total → Matrix konsistent.</p><h2>Operationale Belege je Zeile</h2><ul><li><strong>Technologisch / Produkt</strong>: alle 6 Anbieter beschreiben ihr eigenes JIS-Software-Angebot mit eigenem Abschnitt (amotIQ <strong>JITplant</strong>, nemetris <strong>JIS Software Solutions</strong>, JITpro Warehouse-/Dispositions-Software, Prisma <strong>JIS-System</strong>, Aimtec <strong>DCIx</strong>, WSW SAP-JIT-Modul mit User Exits / BADIs).</li><li><strong>Prozess- und Logistik-Perspektive</strong>: 5 von 6 Seiten widmen Sequenz, Reihenfolge, Belieferung einen eigenen Block. nemetris bleibt rein produktorientiert.</li><li><strong>Daten- und Informations-Perspektive</strong>: Prisma (EDI-Schnittstelle, Sequenzprüfung), Aimtec (EDI-Formate EDIFACT / ODETTE / VDA / ANSI), WSW (Experten für Datenaustausch).</li><li><strong>Risiko- und Kontroll-Perspektive</strong>: Prisma (Sicherheits- und Überwachungsfunktionen, Reichweitenberechnung), Aimtec (Sicherungs- und Kontrollmechanismen, Kunden-Audit), WSW („Warum ist JIS eine Herausforderung? Produktionsstillstand, Lieferantenbewertung\").</li><li><strong>OEM- und Kunden-Perspektive</strong>: nur Aimtec (vollständige OEM-Markenliste) und WSW („Ihre Kunden erwarten…\", „OEM-Ausschreibung\") adressieren das explizit.</li><li><strong>Service- und Betriebs-Perspektive</strong>: amotIQ („Hotline International 24/7 Support\" mit eigenem Block), WSW („ITIL-konformer Support\", Betrieb-Wartung-Update-Leistungsblock).</li><li><strong>Wirtschaftlich-finanzielle Perspektive</strong>: nur amotIQ („Maximale Effizienz – null Lagerbestand\", Vorteile-Block mit Kapitalbindung und Lagerhaltung).</li><li><strong>Methodisch-Beratungs-Perspektive</strong>: nur WSW („JIS-Beratung in jeder Phase\" mit Phasenmodell OEM-Ausschreibung → Strategie → Planung → Software → Implementierung → Betrieb).</li><li><strong>Strategisch-wettbewerbliche Perspektive</strong>: nur WSW („Darum profitieren Sie… Wettbewerbsfähigkeit, Liefertreue, Lieferantenbewertung\").</li><li><strong>Supply-Chain / externe Faktoren</strong>: nur WSW (Externe Faktoren-Block: Materialknappheit, Supply-Chain-Störungen, Produktionsausfälle, Fachkräftemangel).</li><li><strong>Organisation und Menschen</strong>: nur WSW („Supply Chain Manager und Disponenten… Feuerwehr spielen\").</li><li><strong>Branchen- / Marktumfeld-Perspektive</strong>: nur JITpro („Die Automobilindustrie gehört zu den volkswirtschaftlich bedeutendsten Industriezweigen…\" als Einleitungs-Block).</li><li><strong>Integrations- / Vernetzungs-Perspektive</strong>: nur Aimtec („Vernetzen Sie JIS/JIT mit weiteren Systemen und Technologien\" inkl. SAP-Lösung, Eigenständige Lösung, Zebra-Geräte als eigener Abschnitt).</li></ul><h2>Lesarten</h2><ul><li><strong>Reichste Ebenen-Abdeckung</strong>: <strong>WSW mit 10 von 13 Ebenen</strong> – klare Beratungs-Logik, die viele Stakeholder-Frames bespielt (Strategie, Risiko, Organisation, Supply-Chain, Methodik).</li><li><strong>Verfolger</strong>: Aimtec (6) – Tech-Produkt mit OEM-, Daten-, Risiko- und Integrations-Fokus. amotIQ und Prisma gleichauf bei 4, mit komplementärem Profil (amotIQ: Effizienz + Service, Prisma: Daten + Risiko).</li><li><strong>Schmalste Sicht</strong>: nemetris mit nur 1 Ebene (Technologisch / Produkt) – die Seite bleibt fast vollständig auf Produktebene.</li><li><strong>Universelle Ebene</strong> (Σ_row = 6): nur <strong>Technologisch / Produkt</strong> – jeder Anbieter führt sich primär über sein Produkt ein.</li><li><strong>WSW-exklusive Ebenen</strong> (nur WSW = 1): Methodisch-Beratung, Strategisch-wettbewerblich, Supply-Chain, Organisation und Menschen. Das ist die strukturelle Differenz zwischen einer <strong>Beratungs-Landingpage</strong> und einer <strong>Produkt-Landingpage</strong>.</li><li><strong>Branchen-Ebene</strong>: nur JITpro öffnet mit dem volkswirtschaftlichen Rahmen – einziger Anbieter, der seine Seite vom Marktumfeld her aufzieht statt vom Produkt.</li><li><strong>Methodische Grenze</strong>: Statisch gescraptes Markdown, Sharp-Kriterium (eigener Abschnitt). Ebenen, die nur beiläufig im Text vorkommen, werden bewusst als 0 gezählt – das schärft den Vergleich, kann aber bei sehr kompakt formulierten Seiten (nemetris) das Bild zu Lasten der Seite verzerren.</li></ul><h2>Detail-Analyse der drei Exklusiv-Frames</h2><h3>JITpro-exklusiv – Branchen- / Marktumfeld-Perspektive</h3><p><strong>Beleg</strong>: „Die Automobilindustrie gehört zu den volkswirtschaftlich bedeutendsten Industriezweigen in Deutschland. Zu ihrer Erfolgsstrategie in Bezug auf Preisbereitschaft bei den Kunden und Deckungsbeiträge zählt maßgeblich die Abstimmung der Fahrzeuge auf die Bedürfnisse der Kunden.\" sowie „Eine der bedeutendsten Entwicklungen im Automotive-Bereich ist die zunehmende Einbindung softwarebasierter Lösungen.\"</p><p><strong>Mechanik</strong>: JITpro öffnet die Seite nicht mit dem eigenen Produkt, sondern mit der makroökonomischen Bedeutung der Branche. Die eigene Software wird damit als Beitrag zu einem volkswirtschaftlich relevanten Sektor positioniert – nicht als Werkzeug unter vielen.</p><p><strong>Resonanz</strong>: Adressiert Entscheider, die ihre Tätigkeit über die Bedeutung der Branche legitimieren (Geschäftsführung, Vorstand, Standortleitung in Zuliefererbetrieben). Das Software-Investment wird Teil eines größeren Narrativs („Wir tragen die deutsche Automobilindustrie mit\").</p><p><strong>Wirkung</strong>: Status-Aufladung statt Funktions-Argumentation. Wer mit JITpro arbeitet, arbeitet an etwas Bedeutendem – die Software wird emotional aufgewertet, bevor sie überhaupt beschrieben wird.</p><p><strong>Lücke bei den anderen</strong>: Alle übrigen Anbieter starten mit „Was kann das Produkt?\" oder „Was ist JIS?\". Niemand verankert das Thema im Bedeutungsraum der Zielbranche.</p><h3>Aimtec-exklusiv – Integrations- / Vernetzungs-Perspektive</h3><p><strong>Beleg</strong>: Eigener H2-Block „Vernetzen Sie JIS/JIT mit weiteren Systemen und Technologien\" mit dem expliziten Satz „Eine umfassende Nutzung aller Möglichkeiten der JIS/JIT-Lösung wird erst durch die Vernetzung mit einem EDI-System, Informations- und Steuerungssystemen sowie technologischen Anlagen ermöglicht.\" Darunter zwei klar getrennte Architektur-Pfade: <strong>SAP-Lösung</strong> („JIS/JIT im System SAP – Lösung unter Nutzung des vorhandenen SAP-Systems\") und <strong>eigenständige Lösung</strong> („Aimtec DCIx\"). Plus konkreter Hardware-Block „Erweitern Sie Ihre JIS/JIT-Lösung um Zebra-Geräte\".</p><p><strong>Mechanik</strong>: Aimtec nimmt den Architektur-Vorbehalt von IT-Entscheidern direkt vorweg. Statt das Produkt isoliert zu beschreiben, wird es als integrationsfähiger Baustein in der bestehenden IT- und Hardware-Landschaft gezeigt. Die binäre Wahl SAP-eingebettet vs. standalone räumt die größte Architektur-Sorge im SAP-dominierten Zuliefer-Umfeld aus.</p><p><strong>Resonanz</strong>: Adressiert IT-Architekten, CIOs und SAP-Verantwortliche, die wissen, dass JIS-Insellösungen langfristig scheitern. Auch Logistik-Leiter, die die Hardware-Realität (Drucker, Scanner, RF-Geräte) im Blick haben – Zebra ist als Marke konkret und unmittelbar erkennbar.</p><p><strong>Wirkung</strong>: Senkt Risiko-Wahrnehmung („passt das in unsere IT?\") und erweitert die Käufer-Persona vom Logistik-Verantwortlichen auf das IT-Buying-Center.</p><p><strong>Lücke bei den anderen</strong>: WSW erwähnt zwar „technologie­unabhängig (mit oder ohne SAP)\" in einem Service-Punkt, aber ohne eigenen Architektur-Block. Bei amotIQ, nemetris, JITpro und Prisma fehlt das Integrations-Narrativ ganz – sie überlassen die Architektur-Frage dem Erstgespräch.</p><h3>amotIQ-exklusiv – Wirtschaftlich-finanzielle Perspektive</h3><p><strong>Beleg</strong>: Sub-Headline „Maximale Effizienz – null Lagerbestand.\" Plus Vorteilsblock mit fünf wirtschaftlich aufgeladenen Bullets: „Reihengenau synchronisierte Serienfertigung; Ideal für hochwertige Bauteile mit kurzen Lieferzeiten; <strong>Minimale Lagerhaltung beim OEM</strong>; <strong>Geringere Kapitalbindung</strong>; Weniger Fehler durch klar strukturierte Prozesse\".</p><p><strong>Mechanik</strong>: amotIQ übersetzt JIS-Funktion in betriebswirtschaftliche Wirkung. „Kapitalbindung\" und „Lagerhaltung\" sind Buchhaltungs- und Bilanz-Begriffe – sie aktivieren ein anderes Hirn als „Sequenzgenauigkeit\" oder „EDI\". JIS wird zum Bilanz-Hebel.</p><p><strong>Resonanz</strong>: Adressiert CFOs, kaufmännische Leiter, Einkauf, Geschäftsführung – Rollen, die JIS sonst als reines Logistik-Thema delegieren würden. Es macht JIS zum Investitions-Thema mit erwartbarer Rendite, nicht zum Prozesskosten-Thema.</p><p><strong>Wirkung</strong>: Erweitert das Buying-Center um die kaufmännische Seite und erhöht die wahrgenommene Priorität – ein Produkt, das Kapital freisetzt, hat im Budget-Wettbewerb eine andere Position als eines, das „Prozesse verbessert\".</p><p><strong>Lücke bei den anderen</strong>: WSW operiert stark mit <strong>Risiko-Framing</strong> (Bandstillstand, Lieferantenbewertung, Sonderfahrten). Das ist Verlust­vermeidung. Es fehlt die <strong>Gewinn-Argumentation</strong> – sichtbare ROI-Treiber wie Bestandsreduktion oder Kapitalfreisetzung. Bei Prisma, nemetris, JITpro und Aimtec ebenfalls nicht vorhanden.</p><h2>Was kann WSW daraus ableiten?</h2><p>WSW dominiert die Matrix mit 10 von 13 Ebenen – die strukturelle Beratungs-Signatur (Methodik, Strategie, Supply-Chain, Organisation) ist klar und differenzierend. Die drei Lücken sind die drei Exklusiv-Frames der Wettbewerber. Sie zu schließen, ohne die Beratungs-Klammer zu verwässern, ergibt drei konkrete, gezielte Hebel:</p><h3>Hebel 1 – Branchen-/Marktumfeld-Block ganz oben (von JITpro lernen)</h3><ul><li><strong>Was hinzufügen</strong>: Ein kurzer Einleitungs-Block <strong>vor</strong> dem Block „Was ist JIS?\", der JIS als Rückgrat der deutschen Automobil-Lieferkette positioniert (Wertschöpfungsbeitrag, Anteil an Exporten, Bedeutung der Zulieferindustrie für die Standortqualität).</li><li><strong>Effekt</strong>: Hebt die Entscheider-Resonanz aus dem Logistik-Operativen ins Strategisch-Volkswirtschaftliche und legitimiert die Investition als Beitrag zu einem bedeutenden Sektor.</li><li><strong>Risiko</strong>: Floskel-Gefahr. Nur sinnvoll mit einer harten Zahl, einer pointierten These oder einem klaren Standpunkt – nicht als Lehrbuch-Absatz.</li></ul><h3>Hebel 2 – Architektur-/Integrations-Block einführen (von Aimtec lernen)</h3><ul><li><strong>Was hinzufügen</strong>: Eigener Block „So fügt sich JIS in Ihre IT-Landschaft\" mit klarem Bekenntnis zu beiden Pfaden – <strong>SAP-eingebettet</strong> (JIT-Modul, User Exits / BADIs, S/4HANA-fähig) und <strong>Non-SAP-Anbindung</strong> (EDI-Provider, MES, WMS, RF-Hardware). Konkrete Partner-/Hersteller-Nennungen erhöhen Glaubwürdigkeit.</li><li><strong>Effekt</strong>: Erweitert das Buying-Center um IT-Architekten / CIO und senkt deren Architektur-Vorbehalt. Stellt WSW als <strong>integrationsfähigen Partner</strong> dar, nicht als Berater, der die IT-Frage ans Erstgespräch delegiert.</li><li><strong>Risiko</strong>: Nähe zu Software-Anbietern. Sauber abgrenzen: WSW <strong>begleitet</strong> die Integration, baut nicht das Produkt selbst – aber zeigt, dass die Beratung architektur-tauglich ist.</li></ul><h3>Hebel 3 – Business-Case-Block mit harten Zahlen (von amotIQ lernen)</h3><ul><li><strong>Was hinzufügen</strong>: Eigener Block „Was JIS-Optimierung wirtschaftlich bewegt\" mit konkreten Treibern: <strong>Bestandsreduktion</strong>, <strong>Kapitalbindung</strong>, <strong>Sonderfracht-/Eskalationskosten</strong>, <strong>Liefertreue → Lieferantenbewertung → Umsatzsicherung</strong>. Idealerweise gestützt durch Kennzahlen aus dem <strong>Eurofit/Radsystem-Mosel-Case</strong> oder weiteren Projekten.</li><li><strong>Effekt</strong>: Erweitert das Buying-Center um CFO / kaufmännische Leitung. Macht aus der bisherigen <strong>Verlustvermeidungs-Argumentation</strong> (Risiko-Frame) eine <strong>Renditen-Argumentation</strong>. JIS-Beratung wandert vom Kostenstellen-Thema ins Investitions-Thema.</li><li><strong>Risiko</strong>: Zahlen müssen belastbar sein und sich auf konkrete Cases stützen. Sonst Marketing-Inflation.</li></ul><h3>Synthese</h3><p>Mit diesen drei Hebeln wäre WSW <strong>auf allen 13 Ebenen vertreten</strong> – ohne die bestehende Beratungs-Klammer zu verlieren, sondern indem die Beratungslogik in drei zusätzliche Stakeholder-Welten erweitert wird: Strategie/Branche (Geschäftsführung), Architektur (CIO/IT), Wirtschaftlichkeit (CFO/Einkauf). Die heutige Stärke (Methodik, Strategie, Risiko, Organisation, Supply-Chain) bleibt unangetastet; die Lücken zu den drei Tech-/Produkt-Anbietern werden geschlossen, indem die Beratung explizit jene Frames bedient, die heute nur über das Produkt erzählt werden.</p><p><strong>Reihenfolge der Umsetzung</strong>: Hebel 3 (Business-Case) zuerst – größte Buying-Center-Wirkung bei geringstem inhaltlichen Risiko, weil eigene Cases bereits existieren. Dann Hebel 2 (Architektur) – stärkster Konkurrenz-Differenzierer im B2B-IT-Vergleich. Hebel 1 (Branche) zuletzt – wirkt nur, wenn er pointiert genug ist, nicht als Lehrbuch-Einleitung.</p>","created_at":"2026-05-21T16:08:10+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":62,"konversionen":81},{"id":251,"slug":"code/performance/rules/perf-002-core-web-vitals-targets","title":"PERF_002_CORE_WEB_VITALS_TARGETS: Core Web Vitals sind Zielmetriken","meta_description":"PERF_002_CORE_WEB_VITALS_TARGETS (should): Core Web Vitals sind Zielmetriken. Nutzerrelevante Seiten SOLLTEN LCP, INP und CLS messen und Regressionen gegen definierte Schwellen verhindern.","content":"<h1>PERF_002_CORE_WEB_VITALS_TARGETS: Core Web Vitals sind Zielmetriken</h1><p>Severity: <strong>should</strong>. Bereich: <a href=\"/code/performance\">performance</a>.</p><h2>Regel</h2><p>Nutzerrelevante Seiten SOLLTEN LCP, INP und CLS messen und Regressionen gegen definierte Schwellen verhindern.</p><h2>Reflection-Check</h2><pre><code>check:\n  reflect:\n    fields:\n    - target_lcp_ms\n    - target_inp_ms\n    - target_cls\n    object: route_budget</code></pre><h2>Evidence</h2><ul><li><strong>WEB_VITALS</strong>, Web Vitals</li></ul><p><a href=\"/code/performance/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:40:04+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":34,"konversionen":69},{"id":1206,"slug":"wsw-branche","title":"JIS-Beratung für die deutsche Automobil-Zulieferindustrie","meta_description":"Über 30 Jahre JIS-Erfahrung mit deutschen und internationalen OEMs. Tier-1- und Tier-2-Zulieferer, Modul-Lieferanten und Logistikdienstleister – WSW Software kennt die Branchen-Verantwortung.","content":"<h1>JIS-Beratung für die deutsche Automobil-Zulieferindustrie</h1><p><strong>Wenn das Band beim OEM stillsteht, ist Ihr Geschäft in Gefahr. Wir kennen diese Verantwortung seit über 30 Jahren.</strong></p><h2>Warum Branchen-Erfahrung in JIS-Projekten alles entscheidet</h2><p>Die deutsche Automobil-Zulieferindustrie ist das Rückgrat eines der wertvollsten Wirtschaftszweige Europas: hunderttausende Arbeitsplätze, dreistellige Milliarden-Umsätze, eine Lieferkette, in der Sequenzgenauigkeit über den OEM-Auftrag von morgen entscheidet. Wer in diesem Umfeld die Just-in-Sequence-Belieferung verantwortet, hat keinen Spielraum für Lernkurven. Ein falsch sequenziertes Modul am Band kostet nicht nur Sonderfracht – es kostet Lieferantenbewertung. Und eine schlechte Lieferantenbewertung kostet beim nächsten Vergabezyklus den Auftrag.</p><p>WSW Software begleitet seit mehr als drei Jahrzehnten Zulieferer und Komponentenfertiger, die im JIS- und JIT-Verfahren an deutsche und internationale OEMs liefern. Wir haben die spezifischen Anforderungen der großen Marken im Detail durchgearbeitet – von Sequenznummern-Prüfungen über User-Exits im SAP-JIT-Modul bis zur Gelangensbestätigung bei Kreuz-Grenzen-Belieferungen.</p><h2>Für wen wir arbeiten</h2><ul><li>Tier-1-Zulieferer mit Sequenzbelieferung direkt ans Montageband</li><li>Tier-2- und Komponentenfertiger mit hoher Variantenvielfalt</li><li>Modul-Lieferanten im Just-in-Sequence-Verfahren (z. B. Reifen-Rad-Baugruppen, Cockpit-Module, Sitzgruppen)</li><li>Logistikdienstleister, die Sequenzaufgaben für mehrere OEMs konsolidieren</li><li>Werke mit Streckenabwicklung, Lohnbearbeitung oder Just-in-Sequence-Belieferung über EU-Grenzen hinaus</li></ul><h2>Was unsere Branchen-Tiefe konkret bedeutet</h2><p>Wir wissen, was passiert, wenn ein Feinabruf zu spät kommt. Wir kennen die Spielregeln der Lieferantenportale aller großen OEMs. Wir bauen Prozesse, die auch dann tragen, wenn Materialknappheit, Streiks oder Produktionsverlagerungen den Plan über den Haufen werfen. Und wir bringen Erfahrung aus Werken in der DACH-Region, in Osteuropa und in Asien – dort, wo Ihre Kunden produzieren.</p><h2>Warum WSW als Branchen-Partner</h2><ul><li><strong>30+ Jahre JIS-Erfahrung</strong> in der Automobil-Zulieferindustrie</li><li><strong>JIS Competence Center</strong> mit erprobten Methoden und einem festen Experten-Team</li><li><strong>ITIL-konformer Support</strong> für den 24/7-Dauerbetrieb der laufenden Lösung</li><li><strong>Technologieoffen</strong> – mit SAP oder außerhalb von SAP</li><li><strong>Eigene SAP-Add-ons</strong> SPEEDI und JUNIQ, die den SAP-Standard modifikationsfrei erweitern</li></ul><h2>Referenz – Eurofit / Radsystem Mosel</h2><p>Eurofit ist ein Joint Venture von Michelin und Continental mit 18 Werken in Europa, Afrika und Asien und 1.200 Mitarbeitenden. WSW Software hat die Just-in-Sequence-Serienbelieferung der Reifen-Rad-Baugruppen (TWAs) runderneuert: vom EDI-Abruf des OEMs über die sequenzgerechte Produktion bis zur Bandanlieferung in der vorgegebenen Reihenfolge.</p><h2>Lassen Sie uns über Ihre OEM-Konstellation sprechen</h2><p>Jeder OEM kocht sein eigenes Süppchen. Wir kennen die Rezepte. Vereinbaren Sie ein 60-minütiges Erstgespräch mit unseren JIS-Experten – wir hören uns Ihre Situation an und zeigen, welche Stellschrauben in Ihrem konkreten Fall den größten Hebel haben.</p><p><strong>→ <a href=\"https://www.wsw.de/leistungen/jis-beratung/\">Termin für ein Erstgespräch anfragen</a></strong></p>","created_at":"2026-05-21T16:30:55+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":90,"konversionen":5},{"id":157,"slug":"code/http-api/rules/http-002-method-semantics","title":"HTTP_002_METHOD_SEMANTICS: HTTP-Methoden behalten ihre Semantik","meta_description":"HTTP_002_METHOD_SEMANTICS (must): HTTP-Methoden behalten ihre Semantik. GET MUSS lesend bleiben, POST erzeugt oder startet nicht-idempotente Aktionen, PUT/PATCH aktualisieren und DELETE loesch","content":"<h1>HTTP_002_METHOD_SEMANTICS: HTTP-Methoden behalten ihre Semantik</h1><p>Severity: <strong>must</strong>. Bereich: <a href=\"/code/http-api\">http-api</a>.</p><h2>Regel</h2><p>GET MUSS lesend bleiben, POST erzeugt oder startet nicht-idempotente Aktionen, PUT/PATCH aktualisieren und DELETE loescht oder deaktiviert nach fachlicher Definition.</p><h2>Reflection-Check</h2><pre><code>check:\n  reflect:\n    fields:\n    - method\n    object: mutation_contract</code></pre><h2>Evidence</h2><ul><li><strong>RFC9110</strong>, HTTP Semantics</li></ul><p><a href=\"/code/http-api/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:40:01+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":3,"konversionen":36},{"id":1207,"slug":"wsw-wirtschaftlichkeit","title":"JIS-Reibung kostet Sie heute Geld – und morgen den OEM-Auftrag","meta_description":"JIS-Beratung als Bilanz-Hebel: Bestandsreduktion, Kapitalfreisetzung, vermiedene Sonderfahrten, gesicherte Lieferantenbewertung. WSW Software macht den Business Case sichtbar.","content":"<h1>JIS-Reibung kostet Sie heute Geld – und morgen den OEM-Auftrag</h1><p><strong>Sonderfrachten. Sicherheitsbestände. Reaktive Disponenten. Sinkende Lieferantenbewertung. Vier Reibungen, die parallel an Ihrer Bilanz und Ihrer Auftragsbasis arbeiten. Gleichzeitig. Jeden Tag.</strong></p><h2>JIS gehört auf den Schreibtisch der Geschäftsführung</h2><p>Jeden Tag, an dem Ihre Sequenzlogik nicht trägt, passiert mehreres parallel. Disponenten verbringen Stunden mit Notfall-Telefonaten statt mit Planung. Ein Express-Frachtdienstleister fährt eine Lieferung in den roten Bereich, damit das Band beim OEM weiterläuft. Im Lager steht Material, das niemand abgerufen hat – als Sicherheit gegen die nächste Eskalation. Und im Lieferantenportal des OEMs verdichten sich diese Auffälligkeiten zu einer Bewertung, die in 18 Monaten über die nächste Ausschreibung entscheidet.</p><p>Das passiert nicht spektakulär. Es passiert leise, jede Woche, jeden Monat. Bis die Summe – auf der Logistik-Kostenstelle, in der Lagerbestands-Rechnung, im Krankenstand der Disposition und in der OEM-Bewertungs-Mail – nicht mehr zu übersehen ist. JIS-Reibung ist keine operative Unbequemlichkeit. Sie ist ein Bilanz-Hebel, der nach unten zeigt – und am Ende eine Vertrags-Frage.</p><p>Just-in-Sequence-Belieferung ist eines der wenigen Logistik-Themen, bei denen sich Investitionen direkt in der Bilanz nachweisen lassen. Wer Lieferreihenfolge, Sequenzgenauigkeit und Datenflüsse beherrscht, baut Bestände ab, senkt die Kapitalbindung und vermeidet die teuren Eskalationen, die bei jedem Sequenzfehler drohen. Die wirtschaftliche Gretchenfrage liegt offen auf dem Tisch: Wie viel Kapital ist in Ihren Vor- und Halbfertigprodukten gebunden, weil die Sequenzlogik nicht trägt? Und wie viele Sonderfrachten pro Quartal sind nichts anderes als kompensierte Prozessschwäche?</p><h2>Die vier wirtschaftlichen Stellschrauben</h2><p>Die Wirtschaftlichkeit eines JIS-Prozesses entscheidet sich an vier Hebeln. Wir analysieren sie in Ihrem konkreten Fall und übersetzen sie in ein belastbares Business Case mit nachvollziehbaren Annahmen, Quellen und Vergleichswerten:</p><ol><li><strong>Sonderfahrten und Express-Lieferungen</strong> – jede einzelne ist ein Beleg dafür, dass die Sequenzlogik im Regelbetrieb nicht greift. Reduzieren wir die Frequenz, sparen Sie nicht nur Frachtkosten, sondern auch CO₂-Bilanz und Disponenten-Nerven.</li><li><strong>Bestände an Vor- und Halbfertigprodukten</strong> – die häufigste Reaktion auf unsichere Sequenzen ist „mehr Sicherheitsbestand\". Das bindet Kapital und versteckt das eigentliche Problem.</li><li><strong>Personalaufwand für reaktive Disposition</strong> – Supply-Chain-Manager und Disponenten, die ihre Tage damit verbringen, Feuer zu löschen, sind ein klassischer Indikator schlecht laufender JIS-Prozesse.</li><li><strong>Lieferantenbewertung beim OEM</strong> – sie entscheidet über die nächste Ausschreibung. Hohe Liefertreue ist nicht nur ein operatives Ziel, sondern eine Umsatzsicherung im zweistelligen Millionen-Bereich.</li></ol><h2>Typische wirtschaftliche Wirkung in unseren Projekten</h2><ul><li>Bestandsreduktion bei Vor- und Halbfertigprodukten – typischerweise 20–40 %</li><li>Geringere Kapitalbindung über die gesamte Sequenz-Stufe</li><li>Drastischer Rückgang von Sonderfracht und Express-Eskalationen</li><li>Spürbar sinkender Personalaufwand für reaktive Disposition</li><li>Stabilere Lieferantenbewertung und damit gesicherter OEM-Umsatz</li></ul><h2>Warum WSW als Business-Case-Partner</h2><ul><li><strong>30+ Jahre JIS-Erfahrung</strong> mit kaufmännischer Wirkungs-Erhebung in der Automobil-Zulieferindustrie</li><li><strong>Erprobte Methodik</strong> zur Business-Case-Berechnung mit transparenten Annahmen</li><li><strong>Belastbare Vergleichswerte</strong> aus zahlreichen Vorgängerprojekten</li><li><strong>Klare Trennung</strong> zwischen Effizienz-Versprechen, das wir belegen können, und solchen, die Marketing wären</li></ul><h2>Referenz</h2><p>Bei einem Reifen-Rad-Modul-Lieferanten haben wir die Just-in-Sequence-Belieferung an einen großen deutschen OEM so stabilisiert, dass Sonderfahrten und Eskalations-Lieferungen über das Jahr hinweg deutlich zurückgingen – mit einem direkten, sichtbaren Effekt auf die jährliche Logistik-Kostenstelle und auf die Sicherheitsbestände auf Werks-Ebene.</p><h2>Sprechen Sie mit uns über Ihren Business Case</h2><p>Wir zeigen Ihnen die vier Hebel in Ihrer konkreten Situation – mit nachvollziehbaren Annahmen, Vergleichswerten und einer ehrlichen Einschätzung, was wirklich erreichbar ist. Vereinbaren Sie ein 60-minütiges Erstgespräch mit unserer Beratung.</p><p><strong>→ <a href=\"https://www.wsw.de/leistungen/jis-beratung/\">Termin für ein Business-Case-Erstgespräch anfragen</a></strong></p>","created_at":"2026-05-21T16:31:24+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":49,"konversionen":35},{"id":166,"slug":"code/http-api/rules/http-011-schema-documentation","title":"HTTP_011_SCHEMA_DOCUMENTATION: Schemas sind maschinenlesbar","meta_description":"HTTP_011_SCHEMA_DOCUMENTATION (should): Schemas sind maschinenlesbar. JSON-Requests und -Responses SOLLTEN per OpenAPI 3.1 und JSON Schema beschrieben werden, inklusive Pflichtfeldern, Forma","content":"<h1>HTTP_011_SCHEMA_DOCUMENTATION: Schemas sind maschinenlesbar</h1><p>Severity: <strong>should</strong>. Bereich: <a href=\"/code/http-api\">http-api</a>.</p><h2>Regel</h2><p>JSON-Requests und -Responses SOLLTEN per OpenAPI 3.1 und JSON Schema beschrieben werden, inklusive Pflichtfeldern, Formaten, Enums und Fehlervarianten.</p><h2>Reflection-Check</h2><pre><code>check:\n  reflect:\n    fields:\n    - schema_ref\n    object: representation</code></pre><h2>Evidence</h2><ul><li><strong>OPENAPI31</strong>, OpenAPI Specification 3.1</li><li><strong>JSON_SCHEMA_2020_12</strong>, JSON Schema Draft 2020-12 Core</li></ul><p><a href=\"/code/http-api/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:40:02+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":63,"konversionen":66},{"id":167,"slug":"code/http-api/rules/http-012-idempotency-for-risky-mutations","title":"HTTP_012_IDEMPOTENCY_FOR_RISKY_MUTATIONS: Riskante Mutationen sind idempotenzfaehig","meta_description":"HTTP_012_IDEMPOTENCY_FOR_RISKY_MUTATIONS (should): Riskante Mutationen sind idempotenzfaehig. Zahlungs-, Import-, Versand- und aehnlich riskante POST-Aktionen SOLLTEN einen Idempotency-Key oder eine g","content":"<h1>HTTP_012_IDEMPOTENCY_FOR_RISKY_MUTATIONS: Riskante Mutationen sind idempotenzfaehig</h1><p>Severity: <strong>should</strong>. Bereich: <a href=\"/code/http-api\">http-api</a>.</p><h2>Regel</h2><p>Zahlungs-, Import-, Versand- und aehnlich riskante POST-Aktionen SOLLTEN einen Idempotency-Key oder eine gleichwertige serverseitige Deduplizierung nutzen.</p><h2>Reflection-Check</h2><pre><code>check:\n  reflect:\n    fields:\n    - idempotency_key\n    object: mutation_contract</code></pre><h2>Evidence</h2><ul><li><strong>RFC9110</strong>, HTTP Semantics</li><li><strong>OWASP_API_TOP10</strong>, OWASP API Security Top 10 2023</li></ul><p><a href=\"/code/http-api/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:40:02+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":10,"konversionen":89},{"id":1208,"slug":"wsw-integration","title":"So fügt sich JIS in Ihre IT-Landschaft","meta_description":"JIS-Integration mit SAP oder ohne: JIT-Modul, User Exits, BADIs, Add-ons SPEEDI und JUNIQ, EDI sowie MES-, WMS- und Hardware-Anbindung. WSW baut JIS in Ihre Architektur ein.","content":"<h1>So fügt sich JIS in Ihre IT-Landschaft</h1><p><strong>Mit SAP oder ohne. Standard oder Add-on. Wir bauen JIS in die Architektur, die Sie heute betreiben – nicht daneben.</strong></p><h2>JIS-Insellösungen scheitern langfristig</h2><p>Eine JIS-Software, die nicht sauber in das ERP, den EDI-Stack und die Hardware-Welt der Logistik integriert ist, verursacht das, was sie eigentlich vermeiden soll: Doppelpflege, Schnittstellen-Brüche, Datenstaus und im Krisenfall keinen, der noch den Überblick hat. WSW Software begleitet JIS-Projekte deshalb von Anfang an als Integrationsthema. Wir denken nicht in „unserem System\" gegen „Ihre Landschaft\", sondern bauen JIS dort ein, wo Ihre Daten heute leben und wo Ihre Werker und Disponenten morgen damit arbeiten.</p><h2>Zwei Architektur-Pfade – beide voll abgedeckt</h2><p>Wir arbeiten technologieoffen mit den beiden Architektur-Pfaden, die heute im Markt relevant sind. Beide haben wir vielfach umgesetzt – und wir beraten ehrlich, welcher in Ihrem konkreten Fall trägt.</p><h3>SAP-eingebettet</h3><p>Im SAP-Umfeld – ob klassisch ECC oder S/4HANA – nutzen wir das vorhandene <strong>JIT-Modul</strong>, schneiden mit <strong>User Exits</strong> und <strong>BADIs</strong> die OEM-spezifischen Sonderwege passgenau zu und greifen, wo sinnvoll, auf unsere eigenen, <strong>modifikationsfreien SAP-Add-ons SPEEDI und JUNIQ</strong> zurück. Damit bleiben Sie release-fähig, ohne auf JIS-Funktionalität zu verzichten, die der SAP-Standard nicht liefert.</p><h3>Außerhalb von SAP</h3><p>Setzen Sie Best-of-Breed-Komponenten ein oder fahren Sie eine Non-SAP-ERP-Landschaft, binden wir JIS sauber an: ERP-System, EDI-Provider, MES, WMS, Lagerverwaltung und die Hardware-Welt der Sequenz-Realität. Wir bauen Schnittstellen, die auch unter Last halten – und nicht nur im Lastenheft funktionieren.</p><h2>Was wir konkret integrieren</h2><ul><li><strong>SAP ERP (ECC)</strong> und <strong>SAP S/4HANA</strong> mit JIT-Modul, User Exits und BADIs</li><li>WSW-eigene SAP-Add-ons <strong>SPEEDI</strong> und <strong>JUNIQ</strong> – modifikationsfrei integrierbar</li><li>EDI-Anbindung in <strong>EDIFACT</strong>, <strong>ODETTE</strong>, <strong>VDA</strong> und <strong>ANSI X.12</strong></li><li>MES-, WMS- und Lagerverwaltungs-Systeme von Drittanbietern</li><li>SPS-Steuerungen, Etikettierungs- und Kommissionierungs-Hardware</li><li>Sequenz-Logik bis ans Band – inkl. Druck von Rack-Karten und Ladelisten</li></ul><h2>Warum WSW als Integrations-Partner</h2><ul><li><strong>30+ Jahre Integration</strong> in SAP- und Non-SAP-Landschaften der Automobil-Zulieferindustrie</li><li><strong>Eigene Add-ons</strong> SPEEDI und JUNIQ, die den SAP-Standard sauber erweitern, statt ihn zu zerschneiden</li><li><strong>ITIL-konformer Support</strong> für den Dauerbetrieb – damit die Lösung jahrzehntelang trägt</li><li><strong>Architektur-Erfahrung</strong> aus heterogenen Landschaften: vom klassischen ECC bis zur Greenfield-S/4HANA-Migration</li></ul><h2>Referenz</h2><p>Bei <strong>Eurofit / Radsystem Mosel</strong> haben wir die Just-in-Sequence-Serienbelieferung in eine heterogene IT-Architektur eingebettet – mit OEM-spezifischen EDI-Strecken, Sequenz-Logik bis zur Bandanlieferung und durchgängigem Datenfluss von der Reifen-Rad-Baugruppe bis zur Versandbestätigung.</p><h2>Wir prüfen Ihre Architektur kostenfrei</h2><p>Senden Sie uns eine kurze Skizze Ihrer IT-Landschaft oder vereinbaren Sie ein 60-minütiges Architektur-Gespräch. Wir zeigen, wie JIS in Ihrem konkreten Setup tragen kann – mit klaren Empfehlungen für SAP-eingebettete oder Non-SAP-Integration.</p><p><strong>→ <a href=\"https://www.wsw.de/leistungen/jis-beratung/\">Termin für ein Architektur-Erstgespräch anfragen</a></strong></p>","created_at":"2026-05-21T16:32:28+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":69,"konversionen":34},{"id":174,"slug":"code/js/rules","title":"Regeln, js","meta_description":"Liste der 48 Regeln im Bereich js, sortiert nach ID.","content":"<h1>Regeln, js</h1><p>48 Regeln in /var/www/code/js/rules.yaml.</p><table><thead><tr><th>ID</th><th>Titel</th><th>Severity</th></tr></thead><tbody><tr><td><a href=\"/code/js/rules/js-001-vanilla-only-no-frameworks\">JS_001_VANILLA_ONLY_NO_FRAMEWORKS</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/js/rules/js-002-js-is-presentation-adapter-only\">JS_002_JS_IS_PRESENTATION_ADAPTER_ONLY</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/js/rules/js-003-no-domain-invariant-duplication\">JS_003_NO_DOMAIN_INVARIANT_DUPLICATION</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/js/rules/js-004-api-client-as-port-adapter\">JS_004_API_CLIENT_AS_PORT_ADAPTER</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-005-mvc-controller-thin\">JS_005_MVC_CONTROLLER_THIN</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-006-php-contract-explicit\">JS_006_PHP_CONTRACT_EXPLICIT</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-007-server-authoritative-for-mutations\">JS_007_SERVER_AUTHORITATIVE_FOR_MUTATIONS</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/js/rules/js-008-page-bootstrap-single-entry\">JS_008_PAGE_BOOTSTRAP_SINGLE_ENTRY</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-009-srp-module-role\">JS_009_SRP_MODULE_ROLE</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-010-maxloc-module\">JS_010_MAXLOC_MODULE</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-011-maxloc-function\">JS_011_MAXLOC_FUNCTION</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-012-dry-after-second-duplication\">JS_012_DRY_AFTER_SECOND_DUPLICATION</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-013-no-god-state\">JS_013_NO_GOD_STATE</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-014-classes-only-for-lifecycle-or-adapters\">JS_014_CLASSES_ONLY_FOR_LIFECYCLE_OR_ADAPTERS</a></td><td></td><td><strong>minor</strong></td></tr><tr><td><a href=\"/code/js/rules/js-015-new-code-es-modules\">JS_015_NEW_CODE_ES_MODULES</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-016-legacy-script-iife-strict\">JS_016_LEGACY_SCRIPT_IIFE_STRICT</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-017-no-inline-scripts-or-handlers\">JS_017_NO_INLINE_SCRIPTS_OR_HANDLERS</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/js/rules/js-018-bootstrap-dom-ready-correct\">JS_018_BOOTSTRAP_DOM_READY_CORRECT</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-019-feature-detection-over-browser-sniffing\">JS_019_FEATURE_DETECTION_OVER_BROWSER_SNIFFING</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-020-add-event-listener-only\">JS_020_ADD_EVENT_LISTENER_ONLY</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-021-delegate-dynamic-collection-events\">JS_021_DELEGATE_DYNAMIC_COLLECTION_EVENTS</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-022-abort-controller-for-cleanup\">JS_022_ABORT_CONTROLLER_FOR_CLEANUP</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-023-fetch-wrapper-standard\">JS_023_FETCH_WRAPPER_STANDARD</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-024-abort-stale-requests\">JS_024_ABORT_STALE_REQUESTS</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-025-same-origin-csrf-for-mutations\">JS_025_SAME_ORIGIN_CSRF_FOR_MUTATIONS</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/js/rules/js-026-safe-dom-text-by-default\">JS_026_SAFE_DOM_TEXT_BY_DEFAULT</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/js/rules/js-027-html-sinks-central-and-sanitized\">JS_027_HTML_SINKS_CENTRAL_AND_SANITIZED</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/js/rules/js-028-no-eval-or-string-code\">JS_028_NO_EVAL_OR_STRING_CODE</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/js/rules/js-029-progressive-enhancement-baseline\">JS_029_PROGRESSIVE_ENHANCEMENT_BASELINE</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-030-no-modals\">JS_030_NO_MODALS</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/js/rules/js-031-table-search-filters-live-sync\">JS_031_TABLE_SEARCH_FILTERS_LIVE_SYNC</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/js/rules/js-032-live-update-preserves-context\">JS_032_LIVE_UPDATE_PRESERVES_CONTEXT</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-033-status-messages-programmatic\">JS_033_STATUS_MESSAGES_PROGRAMMATIC</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/js/rules/js-034-focus-and-data-preserved\">JS_034_FOCUS_AND_DATA_PRESERVED</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/js/rules/js-035-native-controls-first\">JS_035_NATIVE_CONTROLS_FIRST</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-036-pointer-drag-has-alternative\">JS_036_POINTER_DRAG_HAS_ALTERNATIVE</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/js/rules/js-037-theme-dark-light-compatible\">JS_037_THEME_DARK_LIGHT_COMPATIBLE</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-038-reduced-motion-and-timing\">JS_038_REDUCED_MOTION_AND_TIMING</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-039-page-scoped-loading\">JS_039_PAGE_SCOPED_LOADING</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-040-third-party-containment\">JS_040_THIRD_PARTY_CONTAINMENT</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-041-no-layout-thrash-in-loops\">JS_041_NO_LAYOUT_THRASH_IN_LOOPS</a></td><td></td><td><strong>minor</strong></td></tr><tr><td><a href=\"/code/js/rules/js-042-test-pure-helpers-and-api-adapters\">JS_042_TEST_PURE_HELPERS_AND_API_ADAPTERS</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-043-browser-a11y-regression-for-gui-rules\">JS_043_BROWSER_A11Y_REGRESSION_FOR_GUI_RULES</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-044-lint-baseline\">JS_044_LINT_BASELINE</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-045-observable-errors-not-console-only\">JS_045_OBSERVABLE_ERRORS_NOT_CONSOLE_ONLY</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-046-history-ui-as-presentation-adapter\">JS_046_HISTORY_UI_AS_PRESENTATION_ADAPTER</a></td><td></td><td><strong>blocker</strong></td></tr><tr><td><a href=\"/code/js/rules/js-047-history-live-filter-and-stale-requests\">JS_047_HISTORY_LIVE_FILTER_AND_STALE_REQUESTS</a></td><td></td><td><strong>major</strong></td></tr><tr><td><a href=\"/code/js/rules/js-048-restore-errors-inline\">JS_048_RESTORE_ERRORS_INLINE</a></td><td></td><td><strong>major</strong></td></tr></tbody></table><p><a href=\"/code/js\">Zurück zum Bereich</a></p>","created_at":"2026-05-21T12:40:02+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":92,"konversionen":28},{"id":926,"slug":"code/gui/datentabellen-crud/sources","title":"Quellen, gui/datentabellen-crud","meta_description":"Quellen des Bereichs gui/datentabellen-crud, 14 Eintraege.","content":"<h1>Quellen, gui/datentabellen-crud</h1><p>14 Quellen in /var/www/code/gui/datentabellen-crud/sources.yaml.</p><table><thead><tr><th>ID</th><th>Titel</th><th>URL / Referenz</th><th>Publisher</th><th>Typ</th><th>Relevanz</th></tr></thead><tbody><tr><td><strong>WCAG22</strong></td><td>Web Content Accessibility Guidelines 2.2</td><td><a href=\"https://www.w3.org/TR/WCAG22/\">https://www.w3.org/TR/WCAG22/</a></td><td></td><td></td><td>Normative A/AA/AAA Success Criteria fuer Tabellen, Links, Fokus, Pointer-Ziele, Fehler und Statusmeldungen.</td></tr><tr><td><strong>WAI_WCAG_OVERVIEW</strong></td><td>WCAG 2 Overview</td><td><a href=\"https://www.w3.org/WAI/standards-guidelines/wcag/\">https://www.w3.org/WAI/standards-guidelines/wcag/</a></td><td></td><td></td><td>Stand 2026, Rueckwaertskompatibilitaet und EN-301-549-Hinweis.</td></tr><tr><td><strong>WAI_TABLES</strong></td><td>WAI Tables Tutorial</td><td><a href=\"https://www.w3.org/WAI/tutorials/tables/\">https://www.w3.org/WAI/tutorials/tables/</a></td><td></td><td></td><td>Datentabellen-Semantik, th/td, scope, id/headers, caption und komplexe Header.</td></tr><tr><td><strong>W3C_DESIGN_TABLES</strong></td><td>W3C Design System: Tables</td><td><a href=\"https://design-system.w3.org/styles/tables.html\">https://design-system.w3.org/styles/tables.html</a></td><td></td><td></td><td>Praktische W3C-Pattern fuer Tabellen, Captions, responsive Scroll-Regionen und Header-Scope.</td></tr><tr><td><strong>APG_GRID</strong></td><td>WAI-ARIA APG: Grid Pattern</td><td><a href=\"https://www.w3.org/WAI/ARIA/apg/patterns/grid/\">https://www.w3.org/WAI/ARIA/apg/patterns/grid/</a></td><td></td><td></td><td>Interaktive Data Grids, Fokusmodell, Tastaturnavigation und Rollen.</td></tr><tr><td><strong>W3C_ARIA</strong></td><td>Using ARIA</td><td><a href=\"https://www.w3.org/TR/using-aria/\">https://www.w3.org/TR/using-aria/</a></td><td></td><td></td><td>Native HTML vor ARIA; Custom Controls nur mit vollstaendiger Semantik und Tastaturbedienung.</td></tr><tr><td><strong>WAI_TARGET_SIZE</strong></td><td>Understanding WCAG 2.5.8 Target Size Minimum</td><td><a href=\"https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html\">https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html</a></td><td></td><td></td><td>24px AA, 44px Enhanced/AAA und Spacing-Ausnahmen fuer Actions in Tabellen.</td></tr><tr><td><strong>WAI_FOCUS_APPEARANCE</strong></td><td>Understanding WCAG 2.4.13 Focus Appearance</td><td><a href=\"https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance.html\">https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance.html</a></td><td></td><td></td><td>Enhanced Fokusgroesse und Kontrast fuer Zellen, Links und Row Actions.</td></tr><tr><td><strong>WAI_STATUS</strong></td><td>Understanding WCAG 4.1.3 Status Messages</td><td><a href=\"https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html\">https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html</a></td><td></td><td></td><td>Dynamische Meldungen fuer Laden, Speichern, Loeschen, Filter, Sortierung und Pagination.</td></tr><tr><td><strong>ISO_9241_110</strong></td><td>ISO 9241-110 Interaction principles</td><td><a href=\"https://www.iso.org/standard/75258.html\">https://www.iso.org/standard/75258.html</a></td><td></td><td></td><td>Task suitability, self-descriptiveness, conformity with expectations, controllability und use error robustness.</td></tr><tr><td><strong>MARCHIONINI_ETABLES_2003</strong></td><td>User studies informing E-table interfaces</td><td><a href=\"https://doi.org/10.1016/S0306-4573(02)00043-2\">https://doi.org/10.1016/S0306-4573(02)00043-2</a></td><td></td><td></td><td>User Studies zu elektronischen Tabellen und Table-Browser-Interfaces.</td></tr><tr><td><strong>TAGGLE_2020</strong></td><td>Taggle: Combining overview and details in tabular data visualizations</td><td><a href=\"https://doi.org/10.1177/1473871619878085\">https://doi.org/10.1177/1473871619878085</a></td><td></td><td></td><td>Interaktive Tabellennutzung, Sortieren, Filtern, Gruppieren und Overview/Details fuer grosse Tabellen.</td></tr><tr><td><strong>BAYMARD_PRODUCT_LISTS</strong></td><td>E-Commerce Product Lists and Filtering UX</td><td><a href=\"https://baymard.com/research/ecommerce-product-lists\">https://baymard.com/research/ecommerce-product-lists</a></td><td></td><td></td><td>Gross angelegte UX-Studie zu Scannen, Filtern und Sortieren von Listen/Result-Sets.</td></tr><tr><td><strong>NIELSEN_HEURISTICS</strong></td><td>10 Usability Heuristics for User Interface Design (Nielsen)</td><td><a href=\"https://www.nngroup.com/articles/ten-usability-heuristics/\">https://www.nngroup.com/articles/ten-usability-heuristics/</a></td><td></td><td></td><td>Heuristik 2 Match between system and the real world und Heuristik 4 Consistency and standards - Such-Reichweite muss dem entsprechen, was als Daten sichtbar gerendert wird.</td></tr></tbody></table><p><a href=\"/code/gui/datentabellen-crud\">Zurück zum Bereich</a></p>","created_at":"2026-05-21T12:43:40+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":90,"konversionen":81},{"id":180,"slug":"code/js/rules/js-006-php-contract-explicit","title":"JS_006_PHP_CONTRACT_EXPLICIT:","meta_description":"JS_006_PHP_CONTRACT_EXPLICIT (major): .","content":"<h1>JS_006_PHP_CONTRACT_EXPLICIT: </h1><p>Severity: <strong>major</strong>. Bereich: <a href=\"/code/js\">js</a>.</p><h2>Regel</h2><p>(kein Regeltext)</p><h2>Reflection-Check</h2><pre><code>check:\n  fail: JS parst sichtbaren Text, CSS-Klassen oder DOM-Reihenfolge als fachliche Datenquelle.\n  pass: PHP View/Action und JS stimmen ueber explizite data-* Attribute, JSON-DTOs\n    oder dokumentierte Response-Shapes ueberein.\n  remediation: Datenvertrag in data-* Attributen, application/json script oder Endpoint-DTO\n    sichtbar machen.\n  type: php_contract</code></pre><h2>Evidence</h2><ul><li><strong>COCKBURN_HEXAGONAL</strong>, Alistair Cockburn: Hexagonal Architecture</li><li><strong>DDD_REFERENCE</strong>, Domain Language: Domain-Driven Design Reference</li></ul><p><a href=\"/code/js/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:40:02+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":30,"konversionen":100},{"id":67,"slug":"code/css/rules/css-004-no-authorization-by-display-none","title":"CSS_004_NO_AUTHORIZATION_BY_DISPLAY_NONE:","meta_description":"CSS_004_NO_AUTHORIZATION_BY_DISPLAY_NONE (blocker): .","content":"<h1>CSS_004_NO_AUTHORIZATION_BY_DISPLAY_NONE: </h1><p>Severity: <strong>blocker</strong>. Bereich: <a href=\"/code/css\">css</a>.</p><h2>Regel</h2><p>(kein Regeltext)</p><h2>Reflection-Check</h2><pre><code>check:\n  fail: Button oder Link ist per display:none/hidden Klasse verborgen, aber serverseitig\n    erreichbar oder im DOM vorhanden.\n  pass: Nicht erlaubte Aktionen werden serverseitig nicht gerendert oder serverseitig\n    gesperrt; CSS versteckt sie nicht als Schutz.\n  remediation: Autorisierung in PHP pruefen; DOM nur erlaubte Aktionen rendern; CSS\n    darf optionale Sichtbarkeit nicht als Sicherheitsgrenze nutzen.\n  type: php_css_contract</code></pre><h2>Evidence</h2><ul><li><strong>COCKBURN_HEXAGONAL</strong>, Alistair Cockburn: Hexagonal Architecture</li><li><strong>FOWLER_PRESENTATION_DOMAIN</strong>, Martin Fowler: Presentation Domain Separation</li></ul><p><a href=\"/code/css/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:39:59+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":75,"konversionen":66},{"id":168,"slug":"code/http-api/rules/http-013-rate-limit-and-resource-limits","title":"HTTP_013_RATE_LIMIT_AND_RESOURCE_LIMITS: APIs begrenzen Ressourcenverbrauch","meta_description":"HTTP_013_RATE_LIMIT_AND_RESOURCE_LIMITS (must): APIs begrenzen Ressourcenverbrauch. Suche, Filter, Exporte, Uploads und Mutationen MUESSEN serverseitige Limits fuer Rate, Seitengroesse, Payload und La","content":"<h1>HTTP_013_RATE_LIMIT_AND_RESOURCE_LIMITS: APIs begrenzen Ressourcenverbrauch</h1><p>Severity: <strong>must</strong>. Bereich: <a href=\"/code/http-api\">http-api</a>.</p><h2>Regel</h2><p>Suche, Filter, Exporte, Uploads und Mutationen MUESSEN serverseitige Limits fuer Rate, Seitengroesse, Payload und Laufzeit besitzen.</p><h2>Reflection-Check</h2><pre><code>check:\n  reflect:\n    objects:\n    - query_contract\n    - endpoint</code></pre><h2>Evidence</h2><ul><li><strong>OWASP_API_TOP10</strong>, OWASP API Security Top 10 2023</li></ul><p><a href=\"/code/http-api/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:40:02+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":84,"konversionen":80},{"id":85,"slug":"code/css/rules/css-022-overlay-only-for-non-modal-system-states","title":"CSS_022_OVERLAY_ONLY_FOR_NON_MODAL_SYSTEM_STATES:","meta_description":"CSS_022_OVERLAY_ONLY_FOR_NON_MODAL_SYSTEM_STATES (major): .","content":"<h1>CSS_022_OVERLAY_ONLY_FOR_NON_MODAL_SYSTEM_STATES: </h1><p>Severity: <strong>major</strong>. Bereich: <a href=\"/code/css\">css</a>.</p><h2>Regel</h2><p>(kein Regeltext)</p><h2>Reflection-Check</h2><pre><code>check:\n  applies_when: overlay_style_present == true\n  fail: Overlay blockiert Seite oder imitiert Modal-Verhalten.\n  pass: Overlay ist nicht-blockierend oder technisch notwendig, z.B. Video-Layer/Loading,\n    und verdeckt keine Bedienung ohne Alternative.\n  remediation: Overlay entfernen oder als inline/section loading state umsetzen; Fokus\n    und Bedienbarkeit erhalten.\n  type: component_style</code></pre><h2>Evidence</h2><ul><li><strong>LOCAL_GUI_RULES</strong>, Lokale GUI-YAML-Libraries</li><li><strong>WCAG22</strong>, Web Content Accessibility Guidelines 2.2</li></ul><p><a href=\"/code/css/rules\">alle Regeln dieses Bereichs</a></p>","created_at":"2026-05-21T12:40:00+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":81,"konversionen":97},{"id":3,"slug":"mcp-ki-web","title":"MCP-Server ki-web · Aufbau & Funktionsweise","meta_description":"Wie der MCP-Server für ki.karlkratz.com aufgebaut ist und mit Claude Code, Codex und qwen-code zusammenspielt.","content":"<h1>MCP-Server ki-web</h1><p>Dies ist ein <strong>Model Context Protocol</strong>-Server, der den drei lokal installierten AI-CLIs (Claude Code, Codex, qwen-code) Werkzeuge zum Verwalten von Seiten auf ki.karlkratz.com bereitstellt. Wenn der KI z. B. mitgeteilt wird „lege eine Seite an\", ruft sie das Tool <strong>create_page</strong> auf, der Server schreibt in die Datenbank, die Seite ist sofort live.</p><h2>Datenfluss</h2><ol><li>KI-CLI erkennt aus dem Prompt, dass ein Tool gebraucht wird.</li><li>Sie startet den MCP-Server <strong>ki-web</strong> als stdio-Subprozess und sendet JSON-RPC.</li><li>Die Python-Schicht ruft die <strong>PHP-JSON-API</strong> unter <a href=\"/api/pages\">/api/pages</a> auf.</li><li>PHP validiert (Slug-Regex, Längen-Limits), sanitisiert das HTML und schreibt nach <strong>Postgres</strong> (Datenbank ki_web).</li><li>Die Antwort läuft denselben Pfad zurück bis zur KI.</li></ol><h2>Tools</h2><table><thead><tr><th>Tool</th><th>Wirkung</th></tr></thead><tbody><tr><td>list_pages</td><td>Alle Seiten, mit Suche, Sortierung, Pagination</td></tr><tr><td>get_page</td><td>Eine Seite per Slug</td></tr><tr><td>create_page</td><td>Neue Seite anlegen</td></tr><tr><td>update_page</td><td>Felder einer bestehenden Seite überschreiben</td></tr><tr><td>delete_page</td><td>Seite per Slug löschen</td></tr></tbody></table><h2>Architektur, DDD / Hexagonal</h2><p>Beide Codebases, die PHP-App und der Python-MCP, folgen demselben Muster, jede Datei unter 100 Zeilen.</p><h3>PHP unter /var/www/ki.karlkratz.com/src/</h3><ul><li><strong>Domain</strong>: Page-Entity, Value Objects (Slug, Title, MetaDescription, Content), Repository-Port, HtmlSanitizer-Port, Exceptions.</li><li><strong>Application</strong>: Use Cases CreatePage, UpdatePage, DeletePage, GetPageBySlug, ListPages, dünne Orchestrierung.</li><li><strong>Infrastructure</strong>: PdoPageRepository, DomHtmlSanitizer, Router, Controllers, Views, alles Frameworkartige bleibt hier außen.</li></ul><h3>Python unter /var/www/mcp/</h3><ul><li><strong>domain/page.py</strong>: Dataclass und PagesError.</li><li><strong>application/use_cases.py</strong>: PageUseCases, dünner Wrapper.</li><li><strong>infrastructure/pages_client.py</strong>: httpx-Client gegen die PHP-API.</li><li><strong>server.py</strong>: stdio-Entry, registriert die fünf Tools beim MCP-SDK.</li></ul><h2>DRY: wo passiert Validierung?</h2><p>Ausschließlich in der <strong>PHP-Schicht</strong>. Der Python-MCP ist ein dünner HTTP-Adapter. Slug-Regex, Längen-Limits und die HTML-Tag-Whitelist (h1, h2, h3, p, ol, ul, li, a, strong, table, pre, code) leben ausschließlich im PHP-Code. Das Python-Modul kennt diese Regeln nicht und muss sie auch nicht kennen, fügt man später eine zweite Schnittstelle hinzu (CLI-Tool, Webhook), bleibt die Regel weiterhin an genau einer Stelle.</p><h2>HTML-Sanitization im Detail</h2><p>Der <strong>DomHtmlSanitizer</strong> in PHP parst den eingehenden Body mit DOMDocument, läuft den Baum rückwärts ab und entfernt jeden Tag, der nicht auf der Whitelist steht. Das <strong>a</strong>-Tag darf nur die Attribute href und title behalten; href muss http(s), mailto oder ein relativer Pfad sein. Damit kann auch eine halluzinierende KI keinen Schaden anrichten, ein eingeschleustes Script-Tag wird vor dem INSERT entfernt.</p><h2>Selbst ausprobieren</h2><ol><li>In Claude Code, Codex oder qwen-code formulieren: „lege eine Seite mit Slug foo, Titel ‚Foo‘, kurzer Meta-Description und H1+Absatz an\".</li><li>Die CLI ruft <strong>create_page</strong> auf.</li><li>Die Seite ist sofort unter <a href=\"/foo\">ki.karlkratz.com/foo</a> erreichbar.</li><li>Oder direkt suchen in <a href=\"/admin\">/admin</a>.</li></ol><h2>Wichtigste Pfade</h2><table><thead><tr><th>Pfad</th><th>Inhalt</th></tr></thead><tbody><tr><td>/var/www/mcp/</td><td>Python-MCP-Quellen</td></tr><tr><td>/var/www/ki.karlkratz.com/src/</td><td>PHP-Codebase</td></tr><tr><td>/var/www/ki.karlkratz.com/public/index.php</td><td>Front-Controller</td></tr><tr><td>/var/www/_credentials/ki_web/credentials.json</td><td>DB-Zugang für PHP-App</td></tr><tr><td>/usr/local/bin/ki-web</td><td>Wrapper, startet den MCP über venv-Python</td></tr></tbody></table>","created_at":"2026-05-21T02:47:31+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":82,"konversionen":64},{"id":5,"slug":"mcp-server-erstellen-regeln","title":"Regeln für Python-MCP-Server","meta_description":"Harte Regeln für Python-MCP-Server: DDD/Hexagonal, Max-LoC, stdio-Disziplin, Schema-Akkuratesse, Sicherheit.","content":"<h1>Regeln für Python-MCP-Server</h1><p>Diese Seite fasst zusammen, wie wir auf <strong>ki.karlkratz.com</strong> MCP-Server in Python bauen. Grundlage sind die Architektur-Prinzipien aus <strong>/var/www/code/projektcharakteristika/</strong> (DDD, Hexagonal, SRP, SoC, DRY, SOLID, Clean Code, Max-LoC), übersetzt auf die Eigenheiten des Model-Context-Protocol-stdio-Transports.</p><h2>1. SDK und Transport</h2><ol><li>Verwende das offizielle PyPI-Paket <strong>mcp</strong>, in der Praxis die <strong>FastMCP</strong>-Klasse für deklarative Tool-Registrierung.</li><li>Default-Transport ist <strong>stdio</strong>, eine Subprocess-Instanz pro Client. HTTP-/SSE-Transport nur, wenn Remote-Zugriff explizit gewünscht ist.</li><li>SDK-Version in einer Lockfile fixieren, keine \"latest\"-Floats in Production.</li></ol><h2>2. Goldene stdio-Regel</h2><p><strong>Keine ungewollten Schreibvorgänge auf stdout.</strong> Der stdio-Transport nutzt stdout exklusiv für JSON-RPC-Frames; jedes <strong>print()</strong> oder unbuffered Logging zerstört das Protokoll. Konsequenz:</p><ul><li>Logging immer auf <strong>stderr</strong> oder in eine Datei.</li><li>Bibliotheken, die per Default auf stdout loggen (httpx-Logger, urllib3-Logger), im Composition-Root einmal explizit konfigurieren.</li><li>Auch Banner, \"Loading\"-Anzeigen, Tracebacks gehören auf stderr.</li></ul><h2>3. Tool-Definition</h2><p>Jedes Tool ist eine Funktion mit dem <strong>mcp.tool()</strong>-Decorator. Vier Pflichten:</p><ol><li><strong>Name</strong> in snake_case, fachlich gewählt, ohne technische Präfixe (kein <strong>get_</strong>, <strong>do_</strong>).</li><li><strong>Docstring</strong>, der das Tool für das LLM beschreibt. Erster Satz ist die Kurzfassung; danach Argumentbedingungen, Wertgrenzen, Fehlersignale.</li><li><strong>Type-Hints</strong> für alle Parameter und den Return-Typ. Daraus generiert das SDK das JSON-Schema, das die KI zur Argument-Erzeugung sieht.</li><li><strong>Determinismus dokumentiert</strong>: List/Get sind seiteneffektfrei; Schreibvorgänge sind im Docstring klar als solche markiert.</li></ol><h2>4. Schichten: DDD und Hexagonal</h2><p>Wie in /var/www/code/projektcharakteristika/architecture_layers.yaml beschrieben, übertragen auf Python:</p><table><thead><tr><th>Schicht</th><th>Inhalt</th><th>Darf NICHT enthalten</th></tr></thead><tbody><tr><td>domain/</td><td>Dataclasses (frozen, slots), Domain-Errors, Ports als typing.Protocol</td><td>HTTP-Calls, DB-Treiber, JSON-Parsing, mcp-SDK-Imports</td></tr><tr><td>application/</td><td>Use Cases, orchestrieren Ports, kein I/O</td><td>httpx, psycopg, Dateipfade hartcodiert</td></tr><tr><td>infrastructure/</td><td>Adapter: HTTP-Clients, DB-Connections, Filesystem, externe APIs, Config-Loader</td><td>fachliche Regeln, Validierungs-Algorithmen</td></tr><tr><td>presentation/</td><td>server.py, Tool-Funktionen, JSON-Mapper</td><td>fachliche Wahrheit, Domain-Regeln</td></tr></tbody></table><p><strong>Abhängigkeiten zeigen nur nach innen</strong>, Infrastructure kennt Application, Application kennt Domain. Niemals umgekehrt.</p><h2>5. Quality Principles (aus quality_principles.yaml)</h2><ul><li><strong>SRP</strong>, jedes Tool macht eine fachliche Sache. Kein update_or_create, kein list_with_optional_delete.</li><li><strong>SoC</strong>, die Tool-Funktion enthält keine SQL, kein Body-Mapping, keine Validation. Sie ruft eine Use-Case-Methode auf und reicht das Ergebnis weiter.</li><li><strong>DRY</strong>, Validierung (Längen, Regex, Whitelist) lebt an genau einer Stelle, in der Regel im Backend hinter der API. Der MCP-Server validiert NICHT zusätzlich.</li><li><strong>SOLID</strong>, Use Cases bekommen Ports via Konstruktor injiziert. Konkrete Adapter werden im Composition-Root (server.py) verdrahtet.</li><li><strong>Clean Code</strong>, explizite Namen, kurze Funktionen, keine Cleverness, Type-Hints überall.</li></ul><h2>6. Maximale Dateigröße (hart)</h2><table><thead><tr><th>Datei-Typ</th><th>Hartes Limit (LoC)</th></tr></thead><tbody><tr><td>domain (Dataclasses, Errors, Ports)</td><td>80</td></tr><tr><td>application (Use Cases)</td><td>120</td></tr><tr><td>infrastructure (Adapter)</td><td>200</td></tr><tr><td>server.py (Composition + Tools)</td><td>150</td></tr><tr><td>Test-Dateien</td><td>300</td></tr></tbody></table><p>Überschreitung ist Blocker, bevor das Limit angehoben wird, prüfen ob die Datei mehrere Verantwortungen mischt.</p><h2>7. Forbidden Dependencies</h2><ul><li>Kein Application-Framework als Treiber des MCP, kein FastAPI, kein Flask, kein Django zum Tool-Routing. Diese Pakete sind in Infrastructure-Adaptern erlaubt, wenn das Backend sie spricht.</li><li>Keine ORM-Magie in Use Cases, psycopg oder sqlalchemy.core sind OK, das Mapping bleibt in einer Repository-Klasse.</li><li>Keine globalen Singletons, keine Module-Level-Seiteneffekte außer im Composition-Root.</li></ul><h2>8. Sicherheit und Sandbox</h2><ol><li><strong>Niemals</strong> Pfade aus Tool-Argumenten ohne Whitelist auf Dateioperationen anwenden, Path-Traversal-Schutz via <strong>realpath</strong>-Vergleich gegen einen erlaubten Root.</li><li><strong>Niemals</strong> subprocess oder eval mit ungeprüftem User-Input.</li><li>Secrets liegen in <strong>/var/www/_credentials/&lt;dienst&gt;/credentials.json</strong> oder in ENV-Variablen, niemals im Code.</li><li>Destruktive Tools (delete_, drop_, exec_) verlangen explizite Argumente, keine \"all\"-Variante per Default, kein implizites Cascade.</li></ol><h2>9. Fehlerbehandlung</h2><p>Use Cases werfen Domain-Errors. Die Tool-Funktion fängt sie ab und mappt sie auf MCP-Fehlerantworten. Eine generische <strong>except Exception</strong> ist nur an genau einer Stelle erlaubt: am äußersten Rand. Stack-Traces gehen auf stderr, NICHT in die Tool-Antwort, damit das LLM keine internen Pfade sieht.</p><h2>10. Schema-Akkuratesse</h2><p>Das vom SDK aus den Type-Hints generierte JSON-Schema wird dem LLM gezeigt und definiert, welche Argumente es schicken darf. Konsequenz:</p><ul><li>Optionale Parameter mit sinnvollen Defaults annotieren, sonst kann das LLM sie nicht zuverlässig auslassen.</li><li>Enum-Werte als <strong>Literal[...]</strong> kennzeichnen, damit das LLM nur gültige Optionen sieht.</li><li>Return-Typen so konkret wie möglich, kein <strong>Any</strong> als Default, sonst bleiben Antworten unlesbar.</li></ul><h2>11. Tests</h2><ol><li>Use Cases werden mit Fake-Adaptern getestet, keine echten HTTP- oder DB-Calls.</li><li>Schema-Tests prüfen, dass <strong>tools/list</strong> das erwartete Schema liefert.</li><li>Integration-Test fährt den Server als Subprocess hoch und schickt einen echten <strong>initialize</strong>+<strong>tools/call</strong>-Roundtrip.</li></ol><h2>12. Verzeichnis-Layout (Referenz)</h2><table><thead><tr><th>Pfad</th><th>Inhalt</th></tr></thead><tbody><tr><td>server.py</td><td>Composition-Root: instanziiert Config, Adapter, Use Cases; registriert Tools</td></tr><tr><td>domain/</td><td>Dataclasses, Errors, Ports (typing.Protocol)</td></tr><tr><td>application/</td><td>Use Cases, dünne Orchestrierung</td></tr><tr><td>infrastructure/</td><td>HTTP-Clients, DB-Adapter, Config-Loader</td></tr><tr><td>tests/</td><td>pytest mit Fakes</td></tr><tr><td>pyproject.toml</td><td>Metadaten, Versionen via Lockfile fixiert</td></tr></tbody></table><h2>13. Quellen</h2><ul><li><a href=\"https://modelcontextprotocol.io/\">modelcontextprotocol.io</a>, Spec, Reference Implementations</li><li><a href=\"https://github.com/modelcontextprotocol/python-sdk\">github.com/modelcontextprotocol/python-sdk</a>, offizielles Python-SDK</li><li>/var/www/code/projektcharakteristika/quality_principles.yaml, SRP, SoC, DRY, SOLID, Clean Code, MaxLoC</li><li>/var/www/code/projektcharakteristika/rules.yaml, projektweite Architektur-Hardregeln</li><li>/var/www/code/projektcharakteristika/architecture_layers.yaml, Schicht-Definitionen</li><li>/var/www/code/projektcharakteristika/forbidden_dependencies.yaml, verbotene Pakete und Framework-Kategorien</li></ul>","created_at":"2026-05-21T02:55:01+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":13,"konversionen":66},{"id":16,"slug":"mcp-anleitung","title":"MCP-Server bauen, die ki-web-Anleitung","meta_description":"Schritt-für-Schritt-Anleitung für einen Python-stdio-MCP-Server am Beispiel ki-web, Domain, Application, Infrastructure, Tests, Anbindung.","content":"<h1>MCP-Server bauen, die ki-web-Anleitung</h1><p>Diese Seite zeigt Schritt für Schritt, wie der MCP-Server <strong>ki-web</strong> entstanden ist: ein <strong>stdio</strong>-MCP in Python, der die Verwaltung der Seiten auf ki.karlkratz.com an das PHP-Backend unter <a href=\"/api/pages\">/api/pages</a> delegiert. Diese Anleitung beschreibt jeden Schritt, sodass vergleichbare Adapter mit überschaubarem Aufwand nachgebaut werden können.</p><p>Die hier verwendeten Konventionen sind formal hinterlegt in <a href=\"/mcp-server-erstellen-regeln\">/mcp-server-erstellen-regeln</a> und maschinenlesbar unter <strong>/var/www/code/python-mcp/</strong>.</p><h2>1. Was am Ende läuft</h2><p>Fünf Tools, alle über stdio erreichbar für Claude Code, qwen-code und Codex:</p><table><thead><tr><th>Tool</th><th>Wirkung</th></tr></thead><tbody><tr><td>list_pages</td><td>Suche, Sortierung, Pagination</td></tr><tr><td>get_page</td><td>Eine Seite per Slug</td></tr><tr><td>create_page</td><td>Neue Seite anlegen</td></tr><tr><td>update_page</td><td>Partial-Update, nur geänderte Felder</td></tr><tr><td>delete_page</td><td>Seite per Slug löschen</td></tr></tbody></table><p>Jeder Tool-Aufruf landet als HTTP-Request bei <strong>/api/pages</strong>; Slug-Regex, Length-Limits und HTML-Sanitization passieren ausschließlich im PHP-Backend. Der Python-Code ist <strong>nur ein Adapter</strong>, die fachlichen Regeln liegen damit nur einmal vor.</p><h2>2. Voraussetzungen</h2><ul><li>Python 3.13 mit venv unter <strong>/opt/venv/main</strong></li><li>Pakete <strong>mcp</strong> &gt;= 1.27, <strong>httpx</strong> &gt;= 0.28, <strong>pydantic</strong> &gt;= 2.13 (vor-installiert)</li><li>Backend mit JSON-REST-Schnittstelle, hier die PHP-App unter /api/pages</li><li>Schreibrecht auf <strong>/var/www/mcp</strong> und <strong>/usr/local/bin</strong></li></ul><h2>3. Verzeichnisstruktur</h2><pre><code>/var/www/mcp/\n  pyproject.toml\n  requirements.lock\n  README.md\n  ki_web_mcp/\n    __init__.py\n    server.py             # FastMCP + Tool-Registrierung\n    composition.py        # Composition-Root\n    config.py             # Frozen Config + Env-Loader\n    schemas.py            # Literal-Enums, Annotated-Bounds, TypedDicts\n    domain/\n      __init__.py\n      page.py             # Page-Dataclass\n      errors.py           # BackendError, TransportError\n    application/\n      __init__.py\n      ports.py            # PagesPort als typing.Protocol\n      use_cases.py        # PageUseCases, orchestriert den Port\n    infrastructure/\n      __init__.py\n      pages_client.py     # httpx-Adapter, implementiert PagesPort\n      page_mapper.py      # JSON &lt;-&gt; Page-Mapping\n  tests/\n    __init__.py\n    conftest.py           # FakePages-Port + Fixtures\n    test_use_cases.py     # Use-Case-Unit-Tests\n    test_schema.py        # tools/list-Drift via Subprocess\n    test_e2e.py           # Lifecycle gegen Live-Backend</code></pre><h2>4. pyproject.toml</h2><p>Echtes Python-Package, keine <code>sys.path</code>-Hacks. Entry-Point heißt <strong>ki-web</strong>, der Wrapper unter <strong>/usr/local/bin/ki-web</strong> ruft ihn unbuffered auf.</p><pre><code>[build-system]\nrequires = [\"setuptools&gt;=68\", \"wheel\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"ki-web-mcp\"\nversion = \"0.2.0\"\nrequires-python = \"&gt;=3.13\"\ndependencies = [\n    \"mcp&gt;=1.27,&lt;2\",\n    \"httpx&gt;=0.28,&lt;0.29\",\n    \"pydantic&gt;=2.13,&lt;3\",\n]\n\n[project.scripts]\nki-web = \"ki_web_mcp.server:main\"\n\n[tool.setuptools.packages.find]\ninclude = [\"ki_web_mcp*\"]</code></pre><h2>5. Domain-Schicht, Daten und Fehler</h2><p>Nur Datentypen, keine Imports von HTTP, JSON oder mcp-SDK. So bleibt die Domain testbar und ersetzbar.</p><h3>domain/page.py</h3><pre><code>from __future__ import annotations\nfrom dataclasses import dataclass\nfrom typing import Optional\n\n@dataclass(frozen=True, slots=True)\nclass Page:\n    slug: str\n    title: str\n    meta_description: str\n    content: str\n    id: Optional[int] = None\n    created_at: Optional[str] = None\n    updated_at: Optional[str] = None</code></pre><h3>domain/errors.py</h3><pre><code>from __future__ import annotations\nfrom dataclasses import dataclass\nfrom typing import Any, Optional\n\n@dataclass(slots=True)\nclass BackendError(Exception):\n    status: int\n    error_code: str\n    message: str\n    payload: Optional[dict[str, Any]] = None\n\n@dataclass(slots=True)\nclass TransportError(Exception):\n    status: int\n    detail: str</code></pre><h2>6. Application-Schicht, Port und Use Cases</h2><p>Der Port ist die einzige Schnittstelle, die die Anwendung kennt. Use Cases orchestrieren, keine I/O, kein Mapping.</p><h3>application/ports.py</h3><pre><code>from __future__ import annotations\nfrom typing import Optional, Protocol\nfrom ki_web_mcp.domain.page import Page\n\nclass PagesPort(Protocol):\n    def list(self, search, sort, direction, limit, offset) -&gt; dict: ...\n    def get(self, slug: str) -&gt; Page: ...\n    def create(self, slug, title, meta_description, content) -&gt; Page: ...\n    def update(self, slug, *, title, meta_description, content) -&gt; Page: ...\n    def delete(self, slug: str) -&gt; dict: ...\n    def ping(self) -&gt; bool: ...\n    def close(self) -&gt; None: ...</code></pre><h3>application/use_cases.py</h3><pre><code>from dataclasses import asdict\nfrom ki_web_mcp.application.ports import PagesPort\nfrom ki_web_mcp.domain.page import Page\n\nclass PageUseCases:\n    def __init__(self, pages: PagesPort):\n        self._pages = pages\n\n    def list_pages(self, *, search, sort, direction, limit, offset):\n        r = self._pages.list(search, sort, direction, limit, offset)\n        return {\"total\": r[\"total\"], \"items\": r[\"items\"]}\n\n    def get_page(self, slug):\n        return asdict(self._pages.get(slug))\n\n    def create_page(self, slug, title, meta_description, content):\n        return asdict(self._pages.create(slug, title, meta_description, content))\n\n    def update_page(self, slug, *, title, meta_description, content):\n        return asdict(self._pages.update(\n            slug, title=title, meta_description=meta_description, content=content))\n\n    def delete_page(self, slug):\n        return self._pages.delete(slug)</code></pre><h2>7. Infrastructure, HTTP-Adapter und Mapper</h2><p>Hier passiert die einzige I/O. Der Adapter implementiert den Port, mappt JSON auf Domain-Objekte, kümmert sich um Retries, atexit-Cleanup und Request-Id-Propagation.</p><h3>infrastructure/page_mapper.py</h3><pre><code>from ki_web_mcp.domain.page import Page\n\nclass PageMapper:\n    @staticmethod\n    def from_api(data: dict) -&gt; Page:\n        return Page(\n            slug=data[\"slug\"], title=data[\"title\"],\n            meta_description=data[\"meta_description\"],\n            content=data[\"content\"],\n            id=data.get(\"id\"),\n            created_at=data.get(\"created_at\"),\n            updated_at=data.get(\"updated_at\"),\n        )</code></pre><h3>infrastructure/pages_client.py, Auszug</h3><pre><code>import atexit, uuid, logging\nimport httpx\nfrom ki_web_mcp.domain.errors import BackendError, TransportError\nfrom ki_web_mcp.infrastructure.page_mapper import PageMapper\n\nlog = logging.getLogger(__name__)\n\nclass PagesClient:\n    def __init__(self, base_url: str, timeout_seconds: float, retries: int):\n        self._client = httpx.Client(\n            base_url=base_url,\n            timeout=timeout_seconds,\n            headers={\"Accept\": \"application/json\"},\n            follow_redirects=True,\n            transport=httpx.HTTPTransport(retries=retries),\n        )\n        atexit.register(self._client.close)\n\n    def _request(self, method, path, **kw):\n        request_id = uuid.uuid4().hex[:12]\n        headers = kw.pop(\"headers\", {}) | {\"X-Request-Id\": request_id}\n        try:\n            r = self._client.request(method, path, headers=headers, **kw)\n        except httpx.HTTPError as exc:\n            raise TransportError(599, f\"{type(exc).__name__}: {exc}\") from exc\n        ct = r.headers.get(\"content-type\", \"\")\n        if not ct.startswith(\"application/json\"):\n            raise TransportError(r.status_code, f\"non-JSON content_type={ct!r}\")\n        payload = r.json()\n        if r.status_code &gt;= 400:\n            raise BackendError(\n                status=r.status_code,\n                error_code=str(payload.get(\"error\", \"unknown\")),\n                message=str(payload.get(\"message\", \"\")),\n                payload=payload,\n            )\n        return payload</code></pre><p>Wichtige Disziplin: bei <strong>nicht-JSON</strong>-Antworten (Reverse-Proxy-HTML-Errors, Caddy 502-Seiten) wird der Body NICHT in die Tool-Antwort gereicht, sonst sieht das LLM Stack-Traces.</p><h2>8. Schemas, Literal, Annotated, TypedDict</h2><p>Diese Datei ist der Vertrag zwischen Tool und LLM. Das mcp-SDK liest die Type-Hints und erzeugt daraus das JSON-Schema, das die KI vor jedem Aufruf sieht.</p><pre><code>from __future__ import annotations\nfrom typing import Annotated, Literal, Optional, TypedDict\nfrom pydantic import Field\n\nSortField = Literal[\"slug\", \"title\", \"meta_description\", \"updated_at\", \"created_at\"]\nSortDirection = Literal[\"asc\", \"desc\"]\nLimit = Annotated[int, Field(ge=1, le=200)]\nOffset = Annotated[int, Field(ge=0)]\n\nclass PageDict(TypedDict, total=False):\n    id: Optional[int]\n    slug: str\n    title: str\n    meta_description: str\n    content: str\n    created_at: Optional[str]\n    updated_at: Optional[str]\n\nclass PageListResult(TypedDict):\n    total: int\n    items: list[PageDict]\n\nclass DeleteResult(TypedDict):\n    deleted: str</code></pre><p>Mit dieser Datei kann das LLM bei <strong>sort</strong> nur noch die fünf erlaubten Werte schicken, und <strong>limit</strong> bekommt automatisch eine Schranke 1..200.</p><h2>9. Composition-Root + server.py</h2><p>Composition ist die einzige Stelle, an der konkrete Klassen verdrahtet werden. Tests können sie mit Fake-Ports überschreiben.</p><h3>composition.py</h3><pre><code>from typing import Optional\nfrom ki_web_mcp.application.ports import PagesPort\nfrom ki_web_mcp.application.use_cases import PageUseCases\nfrom ki_web_mcp.config import Config\nfrom ki_web_mcp.infrastructure.pages_client import PagesClient\n\nclass Composition:\n    def __init__(self, config: Config, pages: Optional[PagesPort] = None):\n        self.config = config\n        self._pages = pages or PagesClient(\n            base_url=config.api_base,\n            timeout_seconds=config.timeout_seconds,\n            retries=config.retries,\n        )\n        self.use_cases = PageUseCases(self._pages)\n\n    def close(self):\n        self._pages.close()</code></pre><h3>server.py, Tools registrieren</h3><pre><code>import logging, sys\nfrom typing import Optional\nfrom ki_web_mcp.composition import Composition\nfrom ki_web_mcp.config import Config\nfrom ki_web_mcp.schemas import (\n    DeleteResult, Limit, Offset, PageDict, PageListResult,\n    SortDirection, SortField,\n)\n\ndef _configure_logging(level: str) -&gt; None:\n    logging.basicConfig(stream=sys.stderr,\n        level=getattr(logging, level.upper(), logging.WARNING),\n        format=\"%(asctime)s %(levelname)s %(name)s %(message)s\")\n\ndef build_server(composition):\n    from mcp.server.fastmcp import FastMCP\n    mcp = FastMCP(\"ki-web\")\n    uc = composition.use_cases\n\n    @mcp.tool()\n    def list_pages(search: str = \"\",\n                   sort: SortField = \"updated_at\",\n                   direction: SortDirection = \"desc\",\n                   limit: Limit = 50,\n                   offset: Offset = 0) -&gt; PageListResult:\n        '''List pages with optional search, sort and pagination.'''\n        return uc.list_pages(search=search or None, sort=sort,\n                             direction=direction, limit=limit, offset=offset)\n\n    @mcp.tool()\n    def update_page(slug: str,\n                    title: Optional[str] = None,\n                    meta_description: Optional[str] = None,\n                    content: Optional[str] = None) -&gt; PageDict:\n        '''Partial update, provide only the fields you want to change.'''\n        return uc.update_page(slug, title=title,\n                              meta_description=meta_description, content=content)\n\n    # ... get_page, create_page, delete_page analog\n    return mcp\n\ndef main() -&gt; int:\n    if \"--health\" in sys.argv:\n        cfg = Config.from_env()\n        _configure_logging(cfg.log_level)\n        c = Composition(cfg)\n        try:\n            ok = c.use_cases.ping()\n        finally:\n            c.close()\n        print(\"ok\" if ok else \"fail\", file=sys.stderr)\n        return 0 if ok else 1\n    cfg = Config.from_env()\n    _configure_logging(cfg.log_level)\n    c = Composition(cfg)\n    try:\n        build_server(c).run()\n    finally:\n        c.close()\n    return 0\n\nif __name__ == \"__main__\":\n    raise SystemExit(main())</code></pre><p>Beachte die <strong>Goldene stdio-Regel</strong>: <code>logging.basicConfig(stream=sys.stderr)</code> muss vor jedem Tool-Aufruf konfiguriert sein, sonst landet ein Library-Log auf stdout und korrumpiert die JSON-RPC-Frames.</p><h2>10. Wrapper-Script und Installation</h2><h3>/usr/local/bin/ki-web</h3><pre><code>#!/bin/sh\nexec env PYTHONUNBUFFERED=1 /opt/venv/main/bin/python -u -m ki_web_mcp.server \"$@\"</code></pre><p>Beide Schalter zusammen, <strong>PYTHONUNBUFFERED=1</strong> und <strong>python -u</strong>, verhindern, dass Python stdout/stderr puffert.</p><h3>Installation und Lockfile</h3><pre><code>chmod 0755 /usr/local/bin/ki-web\n/opt/venv/main/bin/pip install -e /var/www/mcp\n/opt/venv/main/bin/pip freeze | sort &gt; /var/www/mcp/requirements.lock</code></pre><h2>11. Tests, drei Schichten</h2><h3>conftest.py, FakePages-Port</h3><pre><code>import pytest\nfrom ki_web_mcp.application.ports import PagesPort\nfrom ki_web_mcp.application.use_cases import PageUseCases\nfrom ki_web_mcp.domain.errors import BackendError\nfrom ki_web_mcp.domain.page import Page\n\nclass FakePages(PagesPort):\n    def __init__(self):\n        self._store: dict[str, Page] = {}\n    def create(self, slug, title, meta, content):\n        if slug in self._store:\n            raise BackendError(409, \"already_exists\", slug)\n        p = Page(slug=slug, title=title, meta_description=meta, content=content)\n        self._store[slug] = p\n        return p\n    # list/get/update/delete/ping/close analog\n    def close(self): pass\n\n@pytest.fixture\ndef use_cases(): return PageUseCases(FakePages())</code></pre><h3>test_use_cases.py, Beispiel</h3><pre><code>import pytest\nfrom ki_web_mcp.domain.errors import BackendError\n\ndef test_create_then_get_roundtrip(use_cases):\n    use_cases.create_page(\"foo\", \"Foo\", \"Meta\", \"&lt;h1&gt;x&lt;/h1&gt;\")\n    page = use_cases.get_page(\"foo\")\n    assert page[\"slug\"] == \"foo\"\n\ndef test_create_duplicate_raises_already_exists(use_cases):\n    use_cases.create_page(\"foo\", \"Foo\", \"Meta\", \"&lt;p&gt;x&lt;/p&gt;\")\n    with pytest.raises(BackendError) as exc:\n        use_cases.create_page(\"foo\", \"Foo\", \"Meta\", \"&lt;p&gt;x&lt;/p&gt;\")\n    assert exc.value.status == 409</code></pre><h3>test_schema.py, Subprocess-Roundtrip</h3><p>Stellt sicher, dass jeder Tool-Name und jedes Schema-Detail (Literal-Enums, Range-Bounds, Optional-Felder bei update_page) erhalten bleibt:</p><pre><code>import json, subprocess, sys\n\ndef _send(p, m): p.stdin.write(json.dumps(m) + \"\\n\"); p.stdin.flush()\ndef _rpc(p, m):\n    _send(p, m); return json.loads(p.stdout.readline())\n\ndef test_tools_list_matches_contract():\n    p = subprocess.Popen(\n        [sys.executable, \"-u\", \"-m\", \"ki_web_mcp.server\"],\n        stdin=subprocess.PIPE, stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE, text=True,\n    )\n    try:\n        _rpc(p, {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\n                 \"params\":{\"protocolVersion\":\"2025-03-26\",\n                           \"capabilities\":{},\n                           \"clientInfo\":{\"name\":\"t\",\"version\":\"0\"}}})\n        _send(p, {\"jsonrpc\":\"2.0\",\"method\":\"notifications/initialized\"})\n        resp = _rpc(p, {\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/list\"})\n    finally:\n        try: p.stdin.close()\n        except BrokenPipeError: pass\n        try: p.wait(timeout=2)\n        except subprocess.TimeoutExpired: p.kill(); p.wait(timeout=2)\n    tools = {t[\"name\"]: t for t in resp[\"result\"][\"tools\"]}\n    assert set(tools) == {\"list_pages\",\"get_page\",\"create_page\",\n                          \"update_page\",\"delete_page\"}\n    assert \"enum\" in json.dumps(tools[\"list_pages\"][\"inputSchema\"][\"properties\"][\"sort\"])</code></pre><p>Wichtig: Notifikationen (notifications/initialized) liefern KEINE Antwort, also nicht <strong>readline()</strong> darauf anwenden, sonst blockt der Test.</p><h2>12. MCP-Clients verbinden</h2><p>Schreibweise je CLI mit den jeweiligen kleinen Unterschieden:</p><pre><code># Claude Code, separator vor dem Command\nclaude mcp add ki-web -- /usr/local/bin/ki-web\n\n# Codex, ebenfalls separator\ncodex mcp add ki-web -- /usr/local/bin/ki-web\n\n# qwen-code, KEIN separator\nqwen mcp add ki-web /usr/local/bin/ki-web</code></pre><p>Verifizieren mit <strong>claude mcp list</strong>, <strong>codex mcp list</strong> bzw. <strong>qwen mcp list</strong>, der Eintrag sollte überall als <strong>connected</strong> auftauchen.</p><h2>13. Debugging</h2><h3>Manueller stdio-Roundtrip</h3><p>Wenn ein Client meldet, der Server bricht ab, fährt ein Hand-Test schneller zur Diagnose als Logs:</p><pre><code>printf '%s\\n' \\\n  '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-03-26\",\"capabilities\":{},\"clientInfo\":{\"name\":\"t\",\"version\":\"0\"}}}' \\\n  '{\"jsonrpc\":\"2.0\",\"method\":\"notifications/initialized\"}' \\\n  '{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/list\"}' \\\n  | /usr/local/bin/ki-web | jq .</code></pre><h3>Healthcheck</h3><pre><code>/usr/local/bin/ki-web --health   # exit 0/1, Trockenlauf gegen /api/pages</code></pre><h3>Schema-Drift</h3><p>Wenn das Backend ein Feld umbenennt, fällt der pytest test_schema sofort um, Pflicht-Bestandteil jedes CI-Laufs.</p><h3>stdout-Pollution finden</h3><p>Wenn die JSON-RPC-Antwort kaputt ankommt, ist meistens ein Library-Log das Problem. Test: vom CLI-Wrapper aus <strong>print()</strong> oder Log-Output durch dieses Kommando schicken, alles, was nicht mit <strong>{</strong> beginnt, ist Pollution:</p><pre><code>/usr/local/bin/ki-web &lt; /dev/null 2&gt;/dev/null | head -5\n# Erwartet: nichts (Server wartet auf Input). Kommt da Text raus,\n# stammt er aus stdout-Pollution einer Dependency.</code></pre><h2>14. Weiterlesen</h2><ul><li><a href=\"/mcp-ki-web\">/mcp-ki-web</a>, Architektur-Sicht: was passiert wo, wer kennt wen</li><li><a href=\"/mcp-server-erstellen-regeln\">/mcp-server-erstellen-regeln</a>, die Regeln, die diese Anleitung umsetzt</li><li><strong>/var/www/code/python-mcp/rules.yaml</strong>, maschinenlesbare Variante (25 Regeln)</li><li><a href=\"https://modelcontextprotocol.io/\">modelcontextprotocol.io</a>, Protokoll-Spec</li><li><a href=\"https://github.com/modelcontextprotocol/python-sdk\">github.com/modelcontextprotocol/python-sdk</a>, Python-SDK</li></ul>","created_at":"2026-05-21T03:33:52+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":37,"konversionen":20},{"id":6,"slug":"mcp-vs-api-vs-cli","title":"KI-Werkzeug-Steckplatz (MCP), Web-Schnittstelle (API) oder Kommandozeile (CLI)?","meta_description":"Direkter Vergleich von MCP, HTTP-API und CLI in einfachen Worten, Fachbegriffe in Klammern. Tabellen für Aufrufer, Geschwindigkeit, Sicherheit, Komposition, Eignung.","content":"<h1>Wann ein KI-Werkzeug-Steckplatz (MCP), wann eine Web-Schnittstelle (API), wann ein Kommandozeilen-Tool (CLI)?</h1><p>Diese Seite vergleicht drei Arten, einen Dienst nach außen anzubieten. Sie schließen sich nicht aus, sie sind <strong>verschiedene Schnittstellen zur selben Funktion</strong>. Die Wahl hängt davon ab, wer durch die Tür kommt: ein KI-Assistent, ein anderer Server oder ein Mensch am Terminal.</p><h2>Was die drei in einem Satz sind</h2><table><thead><tr><th>Tür</th><th>Kurzdefinition</th></tr></thead><tbody><tr><td><strong>KI-Werkzeug-Steckplatz</strong> (MCP, Model Context Protocol)</td><td>Ein KI-Assistent (z. B. Claude Code) startet das Programm und kann während des Gesprächs Werkzeuge daraus aufrufen. Das Programm beschreibt sich selbst, der Assistent sieht, was es kann.</td></tr><tr><td><strong>Web-Schnittstelle</strong> (HTTP-API, oft als REST-API gebaut)</td><td>Ein dauerhaft laufender Server beantwortet Anfragen über das Web. Jeder, der die Adresse kennt und die Berechtigung hat, kann zugreifen, Browser, Handy-App, ein anderer Server.</td></tr><tr><td><strong>Kommandozeilen-Tool</strong> (CLI, Command-Line Interface)</td><td>Ein Programm, das man im Terminal aufruft, Argumente übergibt und dessen Text-Ausgabe liest. Standard-Werkzeug auf Linux- und Mac-Systemen, gut mit anderen kombinierbar.</td></tr></tbody></table><h2>Direktvergleich</h2><p>Eine Zeile pro Vergleichs-Kriterium, drei Spalten, so steht alles nebeneinander.</p><table><thead><tr><th>Vergleichs-Kriterium</th><th>MCP</th><th>HTTP-API</th><th>CLI</th></tr></thead><tbody><tr><td><strong>Wer ruft das auf?</strong> (Aufrufer-Typ)</td><td>Ein KI-Assistent (LLM-Agent) wie Claude Code, Codex, qwen-code</td><td>Browser-Frontend, Handy-App, anderer Server, Skript</td><td>Mensch am Terminal, Shell-Skript, CI-Pipeline</td></tr><tr><td><strong>In welcher Form gehen Daten hin und zurück?</strong> (Wire-Format)</td><td>Strukturierte Nachrichten über die Standard-Ein-/Ausgabe (JSON-RPC via stdio) oder über Web (HTTP/SSE)</td><td>Strukturierte Daten über das Web (JSON über HTTP), oft im REST-Stil</td><td>Kommandozeilen-Argumente rein, Text raus, Fehler-Ausgabe und Erfolgs-Signal extra (argv, stdout, stderr, Exit-Code)</td></tr><tr><td><strong>Wie erfährt der Aufrufer, was es überhaupt gibt?</strong> (Discovery)</td><td><strong>Selbstauskunft</strong>: der Server liefert eine Liste aller Werkzeuge mitsamt Beschreibung und Eingabe-Bauplan (tools/list mit JSON-Schema)</td><td>Per externer Dokumentation, in der Regel eine Spec-Datei (OpenAPI / Swagger). Kein Laufzeit-Abfragen.</td><td><strong>--help</strong>, Handbuch-Seite (manpage), README</td></tr><tr><td><strong>Gibt es ein Gedächtnis zwischen Aufrufen?</strong> (State / Session)</td><td>Ja, Werkzeug-Aufrufe sind in ein <strong>laufendes Gespräch</strong> mit dem KI-Assistenten eingebettet (Session)</td><td>Nein, jede Anfrage steht für sich; ein Gedächtnis muss künstlich nachgebaut werden (Stateless + Token / Cookie / Session-Store)</td><td>Nein, jeder Aufruf ist ein neuer Vorgang (Stateless); Persistenz nur über Dateien, Umgebungsvariablen, Sperrdateien</td></tr><tr><td><strong>Wie schnell antwortet es?</strong> (Latenz-Profil)</td><td>Mittel, der Server muss als Hilfsprogramm gestartet werden (Subprozess), dann sind viele Werkzeug-Aufrufe schnell hintereinander möglich</td><td>Niedrig, die Web-Welt ist dafür optimiert (Zwischenspeicherung / Caching, dauerhafte Verbindungen / Keep-Alive, Auslieferungs-Netzwerke / CDN)</td><td>Sehr niedrig, direkter Programm-Aufruf, kein Netzwerk dazwischen</td></tr><tr><td><strong>Wie viele gleichzeitige Nutzer sind möglich?</strong> (Durchsatz / Skalierung)</td><td>Pro Client ein eigenes Hilfsprogramm (Subprocess); für mehrere Nutzer am besten mit Web-Variante (HTTP/SSE) hinter Last-Verteiler</td><td>Beliebig viele dank Last-Verteiler (Load-Balancer) und Skalierung über mehr Server (horizontale Skalierung)</td><td>Ein Aufruf nach dem anderen; Parallel-Aufrufe über Hilfen wie <strong>xargs -P</strong> oder <strong>GNU parallel</strong></td></tr><tr><td><strong>Wem wird vertraut?</strong> (Trust-Boundary)</td><td>Wer das Programm starten darf, darf alle Werkzeuge nutzen, Trust = Datei-Berechtigung auf demselben Rechner</td><td>Trust = gültige Eintritts-Marke (Token) im HTTP-Kopf, optional delegierte Anmeldung (OAuth) oder gegenseitige Zertifikate (mTLS); funktioniert auch über das öffentliche Netz</td><td>Trust = wer das Programm aufrufen darf; über System-Rechte (sudo, Linux-capabilities, Zugriffs-Listen / ACL)</td></tr><tr><td><strong>Wie stabil bleibt die Schnittstelle?</strong> (Vertrags-Stabilität)</td><td><strong>Dynamisch</strong>, die Werkzeug-Liste kann sich pro Sitzung ändern, der KI-Assistent fragt zur Laufzeit ab</td><td>Stabil und versioniert (z. B. /v1/, /v2/); abwärts-inkompatible Änderungen (Breaking Changes) bekommen einen Übergangs-Pfad</td><td>Versioniert über die Programm-Version; veraltete Flags werden in einem Übergangs-Zeitraum (Deprecation) markiert</td></tr><tr><td><strong>Lässt sich mit anderen Tools verketten?</strong> (Kompositionsfähigkeit)</td><td>Niedrig, kein Daten-Weiterleitungs-Modell (Pipe), jeder Aufruf ist eine eigene Nachricht (JSON-RPC-Call)</td><td>Mittel, mit Helfern wie <strong>curl</strong> + <strong>jq</strong> machbar, aber nicht das natürliche Modell</td><td><strong>Hoch</strong>, die Unix-Philosophie ist genau dafür gemacht: Daten-Weiterleitung (Pipe), Verkettung (&amp;&amp;, ;), Build-Werkzeuge (make), Zeitsteuerung (cron)</td></tr><tr><td><strong>Wie wird vor Missbrauch geschützt?</strong> (Sicherheit / Sandbox)</td><td>Tool-Eingaben werden im Server gegen eine Positiv-Liste (Whitelist) geprüft; Werte sind im Bauplan auf Bereiche oder feste Auswahl gebunden (Literal, Range-Bounds)</td><td>Anmeldung im HTTP-Kopf (Header-Auth), Anfrage-Begrenzung (Rate-Limit), Web-Schutz-Firewall (WAF), Schutz vor Querverweis-Angriffen (CORS, CSRF)</td><td>Datei-System-Berechtigungen, sudo-Regeln, Sicherheits-Profile (AppArmor), Linux-Capabilities</td></tr><tr><td><strong>Was kann man im Nachhinein sehen?</strong> (Observability / Logs)</td><td>Aufzeichnung der JSON-RPC-Nachrichten, MCP-Inspector, Fehler-Ausgabe (stderr) des Hilfsprogramms</td><td>Zugriffs-Logs des Web-Servers, OpenTelemetry-Spuren, Header-basiertes Tracing</td><td>Fehler-Ausgabe (stderr), Erfolgs-Signal (Exit-Code), System-Logs (journal / syslog), Audit-Log</td></tr><tr><td><strong>Wie wird es installiert und betrieben?</strong> (Deployment)</td><td>Ein Wrapper-Programm auf dem Suchpfad ($PATH) + ein Eintrag in der Config des KI-Assistenten</td><td>Dauerhaft laufender Dienst (Long-running Service) hinter einem vorgelagerten Proxy (Reverse-Proxy)</td><td>Programm-Datei auf dem Suchpfad ($PATH); pro Rechner installiert</td></tr><tr><td><strong>Was passiert, wenn ich dasselbe zweimal aufrufe?</strong> (Idempotenz)</td><td>Im Werkzeug-Docstring beschrieben; die KI sollte sich daran halten, keine harte Garantie</td><td>Durch die HTTP-Methode definiert: <strong>GET</strong>, <strong>PUT</strong>, <strong>DELETE</strong> sind wiederholbar ohne Nebeneffekte; <strong>POST</strong> nicht</td><td>Konvention pro Werkzeug; oft als Flag (<strong>--idempotent</strong>, <strong>--retry</strong>)</td></tr><tr><td><strong>Häufiger Denkfehler</strong> (Anti-Pattern)</td><td>Aus jeder vorhandenen Web-API automatisch einen MCP machen, die Werkzeug-Liste wird unüberschaubar</td><td>Ein lokales CLI-Programm in einen Web-Server umhüllen, viel Aufwand, wenig Nutzen</td><td>Aus dem CLI heraus selbst Server starten, um parallel zu skalieren, gehört dann in eine API</td></tr></tbody></table><h2>Geeignet, wenn ...</h2><p>Lesehilfe: <strong>(+)</strong> erste Wahl, <strong>(o)</strong> möglich, <strong>(-)</strong> ungeeignet.</p><table><thead><tr><th>Situation</th><th>MCP</th><th>HTTP-API</th><th>CLI</th></tr></thead><tbody><tr><td>Hauptnutzer ist ein KI-Assistent (LLM-Agent)</td><td>(+)</td><td>(o) als Backend dahinter</td><td>(o) wenn der Assistent Shell-Tools nutzen darf</td></tr><tr><td>Mehrere Konsumenten teilen sich dieselbe Logik</td><td>(o) als Hülle</td><td>(+)</td><td>(-) nur lokal</td></tr><tr><td>Mensch am Terminal, ad-hoc</td><td>(-)</td><td>(o) via curl</td><td>(+)</td></tr><tr><td>Build- oder CI-Pipeline</td><td>(-) klobig</td><td>(+)</td><td>(+)</td></tr><tr><td>Browser-Frontend</td><td>(-)</td><td>(+)</td><td>(-)</td></tr><tr><td>Werkzeug-Liste situativ / kontextspezifisch</td><td>(+)</td><td>(-) starr</td><td>(-) starr</td></tr><tr><td>Compliance verlangt formales Schnittstellen-Verzeichnis (OpenAPI)</td><td>(o) JSON-RPC-Schema</td><td>(+)</td><td>(-)</td></tr><tr><td>Auf demselben Rechner, Trust = Datei-Berechtigungen</td><td>(+)</td><td>(o) Overhead</td><td>(+)</td></tr><tr><td>Aufrufer kommt über das öffentliche Netz</td><td>(-) außer HTTP-Transport</td><td>(+)</td><td>(-)</td></tr><tr><td>Hohe Anfrage-Frequenz, niedrige Antwort-Zeit</td><td>(o)</td><td>(+)</td><td>(+)</td></tr><tr><td>Lange Gesprächs-Sitzungen mit Gedächtnis</td><td>(+)</td><td>(o) mit Session-Store</td><td>(-)</td></tr><tr><td>Verkettung mit jq / grep / xargs / make</td><td>(-)</td><td>(o) via curl</td><td>(+)</td></tr></tbody></table><h2>Entscheidungs-Fragen in Reihenfolge</h2><p>Wenn die Tabellen schon helfen, kann diese Liste übersprungen werden. Falls nicht, fünf Fragen, in dieser Reihenfolge beantwortet:</p><ol><li>Ist der Hauptnutzer ein <strong>KI-Assistent</strong>, der Werkzeuge braucht? → <strong>MCP</strong> (KI-Werkzeug-Steckplatz).</li><li>Brauchen <strong>Browser, App oder andere Server</strong> dieselbe Funktion auch? → <strong>HTTP-API</strong> ist die Wahrheit, der MCP wird ein dünner Adapter darüber.</li><li>Ist der Aufrufer ein <strong>Mensch oder Skript am selben Rechner</strong>? → <strong>CLI</strong> (Kommandozeilen-Tool).</li><li>Soll der Aufrufer die Werkzeug-Liste <strong>zur Laufzeit entdecken</strong>? → MCP gewinnt gegen API, weil das Protokoll Selbstbeschreibung mitbringt.</li><li>Soll die eigentliche Logik <strong>nur an einer Stelle</strong> leben? → sie gehört in die API. MCP und CLI werden dann zu dünnen Hüllen.</li></ol><h2>So sieht das Muster im aktuellen Projekt aus</h2><table><thead><tr><th>Schicht</th><th>Verantwortung</th><th>In diesem Projekt</th></tr></thead><tbody><tr><td>Geschäftslogik (Kern, Use Cases)</td><td>Eingaben-Prüfung (Validierung), HTML-Bereinigung (Sanitization), Datenspeicherung (Persistence)</td><td>PHP-Code in <strong>/var/www/ki.karlkratz.com/src/</strong></td></tr><tr><td>Web-Schnittstelle (HTTP-API)</td><td>Stabile, versionierbare Außenseite</td><td><a href=\"/api/pages\">/api/pages</a>, Anlegen / Lesen / Ändern / Löschen (POST / GET / PATCH / DELETE)</td></tr><tr><td>KI-Werkzeug-Steckplatz (MCP-Adapter)</td><td>Werkzeug-Schemata bereitstellen, Selbstbeschreibung, Kommunikation per stdio</td><td><strong>/var/www/mcp/</strong>, startbar via <strong>/usr/local/bin/ki-web</strong></td></tr><tr><td>Kommandozeilen-Tool (CLI, optional)</td><td>Skript-, Cron- oder Pipe-Zugriff</td><td>Nicht implementiert; würde denselben HTTP-Aufruf gegen <a href=\"/api/pages\">/api/pages</a> machen</td></tr></tbody></table><p>Drei Schnittstellen über einer gemeinsamen Geschäftslogik. Mehr zur Architektur unter <a href=\"/mcp-ki-web\">/mcp-ki-web</a>, die Regeln, an denen wir messen, in <a href=\"/mcp-server-erstellen-regeln\">/mcp-server-erstellen-regeln</a>.</p><h2>Was die drei nicht ersetzen</h2><p>Keine dieser Schnittstellen ersetzt das Nachdenken darüber, <strong>welche Operation überhaupt erlaubt sein soll</strong>. Die Prüf- und Positiv-Listen-Logik (Validierung und Whitelist) gehört unabhängig von der Hülle an genau eine Stelle, sonst entsteht das klassische Problem, dass das CLI strenger prüfen als die API, oder dass der MCP einen Pfad freigibt, den der Browser nicht aufrufen darf. Wer alle drei Hüllen baut, baut sie um einen einzigen, sauber abgegrenzten Kern.</p>","created_at":"2026-05-21T03:09:01+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":10,"konversionen":22},{"id":32,"slug":"web-scraping","title":"Web-Scraping im Karl-Kratz-System","meta_description":"Wie ki-web und kw-scrape zusammenspielen, welche Schnittstellen sie anbieten und welches Architekturmuster dahinter steht.","content":"<h1>Web-Scraping im Karl-Kratz-System</h1><p>Diese Seite beschreibt, wie Web-Scraping unter ki.karlkratz.com eingebettet ist: die beiden fachlichen Bausteine ki-web und kw-scrape, ihre Schnittstellen und das gemeinsame Architekturmuster dahinter.</p><h2>Die Bausteine</h2><h3>ki-web</h3><p>Verwaltet die Seiten dieser Domain (Slug, Titel, Meta-Description, HTML-Content). Die Geschäftslogik (Slug-Regex, HTML-Sanitization, Längen-Limits) liegt einmalig in der PHP-Schicht unter <a href=\"/api/pages\">/api/pages</a> und schreibt nach Postgres. Alle weiteren Zugriffsformen sind dünne Adapter über diese eine API.</p><h3>kw-scrape</h3><p>Eine eigenständige Python-Engine. Sie holt externe URLs mit httpx ab, extrahiert mit trafilatura den Hauptinhalt plus Metadaten (Titel, Autor, Datum, Sprache, Sitename) und gibt eine ScrapeResult-Datenstruktur zurück. JavaScript-gerenderte Seiten werden in dieser Ausbaustufe bewusst nicht unterstützt, weil dafür Playwright nötig wäre und der zusätzliche Aufwand sich für die aktuellen Anwendungsfälle nicht rechnet.</p><h2>Die Schnittstellen-Klassen</h2><p>Jeder Baustein wird über dieselbe Logik aus mehreren Richtungen bedient. Die Klassen sind komplementär und adressieren unterschiedliche Aufrufer.</p><table><thead><tr><th>Klasse</th><th>Wer ruft auf</th><th>ki-web</th><th>kw-scrape</th></tr></thead><tbody><tr><td>HTTP-API</td><td>Browser, andere Server</td><td>/api/pages (PHP)</td><td>noch nicht exponiert</td></tr><tr><td>CLI</td><td>Mensch am Terminal, Skripte, CI</td><td>ki-web-cli</td><td>scrape-cli</td></tr><tr><td>MCP-Server</td><td>Claude Code, Codex, qwen-code</td><td>ki-web</td><td>in Planung</td></tr></tbody></table><h2>Architekturmuster</h2><p>Beide Codebasen folgen dem gleichen DDD-Hexagonal-Schnitt mit drei Schichten.</p><ol><li>Domain: reine Datenstrukturen (Page, ScrapeResult, RawFetch, Extracted) und domänenspezifische Fehler. Kennt weder HTTP noch ein Framework.</li><li>Application: Ports als Python-Protocols (PagesPort, FetcherPort, ExtractorPort) und Use Cases, die die Operationen orchestrieren.</li><li>Infrastructure: die Adapter. PdoPageRepository für Postgres, HttpxFetcher für das Web, TrafilaturaExtractor für die HTML-Analyse, JsonHttpClient für die /api/pages-Aufrufe.</li></ol><p>Die Application-Schicht spricht ausschließlich mit Ports. Konkrete Adapter werden in einem Composition-Root injiziert, sodass Tests den Fetcher gegen einen FakeFetcher tauschen können, ohne das Netzwerk zu berühren. Die gleiche Technik erlaubt, später eine PlaywrightFetcher-Implementierung der FetcherPort hinterzulegen, ohne die Use Cases zu ändern.</p><h2>DRY-Schnitt: wo die Wahrheit lebt</h2><p>Geschäftsregeln existieren genau einmal. Für ki-web liegen sie in der PHP-API. Für kw-scrape im Python-Paket unter <code>/var/www/scrape/</code>. CLI und MCP sind Adapter über diese Engines. Wenn eine Validierung ergänzt werden muss, geschieht das an einer Stelle, nicht parallel in mehreren Clients.</p><h2>Output-Formate der CLIs</h2><p>Sowohl ki-web-cli als auch scrape-cli kennen drei Output-Formate, gesteuert über <code>--format</code>.</p><ul><li><strong>json</strong>: strukturierte Vollausgabe, Default. Geeignet für jq-Pipes und Skripte.</li><li><strong>table</strong>: Spaltenausgabe mit Header und Footer. Für die interaktive Shell.</li><li><strong>plain</strong>: ohne Dekoration. Eine Zeile pro Datensatz, Tab-separierte Spalten. Geeignet für xargs, cut und awk.</li></ul><p>Über <code>--columns slug,title,updated_at</code> lassen sich in table und plain einzelne Felder herausziehen. In json hat das Flag keine Wirkung, weil dort die volle Struktur ohnehin verfügbar ist.</p><h2>Beispiele</h2><h3>ki-web</h3><pre><code>ki-web-cli list --search mcp --limit 5\nki-web-cli get hallo-welt\nki-web-cli --format plain --columns slug list\necho '&lt;h1&gt;Demo&lt;/h1&gt;' | ki-web-cli create --slug demo \\\n  --title \"Demo\" --meta-description \"Test\" --content-file -</code></pre><h3>kw-scrape</h3><pre><code>scrape-cli fetch https://ki.karlkratz.com/mcp-vs-api-vs-cli\nscrape-cli fetch URL | jq -r '.markdown'\nscrape-cli --format table --columns title,sitename,status fetch URL\nscrape-cli batch --file urls.txt -c 20</code></pre><h2>Was bewusst nicht im System ist</h2><ul><li>Kein JavaScript-Rendering. Statische HTML-Seiten werden vollständig unterstützt, JS-gesteuerter Inhalt bleibt zunächst außen vor.</li><li>Keine git-basierten Workflows. Pre-commit-Hooks, CI-Pipelines und PR-Reviews sind in diesem Projekt nicht vorgesehen.</li><li>Keine doppelt gehaltenen Validierungsregeln. Sanitization bleibt in der PHP-Schicht, nicht in den Clients.</li><li>Keine eigene HTTP-API für kw-scrape. Aktuell wird die Engine direkt als Python-Library importiert. Ein /api/scrape-Endpoint folgt erst, wenn ein nicht-Python-Konsument hinzukommt.</li></ul><h2>Wichtigste Pfade</h2><table><thead><tr><th>Pfad</th><th>Inhalt</th></tr></thead><tbody><tr><td>/var/www/ki.karlkratz.com/src/</td><td>PHP-Backend mit /api/pages</td></tr><tr><td>/var/www/mcp/</td><td>MCP-Server ki-web (Python, stdio)</td></tr><tr><td>/var/www/cli/shared/</td><td>Wiederverwendbare CLI-Infrastruktur (PresenterFactory, Streams, Exit-Codes, Help-Aliasse)</td></tr><tr><td>/var/www/cli/ki-web/</td><td>CLI ki-web-cli</td></tr><tr><td>/var/www/scrape/</td><td>Engine kw-scrape</td></tr><tr><td>/var/www/cli/scrape/</td><td>CLI scrape-cli</td></tr><tr><td>/var/www/mcp.scrape/</td><td>geplanter MCP-Server für kw-scrape</td></tr></tbody></table>","created_at":"2026-05-21T11:34:28+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":95,"konversionen":31},{"id":40,"slug":"kw-scrape","title":"kw-scrape: Engine, CLI und MCP","meta_description":"Die kw-scrape-Komponente im Detail: httpx plus trafilatura, das CLI scrape-cli, der MCP-Server, Tool-Surface, Beispiele und Grenzen.","content":"<h1>kw-scrape: Engine, CLI und MCP</h1><p>Diese Seite beschreibt die kw-scrape-Komponente im Detail. Die Einbettung ins Gesamtsystem (Beziehung zu ki-web, gemeinsames Architekturmuster, Schreib- und DRY-Regeln) steht auf der Seite <a href=\"/web-scraping\">/web-scraping</a>.</p><h2>Was kw-scrape macht</h2><p>kw-scrape holt eine oder viele externe URLs, extrahiert den Hauptinhalt als Markdown plus strukturierte Metadaten und gibt das Ergebnis als JSON-serialisierbare Datenstruktur zurück. Das Paket ist in drei Schichten aufgeteilt: eine Engine-Library, ein klassisches CLI und ein MCP-Server für AI-Tools.</p><h2>Stack</h2><ul><li><strong>httpx 0.28</strong>: synchroner Fetch mit Connection-Pooling und Thread-Pool für parallele Batches.</li><li><strong>trafilatura 2.0</strong>: Erkennung des Hauptinhalts, Boilerplate-Entfernung, Metadaten-Extraktion, Markdown-Rendering.</li><li><strong>Python 3.13</strong>: dataclasses, frozen Slots, Protocol-Ports.</li></ul><p>Bewusst nicht enthalten: JavaScript-Rendering. Dynamisch nachgeladener Inhalt wird in dieser Ausbaustufe nicht gesehen.</p><h2>Drei Schnittstellen, eine Engine</h2><table><thead><tr><th>Schicht</th><th>Pfad</th><th>Zugriff</th></tr></thead><tbody><tr><td>Engine (Library)</td><td>/var/www/scrape/</td><td>direkter Python-Import: <code>from kw_scrape.composition import Composition</code></td></tr><tr><td>CLI (scrape-cli)</td><td>/var/www/cli/scrape/</td><td>Wrapper <code>/usr/local/bin/scrape-cli</code></td></tr><tr><td>MCP-Server</td><td>/var/www/mcp/scrape/</td><td>Wrapper <code>/usr/local/bin/scrape</code> (stdio JSON-RPC)</td></tr></tbody></table><p>Die CLI- und MCP-Schichten sind dünne Adapter um dieselbe Engine. Geschäftslogik liegt einmalig in der Engine.</p><h2>Tool-Surface</h2><p>Die drei Tools sind in CLI und MCP semantisch identisch, nur die Aufrufform unterscheidet sich.</p><table><thead><tr><th>Tool</th><th>Zweck</th><th>Hauptargumente</th></tr></thead><tbody><tr><td><code>fetch_url</code> (CLI: <code>fetch</code>)</td><td>Eine URL holen, Hauptinhalt plus Metadaten</td><td>url, want_markdown, want_text, include_raw_html</td></tr><tr><td><code>extract_html</code> (CLI: <code>extract</code>)</td><td>Markdown aus rohem HTML, ohne Netzwerk-Aufruf</td><td>html, base_url, want_markdown, want_text</td></tr><tr><td><code>scrape_urls</code> (CLI: <code>batch</code>)</td><td>Viele URLs parallel, getrennte Erfolg- und Fehlerlisten</td><td>urls, concurrency (1 bis 50), want_markdown, want_text</td></tr></tbody></table><h2>Rückgabe-Struktur (ScrapeResult)</h2><p>Bei <code>fetch_url</code> und jedem Eintrag in <code>scrape_urls.items</code>:</p><ul><li><strong>url</strong>: finale URL nach Redirects</li><li><strong>status</strong>: HTTP-Status, 200 für Erfolg</li><li><strong>byte_size</strong>: ungekürzte HTML-Länge</li><li><strong>fetched_at</strong>: ISO 8601 mit Zeitzone</li><li><strong>title</strong>, <strong>author</strong>, <strong>date</strong>, <strong>description</strong>, <strong>sitename</strong>, <strong>language</strong>: Metadaten von trafilatura, jeweils optional</li><li><strong>markdown</strong>: Markdown-Rendering des Hauptinhalts (None falls want_markdown=False)</li><li><strong>text</strong>: Plain-Text-Variante (None falls want_text=False)</li><li><strong>html_raw</strong>: rohes HTML (None falls include_raw_html=False)</li></ul><h2>CLI-Beispiele</h2><h3>Eine Seite holen</h3><pre><code>scrape-cli fetch https://lisa-sundermeyer.de\nscrape-cli --format table --columns title,sitename,date,language fetch https://lisa-sundermeyer.de\nscrape-cli fetch https://lisa-sundermeyer.de | jq -r '.markdown'</code></pre><h3>HTML aus stdin oder Datei extrahieren</h3><pre><code>cat seite.html | scrape-cli extract --base-url https://example.com/\nscrape-cli extract --file seite.html --base-url https://example.com/</code></pre><h3>Batch mit Fehler-Trennung</h3><pre><code>printf '%s\\n' \\\n  https://ki.karlkratz.com/hallo-welt \\\n  https://ki.karlkratz.com/mcp-demo \\\n  https://ki.karlkratz.com/missing \\\n  | scrape-cli batch -c 3 \\\n  | jq '{total, ok: (.items | length), fail: (.errors | length)}'</code></pre><h3>Pipeline: Root holen, interne Links folgen</h3><pre><code>scrape-cli fetch https://lisa-sundermeyer.de \\\n  | jq -r '.markdown' \\\n  | grep -oE '\\(https://lisa-sundermeyer\\.de/[^)#]+\\)' \\\n  | tr -d '()' \\\n  | sort -u | head -5 \\\n  | scrape-cli --format plain --columns url,title batch -c 5</code></pre><h2>MCP-Integration in drei AI-CLIs</h2><p>Der MCP-Server ist als <code>kw-scrape</code> in allen drei lokalen AI-CLIs registriert: Claude Code, Codex und qwen-code. Tool-Aufrufe laufen über stdio JSON-RPC durch <code>/usr/local/bin/scrape</code>.</p><h3>Claude Code</h3><pre><code>// ~/.claude.json, je Projekt unter mcpServers\n\"kw-scrape\": {\n  \"type\": \"stdio\",\n  \"command\": \"/usr/local/bin/scrape\",\n  \"args\": [],\n  \"env\": {}\n}</code></pre><h3>Codex</h3><pre><code># ~/.codex/config.toml\n[mcp_servers.kw-scrape]\ncommand = \"/usr/local/bin/scrape\"</code></pre><h3>qwen-code</h3><pre><code>// ~/.qwen/settings.json, top-level mcpServers\n\"kw-scrape\": {\n  \"command\": \"/usr/local/bin/scrape\",\n  \"args\": []\n}</code></pre><h2>Performance</h2><p>Eine Seite kostet ungefähr 200 ms Fetch und 30 bis 50 ms Extraktion. Mit Concurrency 10 erreicht das CLI 30 bis 50 Seiten pro Sekunde, bis die Höflichkeit gegen den Zielserver greift. Die typische Decke ist nicht das Tool, sondern die Rate-Limits der Gegenseite.</p><h2>Env-Variablen</h2><table><thead><tr><th>Variable</th><th>Default</th><th>Wirkung</th></tr></thead><tbody><tr><td>KW_SCRAPE_TIMEOUT</td><td>15.0</td><td>HTTP-Timeout in Sekunden</td></tr><tr><td>KW_SCRAPE_RETRIES</td><td>1</td><td>Transport-Retries bei netzseitigen Fehlern</td></tr><tr><td>KW_SCRAPE_USER_AGENT</td><td>kw-scrape/0.1 (+https://ki.karlkratz.com)</td><td>User-Agent-Header</td></tr><tr><td>KW_SCRAPE_MAX_BYTES</td><td>5000000</td><td>Hartes Limit pro Response (5 MB)</td></tr><tr><td>KW_SCRAPE_CONCURRENCY</td><td>10</td><td>Default-Parallelität für Batch</td></tr></tbody></table><h2>Exit-Codes (CLI)</h2><table><thead><tr><th>Code</th><th>Bedeutung</th></tr></thead><tbody><tr><td>0</td><td>OK</td></tr><tr><td>1</td><td>Generischer Fehler</td></tr><tr><td>2</td><td>Usage-Fehler (argparse)</td></tr><tr><td>3</td><td>HTTP 404</td></tr><tr><td>4</td><td>Validierung oder Extract-Fehler</td></tr><tr><td>5</td><td>Backend 5xx</td></tr><tr><td>6</td><td>Transport-Fehler (DNS, Timeout, non-JSON)</td></tr></tbody></table><h2>Grenzen</h2><ul><li>Kein JavaScript-Rendering. Statische HTML-Seiten werden vollständig unterstützt, JS-gesteuerter Inhalt ist nicht sichtbar.</li><li>Kein Sitemap-Crawling, keine Job-Queue, kein Resume. Für mehrere tausend URLs in einem Lauf wäre ein Vollframework (Scrapy oder Crawlee) geeigneter.</li><li>Keine HTTP-API. Die Engine wird direkt als Python-Library importiert. Ein zusätzlicher <code>/api/scrape</code>-Endpoint folgt erst, wenn ein nicht-Python-Konsument hinzukommt.</li><li>Keine eingebaute Authentifizierung. URLs hinter Login sind nicht erreichbar.</li></ul><h2>Erweiterungspunkt: PlaywrightFetcher</h2><p>Die <code>FetcherPort</code>-Schnittstelle ist genau eine Methode: <code>fetch(url)</code> plus <code>fetch_many(urls, concurrency)</code>. Eine zukünftige Playwright-Implementierung lässt sich an dieser Stelle einhängen, ohne UseCases oder die anderen Adapter zu ändern. Der Composition-Root entscheidet, welcher Fetcher genutzt wird.</p><h2>Wichtigste Pfade</h2><table><thead><tr><th>Pfad</th><th>Inhalt</th></tr></thead><tbody><tr><td>/var/www/scrape/</td><td>Engine kw-scrape, Library</td></tr><tr><td>/var/www/cli/scrape/</td><td>CLI scrape-cli</td></tr><tr><td>/var/www/mcp/scrape/</td><td>MCP-Server kw-scrape</td></tr><tr><td>/usr/local/bin/scrape-cli</td><td>CLI-Wrapper</td></tr><tr><td>/usr/local/bin/scrape</td><td>MCP-Wrapper (stdio)</td></tr><tr><td>/etc/bash_completion.d/scrape-cli</td><td>Bash-Completion für das CLI</td></tr></tbody></table>","created_at":"2026-05-21T12:04:52+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":1,"konversionen":2},{"id":33,"slug":"api-referenz","title":"API-Referenz","meta_description":"Endpoints, Validierung, Statuscodes und Beispiele der JSON-API unter /api/pages.","content":"<h1>API-Referenz</h1><p>Die JSON-API von ki.karlkratz.com verwaltet die Seiten, die unter <a href=\"/\">/</a> sowie unter den jeweiligen Slug-URLs ausgeliefert werden. Diese Seite beschreibt jeden Endpoint, das Eingabe-Schema, mögliche Antworten und die Validierungsregeln, die serverseitig durchgesetzt werden.</p><h2>Basisinformationen</h2><table><thead><tr><th>Aspekt</th><th>Wert</th></tr></thead><tbody><tr><td>Basis-URL</td><td><code>https://ki.karlkratz.com/api/pages</code></td></tr><tr><td>Format Anfrage</td><td><code>application/json</code>, UTF-8</td></tr><tr><td>Format Antwort</td><td><code>application/json; charset=utf-8</code></td></tr><tr><td>Authentifizierung</td><td>keine (Demo-System, durch Hetzner-Firewall öffentlich für 0.0.0.0/0 auf Port 443 erreichbar)</td></tr><tr><td>Versionierung</td><td>keine; das Schema steht im PHP-Quelltext unter <code>/var/www/ki.karlkratz.com/src/</code></td></tr><tr><td>Erlaubte HTML-Tags im Feld <code>content</code></td><td><code>h1</code>, <code>h2</code>, <code>h3</code>, <code>p</code>, <code>ol</code>, <code>ul</code>, <code>li</code>, <code>a</code> (mit <code>href</code> und <code>title</code>), <code>strong</code>, <code>table</code>, <code>thead</code>, <code>tbody</code>, <code>tr</code>, <code>th</code>, <code>td</code>, <code>pre</code>, <code>code</code></td></tr></tbody></table><h2>Endpoints im Überblick</h2><table><thead><tr><th>Methode</th><th>Pfad</th><th>Zweck</th></tr></thead><tbody><tr><td>GET</td><td><code>/api/pages</code></td><td>Liste mit Suche, Sortierung, Pagination</td></tr><tr><td>POST</td><td><code>/api/pages</code></td><td>Neue Seite anlegen, alle Felder erforderlich</td></tr><tr><td>GET</td><td><code>/api/pages/&lt;slug&gt;</code></td><td>Eine Seite lesen</td></tr><tr><td>PATCH</td><td><code>/api/pages/&lt;slug&gt;</code></td><td>Felder einzeln aktualisieren</td></tr><tr><td>PUT</td><td><code>/api/pages/&lt;slug&gt;</code></td><td>Alias auf PATCH, identische Semantik</td></tr><tr><td>DELETE</td><td><code>/api/pages/&lt;slug&gt;</code></td><td>Seite löschen</td></tr></tbody></table><h2>Datenstruktur einer Seite</h2><p>Jede Seite hat folgende Felder. Pflicht beim Anlegen sind <code>slug</code>, <code>title</code>, <code>meta_description</code> und <code>content</code>.</p><table><thead><tr><th>Feld</th><th>Typ</th><th>Pflicht beim Anlegen</th><th>Regeln</th></tr></thead><tbody><tr><td>id</td><td>Integer</td><td>nein</td><td>wird serverseitig vergeben (BIGSERIAL)</td></tr><tr><td>slug</td><td>String</td><td>ja</td><td>Regex <code>^[a-z0-9][a-z0-9-]{0,63}$</code>, eindeutig</td></tr><tr><td>title</td><td>String</td><td>ja</td><td>1 bis 200 Zeichen</td></tr><tr><td>meta_description</td><td>String</td><td>ja</td><td>1 bis 200 Zeichen, SEO-Empfehlung 50 bis 160</td></tr><tr><td>content</td><td>String (HTML)</td><td>ja</td><td>wird per DOMDocument auf die Tag-Whitelist gefiltert</td></tr><tr><td>created_at</td><td>ISO-8601-Timestamp</td><td>nein</td><td>serverseitig gesetzt</td></tr><tr><td>updated_at</td><td>ISO-8601-Timestamp</td><td>nein</td><td>Trigger aktualisiert bei jedem Schreibvorgang</td></tr></tbody></table><h2>GET /api/pages, Liste lesen</h2><h3>Query-Parameter</h3><table><thead><tr><th>Parameter</th><th>Default</th><th>Erlaubt</th></tr></thead><tbody><tr><td>q</td><td>leer</td><td>Volltext über slug, title, meta_description (case-insensitive Substring)</td></tr><tr><td>sort</td><td><code>updated_at</code></td><td><code>slug</code>, <code>title</code>, <code>meta_description</code>, <code>updated_at</code>, <code>created_at</code></td></tr><tr><td>dir</td><td><code>desc</code></td><td><code>asc</code>, <code>desc</code></td></tr><tr><td>limit</td><td>50</td><td>1 bis 200</td></tr><tr><td>offset</td><td>0</td><td>0 oder positiv</td></tr></tbody></table><h3>Beispiel</h3><pre><code>curl -sS 'https://ki.karlkratz.com/api/pages?q=mcp&amp;sort=updated_at&amp;dir=desc&amp;limit=10'</code></pre><h3>Antwortformat</h3><pre><code>{\n  \"total\": 7,\n  \"items\": [\n    {\n      \"id\": 16,\n      \"slug\": \"mcp-anleitung\",\n      \"title\": \"MCP-Server bauen, die ki-web-Anleitung\",\n      \"meta_description\": \"...\",\n      \"content\": \"&lt;h1&gt;...&lt;/h1&gt;...\",\n      \"created_at\": \"2026-05-21T03:33:52+02:00\",\n      \"updated_at\": \"2026-05-21T11:42:18+02:00\"\n    }\n  ]\n}</code></pre><h2>GET /api/pages/&lt;slug&gt;, eine Seite lesen</h2><pre><code>curl -sS https://ki.karlkratz.com/api/pages/mcp-anleitung | jq .</code></pre><p>Antwort: identische Struktur wie ein einzelnes Item aus dem Listen-Endpoint. Status <code>200</code> oder <code>404</code>, wenn der Slug nicht existiert.</p><h2>POST /api/pages, neue Seite anlegen</h2><h3>Request-Body</h3><pre><code>{\n  \"slug\": \"neue-seite\",\n  \"title\": \"Neue Seite\",\n  \"meta_description\": \"Kurze Beschreibung der Seite, 50 bis 160 Zeichen.\",\n  \"content\": \"&lt;h1&gt;Überschrift&lt;/h1&gt;&lt;p&gt;Inhalt mit &lt;strong&gt;Hervorhebung&lt;/strong&gt;.&lt;/p&gt;\"\n}</code></pre><h3>Antworten</h3><ul><li><code>201 Created</code> mit dem angelegten Datensatz inklusive <code>id</code>, <code>created_at</code>, <code>updated_at</code></li><li><code>409 Conflict</code> wenn der Slug bereits vergeben ist</li><li><code>422 Unprocessable Entity</code> bei Validierungsfehlern (zum Beispiel Slug-Regex verletzt, Titel zu kurz)</li></ul><h3>Beispiel</h3><pre><code>curl -sS -X POST https://ki.karlkratz.com/api/pages \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"slug\":\"hallo\",\"title\":\"Hallo\",\"meta_description\":\"Eine Begruessung.\",\"content\":\"&lt;h1&gt;Hallo&lt;/h1&gt;\"}'</code></pre><h2>PATCH /api/pages/&lt;slug&gt;, Felder ändern</h2><p>Der Request-Body enthält nur die Felder, die geändert werden sollen. Nicht gelieferte Felder bleiben unverändert. PUT verhält sich identisch.</p><pre><code>curl -sS -X PATCH https://ki.karlkratz.com/api/pages/hallo \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"title\":\"Hallo Welt\"}'</code></pre><p>Antworten: <code>200</code> mit aktualisiertem Datensatz, <code>404</code> wenn der Slug nicht existiert, <code>422</code> bei Validierungsfehlern.</p><h2>DELETE /api/pages/&lt;slug&gt;, Seite löschen</h2><pre><code>curl -sS -X DELETE https://ki.karlkratz.com/api/pages/hallo</code></pre><p>Antwort:</p><pre><code>{\"deleted\": \"hallo\"}</code></pre><p>Status <code>200</code> bei Erfolg, <code>404</code> wenn der Slug nicht existiert.</p><h2>Fehlerformat</h2><p>Fehlerantworten haben einheitliche Struktur:</p><pre><code>{\n  \"error\": \"validation\",\n  \"message\": \"Title length must be 1..200, got 0\"\n}</code></pre><table><thead><tr><th>error</th><th>Status</th><th>Bedeutung</th></tr></thead><tbody><tr><td>not_found</td><td>404</td><td>Slug existiert nicht, oder Pfad ist unbekannt</td></tr><tr><td>already_exists</td><td>409</td><td>POST mit bereits vergebenem Slug</td></tr><tr><td>validation</td><td>422</td><td>Eingabe verletzt eine Regel (Slug-Regex, Längen, Content-Sanitization)</td></tr><tr><td>method_not_allowed</td><td>405</td><td>HTTP-Methode ist auf diesem Pfad nicht unterstützt</td></tr><tr><td>internal</td><td>500</td><td>interner Fehler, Details stehen im Server-Log <code>/var/log/frankenphp/access.log</code></td></tr></tbody></table><h2>Content-Sanitization im Detail</h2><p>Beim Schreiben (POST und PATCH) wird das Feld <code>content</code> per DOMDocument geparst und alle Tags ausserhalb der Whitelist werden entfernt. Das <code>a</code>-Tag akzeptiert nur die Attribute <code>href</code> und <code>title</code>; <code>href</code> muss ein gültiges Schema sein: <code>http</code>, <code>https</code>, <code>mailto</code> oder ein relativer Pfad beginnend mit <code>/</code> oder <code>#</code>. Andere Werte wie <code>javascript:</code> werden ohne Warnung entfernt.</p><p>Code-Beispiele innerhalb von <code>pre</code> oder <code>code</code> müssen vom Aufrufer mit HTML-Entities geliefert werden (<code>&amp;lt;</code> für <code>&lt;</code>, <code>&amp;gt;</code> für <code>&gt;</code>), damit der Sanitizer sie nicht als Markup missversteht.</p><h2>Versionierung und Wiederherstellung</h2><p>Jede Aenderung an einer bestehenden Zeile in <code>pages</code> archiviert die alte Version datenbankseitig vor dem Schreiben. Das passiert ueber einen PostgreSQL-Trigger <code>pages_archive_trigger</code> und ist fuer die Anwendung unsichtbar. DELETE folgt derselben Logik: die Zeile verschwindet aus <code>pages</code>, bleibt in <code>pages_history</code> erhalten und kann ueber den Restore-Endpoint zurueckgeholt werden. Es gibt keinen Weg, eine Aenderung oder Loeschung am Trigger vorbei zu fahren.</p><h3>Aufbau der History-Tabelle</h3><table><thead><tr><th>Spalte</th><th>Typ</th><th>Bedeutung</th></tr></thead><tbody><tr><td>history_id</td><td>Integer</td><td>Primaerschluessel der History-Tabelle</td></tr><tr><td>page_id</td><td>Integer</td><td>id der urspruenglichen Zeile in pages</td></tr><tr><td>slug, title, meta_description, content</td><td>wie pages</td><td>Snapshot des Zustands VOR der Mutation</td></tr><tr><td>created_at, updated_at</td><td>ISO-8601</td><td>kopiert aus dem urspruenglichen Datensatz</td></tr><tr><td>archived_at</td><td>ISO-8601</td><td>Zeitpunkt der Archivierung, also der Mutation auf pages</td></tr><tr><td>archive_op</td><td><code>update</code> oder <code>delete</code></td><td>ausloesendes Ereignis</td></tr><tr><td>archive_actor</td><td>String</td><td>wer hat geschrieben; bei API-Aufrufen <code>php-api</code></td></tr><tr><td>request_id</td><td>String</td><td>16-stellige Hex-ID pro PHP-Request, identisch zum HTTP-Header <code>X-Request-Id</code></td></tr></tbody></table><h3>GET /api/pages/&lt;slug&gt;/history</h3><p>Liefert alle History-Eintraege fuer den angegebenen Slug, sortiert nach <code>archived_at</code> absteigend. Optionale Query-Parameter <code>limit</code> (1 bis 200, Default 50) und <code>offset</code> (ab 0, Default 0).</p><pre><code>curl -sS https://ki.karlkratz.com/api/pages/&lt;slug&gt;/history | jq</code></pre><pre><code>{\n  \"slug\": \"&lt;slug&gt;\",\n  \"total\": 3,\n  \"items\": [\n    {\n      \"history_id\": 7,\n      \"page_id\": 42,\n      \"slug\": \"&lt;slug&gt;\",\n      \"title\": \"alter Titel\",\n      \"meta_description\": \"alte Beschreibung\",\n      \"content\": \"&lt;p&gt;alter Inhalt&lt;/p&gt;\",\n      \"created_at\": \"2026-05-21T10:00:00+02:00\",\n      \"updated_at\": \"2026-05-21T10:05:12+02:00\",\n      \"archived_at\": \"2026-05-21T10:07:33+02:00\",\n      \"archive_op\": \"update\",\n      \"archive_actor\": \"php-api\",\n      \"request_id\": \"367c5efc0d1c\"\n    }\n  ]\n}</code></pre><h3>POST /api/pages/&lt;slug&gt;/restore</h3><p>Stellt einen Slug aus der History wieder her. Ohne Body wird der zuletzt archivierte Snapshot dieses Slugs verwendet. Mit <code>{\"history_id\": N}</code> wird genau dieser Eintrag wiederhergestellt; gehoert er zu einem anderen Slug, antwortet der Server mit <code>404</code>.</p><p>Wenn der Slug aktuell noch in <code>pages</code> existiert, wird die heutige Zeile vor der Wiederherstellung archiviert (UPDATE-Pfad). Wenn der Slug geloescht ist, geht der Restore als INSERT durch und erzeugt keinen zusaetzlichen History-Eintrag.</p><pre><code># Restore des juengsten Snapshots\ncurl -sS -X POST https://ki.karlkratz.com/api/pages/&lt;slug&gt;/restore \\\n  -H 'Content-Type: application/json' -d '{}'\n\n# Restore eines bestimmten Snapshots\ncurl -sS -X POST https://ki.karlkratz.com/api/pages/&lt;slug&gt;/restore \\\n  -H 'Content-Type: application/json' -d '{\"history_id\": 7}'</code></pre><p>Antwort: <code>200</code> mit dem wiederhergestellten Datensatz; <code>404</code> wenn keine History fuer diesen Slug existiert oder die angegebene <code>history_id</code> nicht zu dem Slug gehoert.</p><h3>Hard-Delete?</h3><p>Die API bietet keinen Hard-Delete an. Wer einen Slug endgueltig entfernen will, muss zusaetzlich <code>DELETE FROM pages_history WHERE slug = ...</code> direkt auf der Datenbank ausfuehren. Das ist bewusst so getrennt, damit kein API-Aufruf versehentlich Daten unwiederbringlich loescht.</p><h2>Konsumenten</h2><ul><li>der MCP-Server <strong>ki-web</strong> (Python), siehe <a href=\"/mcp-ki-web\">/mcp-ki-web</a></li><li>das PHP-Frontend selbst, das die Daten ohne HTTP-Hop direkt aus der Geschäftslogik liest</li><li>beliebige curl- oder httpx-Aufrufe mit <code>Content-Type: application/json</code></li></ul><h2>Weiterführend</h2><ul><li><a href=\"/mcp-vs-api-vs-cli\">/mcp-vs-api-vs-cli</a>, Einordnung MCP gegen API gegen CLI</li><li><a href=\"/mcp-anleitung\">/mcp-anleitung</a>, Implementierung des MCP-Adapters über dieser API</li><li><a href=\"/mcp-ki-web\">/mcp-ki-web</a>, Architektur des ki-web-MCP</li></ul>","created_at":"2026-05-21T11:38:40+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":72,"konversionen":51},{"id":47,"slug":"db","title":"kw-db: Postgres-Zugriff via CLI und MCP","meta_description":"Postgres-Werkzeug fuer den lokalen Cluster: dedizierter Admin-User, Schreib-Schranken, Audit-Log, Migrations. Engine, CLI und MCP.","content":"<h1>kw-db: Postgres-Zugriff via CLI und MCP</h1><p>Diese Seite dokumentiert das Postgres-Werkzeug auf diesem Server. Das System folgt KISS und YAGNI: ein Cluster, ein Admin-Konto, eine Engine, je ein dünner Adapter als CLI und MCP. Backups und Multi-Cluster-Unterstützung sind bewusst weggelassen.</p><h2>Was kw-db macht</h2><p>kw-db ist eine Python-Library um den lokalen Postgres-Cluster (17.10). Sie kann Datenbanken auflisten, Tabellen introspizieren, Lese-Queries ausführen, Schreib-Operationen mit Schutz, sowie DDL und destruktive Operationen unter einem Admin-Gate. Eine kleine Migrations-Funktion ist enthalten (nur up, keine downs).</p><h2>Drei Schichten</h2><table><thead><tr><th>Schicht</th><th>Pfad</th><th>Zugriff</th></tr></thead><tbody><tr><td>Engine (Library)</td><td>/var/www/db/</td><td><code>from kw_db.composition import Composition</code></td></tr><tr><td>CLI (db-cli)</td><td>/var/www/cli/db/</td><td>Wrapper <code>/usr/local/bin/db-cli</code></td></tr><tr><td>MCP-Server</td><td>/var/www/mcp/db/</td><td>Wrapper <code>/usr/local/bin/db</code> (stdio JSON-RPC)</td></tr></tbody></table><h2>Konto und Credentials</h2><p>Es gibt einen dedizierten Postgres-Rollen-Account <code>kw_admin</code> mit den Flags <code>LOGIN</code>, <code>CREATEDB</code> und <code>CREATEROLE</code>. Keine Superuser-Rechte: das Tool darf Datenbanken und Rollen anlegen und ändern, aber nicht beispielsweise <code>pg_hba.conf</code> umschreiben.</p><p>Credentials liegen ausschließlich unter <code>/var/www/_credentials/kw_admin/credentials.json</code> mit Modus 0640 und Gruppe www-data. Das ist die einzige Stelle, an der das Passwort steht. Es wird nicht in Repos, Env-Variablen oder anderen Dateien dupliziert.</p><h2>Sicherheitsmodell</h2><p>Drei Schranken greifen ineinander:</p><ol><li><strong>SQL-Klassifizierer</strong>: Jedes Statement bekommt anhand des ersten Tokens eine Klasse zugewiesen (read, write, ddl, destructive). Kommentare werden vorher entfernt.</li><li><strong>Admin-Gate</strong>: DDL- und destruktive Statements (CREATE, ALTER, DROP, TRUNCATE) werden nur ausgeführt, wenn die Umgebungsvariable <code>KW_DB_ADMIN=1</code> gesetzt ist. Default ist 0.</li><li><strong>Protected-DB-Liste</strong>: Die Datenbank <code>ki_web</code> ist hartcodiert geschützt. Schreibzugriffe und DDL werden mit einer eigenen Fehlerklasse abgelehnt, weil diese DB ihre Validierung über die PHP-API erhält. Lesen ist erlaubt.</li></ol><p>Audit-Log: jedes erfolgreiche write- oder DDL-Statement landet als JSON-Zeile in <code>/var/log/kw_db/audit.log</code>. Felder: Zeitstempel, Operation, Datenbank, Erfolg, Detail (z. B. <code>rows=2</code>), erste 1000 Zeichen des SQL. Reads werden nicht geloggt.</p><h2>Tool-Surface des CLIs</h2><table><thead><tr><th>Subcommand</th><th>Klasse</th><th>Bedingung</th></tr></thead><tbody><tr><td><code>list-databases</code></td><td>read</td><td>-</td></tr><tr><td><code>list-tables [-d db] [-s schema]</code></td><td>read</td><td>-</td></tr><tr><td><code>describe TABLE [-d db] [-s schema]</code></td><td>read</td><td>-</td></tr><tr><td><code>query --sql ... oder stdin</code></td><td>nur read</td><td>refused bei DML/DDL</td></tr><tr><td><code>execute --sql ... --yes</code></td><td>write</td><td>--yes; ki_web ist geschützt</td></tr><tr><td><code>admin --sql ... --yes</code></td><td>ddl / destructive</td><td>--yes + KW_DB_ADMIN=1</td></tr><tr><td><code>migrate status</code> bzw. <code>migrate up</code></td><td>migration</td><td>nur up wendet an</td></tr><tr><td><code>ping</code></td><td>read</td><td>-</td></tr></tbody></table><h2>Tool-Surface des MCPs</h2><table><thead><tr><th>Tool</th><th>Bedingung</th></tr></thead><tbody><tr><td><code>list_databases</code>, <code>list_tables</code>, <code>describe_table</code></td><td>jederzeit</td></tr><tr><td><code>query(sql, database?)</code></td><td>nur read</td></tr><tr><td><code>execute_sql(sql, database?)</code></td><td>nur DML; ki_web geschützt</td></tr><tr><td><code>execute_admin_sql(sql, database?)</code></td><td>DDL / destructive; nur mit KW_DB_ADMIN=1</td></tr><tr><td><code>migrate_status</code>, <code>migrate_up</code></td><td>up wendet pending Migrations an</td></tr></tbody></table><p>Der MCP-Server ist als <code>kw-db</code> in Claude Code, Codex und qwen-code registriert. Tool-Aufrufe laufen via stdio JSON-RPC durch <code>/usr/local/bin/db</code>.</p><h2>Output-Formate</h2><p>Sowohl db-cli als auch scrape-cli und ki-web-cli kennen vier Formate, gesteuert über <code>--format</code>: <code>json</code> (Default, für jq-Pipes), <code>table</code> (interaktive Shell), <code>plain</code> (eine Zeile je Record, Tab-separiert, für xargs und cut), <code>csv</code> (neu, mit Header-Zeile, CSV-Escaping nach stdlib). Mit <code>--columns slug,title,updated_at</code> lassen sich in table, plain und csv einzelne Felder herausziehen.</p><h2>Migrations</h2><p>Migration-Files leben unter <code>/var/www/db/migrations/</code> und heißen <code>NNNN_beschreibung.sql</code>. Eine Buchhaltungstabelle <code>kw_db_migrations(name PRIMARY KEY, applied_at)</code> in der Default-DB (postgres) hält fest, welche Files schon angewendet wurden. <code>migrate up</code> wendet alles in Datei-Reihenfolge an, was noch nicht in der Tabelle steht. Jede Anwendung läuft in einer impliziten Transaktion.</p><p>Es gibt bewusst keine down-Migrations und kein Versions-Skipping. Wer eine Migration zurückfahren will, schreibt eine neue Migration, die das Gegenteil tut.</p><h2>Beispiele</h2><h3>Read-only Introspektion</h3><pre><code>db-cli ping\ndb-cli list-databases\ndb-cli --format csv --columns name,owner,size_bytes list-databases\ndb-cli list-tables -d ki_web\ndb-cli --format table --columns name,data_type,is_nullable describe pages -d ki_web</code></pre><h3>Eine Query, eine schreibende Operation</h3><pre><code>db-cli --format json query --sql \"SELECT count(*) AS n FROM pages\" -d ki_web\ndb-cli execute -d kw_demo --yes --sql \"INSERT INTO t (name) VALUES ('hi')\"</code></pre><h3>DDL unter Admin-Gate</h3><pre><code>KW_DB_ADMIN=1 db-cli admin --yes --sql \"CREATE TABLE t (id serial primary key, name text)\" -d kw_demo\nKW_DB_ADMIN=1 db-cli admin --yes --sql \"DROP TABLE t\" -d kw_demo</code></pre><h3>Migrations</h3><pre><code>db-cli migrate status\ndb-cli migrate up</code></pre><h2>Architektur</h2><p>Gleicher DDD-Hexagonal-Schnitt wie ki-web und kw-scrape:</p><ul><li><strong>Domain</strong>: <code>DatabaseInfo</code>, <code>TableInfo</code>, <code>ColumnInfo</code>, <code>RowSet</code>, <code>MigrationRecord</code>, Fehlerklassen, der SQL-Klassifizierer.</li><li><strong>Application</strong>: Ports (<code>SqlExecutorPort</code>, <code>IntrospectorPort</code>, <code>MigrationRunnerPort</code>, <code>AuditLogPort</code>), Use Cases (<code>DbUseCases</code>) mit den drei Guards.</li><li><strong>Infrastructure</strong>: <code>Psycopg3Executor</code> (psycopg 3.3, short-lived Connections, autocommit aus, commit nach jedem write), <code>PgIntrospector</code> (Queries gegen pg_catalog), <code>MigrationRunner</code> (nur up), <code>FileAuditLog</code> (append-only JSONL).</li></ul><h2>Env-Variablen</h2><table><thead><tr><th>Variable</th><th>Default</th><th>Wirkung</th></tr></thead><tbody><tr><td>KW_DB_ADMIN</td><td>0</td><td>Auf 1 setzen, um DDL und destruktive Statements zu erlauben</td></tr><tr><td>KW_DB_AUDIT_LOG</td><td>/var/log/kw_db/audit.log</td><td>Pfad zur Audit-Log-Datei</td></tr><tr><td>KW_DB_MIGRATIONS_DIR</td><td>/var/www/db/migrations</td><td>Verzeichnis mit Migrations-Files</td></tr></tbody></table><h2>Exit-Codes (CLI)</h2><table><thead><tr><th>Code</th><th>Bedeutung</th></tr></thead><tbody><tr><td>0</td><td>OK</td></tr><tr><td>2</td><td>Usage-Fehler (z. B. fehlendes --yes)</td></tr><tr><td>4</td><td>Validierung oder Guard-Verletzung (ki_web protected, Admin-Gate)</td></tr><tr><td>5</td><td>Backend-Fehler (psycopg-Exception, fehlgeschlagene Migration)</td></tr></tbody></table><h2>Was bewusst weggelassen wurde</h2><ul><li>Keine Backups. <code>pg_dump</code> und <code>pg_restore</code> stehen als Shell-Tools weiter zur Verfügung.</li><li>Keine Multi-Cluster-Unterstützung. Nur dieser Server, nur dieses Postgres, nur dieser Cluster.</li><li>Keine Down-Migrations. Wer rückwärts will, schreibt eine neue Migration.</li><li>Keine Connection-Pools. Pro CLI-Aufruf eine Connection. Pro MCP-Tool-Call eine Connection.</li><li>Kein async. psycopg3 läuft synchron.</li><li>Keine git-basierten Workflows.</li></ul><h2>Wichtigste Pfade</h2><table><thead><tr><th>Pfad</th><th>Inhalt</th></tr></thead><tbody><tr><td>/var/www/db/</td><td>Engine kw-db</td></tr><tr><td>/var/www/db/migrations/</td><td>Versionierte SQL-Migrationen</td></tr><tr><td>/var/www/cli/db/</td><td>CLI db-cli</td></tr><tr><td>/var/www/mcp/db/</td><td>MCP-Server kw-db</td></tr><tr><td>/var/www/_credentials/kw_admin/credentials.json</td><td>Login für kw_admin</td></tr><tr><td>/var/log/kw_db/audit.log</td><td>Audit-Log für writes, DDL und Migrationen</td></tr><tr><td>/usr/local/bin/db-cli</td><td>CLI-Wrapper</td></tr><tr><td>/usr/local/bin/db</td><td>MCP-Wrapper (stdio)</td></tr></tbody></table>","created_at":"2026-05-21T12:32:00+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":77,"konversionen":40},{"id":1,"slug":"hallo-welt","title":"Hallo Welt","meta_description":"Test","content":"<h1>Hallo</h1><p>Test mit <strong>strong</strong> und <a href=\"/admin\">Link</a>.</p>","created_at":"2026-05-21T02:35:09+02:00","updated_at":"2026-05-21T17:39:08+02:00","ranking_position":42,"konversionen":88}]}