From c6bbed404981cb4b5e4b6b384d29711938293e0d Mon Sep 17 00:00:00 2001 From: team3 Date: Mon, 7 Sep 2026 07:44:00 +0200 Subject: [PATCH] update --- backend/agents.py | 149 +- backend/auftrag.py | 319 ++ backend/chat.py | 101 +- backend/chatui.png | Bin 0 -> 29952 bytes backend/config.py | 8 +- backend/features.py | 30 +- backend/k1-1024.png | Bin 31742 -> 32048 bytes backend/k1-1280.png | Bin 32992 -> 33245 bytes backend/k1-1600.png | Bin 34587 -> 34633 bytes backend/k1-390.png | Bin 28532 -> 29207 bytes backend/k1-640.png | Bin 30416 -> 31143 bytes backend/k1-820.png | Bin 31811 -> 32676 bytes backend/komfort.png | Bin 22217 -> 21781 bytes backend/offen.png | Bin 26027 -> 25649 bytes backend/planung.py | 14 + backend/pruefung.py | 12 +- backend/recherche.py | 208 ++ backend/routes.py | 103 +- backend/stil/allgemein.md | 30 +- backend/stil/feature-badge.md | 11 +- backend/stil/feature-regeln.md | 9 +- backend/stil/feature-titel.md | 12 +- backend/stil/feature-ziel.md | 13 +- backend/stil/funktion-regeln.md | 11 +- backend/stil/funktion-testen.md | 26 +- backend/stil/funktion-titel.md | 15 +- backend/stil/funktion-ziel.md | 12 +- backend/struktur.py | 68 +- backend/tests/test_auftrag.py | 418 +++ backend/tests/test_chat.py | 111 + backend/tests/test_ledger.py | 21 +- backend/tests/test_planung.py | 30 + backend/tests/test_recherche.py | 193 ++ backend/tests/test_routes.py | 38 + backend/tests/test_struktur.py | 80 +- backend/verzeichnis.py | 75 + daten/DesktopNote/.chat.json | 122 + daten/DesktopNote/.planung/.chat.json | 122 + daten/DesktopNote/.planung/badge.md | 50 + daten/DesktopNote/.planung/setup.md | 25 + daten/DesktopNote/.planung/vision.md | 13 + daten/DesktopNote/badge.md | 50 + daten/DesktopNote/setup.md | 25 + daten/DesktopNote/vision.md | 13 + .../.planung}/.pruefung.json | 0 daten/MtoRagSystem/.planung/.verzeichnis | 1 + daten/MtoRagSystem/.planung/anbindung.md | 157 + daten/MtoRagSystem/.planung/antwort.md | 115 + daten/MtoRagSystem/.planung/auftrag.md | 85 + daten/MtoRagSystem/.planung/batch.md | 118 + daten/MtoRagSystem/.planung/beleg.md | 71 + daten/MtoRagSystem/.planung/benutzer.md | 82 + .../MtoRagSystem/.planung/betriebspruefung.md | 117 + daten/MtoRagSystem/.planung/claim.md | 51 + daten/MtoRagSystem/.planung/diagnose.md | 84 + daten/MtoRagSystem/.planung/dokument.md | 107 + daten/MtoRagSystem/.planung/evalfall.md | 77 + daten/MtoRagSystem/.planung/evallauf.md | 100 + daten/MtoRagSystem/.planung/fremdinhalt.md | 138 + daten/MtoRagSystem/.planung/indexprofil.md | 64 + daten/MtoRagSystem/.planung/konfiguration.md | 46 + daten/MtoRagSystem/.planung/modellprofil.md | 68 + daten/MtoRagSystem/.planung/protokoll.md | 43 + daten/MtoRagSystem/.planung/rueckmeldung.md | 99 + daten/MtoRagSystem/.planung/selbsttest.md | 76 + daten/MtoRagSystem/.planung/shoptreffer.md | 75 + daten/MtoRagSystem/.planung/sicherung.md | 90 + daten/MtoRagSystem/.planung/sitzung.md | 83 + daten/MtoRagSystem/.planung/systemprompt.md | 46 + daten/MtoRagSystem/.planung/tag.md | 92 + daten/MtoRagSystem/.planung/upload.md | 68 + daten/MtoRagSystem/.planung/version.md | 135 + daten/MtoRagSystem/.planung/vision.md | 72 + daten/MtoRagSystem/.planung/werkzeug.md | 56 + daten/MtoRagSystem/.planung/wissensindex.md | 90 + daten/MtoRagSystem/.planung/wissensraum.md | 97 + daten/MtoRagSystem/.pruefung.json | 2735 +++++++++++++++++ daten/MtoRagSystem/.verzeichnis | 1 + daten/MtoRagSystem/anbindung.md | 157 + daten/MtoRagSystem/antwort.md | 115 + daten/MtoRagSystem/auftrag.md | 85 + daten/MtoRagSystem/batch.md | 118 + daten/MtoRagSystem/beleg.md | 71 + daten/MtoRagSystem/benutzer.md | 82 + daten/MtoRagSystem/betriebspruefung.md | 117 + daten/MtoRagSystem/claim.md | 51 + daten/MtoRagSystem/diagnose.md | 84 + daten/MtoRagSystem/dokument.md | 107 + daten/MtoRagSystem/evalfall.md | 77 + daten/MtoRagSystem/evallauf.md | 100 + daten/MtoRagSystem/fremdinhalt.md | 138 + daten/MtoRagSystem/indexprofil.md | 64 + daten/MtoRagSystem/konfiguration.md | 46 + daten/MtoRagSystem/modellprofil.md | 68 + daten/MtoRagSystem/protokoll.md | 43 + daten/MtoRagSystem/rueckmeldung.md | 99 + daten/MtoRagSystem/selbsttest.md | 76 + daten/MtoRagSystem/shoptreffer.md | 75 + daten/MtoRagSystem/sicherung.md | 90 + daten/MtoRagSystem/sitzung.md | 83 + daten/MtoRagSystem/systemprompt.md | 46 + daten/MtoRagSystem/tag.md | 92 + daten/MtoRagSystem/upload.md | 68 + daten/MtoRagSystem/version.md | 135 + daten/MtoRagSystem/vision.md | 72 + daten/MtoRagSystem/werkzeug.md | 56 + daten/MtoRagSystem/wissensindex.md | 90 + daten/MtoRagSystem/wissensraum.md | 97 + .../.planung/.pruefung.json | 537 ---- .../.planung/.verlauf.json | 122 - .../.planung/auswahl-anstossen.md | 49 - .../.planung/beratung-anbieten.md | 47 - .../.planung/layout-zuweisen.md | 69 - .../.planung/option-ansehen.md | 51 - .../.planung/schritt-zeigen.md | 49 - .../.planung/varianten-waehlen.md | 109 - .../.planung/vorschau-zeigen.md | 53 - daten/MtoVariantConfigurator/.verzeichnis | 1 + .../auswahl-anstossen.md | 49 - .../beratung-anbieten.md | 47 - daten/MtoVariantConfigurator/hilfe.md | 40 + daten/MtoVariantConfigurator/konfigurator.md | 100 + .../MtoVariantConfigurator/layout-zuweisen.md | 69 - .../MtoVariantConfigurator/option-ansehen.md | 51 - daten/MtoVariantConfigurator/option.md | 63 + daten/MtoVariantConfigurator/produkt.md | 60 + .../MtoVariantConfigurator/schritt-zeigen.md | 49 - daten/MtoVariantConfigurator/schrittzeile.md | 30 + daten/MtoVariantConfigurator/variante.md | 48 + .../varianten-waehlen.md | 109 - daten/MtoVariantConfigurator/vision.md | 48 + .../MtoVariantConfigurator/vorschau-zeigen.md | 53 - daten/MtoVariantConfigurator/vorschau.md | 52 + .../{karten-besprechen.md => anweisung.md} | 47 +- daten/Planer/.planung/design.md | 44 - daten/Planer/.planung/feature.md | 90 + daten/Planer/.planung/features.md | 109 - daten/Planer/.planung/funktion.md | 66 + daten/Planer/.planung/funktionen.md | 98 - daten/Planer/.planung/k1-1024.png | Bin 31445 -> 33144 bytes daten/Planer/.planung/k1-1280.png | Bin 32564 -> 34288 bytes daten/Planer/.planung/k1-1600.png | Bin 34370 -> 35438 bytes daten/Planer/.planung/k1-390.png | Bin 28243 -> 30270 bytes daten/Planer/.planung/k1-640.png | Bin 30111 -> 32245 bytes daten/Planer/.planung/k1-820.png | Bin 31558 -> 33776 bytes daten/Planer/.planung/karten-pruefen.md | 82 - daten/Planer/.planung/planung.md | 91 + .../.planung/{projekte.md => projekt.md} | 42 +- daten/Planer/.planung/pruefung.md | 46 + .../{vision-festhalten.md => vision-2.md} | 43 +- daten/Planer/.planung/vision.md | 37 +- daten/Planer/.planung/vorschlag.md | 56 + .../{karten-besprechen.md => anweisung.md} | 47 +- daten/Planer/darkmode.md | 23 - daten/Planer/design.md | 44 - daten/Planer/feature.md | 90 + daten/Planer/features.md | 109 - daten/Planer/funktion.md | 66 + daten/Planer/funktionen.md | 98 - daten/Planer/k1-1024.png | Bin 31445 -> 33144 bytes daten/Planer/k1-1280.png | Bin 32564 -> 34288 bytes daten/Planer/k1-1600.png | Bin 34370 -> 35438 bytes daten/Planer/k1-390.png | Bin 28243 -> 30270 bytes daten/Planer/k1-640.png | Bin 30111 -> 32245 bytes daten/Planer/k1-820.png | Bin 31558 -> 33776 bytes daten/Planer/karten-pruefen.md | 82 - daten/Planer/planung.md | 91 + daten/Planer/{projekte.md => projekt.md} | 42 +- daten/Planer/pruefung.md | 46 + .../{vision-festhalten.md => vision-2.md} | 43 +- daten/Planer/vision.md | 37 +- daten/Planer/vorschlag.md | 56 + daten/RAG/admin.md | 93 - daten/RAG/agenten.md | 286 -- daten/RAG/anleitungen.md | 43 - daten/RAG/auftraege.md | 94 - daten/RAG/backup.md | 97 - daten/RAG/benutzer.md | 89 - daten/RAG/berichte.md | 90 - daten/RAG/chat.md | 53 - daten/RAG/diagnose.md | 386 --- daten/RAG/dokumente.md | 127 - daten/RAG/evaluation.md | 100 - daten/RAG/faelle.md | 74 - daten/RAG/feedback.md | 128 - daten/RAG/knowledge-raeume.md | 141 - daten/RAG/konfiguration.md | 129 - daten/RAG/logs.md | 46 - daten/RAG/sonstiges.md | 64 - daten/RAG/system.md | 304 -- daten/RAG/tags.md | 63 - daten/RAG/titel.md | 40 - daten/RAG/uploads.md | 75 - daten/RAG/verlauf.md | 57 - daten/RAG/versionen.md | 75 - daten/TFT/.pruefung.json | 317 -- daten/TFT/analyse.md | 61 - daten/TFT/einheit.md | 35 - daten/TFT/pipeline.md | 60 - daten/TFT/shop.md | 83 - daten/TFT/spiel.md | 98 - daten/TftSimulator/.planung/.chat.json | 10 + daten/TftSimulator/.planung/.verzeichnis | 1 + daten/TftSimulator/.planung/augment.md | 38 + daten/TftSimulator/.planung/champion.md | 91 + daten/TftSimulator/.planung/erfahrung.md | 38 + daten/TftSimulator/.planung/gold.md | 40 + daten/TftSimulator/.planung/item.md | 52 + .../.planung/klasse.md} | 20 +- daten/TftSimulator/.planung/runde.md | 55 + daten/TftSimulator/.planung/staerke.md | 46 + daten/TftSimulator/.planung/stats.md | 62 + daten/TftSimulator/.planung/streak.md | 38 + daten/TftSimulator/.planung/trait.md | 22 + daten/TftSimulator/.planung/vision.md | 19 + daten/TftSimulator/.recherche.json | 45 + daten/TftSimulator/.verzeichnis | 1 + daten/chatui.png | Bin 0 -> 28045 bytes daten/k1-1024.png | Bin 0 -> 31614 bytes daten/k1-1280.png | Bin 0 -> 32737 bytes daten/k1-1600.png | Bin 0 -> 34471 bytes daten/k1-390.png | Bin 0 -> 28294 bytes daten/k1-640.png | Bin 0 -> 30163 bytes daten/k1-820.png | Bin 0 -> 31744 bytes daten/komfort.png | Bin 0 -> 22205 bytes daten/offen.png | Bin 0 -> 26127 bytes frontend/chatui.png | Bin 0 -> 31220 bytes frontend/k1-1024.png | Bin 31614 -> 32048 bytes frontend/k1-1280.png | Bin 32737 -> 33245 bytes frontend/k1-1600.png | Bin 34471 -> 34633 bytes frontend/k1-390.png | Bin 28294 -> 29207 bytes frontend/k1-640.png | Bin 30163 -> 31143 bytes frontend/k1-820.png | Bin 31744 -> 32676 bytes frontend/komfort.png | Bin 22205 -> 34058 bytes frontend/offen.png | Bin 26127 -> 25884 bytes frontend/src/App.vue | 259 +- frontend/src/api.js | 16 +- frontend/src/assets/base.css | 1 + frontend/src/components/ChatPanel.vue | 37 +- frontend/src/components/FeatureKarte.vue | 186 +- frontend/src/components/FeatureListe.vue | 208 +- frontend/src/components/OrdnerWahl.vue | 101 + frontend/src/components/RecherchePanel.vue | 339 ++ frontend/src/components/SeitenLeiste.vue | 35 +- frontend/src/components/VisionKarte.vue | 184 -- frontend/src/composables/entwuerfe.js | 24 + frontend/src/composables/planung.js | 80 +- frontend/src/composables/pruefung.js | 42 +- frontend/src/composables/uhr.js | 19 + vorschlag.png | Bin 0 -> 127829 bytes 250 files changed, 13372 insertions(+), 6203 deletions(-) create mode 100644 backend/auftrag.py create mode 100644 backend/chatui.png create mode 100644 backend/recherche.py create mode 100644 backend/tests/test_auftrag.py create mode 100644 backend/tests/test_chat.py create mode 100644 backend/tests/test_recherche.py create mode 100644 backend/verzeichnis.py create mode 100644 daten/DesktopNote/.chat.json create mode 100644 daten/DesktopNote/.planung/.chat.json create mode 100644 daten/DesktopNote/.planung/badge.md create mode 100644 daten/DesktopNote/.planung/setup.md create mode 100644 daten/DesktopNote/.planung/vision.md create mode 100644 daten/DesktopNote/badge.md create mode 100644 daten/DesktopNote/setup.md create mode 100644 daten/DesktopNote/vision.md rename daten/{RAG => MtoRagSystem/.planung}/.pruefung.json (100%) create mode 100644 daten/MtoRagSystem/.planung/.verzeichnis create mode 100644 daten/MtoRagSystem/.planung/anbindung.md create mode 100644 daten/MtoRagSystem/.planung/antwort.md create mode 100644 daten/MtoRagSystem/.planung/auftrag.md create mode 100644 daten/MtoRagSystem/.planung/batch.md create mode 100644 daten/MtoRagSystem/.planung/beleg.md create mode 100644 daten/MtoRagSystem/.planung/benutzer.md create mode 100644 daten/MtoRagSystem/.planung/betriebspruefung.md create mode 100644 daten/MtoRagSystem/.planung/claim.md create mode 100644 daten/MtoRagSystem/.planung/diagnose.md create mode 100644 daten/MtoRagSystem/.planung/dokument.md create mode 100644 daten/MtoRagSystem/.planung/evalfall.md create mode 100644 daten/MtoRagSystem/.planung/evallauf.md create mode 100644 daten/MtoRagSystem/.planung/fremdinhalt.md create mode 100644 daten/MtoRagSystem/.planung/indexprofil.md create mode 100644 daten/MtoRagSystem/.planung/konfiguration.md create mode 100644 daten/MtoRagSystem/.planung/modellprofil.md create mode 100644 daten/MtoRagSystem/.planung/protokoll.md create mode 100644 daten/MtoRagSystem/.planung/rueckmeldung.md create mode 100644 daten/MtoRagSystem/.planung/selbsttest.md create mode 100644 daten/MtoRagSystem/.planung/shoptreffer.md create mode 100644 daten/MtoRagSystem/.planung/sicherung.md create mode 100644 daten/MtoRagSystem/.planung/sitzung.md create mode 100644 daten/MtoRagSystem/.planung/systemprompt.md create mode 100644 daten/MtoRagSystem/.planung/tag.md create mode 100644 daten/MtoRagSystem/.planung/upload.md create mode 100644 daten/MtoRagSystem/.planung/version.md create mode 100644 daten/MtoRagSystem/.planung/vision.md create mode 100644 daten/MtoRagSystem/.planung/werkzeug.md create mode 100644 daten/MtoRagSystem/.planung/wissensindex.md create mode 100644 daten/MtoRagSystem/.planung/wissensraum.md create mode 100644 daten/MtoRagSystem/.pruefung.json create mode 100644 daten/MtoRagSystem/.verzeichnis create mode 100644 daten/MtoRagSystem/anbindung.md create mode 100644 daten/MtoRagSystem/antwort.md create mode 100644 daten/MtoRagSystem/auftrag.md create mode 100644 daten/MtoRagSystem/batch.md create mode 100644 daten/MtoRagSystem/beleg.md create mode 100644 daten/MtoRagSystem/benutzer.md create mode 100644 daten/MtoRagSystem/betriebspruefung.md create mode 100644 daten/MtoRagSystem/claim.md create mode 100644 daten/MtoRagSystem/diagnose.md create mode 100644 daten/MtoRagSystem/dokument.md create mode 100644 daten/MtoRagSystem/evalfall.md create mode 100644 daten/MtoRagSystem/evallauf.md create mode 100644 daten/MtoRagSystem/fremdinhalt.md create mode 100644 daten/MtoRagSystem/indexprofil.md create mode 100644 daten/MtoRagSystem/konfiguration.md create mode 100644 daten/MtoRagSystem/modellprofil.md create mode 100644 daten/MtoRagSystem/protokoll.md create mode 100644 daten/MtoRagSystem/rueckmeldung.md create mode 100644 daten/MtoRagSystem/selbsttest.md create mode 100644 daten/MtoRagSystem/shoptreffer.md create mode 100644 daten/MtoRagSystem/sicherung.md create mode 100644 daten/MtoRagSystem/sitzung.md create mode 100644 daten/MtoRagSystem/systemprompt.md create mode 100644 daten/MtoRagSystem/tag.md create mode 100644 daten/MtoRagSystem/upload.md create mode 100644 daten/MtoRagSystem/version.md create mode 100644 daten/MtoRagSystem/vision.md create mode 100644 daten/MtoRagSystem/werkzeug.md create mode 100644 daten/MtoRagSystem/wissensindex.md create mode 100644 daten/MtoRagSystem/wissensraum.md delete mode 100644 daten/MtoVariantConfigurator/.planung/.pruefung.json delete mode 100644 daten/MtoVariantConfigurator/.planung/.verlauf.json delete mode 100644 daten/MtoVariantConfigurator/.planung/auswahl-anstossen.md delete mode 100644 daten/MtoVariantConfigurator/.planung/beratung-anbieten.md delete mode 100644 daten/MtoVariantConfigurator/.planung/layout-zuweisen.md delete mode 100644 daten/MtoVariantConfigurator/.planung/option-ansehen.md delete mode 100644 daten/MtoVariantConfigurator/.planung/schritt-zeigen.md delete mode 100644 daten/MtoVariantConfigurator/.planung/varianten-waehlen.md delete mode 100644 daten/MtoVariantConfigurator/.planung/vorschau-zeigen.md create mode 100644 daten/MtoVariantConfigurator/.verzeichnis delete mode 100644 daten/MtoVariantConfigurator/auswahl-anstossen.md delete mode 100644 daten/MtoVariantConfigurator/beratung-anbieten.md create mode 100644 daten/MtoVariantConfigurator/hilfe.md create mode 100644 daten/MtoVariantConfigurator/konfigurator.md delete mode 100644 daten/MtoVariantConfigurator/layout-zuweisen.md delete mode 100644 daten/MtoVariantConfigurator/option-ansehen.md create mode 100644 daten/MtoVariantConfigurator/option.md create mode 100644 daten/MtoVariantConfigurator/produkt.md delete mode 100644 daten/MtoVariantConfigurator/schritt-zeigen.md create mode 100644 daten/MtoVariantConfigurator/schrittzeile.md create mode 100644 daten/MtoVariantConfigurator/variante.md delete mode 100644 daten/MtoVariantConfigurator/varianten-waehlen.md create mode 100644 daten/MtoVariantConfigurator/vision.md delete mode 100644 daten/MtoVariantConfigurator/vorschau-zeigen.md create mode 100644 daten/MtoVariantConfigurator/vorschau.md rename daten/Planer/.planung/{karten-besprechen.md => anweisung.md} (51%) delete mode 100644 daten/Planer/.planung/design.md create mode 100644 daten/Planer/.planung/feature.md delete mode 100644 daten/Planer/.planung/features.md create mode 100644 daten/Planer/.planung/funktion.md delete mode 100644 daten/Planer/.planung/funktionen.md delete mode 100644 daten/Planer/.planung/karten-pruefen.md create mode 100644 daten/Planer/.planung/planung.md rename daten/Planer/.planung/{projekte.md => projekt.md} (55%) create mode 100644 daten/Planer/.planung/pruefung.md rename daten/Planer/.planung/{vision-festhalten.md => vision-2.md} (52%) create mode 100644 daten/Planer/.planung/vorschlag.md rename daten/Planer/{karten-besprechen.md => anweisung.md} (51%) delete mode 100644 daten/Planer/darkmode.md delete mode 100644 daten/Planer/design.md create mode 100644 daten/Planer/feature.md delete mode 100644 daten/Planer/features.md create mode 100644 daten/Planer/funktion.md delete mode 100644 daten/Planer/funktionen.md delete mode 100644 daten/Planer/karten-pruefen.md create mode 100644 daten/Planer/planung.md rename daten/Planer/{projekte.md => projekt.md} (55%) create mode 100644 daten/Planer/pruefung.md rename daten/Planer/{vision-festhalten.md => vision-2.md} (52%) create mode 100644 daten/Planer/vorschlag.md delete mode 100644 daten/RAG/admin.md delete mode 100644 daten/RAG/agenten.md delete mode 100644 daten/RAG/anleitungen.md delete mode 100644 daten/RAG/auftraege.md delete mode 100644 daten/RAG/backup.md delete mode 100644 daten/RAG/benutzer.md delete mode 100644 daten/RAG/berichte.md delete mode 100644 daten/RAG/chat.md delete mode 100644 daten/RAG/diagnose.md delete mode 100644 daten/RAG/dokumente.md delete mode 100644 daten/RAG/evaluation.md delete mode 100644 daten/RAG/faelle.md delete mode 100644 daten/RAG/feedback.md delete mode 100644 daten/RAG/knowledge-raeume.md delete mode 100644 daten/RAG/konfiguration.md delete mode 100644 daten/RAG/logs.md delete mode 100644 daten/RAG/sonstiges.md delete mode 100644 daten/RAG/system.md delete mode 100644 daten/RAG/tags.md delete mode 100644 daten/RAG/titel.md delete mode 100644 daten/RAG/uploads.md delete mode 100644 daten/RAG/verlauf.md delete mode 100644 daten/RAG/versionen.md delete mode 100644 daten/TFT/.pruefung.json delete mode 100644 daten/TFT/analyse.md delete mode 100644 daten/TFT/einheit.md delete mode 100644 daten/TFT/pipeline.md delete mode 100644 daten/TFT/shop.md delete mode 100644 daten/TFT/spiel.md create mode 100644 daten/TftSimulator/.planung/.chat.json create mode 100644 daten/TftSimulator/.planung/.verzeichnis create mode 100644 daten/TftSimulator/.planung/augment.md create mode 100644 daten/TftSimulator/.planung/champion.md create mode 100644 daten/TftSimulator/.planung/erfahrung.md create mode 100644 daten/TftSimulator/.planung/gold.md create mode 100644 daten/TftSimulator/.planung/item.md rename daten/{Planer/.planung/darkmode.md => TftSimulator/.planung/klasse.md} (51%) create mode 100644 daten/TftSimulator/.planung/runde.md create mode 100644 daten/TftSimulator/.planung/staerke.md create mode 100644 daten/TftSimulator/.planung/stats.md create mode 100644 daten/TftSimulator/.planung/streak.md create mode 100644 daten/TftSimulator/.planung/trait.md create mode 100644 daten/TftSimulator/.planung/vision.md create mode 100644 daten/TftSimulator/.recherche.json create mode 100644 daten/TftSimulator/.verzeichnis create mode 100644 daten/chatui.png create mode 100644 daten/k1-1024.png create mode 100644 daten/k1-1280.png create mode 100644 daten/k1-1600.png create mode 100644 daten/k1-390.png create mode 100644 daten/k1-640.png create mode 100644 daten/k1-820.png create mode 100644 daten/komfort.png create mode 100644 daten/offen.png create mode 100644 frontend/chatui.png create mode 100644 frontend/src/components/OrdnerWahl.vue create mode 100644 frontend/src/components/RecherchePanel.vue delete mode 100644 frontend/src/components/VisionKarte.vue create mode 100644 frontend/src/composables/entwuerfe.js create mode 100644 frontend/src/composables/uhr.js create mode 100644 vorschlag.png diff --git a/backend/agents.py b/backend/agents.py index 86a5004..56e2547 100644 --- a/backend/agents.py +++ b/backend/agents.py @@ -1,8 +1,23 @@ -"""Anbindung an MiniMax über das Anthropic-Messages-Format. Kein Fallback: fehlt die -Konfiguration oder antwortet der Provider nicht, bricht der Aufruf mit sichtbarer -Meldung ab.""" +"""Zwei Wege zum Modell, je nach Aufgabe. + +`frage` geht über MiniMax im Anthropic-Messages-Format: die Prüfungen sind hundert +Anfragen je Lauf und leben von der Temperaturstreuung — das muss billig und +parallelisierbar sein. + +`frage_lokal` geht über die angemeldete Claude-CLI, dasselbe Abo wie die +Agenten-Übergabe. Die Gespräche sind einzelne Aufrufe und leben von Urteilskraft; +dort zählt Qualität, nicht Durchsatz. + +Welche Werkzeuge dabei offenstehen, entscheidet die Betriebsart, nicht das Modell: +Planung liest den Projektcode, Recherche sucht im Web, und keine der beiden kann, +was die andere darf. Die Prüfungen bekommen gar nichts — dort ist der Katalog die +einzige zulässige Quelle. + +Kein Fallback zwischen beiden: fehlt ein Weg, bricht der Aufruf mit sichtbarer +Meldung ab, statt still auf das schwächere Modell auszuweichen.""" import asyncio +import json import httpx @@ -12,6 +27,73 @@ ZEITLIMIT = 180.0 MAX_TOKENS = 8000 API_VERSION = "2023-06-01" +GRUNDLAGE = ( + "claude", "-p", "--model", "opus", "--output-format", "json", + # Spart ein Fünftel der Grundlast; was hier gilt, steht ohnehin im eigenen Prompt. + "--exclude-dynamic-system-prompt-sections", + # Ohne das erbt der Aufruf, was am Rechner sonst eingerichtet ist: MCP-Server, + # Workflows, Hooks, ein fremder Antwortstil. Ein Gespräch über Feature-Karten hat + # in keinem Postfach etwas zu suchen. + "--safe-mode", +) + +# Was in keiner Betriebsart erlaubt ist. Beide Gespräche holen fremden Text in den +# Kontext — das eine Suchtreffer, das andere Quelltext — und fremder Text darf keinen +# Terminplan anlegen, keine Nachricht verschicken und keine Agenten starten. Was +# künftig an Werkzeugen dazukommt, steht hier nicht: beim Nachziehen der CLI gehört +# diese Liste geprüft. +GESPERRT = ( + "Write", "Edit", "NotebookEdit", "Bash", "Task", "TodoWrite", + "Workflow", "Skill", "ReportFindings", "ScheduleWakeup", "DesignSync", + "CronCreate", "CronDelete", "CronList", "RemoteTrigger", "PushNotification", + "SendMessage", "Monitor", "EnterWorktree", "ExitWorktree", + "TaskCreate", "TaskGet", "TaskList", "TaskOutput", "TaskStop", "TaskUpdate", +) + + +def _kommando(erlaubt: tuple, gesperrt: tuple, zuege: int) -> tuple: + """Ein Aufruf mit genau den Werkzeugen einer Betriebsart. + + `--allowed-tools` ist nicht bloß die Umkehrung von `--disallowed-tools`: ohne die + Vorabfreigabe fragt die CLI je Suche und je Datei nach Erlaubnis und bekommt im + Stapelbetrieb keine Antwort. Der Versuch endet dann als Absage, nicht als Fehler. + + `ToolSearch` steht nirgends: Suche, Abruf und Lesen sind nachladbar, ohne das + Werkzeug käme das Modell gar nicht an sie heran. Was es nachlädt, ist trotzdem + gesperrt — die Sperre wirkt beim Aufruf, nicht beim Suchen. + """ + return (*GRUNDLAGE, + "--allowed-tools", *erlaubt, + "--disallowed-tools", *GESPERRT, *gesperrt, + "--max-turns", str(zuege)) + + +# Planen heißt: an den Karten arbeiten, mit dem Code als Beleg. Das Web bleibt zu — +# was das Projekt können soll, entscheidet die Person, nicht eine fremde Seite. +PLANUNG_KOMMANDO = _kommando( + ("Read", "Glob", "Grep"), ("WebSearch", "WebFetch"), 20) +# Ohne eingestelltes Arbeitsverzeichnis gibt es nichts zu lesen. Lesen bliebe hier +# nicht folgenlos: ohne gesetzten Ordner liefe die Suche im Serververzeichnis, und +# das Modell beschriebe planer2 statt des Projekts. +PLANUNG_OHNE_CODE = _kommando( + (), ("Read", "Glob", "Grep", "WebSearch", "WebFetch"), 1) +# Recherche geht nach draußen und nirgendwo sonst: kein Blick in Dateien, damit +# nichts aus dem Projekt in einer Suchanfrage landet. +RECHERCHE_KOMMANDO = _kommando( + ("WebSearch", "WebFetch"), ("Read", "Glob", "Grep"), 24) + +# Opus denkt länger als MiniMax, der Prozessstart kostet extra, und Suchen wie +# Codelesen legen mehrere Abrufe obendrauf. +CHAT_ZEITLIMIT = 600.0 + +# Nur fürs Log: welcher Weg gerade lief. Ohne den Namen sagt eine Zeitangabe nichts, +# denn dieselbe Sekundenzahl ist bei einem Zug teuer und bei zwanzig billig. +WEGE = { + PLANUNG_KOMMANDO: "planung+code", + PLANUNG_OHNE_CODE: "planung", + RECHERCHE_KOMMANDO: "recherche", +} + # Der Provider drosselt bei vielen gleichzeitigen Anfragen WIEDERHOLBAR = (429, 500, 502, 503, 504) WIEDERHOLUNGEN = 6 @@ -39,6 +121,67 @@ def pruefe_konfiguration(): raise NichtKonfiguriert(f"Nicht konfiguriert: {', '.join(fehlend)} in .env fehlt") +async def frage_lokal(system: str, inhalt: str, + kommando: tuple = PLANUNG_OHNE_CODE, + ordner: str | None = None) -> str: + """Eine Runde über die Claude-CLI — der Text der Antwort. + + Der Prompt geht über die Standardeingabe: Katalog und Kartenstand sind zu lang, + um sie als Kommandozeilenargument zu übergeben. Keine Temperatur — die CLI kennt + keine; für einen einzelnen Zug braucht es auch keine Streuung. + + `ordner` ist das Verzeichnis, in dem der Aufruf läuft. Es entscheidet, was ein + erlaubtes Lesen erreicht; ohne Angabe erbt der Prozess das Serververzeichnis, und + das ist nur zulässig, solange gar nicht gelesen werden darf. + """ + try: + prozess = await asyncio.create_subprocess_exec( + *kommando, "--system-prompt", system, + cwd=ordner, + stdin=asyncio.subprocess.PIPE, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + ) + except FileNotFoundError: + raise NichtKonfiguriert( + "Claude-CLI nicht gefunden — „claude“ muss im Pfad liegen und angemeldet sein" + ) + try: + aus, err = await asyncio.wait_for( + prozess.communicate(inhalt.encode()), CHAT_ZEITLIMIT) + except asyncio.TimeoutError: + prozess.kill() + raise RuntimeError(f"Claude antwortet nicht innerhalb von {CHAT_ZEITLIMIT:.0f} s") + if prozess.returncode != 0: + raise RuntimeError(f"Claude bricht ab: {err.decode()[-300:].strip() or 'ohne Meldung'}") + try: + daten = json.loads(aus) + except ValueError: + raise RuntimeError("Antwort der Claude-CLI ist kein JSON") + if daten.get("is_error"): + raise RuntimeError(f"Claude meldet einen Fehler: {daten.get('result')}") + _notiere(kommando, daten) + text = str(daten.get("result") or "") + if not text.strip(): + raise RuntimeError("Leere Antwort von Claude") + return text + + +def _notiere(kommando: tuple, daten: dict): + """Wohin die Wartezeit ging — ins Serverlog, eine Zeile je Aufruf. + + Die CLI legt es ohnehin bei; ungelesen bleibt nur die Frage „wieso dauert das so + lange" offen. Ein Zug ist ein Modellaufruf: jede Suche, jeder Abruf, jedes Lesen + zählt einzeln. Sind die Züge hoch, hat das Modell gearbeitet; ist einer teuer, war + der Prompt lang. + """ + zuege = daten.get("num_turns") or 0 + api = (daten.get("duration_api_ms") or 0) / 1000 + print(f"[claude] {WEGE.get(kommando, 'aufruf')}: {api:.0f}s, {zuege} Züge, " + f"{(api / zuege if zuege else api):.0f}s/Zug, " + f"${daten.get('total_cost_usd') or 0:.3f}", flush=True) + + def _pause(res, versuch: int) -> float: """Wie lange bis zum nächsten Versuch — der Provider darf es selbst sagen.""" gesagt = res.headers.get("retry-after") diff --git a/backend/auftrag.py b/backend/auftrag.py new file mode 100644 index 0000000..746b87f --- /dev/null +++ b/backend/auftrag.py @@ -0,0 +1,319 @@ +"""Die Planung an einen Agenten übergeben. + +Claude implementiert die geplanten Änderungen im Arbeitsverzeichnis — lokal über +die Claude-CLI mit dem angemeldeten Konto. Solange er arbeitet, bleibt die +Planung stehen: die Übersicht sagt, was das Projekt kann, und das stimmt erst, +wenn der Code da ist. Erst nach Erfolg wird die Planung übernommen. Ein +Fehlschlag übernimmt nichts; die Planung steht noch und kann erneut los. + +Der Agent meldet jeden erledigten Schritt als eigene Zeile; der Server liest den +Stream mit und hakt die Schritte ab. Zustand nur im Speicher — er überlebt keinen +Serverneustart, der laufende Prozess arbeitet trotzdem zu Ende, übernimmt dann +aber nichts mehr sichtbar. +""" + +import asyncio +import difflib +import json +import re + +import parser +import planung +import projekte +import verzeichnis + +# stream-json liefert je Zeile ein Ereignis: sichtbar wird, woran der Agent +# gerade arbeitet, und die ERLEDIGT-Zeilen kommen an, sobald sie fallen. +KOMMANDO = ("claude", "-p", "--model", "opus", "--permission-mode", "acceptEdits", + "--output-format", "stream-json", "--verbose") +MARKE = "ERLEDIGT:" +# Einzelne Stream-Zeilen tragen ganze Dateien — die Standardgrenze ist zu klein +PUFFER = 10 * 1024 * 1024 + +# projektname -> {"laeuft", "fehler", "text", "schritte", "aktivitaet", "uebernommen"} +_laeufe = {} +_aufgaben = set() + +PRUEFEN = "PRÜFEN" +# Eine neue Funktion ist immer unbewiesen — es gibt noch keinen Code, der sie leistet. +ART = {"weg": "GESTRICHEN", "geaendert": "GEÄNDERT", "neu": PRUEFEN} + +AUFTRAG = """Du bekommst die Feature-Karten eines Projekts und die geplanten Änderungen. +Eine Karte ist ein Auftrag: Regeln sind Zusicherungen, eine Funktion ist etwas, +das man für sich testen kann. Setze den Code in diesem Verzeichnis so um, dass er +den geänderten Karten entspricht. + +- Lies zuerst den bestehenden Code und folge seinen Konventionen. +- Ändere nur, was die Arbeitsschritte verlangen. +- {pruefen} heißt: die Funktion gilt als unbewiesen. Prüfe, ob der Code genau das + leistet, was ihre Testschritte beschreiben. Fehlt sie, baue sie. Weicht sie ab, + bring sie in Ordnung. Sie kann schon einmal gebaut worden sein und trotzdem falsch + arbeiten — glaube dem Code nicht, weil er existiert. +- GEÄNDERT heißt: gebaut, aber die Karte sagt jetzt etwas anderes. +- GESTRICHEN heißt: die Fähigkeit wird entfernt. +- Ein Kommando in Anführungszeichen muss danach genau so aufrufbar sein. +- Führe vorhandene Tests aus, wenn es welche gibt. + +Die Arbeitsschritte: + +{schritte} + +Gib nach jedem abgeschlossenen Schritt sofort eine eigene Textzeile aus, +mit dem Schritt wörtlich wie oben: +{marke} + +Hake nur ab, was du geprüft hast. Konntest du einen Ablauf nicht ausführen — weil +kein Fenster, kein Gerät oder kein Dienst da ist — dann melde ihn NICHT als erledigt. +Schreib am Ende in einer eigenen Zeile, was du nicht prüfen konntest und warum. + +Die betroffenen Karten, wie sie danach gelten: + +{karten}""" + + +def _kartentexte(projekt: str, titel: set) -> str: + """Der volle Text der geplanten Karten — der Sollzustand, nicht der Diff.""" + texte = [] + for datei in sorted(projekte.wurzel(projekt).glob("*.md")): + roh = datei.read_text() + if parser.zerlege(roh)["titel"] in titel: + texte.append(roh.strip()) + return "\n\n=====\n\n".join(texte) or "(keine — nur Streichungen)" + + +def _offene(projekt: str) -> set: + """(Karte, Funktion) für alles, was noch nicht bewiesen ist. + + Auch in Karten, die sich gegenüber dem Stand nicht geändert haben: eine Funktion + zurück auf „offen“ zu setzen ist die Art, eine kaputte Umsetzung zu melden. Sie + muss dann in die Arbeitsliste, sonst hätte der Klick keine Folge. + """ + raus = set() + for datei in projekte.wurzel(projekt).glob("*.md"): + s = parser.zerlege(datei.read_text()) + if s["art"] == parser.VISION: + continue + for f in s["funktionen"]: + if f["stand"] == parser.OFFEN: + raus.add((s["titel"], f["text"])) + return raus + + +def _schritte(projekt: str, aenderungen: dict) -> list[dict]: + """Die Arbeitsliste: ein Eintrag je Streichung, Kopfänderung und Funktion. + + Karte und Funktion stehen daneben, nicht nur im Text. Beim Abhaken wird die + Funktion auf „gebaut“ gesetzt — den Namen aus dem Satz zurückzuparsen wäre + eine zweite Wahrheit über dieselbe Sache. + """ + offen = _offene(projekt) + raus = [] + erledigt = set() + + def funktionsschritt(titel: str, name: str, art: str): + erledigt.add((titel, name)) + # Offen schlägt geändert: „prüfen und herstellen“ deckt beides ab, und der + # Agent soll dem vorhandenen Code nicht glauben. + marke = PRUEFEN if (titel, name) in offen else ART[art] + raus.append({"text": f"{titel} / {name}: {marke}", "karte": titel, + # Eine gestrichene Funktion gibt es hinterher nicht mehr + "funktion": "" if art == "weg" else name}) + + for titel in sorted(aenderungen): + e = aenderungen[titel] + if e["art"] == "weg": + raus.append({"text": f"Karte „{titel}“ streichen", + "karte": titel, "funktion": ""}) + erledigt |= {(titel, n) for n in e.get("funktionen", {})} + continue + if e.get("kopf"): + raus.append({"text": f"Karte „{titel}“: Kartenkopf anpassen", + "karte": titel, "funktion": ""}) + for name, art in sorted(e.get("funktionen", {}).items()): + funktionsschritt(titel, name, art) + + for titel, name in sorted(offen - erledigt): + funktionsschritt(titel, name, "geaendert") + return raus + + +def _visionen(projekt: str) -> set: + """Titel der Vision-Karten, in Stand und Arbeitskopie.""" + titel = set() + for ordner in (projekte.stand(projekt), projekte.wurzel(projekt)): + for datei in ordner.glob("*.md"): + s = parser.zerlege(datei.read_text()) + if s["art"] == parser.VISION: + titel.add(s["titel"]) + return titel + + +def bau_auftrag(projekt: str) -> tuple[str, list[dict]]: + """Prompt und Arbeitsliste, aus dem Stand der laufenden Planung. + + Die Vision bleibt außen vor: sie beschreibt Absicht, keinen Auftrag — + eine geänderte Vision ist nichts, was ein Agent bauen soll. + """ + if not planung.laeuft(projekt): + return "", [] + visionen = _visionen(projekt) + aenderungen = {t: e for t, e in planung.aenderungen(projekt).items() + if t not in visionen} + schritte = _schritte(projekt, aenderungen) + if not schritte: + return "", [] + # Der Sollzustand jeder Karte, die Arbeit trägt — auch der unveränderten mit + # einer offenen Funktion. Ohne ihren Text wüsste der Agent nicht, wogegen er prüft. + bleibend = {s["karte"] for s in schritte if s["karte"] not in { + t for t, e in aenderungen.items() if e["art"] == "weg"}} + text = AUFTRAG.format( + schritte="\n".join(f'- {s["text"]}' for s in schritte), + marke=MARKE, + pruefen=PRUEFEN, + karten=_kartentexte(projekt, bleibend)) + return text, schritte + + +def status(projekt: str) -> dict: + return _laeufe.get(projekt) or { + "laeuft": False, "fehler": "", "text": "", + "schritte": [], "aktivitaet": "", "uebernommen": False, + } + + +# „offen“ steht als eigener Block in der Datei; fehlt er, gilt die Funktion als +# gebaut. Umstellen heißt darum: den Block streichen. Ein Umbau über den Parser +# würde die Datei neu schreiben und dabei unbekannte Blöcke verlieren. +_FUNKTIONSMARKE = re.compile(r"^[ \t]*$", re.M | re.I) +_OFFENBLOCK = re.compile( + r"^[ \t]*\n[ \t]*" + parser.OFFEN + r"[ \t]*\n", re.M | re.I) + + +def _als_gebaut(roh: str, funktion: str) -> str: + """Streicht den offen-Vermerk genau dieser Funktion.""" + marken = [m.start() for m in _FUNKTIONSMARKE.finditer(roh)] + for i, start in enumerate(marken): + ende = marken[i + 1] if i + 1 < len(marken) else len(roh) + block = roh[start:ende] + zeilen = [z.strip() for z in block.splitlines()[1:] if z.strip()] + titel = next((z for z in zeilen + if not z.startswith("\nGalerie\n{T}\n\nBild wählen\n") + features.anlegen("A", f"\nShop\n{T}\n\nKarte kaufen\n") + yield "A" + auftrag._laeufe.clear() + + +def test_ohne_planung_kein_auftrag(projekt): + assert auftrag.bau_auftrag(projekt) == ("", []) + + +def test_leere_planung_kein_auftrag(projekt): + planung.starte(projekt) + assert auftrag.bau_auftrag(projekt) == ("", []) + + +def test_auftrag_nennt_diff_und_sollzustand(projekt): + planung.starte(projekt) + features.anlegen(projekt, f"\nMerkliste\n{T}\n\nProdukt merken\n") + f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Shop") + features.loeschen(projekt, f["id"]) + + text, schritte = auftrag.bau_auftrag(projekt) + texte = [s["text"] for s in schritte] + assert "Merkliste / Produkt merken: PRÜFEN" in texte + assert "Karte „Shop“ streichen" in texte + assert all(s in text for s in texte) + # Die Zuordnung steht daneben, nicht nur im Satz + assert {"text": "Merkliste / Produkt merken: PRÜFEN", "karte": "Merkliste", + "funktion": "Produkt merken"} in schritte + assert {"text": "Karte „Shop“ streichen", "karte": "Shop", + "funktion": ""} in schritte + # Sollzustand: die neue Karte steht voll drin, die gestrichene nicht + assert "\nProdukt merken" in text + assert "Karte kaufen" not in text.split("Die betroffenen Karten")[1] + + +def test_start_braucht_verzeichnis(projekt): + assert auftrag.starte(projekt, "tu was", ["x"]) is False + + +def test_start_braucht_auftrag(projekt, tmp_path): + verzeichnis.setze(projekt, str(tmp_path)) + assert auftrag.starte(projekt, "", []) is False + + +class Strom: + """Attrappe des Claude-Prozesses: gibt vorbereitete Stream-Zeilen aus.""" + + def __init__(self, zeilen, rc=0, gesehen=None): + import json as _json + self._zeilen = [(_json.dumps(z) + "\n").encode() for z in zeilen] + self.returncode = rc + self._gesehen = gesehen if gesehen is not None else {} + + class Stdin: + def write(s, daten): self._gesehen["eingabe"] = daten.decode() + async def drain(s): pass + def close(s): pass + self.stdin = Stdin() + + class Stdout: + async def readline(s): + return self._zeilen.pop(0) if self._zeilen else b"" + self.stdout = Stdout() + + class Stderr: + async def read(s): return b"" + self.stderr = Stderr() + + async def wait(self): + return self.returncode + + +def text_ereignis(text): + return {"type": "assistant", "message": {"content": [{"type": "text", "text": text}]}} + + +def test_start_fuehrt_claude_im_verzeichnis_aus(projekt, tmp_path, monkeypatch): + verzeichnis.setze(projekt, str(tmp_path)) + planung.starte(projekt) + gesehen = {} + + async def unecht(*kommando, cwd, **k): + gesehen["kommando"] = kommando + gesehen["cwd"] = cwd + return Strom([{"type": "result", "result": "fertig"}], gesehen=gesehen) + + monkeypatch.setattr(asyncio, "create_subprocess_exec", unecht) + + async def lauf(): + assert auftrag.starte(projekt, "Setze um: X", + [{"text": "S1", "karte": "", "funktion": ""}]) is True + assert auftrag.status(projekt)["laeuft"] is True + await asyncio.gather(*auftrag._aufgaben) + + asyncio.run(lauf()) + assert gesehen["kommando"][0] == "claude" + assert "--output-format" in gesehen["kommando"] + assert gesehen["cwd"] == str(tmp_path) + assert gesehen["eingabe"] == "Setze um: X" + stand = auftrag.status(projekt) + assert stand["text"] == "fertig" + assert stand["laeuft"] is False + + +def test_schritte_werden_abgehakt_und_planung_uebernommen(projekt, tmp_path, monkeypatch): + verzeichnis.setze(projekt, str(tmp_path)) + planung.starte(projekt) + features.anlegen(projekt, f"\nMerkliste\n{T}\n\nProdukt merken\n") + anweisung, schritte = auftrag.bau_auftrag(projekt) + + async def unecht(*a, **k): + return Strom([ + {"type": "assistant", "message": {"content": [ + {"type": "tool_use", "name": "Edit", "input": {"file_path": "x.py"}}]}}, + text_ereignis(f'ERLEDIGT: {schritte[0]["text"]}'), + {"type": "result", "result": "alles gebaut"}, + ]) + + monkeypatch.setattr(asyncio, "create_subprocess_exec", unecht) + + async def lauf(): + auftrag.starte(projekt, anweisung, schritte) + await asyncio.gather(*auftrag._aufgaben) + + asyncio.run(lauf()) + stand = auftrag.status(projekt) + assert stand["schritte"] == [{**schritte[0], "fertig": True}] + assert stand["uebernommen"] is True + assert planung.laeuft(projekt) is False + assert "Merkliste" in [f["sektionen"]["titel"] for f in features.liste(projekt)] + + +def test_fehlschlag_laesst_die_planung_stehen(projekt, tmp_path, monkeypatch): + verzeichnis.setze(projekt, str(tmp_path)) + planung.starte(projekt) + features.anlegen(projekt, f"\nMerkliste\n{T}\n\nProdukt merken\n") + anweisung, schritte = auftrag.bau_auftrag(projekt) + + async def unecht(*a, **k): + return Strom([], rc=1) + + monkeypatch.setattr(asyncio, "create_subprocess_exec", unecht) + + async def lauf(): + auftrag.starte(projekt, anweisung, schritte) + await asyncio.gather(*auftrag._aufgaben) + + asyncio.run(lauf()) + stand = auftrag.status(projekt) + assert stand["uebernommen"] is False + assert stand["fehler"] + assert planung.laeuft(projekt) is True + assert "Merkliste" not in [f["sektionen"]["titel"] for f in features.liste(projekt, nur_stand=True)] + + +def test_ungefaehre_meldung_hakt_den_naechsten_schritt_ab(): + lauf = {"schritte": [{"text": "Galerie / Bild wählen: NEU", "fertig": False}, + {"text": "Karte „Shop“ streichen", "fertig": False}]} + auftrag._hake_ab("Test", lauf, "ERLEDIGT: Galerie / Bild wählen (NEU)") + assert lauf["schritte"][0]["fertig"] is True + auftrag._hake_ab("Test", lauf, "ERLEDIGT: völlig anderes Zeug") + assert lauf["schritte"][1]["fertig"] is False + + +def test_fehlender_claude_wird_gemeldet(projekt, tmp_path, monkeypatch): + verzeichnis.setze(projekt, str(tmp_path)) + + async def kaputt(*a, **k): + raise FileNotFoundError("claude") + + monkeypatch.setattr(asyncio, "create_subprocess_exec", kaputt) + + async def lauf(): + auftrag.starte(projekt, "X", [{"text": "S", "karte": "", "funktion": ""}]) + await asyncio.gather(*auftrag._aufgaben) + + asyncio.run(lauf()) + assert "claude-CLI nicht gefunden" in auftrag.status(projekt)["fehler"] + assert auftrag.status(projekt)["laeuft"] is False + + +def test_zweiter_start_wird_abgelehnt(projekt, tmp_path): + verzeichnis.setze(projekt, str(tmp_path)) + auftrag._laeufe[projekt] = {"laeuft": True, "fehler": "", "text": "", + "schritte": [], "aktivitaet": "", "uebernommen": False} + with pytest.raises(ValueError): + auftrag.starte(projekt, "X", [{"text": "S", "karte": "", "funktion": ""}]) + + +# ------------------------------------------------------------- Verzeichnis + +def test_verzeichnis_wird_gemerkt(projekt, tmp_path): + verzeichnis.setze(projekt, str(tmp_path)) + assert verzeichnis.lies(projekt) == str(tmp_path) + verzeichnis.loesche(projekt) + assert verzeichnis.lies(projekt) == "" + + +def test_verzeichnis_lehnt_wurzel_und_relatives_ab(projekt): + with pytest.raises(ValueError): + verzeichnis.pruefe("/") + with pytest.raises(ValueError): + verzeichnis.pruefe("relativ/pfad") + with pytest.raises(FileNotFoundError): + verzeichnis.pruefe("/gibt/es/nicht") + + +def test_verzeichnis_liegt_im_stand_nicht_in_der_kopie(projekt, tmp_path): + planung.starte(projekt) + verzeichnis.setze(projekt, str(tmp_path)) + planung.brich_ab(projekt) + assert verzeichnis.lies(projekt) == str(tmp_path) + + +# ------------------------------------------------------------- Durchblättern + +def test_ordner_listet_nur_sichtbare_verzeichnisse(tmp_path): + (tmp_path / "b").mkdir() + (tmp_path / "A").mkdir() + (tmp_path / ".versteckt").mkdir() + (tmp_path / "datei.txt").write_text("x") + antwort = verzeichnis.ordner(str(tmp_path)) + assert antwort["ordner"] == ["A", "b"] + assert antwort["pfad"] == str(tmp_path) + assert antwort["eltern"] == str(tmp_path.parent) + + +def test_ordner_ohne_pfad_beginnt_daheim(): + from pathlib import Path + assert verzeichnis.ordner("")["pfad"] == str(Path.home()) + + +def test_ordner_lehnt_datei_und_relatives_ab(tmp_path): + (tmp_path / "d.txt").write_text("x") + with pytest.raises(FileNotFoundError): + verzeichnis.ordner(str(tmp_path / "d.txt")) + with pytest.raises(ValueError): + verzeichnis.ordner("relativ") + + +def test_vision_gehoert_nie_zum_auftrag(projekt): + features.anlegen(projekt, "\nVision\n\nvision\n\nAlt\n") + planung.starte(projekt) + v = next(f for f in features.liste(projekt) if f["sektionen"]["art"] == "vision") + features.speichern(projekt, v["id"], v["roh"].replace("Alt", "Neu")) + assert auftrag.bau_auftrag(projekt) == ("", []) + + features.anlegen(projekt, f"\nMerkliste\n{T}\n\nProdukt merken\n") + text, schritte = auftrag.bau_auftrag(projekt) + assert [s["text"] for s in schritte] == ["Merkliste / Produkt merken: PRÜFEN"] + assert "Vision" not in text + + +# ------------------------------------------------- Stand: bestellt wird gebaut + +def _stand(projekt, karte, funktion): + f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == karte) + return next(x["stand"] for x in f["sektionen"]["funktionen"] if x["text"] == funktion) + + +def test_abgehakte_funktion_gilt_als_gebaut(projekt, tmp_path, monkeypatch): + """Der Agent hat es gebaut — dann darf die Karte nicht „bestellt“ behaupten.""" + verzeichnis.setze(projekt, str(tmp_path)) + planung.starte(projekt) + features.anlegen(projekt, f"\nMerkliste\n{T}\n\n" + f"Produkt merken\n\noffen\n{T}\n" + f"\nProdukt entfernen\n\noffen\n") + anweisung, schritte = auftrag.bau_auftrag(projekt) + merken = next(s for s in schritte if s["funktion"] == "Produkt merken") + + async def unecht(*a, **k): + return Strom([text_ereignis(f'ERLEDIGT: {merken["text"]}'), + {"type": "result", "result": "eins gebaut"}]) + + monkeypatch.setattr(asyncio, "create_subprocess_exec", unecht) + + async def lauf(): + auftrag.starte(projekt, anweisung, schritte) + await asyncio.gather(*auftrag._aufgaben) + + asyncio.run(lauf()) + # Nur der abgehakte Schritt wandert um; der andere bleibt bestellt + assert _stand(projekt, "Merkliste", "Produkt merken") == "gebaut" + assert _stand(projekt, "Merkliste", "Produkt entfernen") == "offen" + + +def test_gestrichene_funktion_wird_nicht_umgestellt(projekt, tmp_path): + """Was weg ist, ist nicht gebaut — der Schritt trägt darum keinen Namen.""" + planung.starte(projekt) + f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Galerie") + features.speichern(projekt, f["id"], "\nGalerie\n") + _, schritte = auftrag.bau_auftrag(projekt) + weg = next(s for s in schritte if "Bild wählen" in s["text"]) + assert weg["funktion"] == "" + + +def test_offen_vermerk_bleibt_bei_anderer_funktion(projekt): + roh = ("\nGalerie\n" + "\nBild wählen\n\noffen\n" + "\nBild schließen\n\noffen\n") + neu = auftrag._als_gebaut(roh, "Bild schließen") + assert neu.count("offen") == 1 + assert "Bild wählen\n\noffen" in neu + + +def test_unbekannte_bloecke_bleiben_erhalten(projekt): + """Textoperation statt Neuschreiben: der Rest der Datei bleibt Zeichen für Zeichen.""" + roh = ("\nGalerie\n\nnicht anfassen\n" + "\nBild wählen\n\noffen\n" + "\n- Eine Regel\n") + neu = auftrag._als_gebaut(roh, "Bild wählen") + assert "\nnicht anfassen" in neu + assert "\n- Eine Regel" in neu + assert "offen" not in neu + + +# ---------------------------------------- offen heißt: noch nicht bewiesen + +def _auf_offen(projekt, karte, funktion): + """Wie ein Klick auf den Stand: gebaut zurück auf offen.""" + f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == karte) + roh = f["roh"].replace(f"\n{funktion}\n", + f"\n{funktion}\n\noffen\n") + features.speichern(projekt, f["id"], roh) + + +def test_zurueckgesetzte_funktion_kommt_in_die_arbeitsliste(projekt): + """Eine kaputte Umsetzung meldet man, indem man die Funktion auf offen setzt. + + Die Karte ändert sich dadurch, aber sonst nichts — vorher blieb der Klick folgenlos. + """ + planung.starte(projekt) + _auf_offen(projekt, "Galerie", "Bild wählen") + text, schritte = auftrag.bau_auftrag(projekt) + assert [s["text"] for s in schritte] == ["Galerie / Bild wählen: PRÜFEN"] + # Der Sollzustand der Karte gehört dazu, sonst weiß der Agent nicht, wogegen er prüft + assert "\nBild wählen" in text + assert auftrag.PRUEFEN in text + + +def test_offene_funktion_ohne_kartenaenderung(projekt, tmp_path): + """Offen in der Kopie und im Stand: kein Diff, trotzdem Arbeit.""" + f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Shop") + features.speichern(projekt, f["id"], f["roh"].replace( + "\nKarte kaufen\n", + "\nKarte kaufen\n\noffen\n")) + planung.starte(projekt) + assert planung.aenderungen(projekt) == {} + _, schritte = auftrag.bau_auftrag(projekt) + assert [s["text"] for s in schritte] == ["Shop / Karte kaufen: PRÜFEN"] + + +def test_offen_schlaegt_geaendert(projekt): + """Eine offene Funktion wird geprüft, nicht bloß angepasst.""" + planung.starte(projekt) + f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Galerie") + features.speichern(projekt, f["id"], f["roh"].replace( + "\nBild wählen\n", + "\nBild wählen\n\noffen\n" + "\n- Eine neue Regel\n")) + _, schritte = auftrag.bau_auftrag(projekt) + assert [s["text"] for s in schritte] == ["Galerie / Bild wählen: PRÜFEN"] + + +def test_gebaut_und_geaendert_bleibt_geaendert(projekt): + planung.starte(projekt) + f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Galerie") + features.speichern(projekt, f["id"], f["roh"].replace( + "\nBild wählen\n", + "\nBild wählen\n\n- Eine neue Regel\n")) + _, schritte = auftrag.bau_auftrag(projekt) + assert [s["text"] for s in schritte] == ["Galerie / Bild wählen: GEÄNDERT"] + + +def test_gestrichene_karte_zieht_ihre_offenen_nicht_nach(projekt): + """Eine gestrichene Karte darf nicht zusätzlich als „prüfen“ auftauchen.""" + f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Shop") + features.speichern(projekt, f["id"], f["roh"].replace( + "\nKarte kaufen\n", + "\nKarte kaufen\n\noffen\n")) + planung.starte(projekt) + g = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Shop") + features.loeschen(projekt, g["id"]) + _, schritte = auftrag.bau_auftrag(projekt) + assert [s["text"] for s in schritte] == ["Karte „Shop“ streichen"] + + +def test_ohne_planung_kein_lauf(projekt): + """Der Agent arbeitet auf der Planung; ohne sie gibt es keinen Auftrag.""" + _auf_offen(projekt, "Galerie", "Bild wählen") + assert auftrag.bau_auftrag(projekt) == ("", []) + + +def test_auftrag_verlangt_offenlegung_des_ungeprueften(projekt): + planung.starte(projekt) + _auf_offen(projekt, "Galerie", "Bild wählen") + text, _ = auftrag.bau_auftrag(projekt) + assert "nicht prüfen konntest" in text + assert "Hake nur ab, was du geprüft hast" in text diff --git a/backend/tests/test_chat.py b/backend/tests/test_chat.py new file mode 100644 index 0000000..432f51e --- /dev/null +++ b/backend/tests/test_chat.py @@ -0,0 +1,111 @@ +"""Was das Planungsgespräch darf — und was es nicht sieht. + +Geprüft wird nicht die Antwort des Modells, sondern womit es losgeschickt wird: +Werkzeugsatz, Arbeitsverzeichnis und der Absatz im Systemprompt gehören zusammen. +Fällt eines auseinander, behauptet das Modell nachgesehen zu haben, ohne zu können. +""" + +import json + +import pytest + +import agents +import chat +import projekte +import verzeichnis + +KARTE = ("\nUpload\n\nkern\n" + "\nDateien landen im Speicher.\n" + "\nDatei wählen\n\n- Dialog öffnen\n") + + +@pytest.fixture +def projekt(datenordner): + projekte.anlegen("P") + (datenordner / "P" / "upload.md").write_text(KARTE) + return "P" + + +@pytest.fixture +def mitschrift(monkeypatch): + """Fängt den Aufruf ab und gibt eine gültige Antwort zurück.""" + gesehen = {} + + async def antworte(system, inhalt, kommando=None, ordner=None): + gesehen.update(system=system, inhalt=inhalt, kommando=kommando, ordner=ordner) + return json.dumps({"antwort": "Verstanden.", "karten": []}) + + monkeypatch.setattr(agents, "frage_lokal", antworte) + return gesehen + + +async def test_ohne_verzeichnis_kein_lesen(projekt, mitschrift): + await chat.frage(projekt, "Was kann das Projekt?") + assert mitschrift["kommando"] == agents.PLANUNG_OHNE_CODE + assert mitschrift["ordner"] is None + assert chat.CODE_OHNE in mitschrift["system"] + + +async def test_mit_verzeichnis_darf_lesen(projekt, mitschrift, tmp_path): + code = tmp_path / "quelltext" + code.mkdir() + verzeichnis.setze(projekt, str(code)) + await chat.frage(projekt, "Gibt es den Upload schon?") + assert mitschrift["kommando"] == agents.PLANUNG_KOMMANDO + assert mitschrift["ordner"] == str(code.resolve()) + assert chat.CODE_MIT in mitschrift["system"] + + +async def test_toter_pfad_zaehlt_wie_keiner(projekt, mitschrift, tmp_path): + """Sonst startet der Prozess nicht, und die Meldung zeigt auf die CLI.""" + code = tmp_path / "weg" + code.mkdir() + verzeichnis.setze(projekt, str(code)) + code.rmdir() + await chat.frage(projekt, "Und jetzt?") + assert mitschrift["kommando"] == agents.PLANUNG_OHNE_CODE + assert mitschrift["ordner"] is None + + +async def test_planung_sucht_nicht_im_web(projekt, mitschrift, tmp_path): + """Fremdes Wissen kommt aus der Recherche, nicht nebenbei in einen Entwurf.""" + code = tmp_path / "quelltext" + code.mkdir() + verzeichnis.setze(projekt, str(code)) + await chat.frage(projekt, "Wie macht man das üblicherweise?") + for satz in (agents.PLANUNG_KOMMANDO, agents.PLANUNG_OHNE_CODE): + assert "WebSearch" not in _erlaubt(satz) + assert "WebFetch" not in _erlaubt(satz) + + +def test_recherche_sieht_keinen_quelltext(): + """Umgekehrt: aus dem Projekt darf nichts in eine Suchanfrage geraten.""" + erlaubt = _erlaubt(agents.RECHERCHE_KOMMANDO) + assert "WebSearch" in erlaubt and "WebFetch" in erlaubt + for werkzeug in ("Read", "Glob", "Grep"): + assert werkzeug not in erlaubt + + +@pytest.mark.parametrize("kommando", [ + agents.PLANUNG_KOMMANDO, agents.PLANUNG_OHNE_CODE, agents.RECHERCHE_KOMMANDO]) +def test_kein_satz_kann_etwas_anstossen(kommando): + """Fremder Text im Kontext darf nichts auslösen, egal woher er kommt.""" + gesperrt = _gesperrt(kommando) + for werkzeug in ("Write", "Edit", "Bash", "CronCreate", "PushNotification", + "SendMessage", "Workflow", "Task"): + assert werkzeug in gesperrt + assert "--safe-mode" in kommando + + +def _abschnitt(kommando: tuple, flagge: str) -> list: + rest = list(kommando[kommando.index(flagge) + 1:]) + ende = next((i for i, w in enumerate(rest) if w.startswith("--")), len(rest)) + return rest[:ende] + + +def _erlaubt(kommando: tuple) -> list: + return _abschnitt(kommando, "--allowed-tools") + + +def _gesperrt(kommando: tuple) -> list: + return _abschnitt(kommando, "--disallowed-tools") diff --git a/backend/tests/test_ledger.py b/backend/tests/test_ledger.py index a86118c..cd745e0 100644 --- a/backend/tests/test_ledger.py +++ b/backend/tests/test_ledger.py @@ -22,13 +22,16 @@ def projekt(datenordner): def karte(projekt, titel, *funktionen): - """funktionen sind (name, regel) oder (name, regel, [testschritte]).""" + """funktionen sind (name, regel) oder (name, regel, [testschritte]). + + Ohne eigene Schritte bekommt die Funktion einen Platzhalter-Ablauf: Testschritte + sind Pflicht, und ohne sie bricht die Messung vor allem anderen ab. + """ text = f"\n{titel}\n" for eintrag in funktionen: - name, regel, schritte = (*eintrag, [])[:3] + name, regel, schritte = (*eintrag, ["Karte öffnen", "Karte offen"])[:3] text += f"\n{name}\n\n- {regel}\n" - if schritte: - text += "\n" + "".join(f"- {s}\n" for s in schritte) + text += "\n" + "".join(f"- {s}\n" for s in schritte) return features.anlegen(projekt, text) @@ -116,14 +119,14 @@ async def test_stilurteil_wird_gemerkt_und_nicht_neu_gefragt(projekt, monkeypatc liste, arbeite, abschluss = await pruefung._stil_aufgaben(projekt) for a in liste: - assert await arbeite(a, None) == [] + assert await arbeite(a) == [] abschluss() erste = modell.rufe assert erste >= len(pruefung.TEMPERATUREN) liste, arbeite, abschluss = await pruefung._stil_aufgaben(projekt) for a in liste: - assert await arbeite(a, None) == [] + assert await arbeite(a) == [] assert modell.rufe == erste # keine einzige neue Anfrage @@ -136,7 +139,7 @@ async def test_geaenderter_text_wird_neu_gefragt(projekt, monkeypatch): liste, arbeite, abschluss = await pruefung._stil_aufgaben(projekt) for a in liste: - await arbeite(a, None) + await arbeite(a) abschluss() vorher = modell.rufe @@ -144,7 +147,7 @@ async def test_geaenderter_text_wird_neu_gefragt(projekt, monkeypatch): datei.write_text(datei.read_text().replace("- Knopf", "- Ganz anderer Text")) liste, arbeite, _ = await pruefung._stil_aufgaben(projekt) for a in liste: - await arbeite(a, None) + await arbeite(a) assert modell.rufe > vorher @@ -159,7 +162,7 @@ async def test_gemessener_verstoss_kommt_nie_aus_dem_gedaechtnis(projekt, monkey for lauf in range(2): liste, arbeite, abschluss = await pruefung._stil_aufgaben(projekt) - gefunden = [p for a in liste for p in await arbeite(a, None)] + gefunden = [p for a in liste for p in await arbeite(a)] abschluss() assert [p["vorschlag"] for p in gefunden] == ["Passwort prüfen"], lauf assert modell.rufe > len(pruefung.TEMPERATUREN) # zweimal wirklich gefragt diff --git a/backend/tests/test_planung.py b/backend/tests/test_planung.py index b0f5244..296cbb1 100644 --- a/backend/tests/test_planung.py +++ b/backend/tests/test_planung.py @@ -199,3 +199,33 @@ def test_gespraech_und_gedaechtnis_wandern_mit(projekt): def test_die_kopie_kopiert_sich_nicht_selbst(projekt): planung.starte(projekt) assert not (projekte.wurzel(projekt) / projekte.PLANUNG).exists() + + +def test_arbeitsverzeichnis_ueberlebt_das_umsetzen(projekt, tmp_path): + """Erst nach dem Planungsstart festgelegt — dann fehlt es in der Kopie. + + Vorher räumte das Umsetzen es mit dem alten Stand weg, und der nächste Lauf + fand kein Verzeichnis mehr. + """ + import verzeichnis + planung.starte(projekt) + verzeichnis.setze(projekt, str(tmp_path)) + assert not (planung._kopie(projekt) / verzeichnis.DATEI).exists() + + planung.setze_um(projekt) + assert verzeichnis.lies(projekt) == str(tmp_path) + + +def test_geplantes_verzeichnis_gewinnt(projekt, tmp_path): + """Steht es in beiden, gilt die Kopie — sie ist der neuere Stand.""" + import verzeichnis + alt = tmp_path / "alt" + alt.mkdir() + verzeichnis.setze(projekt, str(alt)) + planung.starte(projekt) + neu = tmp_path / "neu" + neu.mkdir() + (planung._kopie(projekt) / verzeichnis.DATEI).write_text(str(neu)) + + planung.setze_um(projekt) + assert verzeichnis.lies(projekt) == str(neu) diff --git a/backend/tests/test_recherche.py b/backend/tests/test_recherche.py new file mode 100644 index 0000000..84f9780 --- /dev/null +++ b/backend/tests/test_recherche.py @@ -0,0 +1,193 @@ +import pytest + +import agents +import projekte +import recherche + + +@pytest.fixture +def projekt(datenordner): + projekte.anlegen("P") + return "P" + + +def test_leeres_projekt_hat_keine_faeden(projekt): + assert recherche.liste(projekt) == [] + + +def test_anlegen_gibt_faden_mit_id(projekt): + faden = recherche.anlegen(projekt) + assert faden["id"] and faden["verlauf"] == [] + assert [f["id"] for f in recherche.liste(projekt)] == [faden["id"]] + + +def test_faeden_haben_eigene_ids(projekt): + a, b = recherche.anlegen(projekt), recherche.anlegen(projekt) + assert a["id"] != b["id"] + assert len(recherche.liste(projekt)) == 2 + + +def test_loeschen_trifft_nur_den_einen(projekt): + a, b = recherche.anlegen(projekt), recherche.anlegen(projekt) + recherche.loeschen(projekt, a["id"]) + assert [f["id"] for f in recherche.liste(projekt)] == [b["id"]] + + +def test_loeschen_ohne_faden_ist_404(projekt): + with pytest.raises(FileNotFoundError): + recherche.loeschen(projekt, "gibtsnicht") + + +def test_faeden_liegen_im_projektstand_nicht_in_der_planung(projekt): + """Nachgeschlagenes überlebt einen Planungsabbruch — es gehört zum Projekt.""" + recherche.anlegen(projekt) + (projekte.stand(projekt) / projekte.PLANUNG).mkdir() + assert len(recherche.liste(projekt)) == 1 + assert (projekte.stand(projekt) / recherche.DATEI).is_file() + + +def _antwort(satz="Laut Quelle X: ja."): + """Eine Modellantwort — Markdown, nicht JSON.""" + async def antworte(system, inhalt, kommando=None, ordner=None): + return satz + return antworte + + +async def test_frage_haengt_beide_zeilen_an(projekt, monkeypatch): + faden = recherche.anlegen(projekt) + monkeypatch.setattr(agents, "frage_lokal", _antwort(" Laut Quelle X: ja. ")) + erg = await recherche.frage(projekt, faden["id"], "Wie geht das?") + assert [(e["rolle"], e["text"]) for e in erg["verlauf"]] == [ + ("person", "Wie geht das?"), ("ki", "Laut Quelle X: ja.")] + + +async def test_erste_frage_benennt_den_faden(projekt, monkeypatch): + faden = recherche.anlegen(projekt) + monkeypatch.setattr(agents, "frage_lokal", _antwort("ok")) + erg = await recherche.frage(projekt, faden["id"], "Wie lädt man\nzu S3 hoch?") + assert erg["titel"] == "Wie lädt man zu S3 hoch?" + # Die zweite Frage lässt den Namen stehen: der Reiter soll nicht wandern + erg = await recherche.frage(projekt, faden["id"], "Und die Grenzen?") + assert erg["titel"] == "Wie lädt man zu S3 hoch?" + + +async def test_langer_titel_wird_gekuerzt(projekt, monkeypatch): + faden = recherche.anlegen(projekt) + monkeypatch.setattr(agents, "frage_lokal", _antwort("ok")) + erg = await recherche.frage(projekt, faden["id"], "w" * 80) + assert len(erg["titel"]) == recherche.TITELLAENGE + 1 + assert erg["titel"].endswith("…") + + +async def test_recherche_bekommt_die_websuche(projekt, monkeypatch): + """Der Werkzeugsatz ist der ganze Unterschied zum Planungsgespräch.""" + faden = recherche.anlegen(projekt) + gesehen = {} + + async def antworte(system, inhalt, kommando=None, ordner=None): + gesehen.update(kommando=kommando, inhalt=inhalt) + return "ok" + + monkeypatch.setattr(agents, "frage_lokal", antworte) + await recherche.frage(projekt, faden["id"], "Was gilt draußen?") + assert gesehen["kommando"] == agents.RECHERCHE_KOMMANDO + + +async def test_die_karten_liegen_im_prompt(projekt, monkeypatch): + """Ohne Bestand ist „was fehlt noch" nicht zu beantworten — dann rät das Modell.""" + (projekte.stand(projekt) / "gold.md").write_text( + "\nGold\n\nkern\n" + "\nSpieler verdient Gold pro Runde.\n" + "\nZinsen erhalten\n\noffen\n" + "\n- Runde spielen\n") + faden = recherche.anlegen(projekt) + gesehen = {} + + async def antworte(system, inhalt, kommando=None, ordner=None): + gesehen["system"] = system + return "ok" + + monkeypatch.setattr(agents, "frage_lokal", antworte) + await recherche.frage(projekt, faden["id"], "Was fehlt noch?") + assert "Zinsen erhalten" in gesehen["system"] + # Der Stand ist der Punkt: er unterscheidet Gebautes von Bestelltem + assert '"stand": "offen"' in gesehen["system"] + # Testabläufe blähen den Prompt und tragen keine Recherche + assert "Runde spielen" not in gesehen["system"] + + +async def test_vision_kommt_mit(projekt, monkeypatch): + (projekte.stand(projekt) / "vision.md").write_text( + "\nVision\n\nvision\n" + "\nTFT im Browser nachbauen.\n") + faden = recherche.anlegen(projekt) + gesehen = {} + + async def antworte(system, inhalt, kommando=None, ordner=None): + gesehen["system"] = system + return "ok" + + monkeypatch.setattr(agents, "frage_lokal", antworte) + await recherche.frage(projekt, faden["id"], "Und nun?") + assert "TFT im Browser nachbauen." in gesehen["system"] + + +async def test_markdown_bleibt_wie_es_kam(projekt, monkeypatch): + """Die Antwort wird als Markdown angezeigt — der Server fasst sie nicht an.""" + roh = "Kurz gesagt.\n\n## Festgelegt\n- **5 Gold** pro Runde\n\n## Quellen\n- [Wiki](http://x)" + faden = recherche.anlegen(projekt) + monkeypatch.setattr(agents, "frage_lokal", _antwort(f"\n{roh}\n")) + erg = await recherche.frage(projekt, faden["id"], "Wie geht Gold?") + assert erg["verlauf"][-1]["text"] == roh + + +async def test_leere_frage_wird_abgelehnt(projekt): + faden = recherche.anlegen(projekt) + with pytest.raises(ValueError): + await recherche.frage(projekt, faden["id"], " ") + + +async def test_geschlossener_faden_verwirft_die_antwort(projekt, monkeypatch): + """Antworten dauern Minuten. Wer inzwischen schließt, will das Ergebnis nicht.""" + faden = recherche.anlegen(projekt) + + async def antworte(system, inhalt, kommando=None, ordner=None): + recherche.loeschen(projekt, faden["id"]) + return "zu spät" + + monkeypatch.setattr(agents, "frage_lokal", antworte) + with pytest.raises(FileNotFoundError): + await recherche.frage(projekt, faden["id"], "Was gilt?") + assert recherche.liste(projekt) == [] + + +async def test_paralleler_faden_bleibt_erhalten(projekt, monkeypatch): + """Der zweite Faden entsteht, während der erste noch wartet.""" + a = recherche.anlegen(projekt) + neu = {} + + async def antworte(system, inhalt, kommando=None, ordner=None): + neu["b"] = recherche.anlegen(projekt) + return "fertig" + + monkeypatch.setattr(agents, "frage_lokal", antworte) + await recherche.frage(projekt, a["id"], "Frage") + faeden = recherche.liste(projekt) + assert [f["id"] for f in faeden] == [a["id"], neu["b"]["id"]] + # Was der eine Faden erfährt, bleibt beim einen + assert len(faeden[0]["verlauf"]) == 2 and faeden[1]["verlauf"] == [] + + +def test_kaputte_datei_gilt_als_leer(projekt): + (projekte.stand(projekt) / recherche.DATEI).write_text("{kein json") + assert recherche.liste(projekt) == [] + + +async def test_tiefe_haelt_den_faden_kurz(projekt, monkeypatch): + faden = recherche.anlegen(projekt) + monkeypatch.setattr(agents, "frage_lokal", _antwort("ok")) + for i in range(recherche.TIEFE): + await recherche.frage(projekt, faden["id"], f"Frage {i}") + verlauf = recherche.liste(projekt)[0]["verlauf"] + assert len(verlauf) == recherche.TIEFE + assert verlauf[-2]["text"] == f"Frage {recherche.TIEFE - 1}" diff --git a/backend/tests/test_routes.py b/backend/tests/test_routes.py index 17e9b28..8167250 100644 --- a/backend/tests/test_routes.py +++ b/backend/tests/test_routes.py @@ -72,3 +72,41 @@ async def test_pruefung_ohne_konfiguration(client, monkeypatch): async def test_unbekanntes_projekt(client): assert (await client.get("/api/projekte/Fremd/features")).status_code == 404 assert (await client.post("/api/projekte/Fremd/features", json={"roh": ROH})).status_code == 404 + assert (await client.get("/api/projekte/Fremd/recherche")).status_code == 404 + + +async def test_recherche_faeden(client, monkeypatch): + import agents + + await client.post("/api/projekte", json={"name": "Alpha"}) + assert (await client.get("/api/projekte/Alpha/recherche")).json()["faeden"] == [] + + a = (await client.post("/api/projekte/Alpha/recherche")).json() + b = (await client.post("/api/projekte/Alpha/recherche")).json() + assert a["id"] != b["id"] + + async def antworte(system, inhalt, kommando=None, ordner=None): + return "## Festgelegt\n- **5 GB** je Sendung" + + monkeypatch.setattr(agents, "frage_lokal", antworte) + res = await client.post(f"/api/projekte/Alpha/recherche/{a['id']}", + json={"text": "Was gilt?"}) + assert res.json()["titel"] == "Was gilt?" + assert len(res.json()["verlauf"]) == 2 + assert res.json()["verlauf"][-1]["text"] == "## Festgelegt\n- **5 GB** je Sendung" + + # Der zweite Faden bleibt leer — Fäden teilen sich nichts + faeden = (await client.get("/api/projekte/Alpha/recherche")).json()["faeden"] + assert [len(f["verlauf"]) for f in faeden] == [2, 0] + + assert (await client.delete(f"/api/projekte/Alpha/recherche/{b['id']}")).status_code == 200 + assert len((await client.get("/api/projekte/Alpha/recherche")).json()["faeden"]) == 1 + assert (await client.delete(f"/api/projekte/Alpha/recherche/{b['id']}")).status_code == 404 + + +async def test_recherche_leere_frage(client): + await client.post("/api/projekte", json={"name": "Alpha"}) + faden = (await client.post("/api/projekte/Alpha/recherche")).json() + res = await client.post(f"/api/projekte/Alpha/recherche/{faden['id']}", + json={"text": " "}) + assert res.status_code == 400 diff --git a/backend/tests/test_struktur.py b/backend/tests/test_struktur.py index f509e82..350eb10 100644 --- a/backend/tests/test_struktur.py +++ b/backend/tests/test_struktur.py @@ -103,7 +103,8 @@ async def test_messung_ist_auftrag_und_tuersteher(datenordner, monkeypatch): f = features.anlegen( "Test", "\nLogin\n\nAnmelden\n" - "\n- Auch Passwort prüfen.\n", + "\n- Auch Passwort prüfen.\n" + "\n- Anmelden\n- Angemeldet\n", ) gesehen = [] # Jede Stimme liefert erst einen halbherzigen Vorschlag: Punkt weg, Füllwort bleibt @@ -141,7 +142,8 @@ async def test_gemessener_verstoss_wird_notfalls_selbst_behoben(datenordner, mon f = features.anlegen( "Test", "\nLogin\n\nAnmelden\n" - "\n- Auch Passwort prüfen.\n", + "\n- Auch Passwort prüfen.\n" + "\n- Anmelden\n- Angemeldet\n", ) async def sturr(system, inhalt, temperatur=0.0): @@ -226,18 +228,24 @@ def test_zeilenfehler_haben_vorrang(): == ["Satzzeichen am Zeilenende, Füllwort „auch“"] -def test_funktion_ohne_jedes_feld_ist_leer(): - """Ein bloßer Titel beschreibt nichts — der Prüfer stülpt ihn über alles.""" +def test_funktion_ohne_testschritte(): + """Ohne Ablauf ist der Titel eine Behauptung — der Prüfer stülpt ihn über alles.""" b = struktur.befunde("funktion", {"titel": "Modal steuern", "ziel": "", "regeln": "", "testen": ""}) - assert _probleme(b) == ["Funktion ohne Ziel, Regeln und Testen"] + assert _probleme(b) == ["Funktion ohne Testschritte"] -def test_ein_einziges_feld_genuegt(): - for feld in ("ziel", "regeln", "testen"): +def test_ziel_und_regeln_ersetzen_die_testschritte_nicht(): + for feld in ("ziel", "regeln"): felder = {"titel": "Modal steuern", "ziel": "", "regeln": "", "testen": ""} felder[feld] = "Etwas tun" if feld == "ziel" else "- Etwas tun" - assert struktur.befunde("funktion", felder) == [], feld + assert _probleme(struktur.befunde("funktion", felder)) \ + == ["Funktion ohne Testschritte"], feld + + +def test_testschritte_genuegen(): + assert struktur.befunde("funktion", {"titel": "Modal steuern", "ziel": "", + "regeln": "", "testen": "- Etwas tun"}) == [] def test_einzelnes_feld_loest_nichts_aus(): @@ -259,3 +267,59 @@ def test_platzhalter_ist_kein_inhalt(): def test_kleiner_als_ist_kein_platzhalter(): assert not struktur._umschreiben("funktion", "regeln", "Wert 3 < 5") + + +def test_kommando_als_testschritt(): + """Ein Setup wird über die Kommandozeile bedient — das muss zulässig sein.""" + assert _pruefe("funktion", "testen", '- Befehl "make install" ausführen') == [] + assert _pruefe("funktion", "titel", "Anwendung installieren") == [] + + +def test_zitat_zaehlt_als_ein_wort(): + """Sonst sprengt jedes Kommando die Wortgrenze.""" + lang = '- Befehl "uv run python -m tft.cli refresh" ausführen' + assert _pruefe("funktion", "testen", lang) == [] + # Ohne Zitat greift die Grenze weiter + assert _probleme(_pruefe("funktion", "testen", + "- Ein sehr langer Schritt mit deutlich zu vielen Wörtern")) \ + == ["Mehr als 8 Wörter"] + + +def test_schraegstrich_im_zitat_ist_erlaubt(): + assert _pruefe("funktion", "testen", '- Befehl "npm run build/dev" ausführen') == [] + assert _probleme(_pruefe("funktion", "regeln", "- Gilt für Bank und/oder Brett")) \ + == ["Klammer oder Schrägstrich"] + + +def test_fuellwort_im_zitat_bleibt_stehen(): + """Der Menüeintrag heißt so — gestrichen zeigte der Schritt auf nichts.""" + assert _pruefe("funktion", "testen", '- Klick auf "Auch Vorlagen zeigen"') == [] + + +def test_kommandoschritt_ist_eine_handlung(): + """Nach dem Ergebnis darf keine Handlung mehr stehen — auch keine mit Kommando.""" + zwei = ('- Befehl "make install" ausführen\n- Anwendung installiert\n' + '- Befehl "make test" ausführen') + assert _probleme(_pruefe("funktion", "testen", zwei)) == \ + ["Zweiter Ablauf in einer Funktion"] + + +def test_ausloeser_ist_kein_funktionstitel(): + """Der Titel nennt die Wirkung; der Griff steht in den Testschritten.""" + for titel in ('Befehl "make install" ausführen', "LMB auf Speichern drücken", + "Klick auf Anlegen ausführen"): + assert "Auslöser statt Wirkung im Titel" in _probleme( + _pruefe("funktion", "titel", titel)), titel + assert _pruefe("funktion", "titel", "Anwendung installieren") == [] + + +def test_vorbedingung_ist_kein_zweiter_ablauf(): + """Der Katalog erlaubt eine Vorbedingung zuerst — sie ist kein Endzustand.""" + text = "- Badge ist sichtbar\n- RMB auf Badge\n- Text ändern\n- Neuer Text sichtbar" + assert _pruefe("funktion", "testen", text) == [] + + +def test_zweiter_ablauf_faellt_weiter_auf(): + text = "- Karte öffnen\n- Karte sichtbar\n- Karte schließen" + assert _probleme(_pruefe("funktion", "testen", text)) \ + == ["Zweiter Ablauf in einer Funktion"] diff --git a/backend/verzeichnis.py b/backend/verzeichnis.py new file mode 100644 index 0000000..c922630 --- /dev/null +++ b/backend/verzeichnis.py @@ -0,0 +1,75 @@ +"""Das Arbeitsverzeichnis eines Projekts — dort implementiert der Agent. + +Der Pfad liegt als eine Zeile im Projektordner und wandert beim Umbenennen mit. +Er ist eine Eigenschaft des Projekts, nicht der Planung: gelesen und geschrieben +wird immer im Projektstand, damit ein Planungsabbruch ihn nicht mitnimmt. +""" + +import os +from pathlib import Path + +import projekte + +DATEI = ".verzeichnis" + + +def _pfad(projekt: str): + return projekte.stand(projekt) / DATEI + + +def lies(projekt: str) -> str: + """Der eingestellte Pfad, oder leer.""" + try: + return _pfad(projekt).read_text().strip() + except OSError: + return "" + + +def pruefe(pfad: str) -> Path: + """Taugt der Pfad als Arbeitsverzeichnis? Gibt ihn aufgelöst zurück oder wirft.""" + pfad = (pfad or "").strip() + if not pfad: + raise ValueError("Kein Pfad angegeben") + ziel = Path(os.path.expanduser(pfad)) + if not ziel.is_absolute(): + raise ValueError("Der Pfad muss absolut sein") + ziel = ziel.resolve() + if not ziel.is_dir(): + raise FileNotFoundError(f"„{ziel}“ ist kein Verzeichnis") + if ziel == Path(ziel.anchor) or ziel == Path.home(): + # Die Wurzel oder das ganze Heimatverzeichnis ist immer ein Fehlgriff + raise ValueError("Bitte ein Projektverzeichnis wählen, nicht die Wurzel") + return ziel + + +def setze(projekt: str, pfad: str) -> str: + ziel = pruefe(pfad) + _pfad(projekt).write_text(f"{ziel}\n") + return str(ziel) + + +def loesche(projekt: str): + _pfad(projekt).unlink(missing_ok=True) + + +def ordner(pfad: str = "") -> dict: + """Ein Verzeichnis zum Durchblättern: Unterordner, ohne Verstecktes. + + Kein Pfad heißt Heimatverzeichnis — dort beginnt die Suche. Die Auswahl + trifft der Mensch; hier wird nur gelistet, nie geschrieben. + """ + ziel = Path(os.path.expanduser(pfad.strip())) if pfad.strip() else Path.home() + if not ziel.is_absolute(): + raise ValueError("Der Pfad muss absolut sein") + ziel = ziel.resolve() + if not ziel.is_dir(): + raise FileNotFoundError(f"„{ziel}“ ist kein Verzeichnis") + try: + unter = sorted( + (e.name for e in ziel.iterdir() + if e.is_dir() and not e.name.startswith(".")), + key=str.lower) + except PermissionError: + raise ValueError(f"„{ziel}“ ist nicht lesbar") + eltern = str(ziel.parent) if ziel.parent != ziel else "" + return {"pfad": str(ziel), "eltern": eltern, "ordner": unter} diff --git a/daten/DesktopNote/.chat.json b/daten/DesktopNote/.chat.json new file mode 100644 index 0000000..c1ed9fe --- /dev/null +++ b/daten/DesktopNote/.chat.json @@ -0,0 +1,122 @@ +[ + { + "rolle": "person", + "text": "Wie wird die Anwendung auf dem PC ausgeführt?" + }, + { + "rolle": "ki", + "text": "Ich weiß nicht, wie die Anwendung gestartet wird. Eine übliche Variante für Ubuntu wäre ein Icon im System Tray, das bei Klick auf das Icon die Topbar öffnet. Soll ich eine Karte dafür anlegen?" + }, + { + "rolle": "person", + "text": "Nein es soll automatisch gestartet werden" + }, + { + "rolle": "ki", + "text": "Entwurf für die Karte. Der Autostart ist kern, weil ohne ihn das Badge nie erscheint, wenn der Benutzer es erwartet." + }, + { + "rolle": "person", + "text": "Braucht autostart nicht sowas wie ein Makefile oder so, dass einmal ausgeführt wird und die anwendung installiert?" + }, + { + "rolle": "ki", + "text": "Guter Punkt. Autostart setzt voraus, dass die Anwendung einmal installiert wird. Das ist ein eigener Schritt, kein Teil des Badges. Hier ein Entwurf für eine Installationskarte. Klärungsbedarf: Muss der Benutzer die Installation selbst durchführen, oder reicht ein Skript?" + }, + { + "rolle": "person", + "text": "ich brauche ein setup mit make commands um die anwendung; welche make commands würde sinn machen?" + }, + { + "rolle": "ki", + "text": "Die Wahl der Make-Befehle ist eine Entscheidung zur Umsetzung, nicht zum Produkt. Ich kann keine passenden Befehle vorschlagen — das ist bei jeder Technologie anders und hängt davon ab, was die Installation umfasst. Wenn du weißt, welche Befehle du brauchst, nenne sie mir. Ich dokumentiere, wie man sie aufruft." + }, + { + "rolle": "person", + "text": "ich brauche ein setup mit make commands um die anwendung; welche make commands würde sinn machen?" + }, + { + "rolle": "ki", + "text": "Ich schlage zwei übliche Make-Befehle vor, die zu fast jedem Projekt passen: \"make install\" für die Erstinstallation und \"make uninstall\" zum Entfernen. \"make\" ohne Ziel zeigt eine Hilfe an. Das sind Konventionen — wenn etwas anderes besser passt, sag Bescheid." + }, + { + "rolle": "person", + "text": "das badge soll eine weitere funktion bekommen; ich will mehrere kurze setze eingaben können; ein satz je zeile; dann kann ich bestimmen welcher satz angezeigt wird; oder ich kann einen idle setzen, dann wechselt der satz alle x Stunden" + }, + { + "rolle": "ki", + "text": "Die Karte Badge wird um zwei Funktionen erweitert: Eintrag auswählen und Idle-Modus aktivieren. Einträge sind Zeilen in der Textarea, aus denen man einen zum Anzeigen wählt. Der Idle-Modus wechselt automatisch alle eingestellten Stunden. Die bestehende Funktion Text anpassen bleibt als RMB-Einstiegspunkt." + }, + { + "rolle": "person", + "text": "die funktionen haben teilweise keine daten" + }, + { + "rolle": "ki", + "text": "Testschritte ergänzt. Eintrag auswählen und Idle-Modus aktivieren haben jetzt Abläufe. Die Texte sind knapp — wenn etwas fehlt, sag Bescheid." + }, + { + "rolle": "person", + "text": "prüfe die karten" + }, + { + "rolle": "ki", + "text": "Vier klare Verstöße korrigiert: die Icon-Regel, die Position „Links in der Topbar\", „Makefile im Projektroot\" als Bauweise und „Bestätigen klicken\" ohne Maustaste. Dazu heißt „Textarea\" jetzt überall „Textfeld\", das Kartenziel ist nicht mehr zirkulär, „Idle-Modus\" wurde zu „Automatischen Wechsel aktivieren\" verdeutscht. Offene Frage: gilt jede Zeile als ein Eintrag, oder trennt wirklich eine Leerzeile die Einträge — beides stand widersprüchlich auf der Karte, ich habe „Jede Zeile ist ein Eintrag\" gesetzt. Zweite Frage: wie heißt der Schalter für den automatischen Wechsel, ich habe „Automatisch wechseln\" angenommen." + }, + { + "rolle": "person", + "text": "einige funktionen haben keinen inhalt" + }, + { + "rolle": "ki", + "text": "Zwei Funktionen hatten keine Testschritte: Einträge bearbeiten und Automatischen Wechsel aktivieren. Beide sind jetzt ausgefüllt. Beim automatischen Wechsel habe ich \"Automatisch wechseln\" als Schalter und ein Feld für Stunden angenommen — stimmt das? Bei Einträge bearbeiten nehme ich an, dass RMB direkt das Textfeld öffnet und \"Bestätigen\" speichert." + }, + { + "rolle": "person", + "text": "prüfe die planung" + }, + { + "rolle": "ki", + "text": "Vier Verstöße korrigiert: \"Abbrechen\" ist jetzt zitiert, die Regel \"Jede Zeile ist ein Eintrag\" stand doppelt in den Testschritten, dem Deinstallieren fehlte die Vorbedingung, und das Setup-Ziel nannte nur die Installation. Der Endzustand bei \"Einträge bearbeiten\" heißt jetzt \"Einträge gespeichert\", weil ein zuvor gewählter Eintrag sonst überschrieben würde. Neu als Entwurf, bitte prüfen: Einträge überleben das Abmelden, und die Auswahl eines Eintrags beendet den automatischen Wechsel — sonst gibt es keinen Weg zurück. Offener Widerspruch: \"Ohne Eintrag bleibt das Badge sichtbar\" widerspricht deiner Ansage \"sichtbar, wenn ein Text definiert ist\"; ich habe sie behalten, weil man nach der Installation sonst kein Ziel für RMB hat." + }, + { + "rolle": "person", + "text": "Bleiben die Einträge persistent über den Neustart hinaus?" + }, + { + "rolle": "ki", + "text": "Ja — die Regel \"Einträge bleiben nach dem Abmelden erhalten\" steht schon auf der Karte, sie deckt Abmelden und Neustart. Ich schärfe sie zu \"Einträge bleiben nach einem Neustart erhalten\", damit kein Zweifel bleibt. Offen: gilt das auch für den gewählten Eintrag und den automatischen Wechsel — laufen die nach dem Neustart weiter? Mein Entwurf nimmt Ja an und setzt je eine Regel dafür." + }, + { + "rolle": "person", + "text": "okay fehlt noch etwas?" + }, + { + "rolle": "ki", + "text": "Zwei Lücken sehe ich. Erstens: welcher Eintrag erscheint ohne eigene Auswahl — mein Entwurf setzt den ersten. Zweitens: überleben gewählter Eintrag und automatischer Wechsel einen Neustart — der Entwurf nimmt Ja an und schärft die Abmelde-Regel zum Neustart. Sonst ist die Planung vollständig, Setup bleibt unverändert." + }, + { + "rolle": "person", + "text": "prüfe die features auf kompaktheit" + }, + { + "rolle": "ki", + "text": "Drei Stellen waren doppelt: die Neustart-Zusage stand dreimal, ich fasse sie als Kartenregel \"Einstellungen bleiben nach einem Neustart erhalten\" zusammen. Beim automatischen Wechsel werden Reihenfolge und Umbruch zu einer Regel \"Wechsel läuft zyklisch durch die Einträge\". Die Regel zum ersten Eintrag ist kürzer formuliert, Setup bleibt unverändert. Sag Bescheid, falls die Sammelregel dir zu grob ist — dann trenne ich Einträge, Auswahl und Wechsel wieder." + }, + { + "rolle": "person", + "text": "prüfe die karten" + }, + { + "rolle": "ki", + "text": "Setup steht auf optional, trägt aber die Installation — ohne sie läuft nichts, also kern. \"Text eingeben\" sagt nicht, wohin — jetzt \"Text in das Textfeld eingeben\". Ebenso präzisiert: \"LMB auf die Zeile im Textfeld\". Offen: erfolgt die Auswahl wirklich im Bearbeitungs-Textfeld oder in einer eigenen Liste?" + }, + { + "rolle": "person", + "text": "ich kann keinen text eintragen" + }, + { + "rolle": "ki", + "text": "Mein Fehler in der Annahme: RMB öffnet kein Textfeld, sondern ein Menü. Entwurf: RMB auf Badge, dann Klick auf \"Einträge bearbeiten\" — erst dann kommt das Textfeld. Die Auswahl habe ich damit auf das Menü gelegt: LMB auf den Eintrag im Menü, ohne Bestätigen. Stimmen die Menüeinträge so, und ist es RMB oder öffnet LMB das Menü?" + } +] diff --git a/daten/DesktopNote/.planung/.chat.json b/daten/DesktopNote/.planung/.chat.json new file mode 100644 index 0000000..c1ed9fe --- /dev/null +++ b/daten/DesktopNote/.planung/.chat.json @@ -0,0 +1,122 @@ +[ + { + "rolle": "person", + "text": "Wie wird die Anwendung auf dem PC ausgeführt?" + }, + { + "rolle": "ki", + "text": "Ich weiß nicht, wie die Anwendung gestartet wird. Eine übliche Variante für Ubuntu wäre ein Icon im System Tray, das bei Klick auf das Icon die Topbar öffnet. Soll ich eine Karte dafür anlegen?" + }, + { + "rolle": "person", + "text": "Nein es soll automatisch gestartet werden" + }, + { + "rolle": "ki", + "text": "Entwurf für die Karte. Der Autostart ist kern, weil ohne ihn das Badge nie erscheint, wenn der Benutzer es erwartet." + }, + { + "rolle": "person", + "text": "Braucht autostart nicht sowas wie ein Makefile oder so, dass einmal ausgeführt wird und die anwendung installiert?" + }, + { + "rolle": "ki", + "text": "Guter Punkt. Autostart setzt voraus, dass die Anwendung einmal installiert wird. Das ist ein eigener Schritt, kein Teil des Badges. Hier ein Entwurf für eine Installationskarte. Klärungsbedarf: Muss der Benutzer die Installation selbst durchführen, oder reicht ein Skript?" + }, + { + "rolle": "person", + "text": "ich brauche ein setup mit make commands um die anwendung; welche make commands würde sinn machen?" + }, + { + "rolle": "ki", + "text": "Die Wahl der Make-Befehle ist eine Entscheidung zur Umsetzung, nicht zum Produkt. Ich kann keine passenden Befehle vorschlagen — das ist bei jeder Technologie anders und hängt davon ab, was die Installation umfasst. Wenn du weißt, welche Befehle du brauchst, nenne sie mir. Ich dokumentiere, wie man sie aufruft." + }, + { + "rolle": "person", + "text": "ich brauche ein setup mit make commands um die anwendung; welche make commands würde sinn machen?" + }, + { + "rolle": "ki", + "text": "Ich schlage zwei übliche Make-Befehle vor, die zu fast jedem Projekt passen: \"make install\" für die Erstinstallation und \"make uninstall\" zum Entfernen. \"make\" ohne Ziel zeigt eine Hilfe an. Das sind Konventionen — wenn etwas anderes besser passt, sag Bescheid." + }, + { + "rolle": "person", + "text": "das badge soll eine weitere funktion bekommen; ich will mehrere kurze setze eingaben können; ein satz je zeile; dann kann ich bestimmen welcher satz angezeigt wird; oder ich kann einen idle setzen, dann wechselt der satz alle x Stunden" + }, + { + "rolle": "ki", + "text": "Die Karte Badge wird um zwei Funktionen erweitert: Eintrag auswählen und Idle-Modus aktivieren. Einträge sind Zeilen in der Textarea, aus denen man einen zum Anzeigen wählt. Der Idle-Modus wechselt automatisch alle eingestellten Stunden. Die bestehende Funktion Text anpassen bleibt als RMB-Einstiegspunkt." + }, + { + "rolle": "person", + "text": "die funktionen haben teilweise keine daten" + }, + { + "rolle": "ki", + "text": "Testschritte ergänzt. Eintrag auswählen und Idle-Modus aktivieren haben jetzt Abläufe. Die Texte sind knapp — wenn etwas fehlt, sag Bescheid." + }, + { + "rolle": "person", + "text": "prüfe die karten" + }, + { + "rolle": "ki", + "text": "Vier klare Verstöße korrigiert: die Icon-Regel, die Position „Links in der Topbar\", „Makefile im Projektroot\" als Bauweise und „Bestätigen klicken\" ohne Maustaste. Dazu heißt „Textarea\" jetzt überall „Textfeld\", das Kartenziel ist nicht mehr zirkulär, „Idle-Modus\" wurde zu „Automatischen Wechsel aktivieren\" verdeutscht. Offene Frage: gilt jede Zeile als ein Eintrag, oder trennt wirklich eine Leerzeile die Einträge — beides stand widersprüchlich auf der Karte, ich habe „Jede Zeile ist ein Eintrag\" gesetzt. Zweite Frage: wie heißt der Schalter für den automatischen Wechsel, ich habe „Automatisch wechseln\" angenommen." + }, + { + "rolle": "person", + "text": "einige funktionen haben keinen inhalt" + }, + { + "rolle": "ki", + "text": "Zwei Funktionen hatten keine Testschritte: Einträge bearbeiten und Automatischen Wechsel aktivieren. Beide sind jetzt ausgefüllt. Beim automatischen Wechsel habe ich \"Automatisch wechseln\" als Schalter und ein Feld für Stunden angenommen — stimmt das? Bei Einträge bearbeiten nehme ich an, dass RMB direkt das Textfeld öffnet und \"Bestätigen\" speichert." + }, + { + "rolle": "person", + "text": "prüfe die planung" + }, + { + "rolle": "ki", + "text": "Vier Verstöße korrigiert: \"Abbrechen\" ist jetzt zitiert, die Regel \"Jede Zeile ist ein Eintrag\" stand doppelt in den Testschritten, dem Deinstallieren fehlte die Vorbedingung, und das Setup-Ziel nannte nur die Installation. Der Endzustand bei \"Einträge bearbeiten\" heißt jetzt \"Einträge gespeichert\", weil ein zuvor gewählter Eintrag sonst überschrieben würde. Neu als Entwurf, bitte prüfen: Einträge überleben das Abmelden, und die Auswahl eines Eintrags beendet den automatischen Wechsel — sonst gibt es keinen Weg zurück. Offener Widerspruch: \"Ohne Eintrag bleibt das Badge sichtbar\" widerspricht deiner Ansage \"sichtbar, wenn ein Text definiert ist\"; ich habe sie behalten, weil man nach der Installation sonst kein Ziel für RMB hat." + }, + { + "rolle": "person", + "text": "Bleiben die Einträge persistent über den Neustart hinaus?" + }, + { + "rolle": "ki", + "text": "Ja — die Regel \"Einträge bleiben nach dem Abmelden erhalten\" steht schon auf der Karte, sie deckt Abmelden und Neustart. Ich schärfe sie zu \"Einträge bleiben nach einem Neustart erhalten\", damit kein Zweifel bleibt. Offen: gilt das auch für den gewählten Eintrag und den automatischen Wechsel — laufen die nach dem Neustart weiter? Mein Entwurf nimmt Ja an und setzt je eine Regel dafür." + }, + { + "rolle": "person", + "text": "okay fehlt noch etwas?" + }, + { + "rolle": "ki", + "text": "Zwei Lücken sehe ich. Erstens: welcher Eintrag erscheint ohne eigene Auswahl — mein Entwurf setzt den ersten. Zweitens: überleben gewählter Eintrag und automatischer Wechsel einen Neustart — der Entwurf nimmt Ja an und schärft die Abmelde-Regel zum Neustart. Sonst ist die Planung vollständig, Setup bleibt unverändert." + }, + { + "rolle": "person", + "text": "prüfe die features auf kompaktheit" + }, + { + "rolle": "ki", + "text": "Drei Stellen waren doppelt: die Neustart-Zusage stand dreimal, ich fasse sie als Kartenregel \"Einstellungen bleiben nach einem Neustart erhalten\" zusammen. Beim automatischen Wechsel werden Reihenfolge und Umbruch zu einer Regel \"Wechsel läuft zyklisch durch die Einträge\". Die Regel zum ersten Eintrag ist kürzer formuliert, Setup bleibt unverändert. Sag Bescheid, falls die Sammelregel dir zu grob ist — dann trenne ich Einträge, Auswahl und Wechsel wieder." + }, + { + "rolle": "person", + "text": "prüfe die karten" + }, + { + "rolle": "ki", + "text": "Setup steht auf optional, trägt aber die Installation — ohne sie läuft nichts, also kern. \"Text eingeben\" sagt nicht, wohin — jetzt \"Text in das Textfeld eingeben\". Ebenso präzisiert: \"LMB auf die Zeile im Textfeld\". Offen: erfolgt die Auswahl wirklich im Bearbeitungs-Textfeld oder in einer eigenen Liste?" + }, + { + "rolle": "person", + "text": "ich kann keinen text eintragen" + }, + { + "rolle": "ki", + "text": "Mein Fehler in der Annahme: RMB öffnet kein Textfeld, sondern ein Menü. Entwurf: RMB auf Badge, dann Klick auf \"Einträge bearbeiten\" — erst dann kommt das Textfeld. Die Auswahl habe ich damit auf das Menü gelegt: LMB auf den Eintrag im Menü, ohne Bestätigen. Stimmen die Menüeinträge so, und ist es RMB oder öffnet LMB das Menü?" + } +] diff --git a/daten/DesktopNote/.planung/badge.md b/daten/DesktopNote/.planung/badge.md new file mode 100644 index 0000000..323332a --- /dev/null +++ b/daten/DesktopNote/.planung/badge.md @@ -0,0 +1,50 @@ + +Badge +---------------------------------------- + +kern +---------------------------------------- + +Zeigt einen von mehreren Einträgen in der Topbar an +---------------------------------------- + +- Ohne Eintrag bleibt das Badge sichtbar +- Beliebige Schriftzeichen erlaubt +- Jede Zeile ist ein Eintrag +- Ohne Auswahl erscheint der erste Eintrag +- Einstellungen bleiben nach einem Neustart erhalten +---------------------------------------- + +Einträge bearbeiten + +- Textfeld zeigt die vorhandenen Einträge +- "Abbrechen" verwirft die Änderung + +- RMB auf Badge +- Klick auf "Einträge bearbeiten" +- Text in das Textfeld eingeben +- LMB auf "Bestätigen" +- Einträge gespeichert + +Eintrag auswählen + +- Menü listet alle Einträge + +- Mehrere Einträge vorhanden +- RMB auf Badge +- LMB auf den Eintrag im Menü +- Gewählter Eintrag im Badge + +Automatischen Wechsel aktivieren + +Zeigt die Einträge ohne Zutun nacheinander + +- Wechsel läuft zyklisch durch die Einträge +- Auswahl eines Eintrags beendet den Wechsel + +- Mehrere Einträge vorhanden +- RMB auf Badge +- Klick auf "Automatisch wechseln" +- Stunden bis zum Wechsel eingeben +- LMB auf "Bestätigen" +- Badge wechselt nach der eingestellten Zeit diff --git a/daten/DesktopNote/.planung/setup.md b/daten/DesktopNote/.planung/setup.md new file mode 100644 index 0000000..c159292 --- /dev/null +++ b/daten/DesktopNote/.planung/setup.md @@ -0,0 +1,25 @@ + +Setup +---------------------------------------- + +kern +---------------------------------------- + +Bringt die Anwendung auf den Rechner und entfernt sie wieder +---------------------------------------- + +- Befehl "make" zeigt die Hilfe +---------------------------------------- + +Anwendung installieren + +- Befehl "make install" ausführen +- Abmelden und wieder anmelden +- Badge in der Topbar sichtbar + +Anwendung deinstallieren + +- Anwendung installiert +- Befehl "make uninstall" ausführen +- Abmelden und wieder anmelden +- Badge fehlt in der Topbar diff --git a/daten/DesktopNote/.planung/vision.md b/daten/DesktopNote/.planung/vision.md new file mode 100644 index 0000000..a75ea68 --- /dev/null +++ b/daten/DesktopNote/.planung/vision.md @@ -0,0 +1,13 @@ + +Vision +---------------------------------------- + +vision +---------------------------------------- + +Text in der Topbar vom Ubuntu Desktop anzeigen. +---------------------------------------- + +- Stop trying to get rich, start trying to follow the rules +- Stop act like a person, become that person +- Discipline is the game diff --git a/daten/DesktopNote/badge.md b/daten/DesktopNote/badge.md new file mode 100644 index 0000000..323332a --- /dev/null +++ b/daten/DesktopNote/badge.md @@ -0,0 +1,50 @@ + +Badge +---------------------------------------- + +kern +---------------------------------------- + +Zeigt einen von mehreren Einträgen in der Topbar an +---------------------------------------- + +- Ohne Eintrag bleibt das Badge sichtbar +- Beliebige Schriftzeichen erlaubt +- Jede Zeile ist ein Eintrag +- Ohne Auswahl erscheint der erste Eintrag +- Einstellungen bleiben nach einem Neustart erhalten +---------------------------------------- + +Einträge bearbeiten + +- Textfeld zeigt die vorhandenen Einträge +- "Abbrechen" verwirft die Änderung + +- RMB auf Badge +- Klick auf "Einträge bearbeiten" +- Text in das Textfeld eingeben +- LMB auf "Bestätigen" +- Einträge gespeichert + +Eintrag auswählen + +- Menü listet alle Einträge + +- Mehrere Einträge vorhanden +- RMB auf Badge +- LMB auf den Eintrag im Menü +- Gewählter Eintrag im Badge + +Automatischen Wechsel aktivieren + +Zeigt die Einträge ohne Zutun nacheinander + +- Wechsel läuft zyklisch durch die Einträge +- Auswahl eines Eintrags beendet den Wechsel + +- Mehrere Einträge vorhanden +- RMB auf Badge +- Klick auf "Automatisch wechseln" +- Stunden bis zum Wechsel eingeben +- LMB auf "Bestätigen" +- Badge wechselt nach der eingestellten Zeit diff --git a/daten/DesktopNote/setup.md b/daten/DesktopNote/setup.md new file mode 100644 index 0000000..c159292 --- /dev/null +++ b/daten/DesktopNote/setup.md @@ -0,0 +1,25 @@ + +Setup +---------------------------------------- + +kern +---------------------------------------- + +Bringt die Anwendung auf den Rechner und entfernt sie wieder +---------------------------------------- + +- Befehl "make" zeigt die Hilfe +---------------------------------------- + +Anwendung installieren + +- Befehl "make install" ausführen +- Abmelden und wieder anmelden +- Badge in der Topbar sichtbar + +Anwendung deinstallieren + +- Anwendung installiert +- Befehl "make uninstall" ausführen +- Abmelden und wieder anmelden +- Badge fehlt in der Topbar diff --git a/daten/DesktopNote/vision.md b/daten/DesktopNote/vision.md new file mode 100644 index 0000000..a75ea68 --- /dev/null +++ b/daten/DesktopNote/vision.md @@ -0,0 +1,13 @@ + +Vision +---------------------------------------- + +vision +---------------------------------------- + +Text in der Topbar vom Ubuntu Desktop anzeigen. +---------------------------------------- + +- Stop trying to get rich, start trying to follow the rules +- Stop act like a person, become that person +- Discipline is the game diff --git a/daten/RAG/.pruefung.json b/daten/MtoRagSystem/.planung/.pruefung.json similarity index 100% rename from daten/RAG/.pruefung.json rename to daten/MtoRagSystem/.planung/.pruefung.json diff --git a/daten/MtoRagSystem/.planung/.verzeichnis b/daten/MtoRagSystem/.planung/.verzeichnis new file mode 100644 index 0000000..22ab7ba --- /dev/null +++ b/daten/MtoRagSystem/.planung/.verzeichnis @@ -0,0 +1 @@ +/home/arbeit/arbeit/MtoRagSystem diff --git a/daten/MtoRagSystem/.planung/anbindung.md b/daten/MtoRagSystem/.planung/anbindung.md new file mode 100644 index 0000000..1f301e8 --- /dev/null +++ b/daten/MtoRagSystem/.planung/anbindung.md @@ -0,0 +1,157 @@ + +Anbindung +---------------------------------------- + +optional +---------------------------------------- + +Bindet einen externen Server kontrolliert an +---------------------------------------- + +- Ein Token wird nie gespeichert, nur sein Name +- Eine Anbindung startet eingeschaltet, ohne Chatfreigabe +- Eine Anbindung wirkt erst nach Freigabe +- Ein Import führt nie ein Werkzeug aus +- Ein Import liest keine Inhalte +- Anweisungen fremder Inhalte werden entfernt +- Ein Transport über Standardeingabe ist gesperrt +- Nur verschlüsselte Verbindungen sind erlaubt +- Interne Netze sind gesperrt +- Weiterleitungen werden nicht verfolgt +- Protokolle enthalten nur Metadaten +- Der Bereich braucht die höchste Rolle +---------------------------------------- + +Anbindung anlegen + +- Speichern folgt einer bestandenen Prüfung +- Ein Speichern ändert keine Antwort +- Ein Formulartoken ist Pflicht + +- Menüeintrag MCP Quellen wählen +- Reiter Anbindung anlegen wählen +- Formular ausfüllen +- Anbindung speichern +- Anbindung in der Übersicht +---------------------------------------- + +Anbindung prüfen + +Testet die Angaben gegen Erlaubnisliste und Regeln + +- Ohne Onlinetest entstehen keine Abrufe +- Das Ergebnis nennt den Grund +- Die Prüfung speichert nicht + +- Formular ausfüllen +- LMB auf Anbindung prüfen +- Prüfergebnis mit Begründung +---------------------------------------- + +Anbindung bearbeiten + +- Änderungen wirken erst nach dem Speichern +- Werkzeugdaten bleiben erhalten +- Zugewiesene Inhalte bleiben am Kurznamen gebunden + +- Übersicht öffnen +- LMB auf Bearbeiten +- Formular vorbefüllt +---------------------------------------- + +Anbindung umschalten + +Legt eine Anbindung vorübergehend still + +- Ausgewählte Inhalte bleiben gespeichert +- Eine stillgelegte Anbindung wirkt nicht +- Wiedereinschalten braucht keine neue Freigabe + +- Übersicht öffnen +- LMB auf Deaktivieren +- Zustandsmarke wechselt +---------------------------------------- + +Anbindung entfernen + +- Der Raum wird zuvor abgeschaltet +- Eine Rückfrage geht voraus + +- Übersicht öffnen +- LMB auf Entfernen +- Bestätigen +- Anbindung verschwindet +---------------------------------------- + +Ressource übernehmen + +Schreibt eine gefundene Ressource in die Anbindung + +- Nur erkannte Ressourcen sind übernehmbar +- Die Übernahme schaltet den Chat nicht ein + +- Serverinhalte aktualisieren +- LMB auf Ressource übernehmen +- Ressource in der Anbindung +---------------------------------------- + +Serverinhalte aktualisieren + +Erkennt Ressourcen, Werkzeuge und Vorlagen als Metadaten + +- Kein Werkzeug wird ausgeführt +- Vorlagen werden erkannt, nie ausgeführt +- Ressourcen werden nicht gelesen +- Gefundene Werkzeuge sind zunächst gesperrt + +- Übersicht öffnen +- LMB auf Inhalte aktualisieren +- Gefundene Inhalte sichtbar +---------------------------------------- + +Anbindung online prüfen + +Prüft eine gespeicherte Anbindung im Terminal + +- Geprüft werden Freigabe und ein Inhalt +- Ohne prüfbaren Inhalt bricht der Lauf ab +- Ein fehlendes Geheimnis blockt vorher +- Anfragen werden bereinigt protokolliert + +- Kommando mit Servernamen aufrufen +- Prüfbericht sichtbar +---------------------------------------- + +Schutzregeln ansehen + +Zeigt Grenzen und Systemprüfung der Anbindungen + +- Die Anzeige ruft nichts extern ab +- Freie Werkzeugnutzung ist gesperrt + +- Menüeintrag Quellen wählen +- Reiter Sicherheit wählen +- Grenzen und Prüfstand sichtbar +---------------------------------------- + +Freigaben prüfen + +Prüft die Serverliste der Grundeinstellung + +- Kein Transport wird geöffnet +- Das Ergebnis nennt Server, Fehler und Warnungen + +- Kommando aufrufen +- Prüfstand je Regel sichtbar +---------------------------------------- + +Brücke trocken testen + +Prüft Bereinigung und Belegbrücke ohne Serverkontakt + +- Nur lokale Nutzlasten werden geprüft +- Kein Transport, keine Chatwirkung +- Fremde Anweisungsmarker fallen weg + +- Kommando aufrufen +- Bereinigte Nutzlast sichtbar diff --git a/daten/MtoRagSystem/.planung/antwort.md b/daten/MtoRagSystem/.planung/antwort.md new file mode 100644 index 0000000..3fb4237 --- /dev/null +++ b/daten/MtoRagSystem/.planung/antwort.md @@ -0,0 +1,115 @@ + +Antwort +---------------------------------------- + +kern +---------------------------------------- + +Beantwortet eine Frage aus geprüften Quellen +---------------------------------------- + +- Nur Aussagen aus den Quellen +- Fehlende Werte werden nicht erfunden +- Keine Schätzung ersetzt einen fehlenden Wert +- Fakten und Ableitungen bleiben getrennt +- Ableitungen sind als solche markiert +- Eignung gilt als belegpflichtige Aussage +- Negativaussagen brauchen einen Quellenbeleg +- Werbesprache ist untersagt +- Sprache der Frage gilt für die Antwort +- Interne Belegkennungen bleiben auf Nachfrage beschränkt +- Interne Denktexte erreichen niemanden +- Die genutzte Datenbasis steht an der Antwort +- Trefferzahl aus Wissen und Shop liegt bei +- Die Antwortdauer wird ausgewiesen +- Ein Vertrauensabzeichen steht an der Antwort +- Wiederholungsschleifen werden sichtbar abgeschnitten +- Transparente Unsicherheit schlägt sichere Falschaussage +---------------------------------------- + +Frage stellen + +Sendet eine Frage und empfängt die Antwort laufend + +- Leere Frage wird abgewiesen +- Höchstens 10000 Zeichen +- Warnung ab 7500 Zeichen +- Erneutes Senden bleibt bis zum Ende gesperrt +- Entwurf überlebt einen Neuladen +- Unterbrochener Empfang wird fortgesetzt +- Ein Lauf verfällt nach 900 Sekunden +- Ein stehender Lauf wird beendet + +- Text eingeben +- Enter drücken +- Frage im Verlauf +- Antwort läuft ein +---------------------------------------- + +Antwort abbrechen + +Beendet eine laufende Antwort vorzeitig + +- Nur während des Empfangs möglich +- Der Serverlauf arbeitet weiter +- Der Vermerk gilt nur in der laufenden Ansicht +- Nach dem Neuladen steht die volle Antwort + +- Frage stellen +- LMB auf Abbrechen +- Abbruchvermerk im Verlauf +---------------------------------------- + +Frage erneut senden + +Wiederholt die Frage mit anderer Einstellung + +- Angeboten sind nur ungenutzte Varianten +- Der Klick setzt die Einstellung passend +- Während des Empfangs gesperrt + +- Frage stellen +- LMB auf eine Variante +- Frage erneut im Verlauf +---------------------------------------- + +Antwortmodus wählen + +Wählt zwischen gründlicher und schneller Antwort + +- Zwei Werte: Standard und schnell +- Ungültiger Wert fällt auf Standard +- Der schnelle Modus nutzt ein anderes Modell +- Der schnelle Modus antwortet ungenauer +- Die Wahl gilt für die ganze Unterhaltung + +- Chat-Einstellungen öffnen +- Antwortmodus wählen +- Modus an der nächsten Antwort +---------------------------------------- + +Datenbasis wählen + +Legt fest, ob Wissen oder Shopdaten zählen + +- Vier Werte: automatisch, Wissen, Shop, beides +- Unbekannter Wert fällt auf automatisch +- Nur Wissen löst keine Shopsuche aus +- Die genutzte Basis steht in der Antwort + +- Chat-Einstellungen öffnen +- Datenbasis wählen +- Basis in der Zusammenfassung +---------------------------------------- + +Folgeaktion auslösen + +Sendet eine vorgeschlagene Folgefrage sofort + +- Der Fragetext kommt vom Server +- Angebot entfällt bei ablehnender Antwort +- Während des Empfangs passiert nichts + +- Frage stellen +- LMB auf eine Folgeaktion +- Folgefrage im Verlauf diff --git a/daten/MtoRagSystem/.planung/auftrag.md b/daten/MtoRagSystem/.planung/auftrag.md new file mode 100644 index 0000000..6d78ced --- /dev/null +++ b/daten/MtoRagSystem/.planung/auftrag.md @@ -0,0 +1,85 @@ + +Auftrag +---------------------------------------- + +kern +---------------------------------------- + +Führt Indexierung und Neuaufbau nachvollziehbar aus +---------------------------------------- + +- Jeder Lauf hinterlässt einen Auftrag +- Der Auftrag nennt Typ, Zustand, Zeiten und Person +- Fünf Zustände bis zum Abbruch +- Nur der Neuaufbau schreibt eine Protokolldatei +- Nur ein Indexlauf läuft gleichzeitig +- Ein Strukturwechsel erzwingt einen sichtbaren Neuaufbau +- Ein unvollständiger Aufbau bricht ab +---------------------------------------- + +Aufträge einsehen + +Zeigt den Verlauf aller Indexläufe + +- Neueste Aufträge stehen oben +- Der Fehlertext endet in der Liste bei 120 Zeichen + +- Menüeintrag Aufträge wählen +- Auftragsliste sichtbar +---------------------------------------- + +Auftrag verfolgen + +Beobachtet einen einzelnen Lauf bis zum Ende + +- Die Kennung muss dem Kennungsformat folgen +- Der Stand wird zweisekündlich nachgeladen +- Geliefert werden Typ, Zustand, Zeiten und Fehler +- Das Nachladen endet mit dem Auftrag + +- Auftragsliste öffnen +- LMB auf eine Kennung +- Zustandsmarke wechselt +---------------------------------------- + +Index neu aufbauen + +Überführt vorgemerkte Änderungen in den Index + +- Nur die höchste Rolle darf starten +- Der Auftrag beginnt wartend +- Die Arbeit läuft im Hintergrund +- Ein Fehlstart markiert den Auftrag als gescheitert +- Nach Erfolg wird der Zwischenspeicher geleert + +- Dokumentliste öffnen +- LMB auf Index neu aufbauen +- Bestätigen +- Auftragsseite sichtbar +---------------------------------------- + +Auftrag ausführen + +Startet einen vorhandenen Auftrag im Terminal + +- Unbekannte Kennung wird abgewiesen +- Abgeschlossene Aufträge laufen nicht erneut +- Ein Trockenlauf vermeidet schwere Schritte + +- Kommando mit Kennung aufrufen +- Zustandszeile sichtbar +---------------------------------------- + +Index hart neu aufbauen + +Baut Chunks, Vektoren und Tags vollständig neu + +- Ohne Erzwingen bricht der Lauf ab +- Vier Schritte laufen in fester Reihenfolge +- Einzelne Schritte lassen sich überspringen +- Ein gescheiterter Schritt beendet den Lauf +- Ein Trockenlauf schreibt keine Indexdatei + +- Kommando mit Erzwingen aufrufen +- Vier Schritte sichtbar +- Gesundheitsstand am Ende diff --git a/daten/MtoRagSystem/.planung/batch.md b/daten/MtoRagSystem/.planung/batch.md new file mode 100644 index 0000000..82f685c --- /dev/null +++ b/daten/MtoRagSystem/.planung/batch.md @@ -0,0 +1,118 @@ + +Batch +---------------------------------------- + +optional +---------------------------------------- + +Importiert viele Dokumente in einem Lauf +---------------------------------------- + +- Höchstens 250 Dateien je Upload +- Erlaubt sind PDF, Text, Markdown und Word +- Geschützte PDF gelten als nicht verarbeitbar +- Doppelte Prüfsummen werden übersprungen +- Höchstens ein Neuaufbau je Lauf +- Ohne Indexwirkung entfällt der Neuaufbau +- Der Eingang wird nach dem Lauf geräumt +- Je gelungener Lauf entsteht ein Bericht +---------------------------------------- + +Batch hochladen + +Lädt viele Dateien gesammelt und verarbeitet sie + +- Ohne Datei bricht der Lauf ab +- Titel entstehen aus Dateinamen oder Manifest +- Schwache Titel werden markiert +- Wissenskarten entstehen nur auf Wunsch +- Aktivierung ohne Wissenskarte wird verworfen + +- Menüeintrag Batch wählen +- Dateien wählen +- Batch starten +- Ergebniszahlen sichtbar +---------------------------------------- + +Batch vorab prüfen + +Prüft einen Eingang ohne jede Schreibwirkung + +- Kein Dokument wird importiert +- Kein Modell wird aufgerufen +- Dateityp, Prüfsumme und Dubletten werden geprüft +- Zusatzschalter erzeugen eine Warnung + +- Kommando im Trockenlauf aufrufen +- Bericht mit Dateiliste sichtbar +---------------------------------------- + +Batch importieren + +Importiert einen Eingang im Terminal + +- Der Import ist über Prüfsummen wiederholbar +- Ohne eindeutigen Benutzer bricht der Lauf ab +- Der Kommandolauf hat keine Dateigrenze +- Erfolgreiche Quellen verlassen den Eingang +- Fehler und Übersprungenes landen getrennt +- Abgeleitete Versionen bleiben ohne Schalter inaktiv + +- Kommando mit Eingang aufrufen +- Bericht als Datei geschrieben +---------------------------------------- + +Berichte auflisten + +- Höchstens 100 Berichte, neueste oben +- Defekte Berichte werden übersprungen + +- Menüeintrag Batch wählen +- Berichtsliste sichtbar +---------------------------------------- + +Bericht ansehen + +Zeigt einen Lauf je Datei und Schritt + +- Die Kennung darf keine Sonderzeichen tragen +- Ein unbekannter Bericht meldet einen Fehler +- Die Ansicht startet keine Verarbeitung + +- Berichtsliste öffnen +- LMB auf Anzeigen +- Schritte und Dateien sichtbar +---------------------------------------- + +Bericht herunterladen + +- Zwei Formate: JSON und Markdown +- Eine fehlende Datei meldet einen Fehler + +- Berichtsliste öffnen +- LMB auf ein Format +- Datei im Download +---------------------------------------- + +Bericht löschen + +- Beide Formate fallen zusammen weg +- Dokumente und Index bleiben unberührt + +- Berichtsliste öffnen +- LMB auf Löschen +- Bestätigen +- Bericht verschwindet +---------------------------------------- + +Eingang bereinigen + +Räumt leere Ordner und falsche Ablagen auf + +- Die Bereinigung wirkt nur im Importverzeichnis +- Namenskollisionen bekommen einen Zähler +- Kein Einfluss auf Suche oder Antwort + +- Menüeintrag Batch wählen +- LMB auf Eingang bereinigen +- Zahl geräumter Ordner sichtbar diff --git a/daten/MtoRagSystem/.planung/beleg.md b/daten/MtoRagSystem/.planung/beleg.md new file mode 100644 index 0000000..a2e1565 --- /dev/null +++ b/daten/MtoRagSystem/.planung/beleg.md @@ -0,0 +1,71 @@ + +Beleg +---------------------------------------- + +kern +---------------------------------------- + +Weist nach, worauf eine Aussage sich stützt +---------------------------------------- + +- Belegquellen sind Wissen, Shop und URL-Inhalte +- Frühere Antworten belegen keine Fachwerte +- Jede Antwort erhält genau einen Belegzustand +- Direkt belegt gilt nur bei einem tragenden Beleg +- Verstreute Anforderungen ergeben schwach belegt +- Fehlende Pflichtangabe ergibt nicht vollständig belegt +- Ohne Quelle gilt nicht geprüft +- Jeder Beleg trägt eine Stärke +- Fehlende Pflichtmerkmale werden einzeln benannt +- Direkte Dokumentquellen stehen unter der Antwort +- Höchstens vier Quellentitel erscheinen +- Eine genutzte Uploaddatei bleibt in der Quellenliste +---------------------------------------- + +Belegdetails aufklappen + +Zeigt Prüfsignale hinter der Vertrauenslage + +- Ohne echte Signale erscheint keine Belegkarte +- Konflikte werden gesondert benannt +- Die Anzeige gilt für alle sichtbaren Antworten + +- Frage stellen +- LMB auf technische Details +- Claims und Belege sichtbar +---------------------------------------- + +Zusatzinfos umschalten + +Blendet Quellen und Folgeaktionen ein + +- Nur genutzte Quellen werden gelistet +- Die Einstellung überlebt einen Neuladen + +- Chat-Einstellungen öffnen +- Zusatzinfos umschalten +- Quellenblock verschwindet +---------------------------------------- + +Statusprotokoll einschalten + +Macht Prüf- und Quellenschritte sichtbar + +- Der Bereich öffnet sich beim Einschalten +- Statusinfos stehen neben dem Verlauf +- Fehlermeldungen bleiben immer sichtbar +- Prompts und Geheimnisse erscheinen nie + +- Chat-Einstellungen öffnen +- Statusprotokoll einschalten +- Seitenbereich mit Zeitleiste sichtbar +---------------------------------------- + +Statusprotokoll schließen + +- Schließen schaltet die Einstellung aus +- Der Zustand überlebt einen Neuladen + +- Statusprotokoll einschalten +- LMB auf Schließen im Bereich +- Bereich verschwindet diff --git a/daten/MtoRagSystem/.planung/benutzer.md b/daten/MtoRagSystem/.planung/benutzer.md new file mode 100644 index 0000000..4b34aa4 --- /dev/null +++ b/daten/MtoRagSystem/.planung/benutzer.md @@ -0,0 +1,82 @@ + +Benutzer +---------------------------------------- + +kern +---------------------------------------- + +Regelt Zugang und Rollen der Menschen +---------------------------------------- + +- Ein Passwort wird nur verschlüsselt gespeichert +- Eine E-Mail ist eindeutig +- Ein deaktiviertes Konto wird abgewiesen +- Niemand deaktiviert sich selbst +- Der letzte oberste Verwalter bleibt geschützt +- Die Verwaltung braucht die höchste Rolle +- Ein Konto lässt sich nicht löschen +- Deaktivierung beendet die laufende Sitzung +---------------------------------------- + +Benutzer filtern + +- Filter nach Text, Zustand und Rolle +- Die Suche trifft Namen, E-Mail und Abteilung +- Ein ungültiger Wert fällt auf alle +- Die Gesamtzahlen bleiben ungefiltert + +- Menüeintrag Benutzer wählen +- Filter setzen +- LMB auf Filtern +- Trefferzahl sichtbar +---------------------------------------- + +Benutzer erstellen + +- Das Passwort braucht acht Zeichen +- Die Wiederholung muss übereinstimmen +- Mindestens eine Rolle ist Pflicht +- Unbekannte Rollen werden abgewiesen +- Die Grundrolle ist nicht vergebbar + +- Benutzerliste öffnen +- Formular ausfüllen +- Rollen ankreuzen +- Erstellen +- Benutzer in der Liste +---------------------------------------- + +Benutzer bearbeiten + +- Leeres Passwortfeld ändert nichts +- Die oberste Rolle entzieht sich niemand selbst +- Namen enden bei 100 Zeichen +- Abteilung endet bei 120 Zeichen + +- Benutzerliste öffnen +- LMB auf Bearbeiten +- Felder ändern +- Speichern +- Änderung in der Liste +---------------------------------------- + +Benutzer umschalten + +Sperrt oder öffnet den Zugang sofort + +- Bestehende Rollen bleiben erhalten + +- Benutzerliste öffnen +- LMB auf Zustand +- Bestätigen +- Zustandsspalte wechselt +---------------------------------------- + +Benutzer im Terminal anlegen + +- Doppelte E-Mail wird abgewiesen +- Die Eingabe erfolgt abgefragt + +- Kommando aufrufen +- Angaben eintragen +- Benutzer angelegt diff --git a/daten/MtoRagSystem/.planung/betriebspruefung.md b/daten/MtoRagSystem/.planung/betriebspruefung.md new file mode 100644 index 0000000..229cd66 --- /dev/null +++ b/daten/MtoRagSystem/.planung/betriebspruefung.md @@ -0,0 +1,117 @@ + +Betriebsprüfung +---------------------------------------- + +optional +---------------------------------------- + +Bewertet Betriebsreife vor der Abnahme +---------------------------------------- + +- Jede Prüfung liest nur lokale Angaben +- Kein Chat, kein Shop, kein Modell läuft +- Ein Fehler setzt den Gesamtstand +- Ein fehlender Nachweis wird zur Warnung +- Ein Nachweis wird nie stillschweigend angenommen +- Geheimnisse bleiben Verweise +- Der Restore-Nachweis bleibt Betreiberaufgabe +- Das System richtet keine Zeitsteuerung ein +- Jedes Ergebnis landet bereinigt im Protokoll +---------------------------------------- + +Betrieb überblicken + +Fasst alle Prüfstände und die letzte Sicherung + +- Die Seite bewertet bei jedem Aufruf neu +- Nur ausgelöste Prüfungen landen im Protokoll +- Der nächste sinnvolle Schritt steht dabei + +- Menüeintrag Betrieb wählen +- Gesamtstand und Teilstände sichtbar +---------------------------------------- + +Sicherheit prüfen + +Prüft Rollen, Geheimnisse und Grenzen + +- Die Prüfung ersetzt kein externes Audit +- Geheimniswerte werden nicht gelesen + +- Betriebsseite öffnen +- LMB auf Sicherheit prüfen +- Fallliste mit Ständen sichtbar +---------------------------------------- + +Sicherungsweg prüfen + +Bewertet Pfad, Umfang und Restore-Nachweis + +- Es entsteht keine Sicherung +- Ein Restore-Erfolg wird nicht behauptet + +- Betriebsseite öffnen +- LMB auf Sicherungsweg prüfen +- Prüfpunkte sichtbar +---------------------------------------- + +Zeitsteuerung prüfen + +Bewertet Automatik, Turnus und Betreibernachweise + +- Der Betreiber dokumentiert Automatik selbst +- Nicht beschreibbare Pfade erzeugen Hinweise + +- Betriebsseite öffnen +- LMB auf Zeitsteuerung prüfen +- Nachweistabelle sichtbar +---------------------------------------- + +Protokoll einsehen + +Zeigt die zuletzt ausgelösten Prüfungen + +- Keine Prompts und keine Rohantworten +- Keine Geheimnisse und keine Zugangsdaten +- Der Text endet bei 220 Zeichen +- Höchstens 50 Einträge bleiben erhalten +- Die Anzeige zeigt die letzten acht + +- Betriebsseite öffnen +- Protokollbereich lesen +- Letzte Prüfungen sichtbar +---------------------------------------- + +Abnahmebericht ausgeben + +Lädt den bereinigten Bericht zur Abnahme + +- Zwei Formate: JSON und Markdown +- Die Datengrenze steht im Bericht +- Erledigte Aufgaben fallen weg +- Der Export startet keine Prüfung + +- Betriebsseite öffnen +- Format wählen +- Bericht im Download +---------------------------------------- + +Betriebsreife im Terminal prüfen + +- Nur ein grüner Stand endet ohne Fehler +- Warnungen ändern den Ausgang nicht + +- Kommando aufrufen +- Fallliste sichtbar +---------------------------------------- + +Unterlagen öffnen + +Zeigt Runbook und Checklisten im Adminbereich + +- Nur Markdown aus dem Projektverzeichnis +- Die Anzeige ist rein lesend + +- Menüeintrag Leitfäden wählen +- Dokument wählen +- Inhalt sichtbar diff --git a/daten/MtoRagSystem/.planung/claim.md b/daten/MtoRagSystem/.planung/claim.md new file mode 100644 index 0000000..3b790d7 --- /dev/null +++ b/daten/MtoRagSystem/.planung/claim.md @@ -0,0 +1,51 @@ + +Claim +---------------------------------------- + +kern +---------------------------------------- + +Prüft einzelne Aussagen der Antwort gegen Belege +---------------------------------------- + +- Geprüft werden Werte, Preise und Artikelnummern +- Geprüft werden URLs und Rollencodes +- Geprüft werden Relationen und Kompatibilitätsaussagen +- Ein Claim ohne Quelle gilt als unbelegt +- Ein unbelegter Claim setzt ein Prüfsignal +- Unbelegte Claims werden benannt +- Höchstens fünf Beispiele erscheinen +- Rollencodes gelten nur bei genauer Übereinstimmung +- Relationen brauchen beide Partner in einem Dokument +- Eine leere Antwort gilt als ungeprüft +- Sieben Claim-Arten stehen fest +---------------------------------------- + +Antwort bewerten + +Meldet falsche Zuordnung oder Quellenfehler zurück + +- Zwei Werte: zustimmend und ablehnend +- Ablehnung erlaubt einen Kommentar +- Kommentar wird auf 2000 Zeichen gekürzt +- Bewertung braucht eine fertige Antwort +- Eine fremde Antwort wird abgewiesen +- Die Oberfläche sperrt nach dem Speichern +- Ein erneuter Aufruf überschreibt die Bewertung +- Frage und Antwort werden mitgespeichert + +- Frage stellen +- LMB auf eine Bewertung +- Bestätigung sichtbar +---------------------------------------- + +Prompt kopieren + +Übernimmt die eigene Frage in die Zwischenablage + +- Kopiert wird nur der Fragetext +- Erfolg wird kurz gemeldet + +- Frage stellen +- LMB auf Kopieren +- Rückmeldung an der Schaltfläche diff --git a/daten/MtoRagSystem/.planung/diagnose.md b/daten/MtoRagSystem/.planung/diagnose.md new file mode 100644 index 0000000..59ca8f0 --- /dev/null +++ b/daten/MtoRagSystem/.planung/diagnose.md @@ -0,0 +1,84 @@ + +Diagnose +---------------------------------------- + +optional +---------------------------------------- + +Untersucht einzelne Teile des Antwortwegs +---------------------------------------- + +- Diagnosen ändern Antwortgüte und Wahrheitssicherung nicht +- Prompts und Rohantworten werden nie ausgegeben +- Betriebsfunktionen beeinflussen die Antwort nicht +---------------------------------------- + +Im Terminal fragen + +Stellt Fragen an das System ohne Oberfläche + +- Die Antwort läuft in Stücken ein +- Statusmeldungen stehen dazwischen +- Der Lauf löst echte Modellaufrufe aus + +- Kommando aufrufen +- Frage eintragen +- Antwort läuft ein +---------------------------------------- + +Suchweg testen + +Prüft den hybriden Suchweg zu einer Frage + +- Leere Frage wird abgewiesen +- Die Ausgabe nennt Dauer und Trefferzahl + +- Kommando mit Frage aufrufen +- Trefferliste sichtbar +---------------------------------------- + +Faktenabdeckung prüfen + +Prüft, wie gut Fakten eine Frage abdecken + +- Eine leere Frage wird abgewiesen +- Eine Mindestgüte ist wählbar + +- Kommando mit Frage aufrufen +- Abdeckung mit Zusammenfassung sichtbar +---------------------------------------- + +Ankerauflösung testen + +Prüft die Auflösung einer Folgefrage trocken + +- Kein Eingriff in die Laufzeit +- Mehrdeutige Anker werden verworfen +- Eine genannte Artikelnummer schlägt jeden Anker + +- Kommando mit Folgefrage aufrufen +- Auflösungsbericht sichtbar +---------------------------------------- + +Verlaufsanker auslesen + +Zieht Bezugsanker aus einem Gesprächsverlauf + +- Anker belegen keine Fachwerte +- Eingabe per Argument, Datei oder Strom +- Ein eingebauter Rauchtest ist wählbar + +- Kommando mit Rauchtest aufrufen +- Ankerliste sichtbar +---------------------------------------- + +Fakten inspizieren + +Untersucht gespeicherte Fakten der Chunkdatei + +- Eine fehlende Chunkdatei meldet einen Fehler +- Nur lesender Zugriff auf den Index +- Filter nach Text, Typ und Anzahl + +- Kommando mit Suchtext aufrufen +- Trefferliste sichtbar diff --git a/daten/MtoRagSystem/.planung/dokument.md b/daten/MtoRagSystem/.planung/dokument.md new file mode 100644 index 0000000..a4ae5a2 --- /dev/null +++ b/daten/MtoRagSystem/.planung/dokument.md @@ -0,0 +1,107 @@ + +Dokument +---------------------------------------- + +kern +---------------------------------------- + +Führt eine Wissensquelle über ihre Versionen +---------------------------------------- + +- Ein Dokument hält mehrere Versionen +- Genau eine Version ist aktiv +- Tags hängen am Dokument, nicht an der Version +- Schreiben an Dokument oder Version ändert den Index nicht +---------------------------------------- + +Dokumente filtern + +Grenzt die Liste nach Zustand und Pflege ein + +- Sechs Filter: Suche, Status, Index, Version, Titel, Tags +- Unbekannter Filterwert fällt auf alle +- Die Suche trifft Titel, Kennung und Dateiname +- Kennzahlen zählen immer den Gesamtbestand + +- Dokumentliste öffnen +- Filter setzen +- LMB auf Filtern +- Trefferzahl sichtbar +---------------------------------------- + +Dokument hochladen + +Legt eine Wissensquelle mit erster Version an + +- Die Datei ist Pflicht +- Ohne Titel dient der Dateiname als Titel +- Ein schwacher Titel bekommt einen Prüfhinweis +- Version eins entsteht aktiv +- Je Version wird eine Prüfsumme gespeichert +- Der Index bleibt bis zum Neuaufbau unverändert + +- Dokumentliste öffnen +- LMB auf neues Dokument +- Datei wählen +- Speichern +- Dokumentseite sichtbar +---------------------------------------- + +Titel ändern + +Ersetzt einen schwachen Titel fachlich + +- Leerer Titel wird abgewiesen +- Höchstens 255 Zeichen +- Der Prüfhinweis entfällt danach +- Index und Antwortlogik bleiben unberührt + +- Dokumentseite öffnen +- Titel ändern +- Speichern +- Titel als geprüft markiert +---------------------------------------- + +Titel vorschlagen lassen + +Erzeugt Titelkandidaten aus dem Dokumentanfang + +- Der Ausschnitt endet bei 9000 Zeichen +- Höchstens sechs Vorschläge +- Höchstens 120 Zeichen je Vorschlag +- Zu kurze Kandidaten fallen weg +- Ein Klick füllt nur das Feld +- Dokument, Version und Index bleiben unberührt + +- Dokumentseite öffnen +- LMB auf Titel vorschlagen +- Kandidat wählen +- Titelfeld gefüllt +---------------------------------------- + +Indexbereitschaft ansehen + +Zeigt, was den Index bisher nicht erreicht hat + +- Offene Änderungen werden gezählt +- Gelöschte Dokumente im Index werden benannt + +- Dokumentliste öffnen +- Bereitschaftsblock lesen +- Zahl offener Änderungen sichtbar +---------------------------------------- + +Dokument löschen + +Entfernt Dokument, Versionen und Dateien endgültig + +- Nur die höchste Rolle darf löschen +- Ein laufender Neuaufbau verhindert das Löschen +- Versionsdateien werden mitgelöscht +- Ein Auftrag hält den Vorgang fest +- Der Index ändert sich beim nächsten Neuaufbau + +- Dokumentliste öffnen +- LMB auf Löschen +- Bestätigen +- Dokument verschwindet diff --git a/daten/MtoRagSystem/.planung/evalfall.md b/daten/MtoRagSystem/.planung/evalfall.md new file mode 100644 index 0000000..7438a6b --- /dev/null +++ b/daten/MtoRagSystem/.planung/evalfall.md @@ -0,0 +1,77 @@ + +Evalfall +---------------------------------------- + +optional +---------------------------------------- + +Beschreibt einen prüfbaren Fall für die Antwortgüte +---------------------------------------- + +- Neun Falltypen stehen im Adminbereich +- Ein zehnter Typ läuft nur im Terminal +- Eine Fallkennung ist projektweit eindeutig +- Pflichtfelder sind Kennung, Typ und Frage +- Fälle liegen als Zeilendatei je Typ und Bereich +- Schreiben erfolgt mit ausschließender Sperre +---------------------------------------- + +Bereich wählen + +Schaltet zwischen Systembasis und Fachbereich + +- Der Bereich prägt jede weitere Handlung +- Fachbereiche liegen in eigenen Ordnern + +- Menüeintrag Eval Suite wählen +- LMB auf einen Bereichsreiter +- Fälle des Bereichs sichtbar +---------------------------------------- + +Evalfall anlegen + +- Doppelte Kennung wird abgewiesen +- Erwartung muss ein Objekt sein +- Verlauf muss eine Liste sein +- Ein Fehler verhindert jede Änderung + +- Menüeintrag Eval Suite wählen +- LMB auf neuer Test +- Formular ausfüllen +- Absenden +- Fall in der Datei +---------------------------------------- + +Evalfall geführt anlegen + +Legt einen Fall über einen Assistenten an + +- Eigener Entwurf mit eigener Fehlerprüfung + +- Menüeintrag Eval Suite wählen +- LMB auf Assistent +- Schritte ausfüllen +- Fall in der Datei +---------------------------------------- + +Evalfall ableiten + +Übernimmt einen gescheiterten Lauf als Fall + +- Kennung und Frage werden vorbelegt + +- Lauf mit Fehlschlag öffnen +- LMB auf Fall übernehmen +- Formular vorbefüllt +---------------------------------------- + +Evalfall löschen + +- Eine defekte Zeile verhindert die Änderung +- Unbekannte Kennung meldet einen Fehler +- Eine Rückfrage geht voraus + +- Seite neuer Test öffnen +- LMB auf Löschen +- Bestätigen +- Fall verschwindet diff --git a/daten/MtoRagSystem/.planung/evallauf.md b/daten/MtoRagSystem/.planung/evallauf.md new file mode 100644 index 0000000..aae1024 --- /dev/null +++ b/daten/MtoRagSystem/.planung/evallauf.md @@ -0,0 +1,100 @@ + +Evallauf +---------------------------------------- + +optional +---------------------------------------- + +Prüft die Antwortpipeline gegen gespeicherte Fälle +---------------------------------------- + +- Ein gescheiterter Fall setzt den Gesamtstand +- Eine leere Auswahl gilt nicht als Fehlschlag +- Berichte entstehen unteilbar +- Evals messen Fälle, nicht jede mögliche Frage +- Fünf Falltypen rufen das Modell +- Vier Falltypen laufen ohne Modell +---------------------------------------- + +Evallauf starten + +Führt Fälle aus dem Adminbereich aus + +- Der Lauf braucht die Wissensrolle +- Der Bericht wird zusätzlich archiviert +- Der Lauf blockiert die Anfrage bis zum Ende + +- Menüeintrag Eval Suite wählen +- Auswahl treffen +- Lauf starten +- Ergebnis je Fall sichtbar +---------------------------------------- + +Einzelfall erneut testen + +Wiederholt genau einen gescheiterten Fall + +- Nur der gewählte Fall läuft + +- Lauf mit Fehlschlag öffnen +- LMB auf erneut testen +- Ergebnis des Falls sichtbar +---------------------------------------- + +Läufe vergleichen + +Stellt zwei Berichte als Unterschied gegenüber + +- Der Vergleich nennt behoben, neu und entfernt + +- Menüeintrag Eval Suite wählen +- Vergleichsbasis wählen +- Unterschied sichtbar +---------------------------------------- + +Evallauf im Terminal ausführen + +- Die Auswahl folgt Typ und Bereich +- Ein Abbruch nach dem ersten Fehler ist wählbar +- Ein Lauf ohne Schreiben ist wählbar +- Fälle lassen sich nur auflisten + +- Kommando mit Typ aufrufen +- Ergebnis je Fall sichtbar +---------------------------------------- + +Evallauf parallelisieren + +Verteilt Fälle auf mehrere Kindprozesse + +- Zwischen einem und 32 Prozessen +- Vorgabe sind zwei Prozesse +- Ein Zeitlimit je Prozess ist wählbar +- Das Ergebnis ist ein Sammelbericht + +- Kommando mit Prozesszahl aufrufen +- Sammelbericht sichtbar +---------------------------------------- + +Berichte aufräumen + +- Nur erzeugte Dateinamen fallen weg +- Aufräumen behält 20 Läufe je Bereich +- Die Liste zeigt zehn Läufe + +- Menüeintrag Eval Suite wählen +- LMB auf Aufräumen +- Berichtszahl sinkt +---------------------------------------- + +Berichte löschen + +Entfernt alle Läufe eines Bereichs + +- Der aktuelle Lauf fällt mit weg +- Eine Rückfrage geht voraus + +- Menüeintrag Eval Suite wählen +- LMB auf alle löschen +- Bestätigen +- Berichtsliste leer diff --git a/daten/MtoRagSystem/.planung/fremdinhalt.md b/daten/MtoRagSystem/.planung/fremdinhalt.md new file mode 100644 index 0000000..e100caf --- /dev/null +++ b/daten/MtoRagSystem/.planung/fremdinhalt.md @@ -0,0 +1,138 @@ + +Fremdinhalt +---------------------------------------- + +optional +---------------------------------------- + +Prüft externe Inhalte vor jeder Nutzung +---------------------------------------- + +- Geprüft wird der ausgewählte Inhalt +- Ein Lesen führt kein Werkzeug aus +- Ein Lesen ändert die Antwortpipeline nicht +- Vorschauen sind gekürzt und bereinigt +- Externe Inhalte heben ihren Rang nicht selbst +- Der Bereich braucht die höchste Rolle +- Keine Übernahme ins Standardwissen erfolgt automatisch +---------------------------------------- + +Inhalt live prüfen + +Liest den ausgewählten Inhalt einmalig online + +- Nur der gewählte Inhalt wird gelesen +- Ohne Zutun wird nichts gespeichert + +- Übersicht öffnen +- LMB auf Inhalt prüfen +- Bestätigen +- Vorschau mit Abrufzahl +---------------------------------------- + +Inhalt bereitstellen + +Merkt einen gelesenen Inhalt als Kandidat vor + +- Chat und Antwortnutzung bleiben aus +- Der Kandidat startet ohne Freigabe +- Eine Rückfrage geht voraus + +- Inhalt live prüfen +- LMB auf bereitstellen +- Bestätigen +- Kandidat in der Liste +---------------------------------------- + +Inhalt auswählen + +Ordnet einen Inhalt einem Raum zur Prüfung zu + +- Zwei Arten: eigener Raum und Ergänzung +- Die Auswahl gilt schon als geprüft +- Die Auswahl schaltet den Chat nicht ein +- Standardwissen wird dadurch nicht ergänzt + +- Räume überblicken +- LMB auf Inhalt auswählen +- Bestätigen +- Inhalt im Freigabebereich +---------------------------------------- + +Inhalt entscheiden + +Gibt einen geprüften Inhalt frei oder stellt zurück + +- Fünf Wege bis zum Zurücksetzen +- Eine unbekannte Entscheidung wird abgewiesen +- Eine Freigabe schaltet den Chat nicht ein +- Die Notiz endet bei 1000 Zeichen + +- Freigabebereich öffnen +- LMB auf Inhalt ansehen +- Entscheidung wählen +- Zustandsmarke wechselt +---------------------------------------- + +Inhalt im Chat einschalten + +Fügt einen freigegebenen Inhalt dem Raum zu + +- Nur geprüfte Inhalte eines eigenen Raums +- Nicht vorbereitete Inhalte werden abgewiesen +- Suche und Belege bleiben unberührt +- Es entsteht kein gespeichertes Wissen + +- Freigabebereich öffnen +- LMB auf im Chat einschalten +- Inhalt als aktiv markiert +---------------------------------------- + +Kandidaten filtern + +Grenzt vorbereitete Inhalte nach Zustand ein + +- Filter nach Zustand, Anbindung, Art und Zeit +- Das Filtern ruft nichts extern ab + +- Vorbereitete Inhalte öffnen +- Filter setzen +- Trefferliste eingegrenzt +---------------------------------------- + +Kandidat entfernen + +Löscht einen vorbereiteten Inhalt endgültig + +- Die Vorschau fällt mit weg + +- Vorbereitete Inhalte öffnen +- LMB auf Entfernen +- Kandidat verschwindet +---------------------------------------- + +Kandidaten ausgeben + +Lädt vorbereitete Inhalte als Datei herunter + +- Zwei Formate: Markdown und JSONL +- Der Export gibt die gefilterte Menge aus +- Der Export wirkt nicht als Freigabe + +- Vorbereitete Inhalte öffnen +- Format wählen +- Herunterladen +- Datei im Download +---------------------------------------- + +Ressource lesen + +Liest eine freigegebene Ressource im Terminal + +- Nur erlaubte Server und Adressen +- Der Inhalt wird bereinigt +- Ausgegeben werden nur Metadaten und Prüfsumme +- Eine Kürzung wird gekennzeichnet + +- Kommando mit Adresse aufrufen +- Metadaten und Prüfsumme sichtbar diff --git a/daten/MtoRagSystem/.planung/indexprofil.md b/daten/MtoRagSystem/.planung/indexprofil.md new file mode 100644 index 0000000..51e6894 --- /dev/null +++ b/daten/MtoRagSystem/.planung/indexprofil.md @@ -0,0 +1,64 @@ + +Indexprofil +---------------------------------------- + +optional +---------------------------------------- + +Legt Struktur für Chunking und Einbettung fest +---------------------------------------- + +- Ein Profil ist unveränderlich +- Genau ein Profil ist aktiv +- Einsehen braucht die Wissensrolle +- Ändern braucht die höchste Rolle +- Die Version zählt beim Anlegen hoch +- Ein neues Profil entsteht inaktiv +---------------------------------------- + +Profile prüfen + +Gleicht das aktive Profil gegen den Index ab + +- Der Vergleich läuft gegen die Indexmetadaten +- Eine abweichende Zeile setzt den Gesamtstand +- Fehlende Metadaten gelten als Strukturabweichung +- Die Ansicht startet keinen Neuaufbau + +- Menüeintrag Indexprofile wählen +- Abweichungen je Zeile sichtbar +---------------------------------------- + +Profil anlegen + +- Chunkgröße von 50 bis 1000 in Schritten von 25 +- Überlappung von 25 bis 200 in Schritten von 25 +- Das Einbettungsmodell ist Pflicht +- Fehlende Pflichtwerte nennen das Feld +- Nur die höchste Rolle darf anlegen + +- Indexprofile öffnen +- Werte eintragen +- Profil erstellen +- Inaktives Profil sichtbar +---------------------------------------- + +Profil aktivieren + +- Das bisherige Profil wird deaktiviert +- Die Aktivierung startet keinen Neuaufbau + +- Indexprofile öffnen +- LMB auf Aktivieren +- Bestätigen +- Profil als aktiv markiert +---------------------------------------- + +Profil löschen + +- Der Löschweg erscheint nur bei inaktiven Profilen + +- Indexprofile öffnen +- LMB auf Löschen +- Bestätigen +- Profil verschwindet diff --git a/daten/MtoRagSystem/.planung/konfiguration.md b/daten/MtoRagSystem/.planung/konfiguration.md new file mode 100644 index 0000000..45db7ca --- /dev/null +++ b/daten/MtoRagSystem/.planung/konfiguration.md @@ -0,0 +1,46 @@ + +Konfiguration +---------------------------------------- + +optional +---------------------------------------- + +Prüft die wirksamen Einstellungen vor dem Betrieb +---------------------------------------- + +- Fachsemantik gehört in die Konfiguration +- Harte Sonderpfade im Antwortkern sind verboten +- Geänderter Kataloginhalt wirkt ohne Codeänderung +---------------------------------------- + +Konfiguration validieren + +- Fehler und Warnungen erscheinen getrennt +- Warnungen ändern den Ausgang nicht +- Regressionswächter melden nur Warnungen + +- Kommando aufrufen +- Fehler- und Warnliste sichtbar +---------------------------------------- + +Konfiguration ausgeben + +Zeigt die aufgelöste Einstellung zur Diagnose + +- Die Ausgabe ist nicht bereinigt +- Pfade und Adressen stehen darin +- Nur der Shopschlüssel bleibt verborgen + +- Kommando aufrufen +- Vollständige Ausgabe sichtbar +---------------------------------------- + +Quellen auditieren + +Prüft Herkunft, Muster und Fachneutralität + +- Reine Quelltextanalyse ohne Laufzeitwirkung +- Ein Fehlerstand beendet den Lauf + +- Kommando aufrufen +- Kennzahlen und Funde sichtbar diff --git a/daten/MtoRagSystem/.planung/modellprofil.md b/daten/MtoRagSystem/.planung/modellprofil.md new file mode 100644 index 0000000..8497f9a --- /dev/null +++ b/daten/MtoRagSystem/.planung/modellprofil.md @@ -0,0 +1,68 @@ + +Modellprofil +---------------------------------------- + +optional +---------------------------------------- + +Stellt Modell und Suchparameter der Antwort ein +---------------------------------------- + +- Höchstens ein Profil ist systemweit aktiv +- Ohne aktives Profil greifen die Vorgabewerte +- Die Version zählt je Modellname hoch +- Ein neues Profil entsteht inaktiv +- Ein aktives Profil lässt sich nicht löschen +- Nur fehlende Felder erben die Vorgabewerte +- Wertebereiche greifen erst beim Aktivieren +- Suchwerte werden still auf 1 bis 200 begrenzt +---------------------------------------- + +Profile auflisten + +- Das aktive Profil steht oben +- Die Anzeige startet keine Erzeugung + +- Menüeintrag Modellsetup wählen +- Profilliste sichtbar +---------------------------------------- + +Profil erstellen + +- Der Modellname ist Pflicht +- Nur die höchste Rolle darf anlegen + +- Profilliste öffnen +- Werte eintragen +- Absenden +- Inaktives Profil sichtbar +---------------------------------------- + +Profil aktivieren + +- Profilliste öffnen +- LMB auf Aktivieren +- Bestätigen +- Profil als aktiv markiert +---------------------------------------- + +Profil löschen + +- Profilliste öffnen +- LMB auf Löschen +- Bestätigen +- Profil verschwindet +---------------------------------------- + +Suche testen + +Prüft das Trefferverhalten eines Profils + +- Leere Frage liefert kein Ergebnis +- Der Test ändert das Profil nicht +- Der Test aktiviert das Profil nicht + +- Profilliste öffnen +- LMB auf Testen +- Frage eintragen +- Trefferliste sichtbar diff --git a/daten/MtoRagSystem/.planung/protokoll.md b/daten/MtoRagSystem/.planung/protokoll.md new file mode 100644 index 0000000..24dfe5d --- /dev/null +++ b/daten/MtoRagSystem/.planung/protokoll.md @@ -0,0 +1,43 @@ + +Protokoll +---------------------------------------- + +optional +---------------------------------------- + +Zeigt Betriebsmeldungen der Dienste +---------------------------------------- + +- Nur die höchste Rolle darf lesen +- Die Anzeige ist rein lesend +- Kein Löschen ist vorgesehen +---------------------------------------- + +Protokolle auflisten + +- Nur Dateien nach festem Namensmuster +- Neueste Änderung steht oben + +- Menüeintrag Protokolle wählen +- Dateiliste mit Größe sichtbar +---------------------------------------- + +Protokoll anzeigen + +- Höchstens 1000 Zeilen +- Gelesen wird vom Dateiende +- Eine fehlende Datei meldet einen Fehler + +- Protokollliste öffnen +- LMB auf Anzeigen +- Letzte Zeilen sichtbar +---------------------------------------- + +Vektorprotokoll anzeigen + +- Feste Quelle im Protokollverzeichnis +- Höchstens 500 Zeilen +- Eine fehlende Datei meldet einen Hinweis + +- Menüeintrag Vektorprotokoll wählen +- Letzte Zeilen sichtbar diff --git a/daten/MtoRagSystem/.planung/rueckmeldung.md b/daten/MtoRagSystem/.planung/rueckmeldung.md new file mode 100644 index 0000000..c1d4115 --- /dev/null +++ b/daten/MtoRagSystem/.planung/rueckmeldung.md @@ -0,0 +1,99 @@ + +Rückmeldung +---------------------------------------- + +optional +---------------------------------------- + +Sammelt Nutzerkritik für die Verbesserung +---------------------------------------- + +- Eine Rückmeldung hängt an einer Antwort +- Die Adminsicht braucht die Wissensrolle +- Ein Löschen ist endgültig +- Der Export enthält Frage und Antwort im Klartext +- Der Export folgt den gesetzten Filtern +---------------------------------------- + +Rückmeldungen filtern + +Grenzt Fälle nach zehn Merkmalen ein + +- Filter nach Bewertung und Bearbeitungsstand +- Filter nach Einordnung und Fehlerverdacht +- Filter nach Vorrang und Referenzwert +- Seitengröße wählbar mit 25, 50 oder 100 + +- Menüeintrag Chat-Feedback wählen +- Filter setzen +- Trefferliste sichtbar +---------------------------------------- + +Rückmeldung ansehen + +Zeigt einen Fall mit Frage und Antwort + +- Rückmeldungen filtern +- LMB auf einen Fall +- Frage und Antwort sichtbar +---------------------------------------- + +Rückmeldung erledigen + +- Eine Notiz ist möglich + +- Rückmeldung ansehen +- LMB auf erledigt +- Zustand wechselt +---------------------------------------- + +Rückmeldung wieder öffnen + +- Erledigte Rückmeldung ansehen +- LMB auf wieder öffnen +- Zustand wechselt +---------------------------------------- + +Rückmeldungen gesammelt erledigen + +Setzt den Stand für die ganze Auswahl + +- Auswahl über Kästchen oder Filter +- Höchstens 5000 Fälle je Aktion + +- Rückmeldungen filtern +- Auswahl treffen +- LMB auf Auswahl erledigen +- Zustände wechseln +---------------------------------------- + +Rückmeldung löschen + +- Rückmeldung ansehen +- LMB auf Löschen +- Bestätigen +- Eintrag verschwindet +---------------------------------------- + +Rückmeldungen ausgeben + +- Zwei Formate: Markdown und JSONL +- Der Export ist nicht bereinigt +- Vorgefertigte Auszüge je Vorrang + +- Rückmeldungen filtern +- Format wählen +- Datei im Download +---------------------------------------- + +Rückmeldungen einordnen + +Bestimmt Typ, Risiko und Vorrang im Terminal + +- Ohne Erzwingen nur ungeordnete Einträge +- Höchstens 5000 Einträge je Lauf +- Vorgabe sind 500 Einträge +- Zwischenstände werden gespeichert + +- Kommando aufrufen +- Zähler je Risiko sichtbar diff --git a/daten/MtoRagSystem/.planung/selbsttest.md b/daten/MtoRagSystem/.planung/selbsttest.md new file mode 100644 index 0000000..ac14084 --- /dev/null +++ b/daten/MtoRagSystem/.planung/selbsttest.md @@ -0,0 +1,76 @@ + +Selbsttest +---------------------------------------- + +optional +---------------------------------------- + +Sichert Grenzen des Systems gegen Rückschritte +---------------------------------------- + +- 23 Selbsttests decken die Regressionsfläche +- Jeder Test hat sein eigenes Kommando +- Es gibt kein Sammelkommando +- Jeder Test liefert Fallliste und Ausgang +- Jeder Test kennt eine maschinenlesbare Ausgabe +- 15 Tests prüfen nur den Quelltext +- Sechs Tests prüfen gemischt +- Zwei Tests prüfen nur Verhalten +---------------------------------------- + +Einzeltest ausführen + +Prüft eine benannte Grenze des Systems + +- Kein Modell, kein Netz, keine Antwort +- Keine Datenbank und kein Import +- Ein gescheiterter Fall beendet den Lauf + +- Kommandonamen aus der Übersicht holen +- Kommando aufrufen +- Fallliste mit Ständen sichtbar +---------------------------------------- + +Ingestgrenzen prüfen + +Sichert Markdown, Chunks und Batchgrenzen ab + +- Zwölf Kommandos decken diesen Bereich +- Ein Test räumt sein Verzeichnis selbst auf + +- Kommando aus der Ingestgruppe aufrufen +- Fallliste mit Ständen sichtbar +---------------------------------------- + +Anbindungsgrenzen prüfen + +Sichert Fremddaten und Werkzeuggrenzen ab + +- Drei Kommandos decken diesen Bereich +- Verbotene Zeichenketten gelten als Fall + +- Kommando aus der Anbindungsgruppe aufrufen +- Fallliste mit Ständen sichtbar +---------------------------------------- + +Architekturgrenzen prüfen + +Sichert Flussgrenzen und Produktregeln ab + +- Fünf Kommandos decken diesen Bereich +- Ein Test hängt an einer Freigabeversion + +- Kommando aus der Architekturgruppe aufrufen +- Fallliste mit Ständen sichtbar +---------------------------------------- + +Antwortgrenzen prüfen + +Sichert Anker, Prüfung und Raumauswahl ab + +- Drei Kommandos decken diesen Bereich +- Keine Chatantwort und kein Shopzugriff +- Unbelegte Begriffe bleiben unrepariert + +- Kommando aus der Antwortgruppe aufrufen +- Fallliste mit Ständen sichtbar diff --git a/daten/MtoRagSystem/.planung/shoptreffer.md b/daten/MtoRagSystem/.planung/shoptreffer.md new file mode 100644 index 0000000..a386971 --- /dev/null +++ b/daten/MtoRagSystem/.planung/shoptreffer.md @@ -0,0 +1,75 @@ + +Shoptreffer +---------------------------------------- + +optional +---------------------------------------- + +Liefert Preis und Verfügbarkeit aus dem Shop +---------------------------------------- + +- Der Preis stammt allein aus dem Shopdatensatz +- Ohne Shoppreis erscheint kein Preis +- Ein fehlender Preis wird nicht zu null +- Kostenlos gilt nur mit Quellenbeleg +- Verfügbarkeit stammt allein aus dem Shopfeld +- Die Produktadresse stammt aus dem Shoppfad +- Reine Wissensantworten tragen keine Shopadressen +- Ein Shoptreffer belegt keine technische Eignung +- Zubehör wird nicht als Hauptgerät ausgegeben +- Bündelangaben bleiben unzerlegt +- Gefilterte Treffer sind keine fehlenden Treffer +- Kein Treffer bedeutet nicht: gibt es nicht +- Ein Shopausfall wird gemeldet +- Bei automatischer Basis startet sie nur bei Kaufbezug +- Die Basis Shop erzwingt die Suche +- Die gesendete Suchanfrage wird offengelegt +- Bilder stammen aus dem Bildfeld desselben Datensatzes +---------------------------------------- + +Shopsuche auslösen + +Sucht aus einer Wissensantwort passende Produkte + +- Angebot entfällt bei gleicher Suche +- Angebot entfällt bei ablehnender Antwort +- Eine erweiterte Suche wird ausgewiesen + +- Frage stellen +- LMB auf Shopsuche +- Trefferliste sichtbar +---------------------------------------- + +Preis nachfragen + +Ruft Handelsdaten zum genannten Produkt ab + +- Angebot entfällt bei genanntem Preis +- Die Folgeantwort bleibt am Produkt + +- Frage nach einem Produkt stellen +- LMB auf Preis anzeigen +- Preis und Artikelnummer sichtbar +---------------------------------------- + +Treffer filtern + +Grenzt die Liste auf Zubehör oder Geräte ein + +- Angebot erscheint nur bei Wirkung +- Mehrdeutige Rollen gelten nicht als Gerät + +- Shopsuche auslösen +- LMB auf eine Rolle +- Liste eingegrenzt +---------------------------------------- + +Shopsuche diagnostizieren + +Prüft eine Suchanfrage samt Reparatur im Terminal + +- Der Zugriff läuft live gegen den Shop +- Die Reparatursuche bevorzugt den angefragten Code + +- Kommando mit Suchtext aufrufen +- Suchanfrage und Treffer sichtbar diff --git a/daten/MtoRagSystem/.planung/sicherung.md b/daten/MtoRagSystem/.planung/sicherung.md new file mode 100644 index 0000000..0595250 --- /dev/null +++ b/daten/MtoRagSystem/.planung/sicherung.md @@ -0,0 +1,90 @@ + +Sicherung +---------------------------------------- + +optional +---------------------------------------- + +Sichert Anwendung und Datenbank nachvollziehbar +---------------------------------------- + +- Geheimnisse werden nie mitkopiert +- Fremdbibliotheken und Zwischenspeicher bleiben draußen +- Ein Datenbankabzug entsteht auf Anforderung oder Vorgabe +- Eine Sperrdatei verhindert parallele Läufe +- Sieben Stände bleiben rollierend erhalten +- Symlinks werden übersprungen +- Ein Verzeichnis nennt Umfang und Kennung +- Eine gelungene Sicherung beweist keinen Restore +---------------------------------------- + +Sicherung testen + +Prüft den geplanten Umfang ohne Schreibvorgang + +- Keine Sicherungsdatei entsteht +- Keine alte Sicherung fällt weg +- Fehlende Pflichtquellen erscheinen als Warnung +- Fehlende Zusatzquellen zählen getrennt + +- Betriebsseite öffnen +- LMB auf Sicherung testen +- Umfang und Warnungen sichtbar +---------------------------------------- + +Sicherung starten + +- Ein Datenbankabzug braucht Schalter oder Vorgabe +- Das Verzeichnis nennt keinen Zugang +- Geräumte Sicherungen werden benannt +- Eine Rückfrage geht voraus + +- Betriebsseite öffnen +- LMB auf Sicherung starten +- Bestätigen +- Sicherung in der Liste +---------------------------------------- + +Sicherung herunterladen + +Holt ein Archiv für den Restore-Test + +- Nur die höchste Rolle darf herunterladen +- Nur gültige lokale Kennungen +- Der Abruf startet keine Sicherung + +- Betriebsseite öffnen +- LMB auf Herunterladen +- Archiv im Download +---------------------------------------- + +Restore prüfen + +Bewertet eine Sicherung als Wiederherstellungsgrundlage + +- Nur die höchste Rolle darf prüfen +- Es läuft keine Wiederherstellung +- Kein Datenbankimport erfolgt +- Gelesen werden Verzeichnis und Bestandteile +- Das Ergebnis liefert einen Plan + +- Betriebsseite öffnen +- LMB auf Restore prüfen +- Prüfpunkte und Plan sichtbar +---------------------------------------- + +Sicherung im Terminal erstellen + +- Ein Trockenlauf schreibt keine Datei +- Die Aufbewahrung ist wählbar + +- Kommando aufrufen +- Kennung und Umfang sichtbar +---------------------------------------- + +Restore im Terminal prüfen + +- Kein Netz, kein Modell, kein Chat + +- Kommando mit Kennung aufrufen +- Prüfpunkte und Plan sichtbar diff --git a/daten/MtoRagSystem/.planung/sitzung.md b/daten/MtoRagSystem/.planung/sitzung.md new file mode 100644 index 0000000..241fbe9 --- /dev/null +++ b/daten/MtoRagSystem/.planung/sitzung.md @@ -0,0 +1,83 @@ + +Sitzung +---------------------------------------- + +kern +---------------------------------------- + +Hält Zugang und Verlauf einer Unterhaltung +---------------------------------------- + +- Chat und Adminbereich teilen eine Anmeldung +- Ein Abmelden beendet beide Bereiche +- Der Verlauf hängt an einem Browserkennzeichen +- Ein Abmelden löscht dieses Kennzeichen nicht +- Deaktivierte Konten werden abgewiesen +- Der Verlauf löst nur Bezüge auf +- Der Verlauf belegt keine Fachwerte +- Ein Hinweis nennt Fehlerrisiko und Datennutzung +---------------------------------------- + +Am Chat anmelden + +- E-Mail und Passwort sind Pflicht +- Ohne Chatrolle erscheint eine Verbotsseite +- Falscher Zugang behält die E-Mail +- Angemeldete landen sofort im Chat + +- Anmeldeseite aufrufen +- E-Mail und Passwort eintragen +- Bestätigen +- Chat mit Verlauf sichtbar +---------------------------------------- + +Vom Chat abmelden + +- Gemerkte Einstellungen bleiben erhalten + +- LMB auf Abmelden +- Anmeldeseite sichtbar +---------------------------------------- + +Am Adminbereich anmelden + +- Ohne Adminrolle erscheint eine Verbotsseite +- Berechtigte landen auf der Systemübersicht +- Der letzte Benutzername ist vorbelegt + +- Adminanmeldung aufrufen +- E-Mail und Passwort eintragen +- Bestätigen +- Systemübersicht sichtbar +---------------------------------------- + +Vom Adminbereich abmelden + +- LMB auf Abmelden +- Anmeldeseite sichtbar +---------------------------------------- + +Verlauf löschen + +Entfernt Gespräch, Produktbezüge und Uploads + +- Während des Empfangs gesperrt +- Löscht alle temporären Uploads mit +- Keine Rückfrage, keine Wiederherstellung +- Danach fehlen alle Bezugsanker + +- LMB auf Verlauf löschen +- Verlauf leer +- Uploadliste leer +---------------------------------------- + +Hilfe öffnen + +Zeigt das Bedienhandbuch im Chat + +- Nur bei vorhandener Handbuchdatei +- Höchstens 512 KB werden gelesen +- Die Hilfe ändert keine Antwortlogik + +- LMB auf Hilfe +- Handbuch im Fenster sichtbar diff --git a/daten/MtoRagSystem/.planung/systemprompt.md b/daten/MtoRagSystem/.planung/systemprompt.md new file mode 100644 index 0000000..3827769 --- /dev/null +++ b/daten/MtoRagSystem/.planung/systemprompt.md @@ -0,0 +1,46 @@ + +Systemprompt +---------------------------------------- + +optional +---------------------------------------- + +Steuert die Grundanweisung an das Modell +---------------------------------------- + +- Genau eine Version ist aktiv +- Die Version zählt fortlaufend hoch +- Eine neue Version überschreibt keine alte +- Nur die höchste Rolle darf ändern +---------------------------------------- + +Version speichern + +- Leerer Inhalt wird abgewiesen +- Die neue Version wird sofort aktiv +- Die bisherige Version wird abgeschaltet + +- Menüeintrag Systemprompt wählen +- Text eintragen +- Speichern +- Neue aktive Version oben +---------------------------------------- + +Version aktivieren + +Schaltet auf eine frühere Version zurück + +- Systemprompt öffnen +- LMB auf Aktivieren +- Bestätigen +- Kennzeichnung wechselt +---------------------------------------- + +Version löschen + +- Eine aktive Version bleibt geschützt + +- Systemprompt öffnen +- LMB auf Löschen +- Bestätigen +- Version verschwindet diff --git a/daten/MtoRagSystem/.planung/tag.md b/daten/MtoRagSystem/.planung/tag.md new file mode 100644 index 0000000..6351030 --- /dev/null +++ b/daten/MtoRagSystem/.planung/tag.md @@ -0,0 +1,92 @@ + +Tag +---------------------------------------- + +optional +---------------------------------------- + +Lenkt die Suche über gepflegte Signale +---------------------------------------- + +- Drei Typen: allgemein, Katalogobjekt, Vertriebssignal +- Unbekannter Typ fällt auf allgemein +- Ein Slug ist eindeutig +- Jede Änderung stößt einen Neuaufbau an +- Ein laufender Neuaufbau verhindert einen zweiten +---------------------------------------- + +Tag anlegen + +- Slug und Bezeichnung sind Pflicht +- Der Slug wird kleingeschrieben +- Leerzeichen werden zu Bindestrichen +- Ein doppelter Slug wird abgewiesen + +- Tagliste öffnen +- Bezeichnung und Slug eintragen +- Anlegen +- Tag in der Liste +---------------------------------------- + +Tag löschen + +- Alle Zuweisungen fallen mit weg + +- Tagliste öffnen +- LMB auf Löschen +- Bestätigen +- Tag verschwindet +---------------------------------------- + +Dokumente zuweisen + +Ordnet einem Tag mehrere Dokumente zu + +- Nur aktive Dokumente stehen zur Wahl +- Doppelte Kennungen werden entfernt +- Nur Unterschiede werden geschrieben + +- Tagliste öffnen +- LMB auf Zuweisen +- Dokumente ankreuzen +- Speichern +- Zähler angepasst +---------------------------------------- + +Dokument-Tags bearbeiten + +Setzt die Tags eines einzelnen Dokuments + +- Tags erscheinen nach Typ sortiert +- Nicht angekreuzte Tags fallen weg + +- Dokumentliste öffnen +- LMB auf Tags +- Tags ankreuzen +- Speichern +- Neuaufbau angestoßen +---------------------------------------- + +Neuaufbau verfolgen + +Zeigt den Fortschritt des Tag-Neuaufbaus laufend + +- Der Stand wird zweisekündlich abgefragt +- Ein Lebenszeichen kommt zehnsekündlich +- Vier Zustände: wartend, laufend, fertig, gescheitert +- Das Zusehen stößt keinen Neuaufbau an + +- Tagliste öffnen +- Statuszeile beobachten +- Zustand wechselt bis fertig +---------------------------------------- + +Tagindex neu aufbauen + +Baut Tagexport und Tagvektoren im Terminal neu + +- Entweder Auftragskennung oder Neuanlage +- Eine Sperrdatei verhindert Parallelläufe + +- Kommando mit Neuanlage aufrufen +- Kennzahlen sichtbar diff --git a/daten/MtoRagSystem/.planung/upload.md b/daten/MtoRagSystem/.planung/upload.md new file mode 100644 index 0000000..963d239 --- /dev/null +++ b/daten/MtoRagSystem/.planung/upload.md @@ -0,0 +1,68 @@ + +Upload +---------------------------------------- + +kern +---------------------------------------- + +Stellt eine Datei als Quelle der Sitzung bereit +---------------------------------------- + +- Erlaubt sind PDF, Markdown und Text +- Höchstens drei Dateien je Sitzung +- Höchstens 10 MB je Datei +- Ein Upload verfällt nach 60 Minuten +- Uploads ändern die Wissensbasis nie +- Ein Upload beginnt nachrangig +- Ein Upload lässt sich auf vorrangig stellen +- Der ausgewertete Text endet bei 60000 Zeichen +- Der Client prüft, der Server prüft erneut +---------------------------------------- + +Datei hochladen + +- Eine leere Datei weist erst der Server ab +- Übergroße Datei wird abgewiesen +- Bei erreichtem Maximum ist der Zugang gesperrt +- Ein Upload beginnt nachrangig + +- LMB auf Hinzufügen +- Datei wählen +- Datei mit Größe sichtbar +---------------------------------------- + +Nutzung wählen + +Legt fest, ob der Upload allein zählt + +- Abfrage erscheint nach dem Hochladen +- Als eigener Raum zählt nur der Upload +- Als Ergänzung bleibt Standardwissen führend +- Ohne Freigabe bleibt Standardwissen wirksam + +- Datei hochladen +- Eine Nutzungsart wählen +- Wissensraum passt sich an +---------------------------------------- + +Upload priorisieren + +Hebt den Upload gegenüber dem Wissen an + +- Zwei Modi: nachrangig und vorrangig +- Als eigener Raum entfällt der Schalter +- Ein Widerspruch bleibt sichtbar ausgewiesen + +- Datei hochladen +- LMB auf den Rangvermerk +- Vermerk zeigt vorrangig +---------------------------------------- + +Upload entfernen + +- Wirkt nur auf eigene Uploads +- Ohne Upload fällt der Raum zurück + +- Datei hochladen +- LMB auf Entfernen +- Datei verschwindet diff --git a/daten/MtoRagSystem/.planung/version.md b/daten/MtoRagSystem/.planung/version.md new file mode 100644 index 0000000..678a70c --- /dev/null +++ b/daten/MtoRagSystem/.planung/version.md @@ -0,0 +1,135 @@ + +Version +---------------------------------------- + +kern +---------------------------------------- + +Hält einen unveränderlichen Stand eines Dokuments +---------------------------------------- + +- Eine Version wird nie überschrieben +- Jede Version trägt eine Prüfsumme +- Eine neue Version entsteht inaktiv +- Nur die aktive Version speist den Index +---------------------------------------- + +Version hochladen + +Legt einen Nachfolgestand als neue Version ab + +- Die Datei ist Pflicht +- Die Nummer zählt vom höchsten Stand hoch +- Die aktive Version bleibt unverändert + +- Dokumentseite öffnen +- LMB auf neue Version +- Datei wählen +- Hochladen +- Inaktive Version sichtbar +---------------------------------------- + +Originaltext ansehen + +Zeigt die Textbasis vor der Chunk-Erzeugung + +- Die Anzeige ändert die Datei nicht +- Jede Seite liefert 40000 Zeichen +- Eine angeforderte Seitengröße endet bei 80000 +- Weitere Seiten laden beim Blättern nach +- Nicht lesbare Formate melden einen Fehler + +- Dokumentseite öffnen +- LMB auf Original ansehen +- Text im Fenster sichtbar +---------------------------------------- + +Version ableiten + +Speichert korrigierten Text als neue Version + +- Die Arbeitskopie endet bei 180000 Zeichen +- Leerer Inhalt wird abgewiesen +- Der Dateiname nennt die Quellversion +- Quelle und aktive Version bleiben unberührt +- Die neue Version ist inaktiv + +- Originaltext ansehen +- Text anpassen +- Als neue Version speichern +- Inaktive Version sichtbar +---------------------------------------- + +Wissenskarte erzeugen + +Erstellt eine strukturierte Markdown-Fassung der Version + +- Die Quelle wird segmentiert verarbeitet +- Ein unvollständiger Plan bricht ab +- Der Zusammenbau erfolgt durch das System +- Der Nachweis nennt Modell und Segmentzahl +- Kein Index wird geschrieben +- Doppelklicks bleiben während des Laufs gesperrt + +- Dokumentseite öffnen +- LMB auf Wissenskarte erzeugen +- Bestätigen +- Neue inaktive Version sichtbar +---------------------------------------- + +Version aktivieren + +Wählt eine Version als künftige Antwortbasis + +- Genau eine Version bleibt aktiv +- Die Version wird zum Neuaufbau vorgemerkt +- Kein Auftrag und kein Neuaufbau startet +- Bis dahin gilt der letzte stabile Index + +- Dokumentseite öffnen +- LMB auf Version aktivieren +- Bestätigen +- Warnung zum Neuaufbau sichtbar +---------------------------------------- + +Version vormerken + +Markiert die aktive Version für den Neuaufbau + +- Nur die aktive Version lässt sich vormerken +- Es startet kein Einzellauf + +- Dokumentseite öffnen +- LMB auf vormerken +- Bestätigen +- Version als vorgemerkt markiert +---------------------------------------- + +Chunks lesen + +Zeigt die Chunks einer Version aus dem Index + +- Die Anzeige ändert keine Antwortlogik +- Höchstens 300 Chunks je Version +- Je Chunk höchstens 1400 Zeichen +- Je Chunk höchstens 30 Fakten +- Ohne Indexeinträge erscheint eine Warnung + +- Dokumentseite öffnen +- LMB auf Chunks lesen +- Chunkliste sichtbar +---------------------------------------- + +Chunkgüte vergleichen + +Stellt Original und Wissenskarte gegenüber + +- Die Prüfung läuft nur im Speicher +- Kein Index wird geschrieben +- Kein Modell wird aufgerufen +- Ein fehlendes Gegenstück meldet einen Hinweis +- Der Vergleich nennt Chunks, Tabellen und Fakten + +- Dokumentseite öffnen +- LMB auf Güte vergleichen +- Vergleich sichtbar diff --git a/daten/MtoRagSystem/.planung/vision.md b/daten/MtoRagSystem/.planung/vision.md new file mode 100644 index 0000000..62a5b93 --- /dev/null +++ b/daten/MtoRagSystem/.planung/vision.md @@ -0,0 +1,72 @@ + +Vision +---------------------------------------- + +vision +---------------------------------------- + +Antworten sollen nicht nur plausibel klingen, sondern nachprüfbar sein. +---------------------------------------- + +Beleggeführt antworten + +Jede Aussage bekommt einen nachvollziehbaren Belegzustand +- Was nicht in den Quellen steht, wird nicht behauptet +- Belegzustand und Abdeckung sind ablesbar +- Einzelne Aussagen werden gegen die Belege geprüft +---------------------------------------- + +Grenzen zeigen + +Fehlendes, Schwaches und Widersprüchliches bleibt sichtbar +- Fehlende Quellen werden benannt, nicht ersetzt +- Quellenkonflikte werden gezeigt statt zusammengeführt +- Transparente Unsicherheit schlägt sichere Falschaussage +---------------------------------------- + +Quellen trennen + +Fachwissen, Handelsdaten und Uploads bleiben unterscheidbar +- Ein Shoppreis belegt keine technische Eignung +- Wissensräume trennen die Bestände sichtbar +- Ein Upload bleibt temporär und nachrangig +---------------------------------------- + +Wissen pflegen + +Dokumente werden antwortfähig, nicht nur abgelegt +- Versionen bleiben einzeln nachvollziehbar +- Struktur, Chunks und Fakten sind einsehbar +- Ein Neuaufbau ist eine bewusste Entscheidung +---------------------------------------- + +Fremddaten kontrollieren + +Externe Quellen wirken nur nach bewusster Freigabe +- Nichts wird automatisch zu Standardwissen +- Nur lesende Werkzeuge, nie Schreibaktionen +- Jede Freigabe ist eine eigene Entscheidung +---------------------------------------- + +Fachfrei bleiben + +Fachsemantik gehört in Konfiguration, nicht in den Kern +- Harte Sonderpfade im Antwortkern sind verboten +- Ein Fachpaket ist pflegbar ohne Codeänderung +- Diagnosen verändern die Antwortgüte nicht +---------------------------------------- + +Betrieb nachweisen + +Der Betreiber kann belegen, dass das System trägt +- Prüfungen, Sicherungen und Berichte sind abrufbar +- Berichte enthalten keine Geheimnisse +- Ein Restore-Nachweis bleibt Aufgabe des Betreibers +---------------------------------------- + +Grenzen des Systems anerkennen + +Das System ersetzt keine Prüfung durch Menschen +- Es gibt keine Rechteverwaltung im Wissen +- Kein Ersatz für Audit, Rechtsrat oder Abkommen +- Evals messen Fälle, nicht universelle Wahrheit diff --git a/daten/MtoRagSystem/.planung/werkzeug.md b/daten/MtoRagSystem/.planung/werkzeug.md new file mode 100644 index 0000000..a14db82 --- /dev/null +++ b/daten/MtoRagSystem/.planung/werkzeug.md @@ -0,0 +1,56 @@ + +Werkzeug +---------------------------------------- + +optional +---------------------------------------- + +Erlaubt ein lesendes Werkzeug im Anbindungsraum +---------------------------------------- + +- Nur eindeutig lesende Werkzeuge sind erlaubt +- Werkzeuge mit Schreibrisiko bleiben gesperrt +- Eine Freigabe gilt nur für ihren Raum +- Das Modell schlägt vor, das System führt aus +- Ein freigegebenes Werkzeug läuft ohne Rückfrage +- Höchstens ein Werkzeug je Antwort +- Jede Nutzung erhält einen Nachweis +- Ein Werkzeugfehler wird sichtbar gemeldet +- Standardwissen und Shop bleiben ausgeschlossen +- Der Bereich braucht die höchste Rolle +---------------------------------------- + +Werkzeug freigeben + +- Nicht eindeutig lesende Werkzeuge bleiben gesperrt +- Der Grund für eine Sperre steht dabei +- Die Freigabe führt kein Werkzeug aus + +- Räume überblicken +- Abschnitt Werkzeuge aufklappen +- LMB auf freigeben +- Werkzeug als freigegeben markiert +---------------------------------------- + +Werkzeugfreigabe zurücknehmen + +- Die Rücknahme wirkt sofort + +- Räume überblicken +- Abschnitt Werkzeuge aufklappen +- LMB auf Freigabe entfernen +- Werkzeug wieder gesperrt +---------------------------------------- + +Werkzeugergebnis auswählen + +Ordnet ein gespeichertes Ergebnis einem Raum zu + +- Kein Werkzeug läuft dabei +- Ergebnisse bleiben gespeicherte Prüfinformationen +- Ergebnisse sind nicht live lesbar + +- Räume überblicken +- Abschnitt Ergebnisse aufklappen +- LMB auf auswählen +- Ergebnis im Freigabebereich diff --git a/daten/MtoRagSystem/.planung/wissensindex.md b/daten/MtoRagSystem/.planung/wissensindex.md new file mode 100644 index 0000000..5b682fc --- /dev/null +++ b/daten/MtoRagSystem/.planung/wissensindex.md @@ -0,0 +1,90 @@ + +Wissensindex +---------------------------------------- + +kern +---------------------------------------- + +Hält die durchsuchbare Fassung des Wissens +---------------------------------------- + +- Treffer unter der Mindestgüte fallen weg +- Jeder Treffer trägt eine Chunkkennung +- Dokument und Abschnitt kommen mit, sofern vorhanden +- Eine nicht erreichbare Suche liefert keine Treffer +- Ein veralteter Index wird gemeldet +- Ein unvollständiger Aufbau bricht ab +---------------------------------------- + +Systemstand ansehen + +Zeigt Chunkzahl und Gesundheit der Dienste + +- Die Anzeige schreibt nichts +- Die harte Chunkgrenze liegt bei 25000 + +- Menüeintrag Systemübersicht wählen +- Chunkzahl und Gesundheit sichtbar +---------------------------------------- + +Chunkindex einsehen + +- Nur die höchste Rolle darf einsehen +- Vorgabe 50, höchstens 200 Einträge je Seite +- Die Anzeige startet keinen Neuaufbau + +- Menüeintrag Wissensbasis wählen +- Metadaten und Einträge sichtbar +---------------------------------------- + +Zwischenspeicher leeren + +Verwirft kurzlebige Zwischenstände nach Wartung + +- Der Dienst kennt keine Antwortlogik +- Ein nicht erreichbarer Vektordienst ergibt eine Warnung +- Eine Rückfrage geht voraus + +- Systemübersicht öffnen +- LMB auf Zwischenspeicher leeren +- Bestätigen +- Ergebnismeldung sichtbar +---------------------------------------- + +Gesundheit prüfen + +Prüft Vektor- und Tagindex im Terminal + +- Gesund ist jeder Zustand mit Vorsilbe OK +- Es entsteht kein Schreibzugriff + +- Kommando aufrufen +- Prüfbericht sichtbar +---------------------------------------- + +Vektordienst steuern + +Startet, stoppt oder lädt den Vektordienst neu + +- Die Steuerung läuft über das Kontrollskript +- Das Zeitlimit beträgt 600 Sekunden + +- Kommando mit Aktion aufrufen +- Ausgabe des Skripts sichtbar +---------------------------------------- + +Wissen zurücksetzen + +Löscht Dokumente, Versionen, Tags und Indexdateien + +- Nur die höchste Rolle darf ausführen +- Die Funktion ist standardmäßig gesperrt +- Der Bestätigungstext muss wörtlich stimmen +- Zuvor entsteht eine Sicherung +- Ein Fehlschlag der Sicherung bricht ab + +- Systemübersicht öffnen +- Bestätigungstext eintippen +- Absenden +- Bestätigen +- Sicherungspfad sichtbar diff --git a/daten/MtoRagSystem/.planung/wissensraum.md b/daten/MtoRagSystem/.planung/wissensraum.md new file mode 100644 index 0000000..58c7074 --- /dev/null +++ b/daten/MtoRagSystem/.planung/wissensraum.md @@ -0,0 +1,97 @@ + +Wissensraum +---------------------------------------- + +kern +---------------------------------------- + +Bestimmt, welcher Bestand eine Antwort trägt +---------------------------------------- + +- Standardwissen ist immer verfügbar +- Standardwissen lässt sich nicht abschalten +- Ein Uploadraum antwortet nur aus dem Upload +- Ein Uploadraum kennt keinen stillen Rückfall +- Ein Anbindungsraum liest nur Freigegebenes +- Ein Anbindungsraum mischt kein Standardwissen +- Ein unbekannter Raum fällt auf Standardwissen +- Freigegebene Inhalte und Werkzeugergebnisse sind nachrangig +- Beide bleiben vom Rangvorteil ausgenommen +---------------------------------------- + +Wissensraum wählen + +Legt die Antwortgrundlage der Unterhaltung fest + +- Der Uploadraum braucht einen gültigen Upload +- Gesperrte Räume sind nicht wählbar +- Während des Empfangs gesperrt + +- Chat-Einstellungen öffnen +- Wissensraum wählen +- Raum in der Zusammenfassung +---------------------------------------- + +Räume überblicken + +Zeigt, welche Räume arbeiten und angeboten werden + +- Der Zugang braucht die höchste Rolle +- Anbindungen sind erst nach Freigabe wirksam + +- Menüeintrag Wissensräume wählen +- Räume mit Zählern sichtbar +---------------------------------------- + +Chatauswahl umschalten + +Gibt einen Raum für die Chatauswahl frei + +- Standardwissen bleibt gesperrt +- Ausschalten löscht keine Freigaben +- Wiedereinschalten braucht keine neue Freigabe +- Nicht vorgesehene Räume werden abgewiesen + +- Räume überblicken +- LMB auf Einschalten +- Raum als aktiv markiert +---------------------------------------- + +Freigegebenen Inhalt vorschauen + +Liest einen freigegebenen Inhalt vor der Entscheidung + +- Der Dialog liest nur auf Klick +- Kein Standardwissen und kein Werkzeug +- Es wird nichts gespeichert + +- Räume überblicken +- Freigabebereich öffnen +- LMB auf live lesen +- Textvorschau sichtbar +---------------------------------------- + +Herkunft ansehen + +Zeigt, welche Inhalte welchem Raum gehören + +- Reine Anzeige ohne Freigabe +- Kein externer Abruf entsteht + +- Räume überblicken +- Abschnitt Herkunft aufklappen +- Zuordnungen je Raum sichtbar +---------------------------------------- + +Raumgrenzen prüfen + +Führt sechs Selbsttests zu den Raumgrenzen aus + +- Es entsteht keine Chatantwort +- Kein Werkzeug wird ausgeführt +- Kein Inhalt wird live gelesen +- Netz und Speicher werden je Test ausgewiesen + +- Räume überblicken +- LMB auf Prüfungen ausführen +- Sammelergebnis sichtbar diff --git a/daten/MtoRagSystem/.pruefung.json b/daten/MtoRagSystem/.pruefung.json new file mode 100644 index 0000000..13292ac --- /dev/null +++ b/daten/MtoRagSystem/.pruefung.json @@ -0,0 +1,2735 @@ +{ + "abdeckung": { + "befehl:mto:agent:architecture:flow-boundary-lock-self-test": { + "abdruck": "c925f9ebbfd2ac93", + "funktion": "Flow-Grenze sperren", + "trug": "ea1cbd831236ff9b" + }, + "befehl:mto:agent:architecture:product-label-formatter-self-test": { + "abdruck": "0d4a6b2e979afd6b", + "funktion": "Produktlabel-Formatierer testen", + "trug": "74392b10f4a0556c" + }, + "befehl:mto:agent:architecture:product-role-code-assignment-guard-self-test": { + "abdruck": "60e19a0ea2d093fe", + "funktion": "Rollencode-Zuweisung prüfen", + "trug": "f2997c6adf648e7d" + }, + "befehl:mto:agent:architecture:retrieval-boundary-plan-self-test": { + "abdruck": "7f8215ff3dff4b5c", + "funktion": "Abrufgrenzen prüfen", + "trug": "f28e16b270157b1c" + }, + "befehl:mto:agent:chat": { + "abdruck": "097710e520fe8631", + "funktion": "Mit Agent chatten", + "trug": "1229550e6c0369a3" + }, + "befehl:mto:agent:config:audit-patterns": { + "abdruck": "0b1c8dad920a1d05", + "funktion": "Konfigurationsmuster prüfen", + "trug": "1b7dd0cb5cba69f8" + }, + "befehl:mto:agent:config:dump-effective": { + "abdruck": "0ba647f167567c2b", + "funktion": "Konfiguration anzeigen", + "trug": "2511a19eea51ca10" + }, + "befehl:mto:agent:config:validate": { + "abdruck": "cb09c2dfeb607be8", + "funktion": "Konfiguration prüfen", + "trug": "108abbfa38def03f" + }, + "befehl:mto:agent:enterprise:backup-restore-readiness": { + "abdruck": "ad2992db1999b947", + "funktion": "Backup-Tauglichkeit prüfen", + "trug": "990d7d1975e35860" + }, + "befehl:mto:agent:enterprise:backup-run": { + "abdruck": "e5e1870cc5f2a2c7", + "funktion": "Daten sichern", + "trug": "6391c6a03fff9ba3" + }, + "befehl:mto:agent:enterprise:deployment-scheduler-readiness": { + "abdruck": "b7f9a71b8bce1733", + "funktion": "Bereitschaftsbericht ausgeben", + "trug": "1961781c00c38587" + }, + "befehl:mto:agent:enterprise:operations-overview": { + "abdruck": "941982a7c7e9d9df", + "funktion": "Übersicht rendern", + "trug": "d6b379dbcf57c5dc" + }, + "befehl:mto:agent:enterprise:operator-report": { + "abdruck": "3305eaab802a8180", + "funktion": "Akzeptanzbericht generieren", + "trug": "1e122f300e60146f" + }, + "befehl:mto:agent:enterprise:readiness-check": { + "abdruck": "c5898cf586f10094", + "funktion": "Betriebsbereitschaft prüfen", + "trug": "dd4dda8395a78a97" + }, + "befehl:mto:agent:enterprise:restore-dry-run": { + "abdruck": "f471bab3a3187f13", + "funktion": "Backup-Trockenlauf prüfen", + "trug": "38cceaaa7e618c63" + }, + "befehl:mto:agent:enterprise:security-data-protection-readiness": { + "abdruck": "0a15e861d54def48", + "funktion": "Sicherheitsstatus prüfen", + "trug": "95276315f7c29265" + }, + "befehl:mto:agent:eval:parallel": { + "abdruck": "440dabce16816af3", + "funktion": "Eval-Fälle parallelisieren", + "trug": "8de24027a3e2c83c" + }, + "befehl:mto:agent:eval:run": { + "abdruck": "85ce4fdd99e94c23", + "funktion": "Eval-Fälle ausführen", + "trug": "73538935d4ddd959" + }, + "befehl:mto:agent:feedback:classify": { + "abdruck": "5428da2879624973", + "funktion": "Feedback klassifizieren", + "trug": "00b9152d4536b7ac" + }, + "befehl:mto:agent:genre:audit-core-neutrality": { + "abdruck": "f97cab11f1213a75", + "funktion": "Genre-Hotspots prüfen", + "trug": "91bc58442eee2f36" + }, + "befehl:mto:agent:history:anchors": { + "abdruck": "69a43649a218b596", + "funktion": "Verankerungen extrahieren", + "trug": "4b9bd02538873b0f" + }, + "befehl:mto:agent:history:followup-dry-run": { + "abdruck": "2af2830fff693f92", + "funktion": "Verankerung testen", + "trug": "9803f7bc34ffb84d" + }, + "befehl:mto:agent:ingest:chunk-quality": { + "abdruck": "179b20588e0c26d7", + "funktion": "Datenqualität prüfen", + "trug": "a162e9d2ed54a9e5" + }, + "befehl:mto:agent:ingest:chunk-quality-self-test": { + "abdruck": "7f431dab24f49f21", + "funktion": "Vergleichsgrenzen validieren", + "trug": "a9bb27f89b92b3a2" + }, + "befehl:mto:agent:ingest:deferred-reindex-state-self-test": { + "abdruck": "4decd99e80b91dd7", + "funktion": "Indizierungszustand prüfen", + "trug": "3ff8ed7e97021ae8" + }, + "befehl:mto:agent:ingest:markdown-derived-chunk-diagnostics-self-test": { + "abdruck": "ab9c4c968bef5c19", + "funktion": "Provenienz prüfen", + "trug": "7c406a0b8ca3453d" + }, + "befehl:mto:agent:ingest:markdown-normalization-foundation-self-test": { + "abdruck": "3f7feb1c5b040048", + "funktion": "Normalisierung prüfen", + "trug": "109ef8545f52ea37" + }, + "befehl:mto:agent:ingest:markdown-normalization-preview-self-test": { + "abdruck": "0f88411e0d7407b2", + "funktion": "Preview prüfen", + "trug": "fc8906b1cdfef658" + }, + "befehl:mto:agent:ingest:run": { + "abdruck": "aef780b3982b6bed", + "funktion": "Ingest-Job starten", + "trug": "f887e188d6183e35" + }, + "befehl:mto:agent:ingest:segmented-markdown-normalization-self-test": { + "abdruck": "21912db371ab9e77", + "funktion": "Segmentierung prüfen", + "trug": "34003cb287e4f9d7" + }, + "befehl:mto:agent:knowledge-space:chat-selection-guard-self-test": { + "abdruck": "601aa7233164d6b5", + "funktion": "Chat-Auswahl-Guard testen", + "trug": "ac7be281304f5f16" + }, + "befehl:mto:agent:knowledge:batch-admin-upload-self-test": { + "abdruck": "21121f956adc3ca0", + "funktion": "Stapel-Upload verifizieren", + "trug": "df545dae80c027af" + }, + "befehl:mto:agent:knowledge:batch-finalize-self-test": { + "abdruck": "4d4c21b129b2a50c", + "funktion": "Wissensbatch finalisieren testen", + "trug": "e9d61c0127ac4796" + }, + "befehl:mto:agent:knowledge:batch-hygiene-self-test": { + "abdruck": "6e777c8e17e244c3", + "funktion": "Hygieneregeln prüfen", + "trug": "761903cb0a2d2033" + }, + "befehl:mto:agent:knowledge:batch-import": { + "abdruck": "47be9b2b1135f1f4", + "funktion": "Batch-Import durchführen", + "trug": "baeac712078f4a8f" + }, + "befehl:mto:agent:knowledge:batch-inbox-disposition-self-test": { + "abdruck": "3e2e59ae7e444730", + "funktion": "Hygieneregeln prüfen", + "trug": "761903cb0a2d2033" + }, + "befehl:mto:agent:mcp:admin-source-check": { + "abdruck": "414f4d925dd1dd7b", + "funktion": "MCP-Quelle prüfen", + "trug": "0917ca989dcd1b58" + }, + "befehl:mto:agent:mcp:admin-source-discover": { + "abdruck": "333c1e221f30b3b8", + "funktion": "Fähigkeiten ermitteln", + "trug": "1e53c164947ea291" + }, + "befehl:mto:agent:mcp:evidence-dry-run": { + "abdruck": "695d5fa49f9a7743", + "funktion": "Simulation ausführen", + "trug": "0f010df62c3d5412" + }, + "befehl:mto:agent:mcp:gateway-dry-run": { + "abdruck": "bf9c879d67aac387", + "funktion": "MCP-Gateway trocken ausführen", + "trug": "59f4089864406319" + }, + "befehl:mto:agent:mcp:hybrid-tool-selection-planner-self-test": { + "abdruck": "d082f417503050bd", + "funktion": "Hybrid-Tool-Auswahl testen", + "trug": "9c05f0bc361a0308" + }, + "befehl:mto:agent:mcp:read-only-tool-execution-self-test": { + "abdruck": "99468d4b3ccde91e", + "funktion": "MCP-Laufzeit-Gate prüfen", + "karten": "69d65c7a24056348", + "trug": "c67fbeaf071e4f1d" + }, + "befehl:mto:agent:mcp:resource-check": { + "abdruck": "e2bec83222815992", + "funktion": "Ressource validieren", + "trug": "3e0c5e7c05c447b1" + }, + "befehl:mto:agent:mcp:resource-read": { + "abdruck": "3bbcf40c19dfb416", + "funktion": "Ressource abrufen", + "trug": "c56c2251c777e9cd" + }, + "befehl:mto:agent:mcp:runtime-boundary-self-test": { + "abdruck": "d736aecb78b903c0", + "funktion": "MCP-Laufzeitgrenze testen", + "trug": "228e1329bb95848b" + }, + "befehl:mto:agent:mcp:runtime-gate-check": { + "abdruck": "157fd59080f4b577", + "funktion": "MCP-Laufzeit-Gate prüfen", + "trug": "c67fbeaf071e4f1d" + }, + "befehl:mto:agent:performance:cache:clear": { + "abdruck": "763defd74a61b330", + "funktion": "Performance-Cache leeren", + "trug": "46d7cac0b9f2f79c" + }, + "befehl:mto:agent:proofing:unsupported-tool-term-guard-self-test": { + "abdruck": "1be9660daebca409", + "funktion": "Guard-Mechanismus prüfen", + "trug": "464037018968440b" + }, + "befehl:mto:agent:release:v1-10-8-lock-self-test": { + "abdruck": "28db5aea7efa396a", + "funktion": "Release-Selbsttest bereitstellen", + "trug": "51c4e03a2afc8beb" + }, + "befehl:mto:agent:retrieval:test": { + "abdruck": "66a9907312e411fc", + "funktion": "Retrieval-Pipeline testen", + "trug": "7dfd51b13de31ffe" + }, + "befehl:mto:agent:shop-followup-anchor-stability-self-test": { + "abdruck": "3fbc5cbbb9918cd2", + "funktion": "Stabilitäts-Selbsttest bereitstellen", + "trug": "307662914163e231" + }, + "befehl:mto:agent:tag:health": { + "abdruck": "34aaf86ed8aa379c", + "funktion": "Tag-Index-Gesundheit prüfen", + "trug": "478f95e9cc14f7d3" + }, + "befehl:mto:agent:tags:job:run": { + "abdruck": "5bb98e3f933da917", + "funktion": "Tag-Rebuild-Auftrag ausführen", + "trug": "1b02b00a7521be25" + }, + "befehl:mto:agent:test:shop-search": { + "abdruck": "5f78005e426d4c4f", + "funktion": "Shop-Suche testen", + "trug": "e4f9db3bd08ba93c" + }, + "befehl:mto:agent:user:create": { + "abdruck": "68921f1ed8e70531", + "funktion": "Benutzer anlegen", + "trug": "d3905c51b162b0ce" + }, + "befehl:mto:agent:vector:control": { + "abdruck": "1c3e9261c8b0c2c5", + "funktion": "Vektordienst steuern", + "trug": "be8c0401addb4adc" + }, + "befehl:mto:agent:vector:health": { + "abdruck": "ab957428c904d078", + "funktion": "Systemzustand prüfen", + "trug": "340f9bb7cc48ab64" + }, + "befehl:mto:ingest:facts:coverage": { + "abdruck": "dcf005cfc8d9b45f", + "funktion": "Abdeckung prüfen", + "trug": "d90435a4cc615013" + }, + "befehl:mto:ingest:facts:inspect": { + "abdruck": "5463537ee443fe78", + "funktion": "Facts prüfen", + "trug": "76dd7c085b763488" + }, + "einbinden:erweitert admin/base.html.twig": { + "abdruck": "dfcfeacbc81295ab", + "funktion": "Chat-Feedback anzeigen", + "trug": "0fb753e62f2eb09b" + }, + "einbinden:erweitert error/access_denied.html.twig": { + "abdruck": "30769f2d88587d3d", + "funktion": "Access-Denied-Fehler bereitstellen", + "trug": "c664c4eb298dd322" + }, + "route:delete /chat-uploads/{uploadId}": { + "abdruck": "a0153beebed60be4", + "funktion": "Upload entfernen", + "trug": "eeec4fdfa3e38511" + }, + "route:get /": { + "abdruck": "de9b287ba64070d2", + "funktion": "Eval-Berichte anzeigen", + "trug": "2f9bb8b3d22f8dbe" + }, + "route:get /admin": { + "abdruck": "8c0cdf9bd2b315ea", + "funktion": "Zum Dashboard weiterleiten", + "trug": "709c61628f0f66ea" + }, + "route:get /admin/": { + "abdruck": "244b9c6384096f5d", + "funktion": "Zum Dashboard weiterleiten", + "trug": "709c61628f0f66ea" + }, + "route:get /admin/chat-feedback": { + "abdruck": "e639b1e43a886a35", + "funktion": "Chat-Feedback anzeigen", + "trug": "0fb753e62f2eb09b" + }, + "route:get /admin/chat-feedback/export": { + "abdruck": "89b2621e72d8b40e", + "funktion": "Feedback exportieren", + "trug": "37a8b8e0632ad60e" + }, + "route:get /admin/chat-feedback/{id}": { + "abdruck": "edae161a247e6bfb", + "funktion": "Feedback-Details anzeigen", + "trug": "a727999800a26db6" + }, + "route:get /admin/dashboard": { + "abdruck": "2acfe2685cf601e1", + "funktion": "Dashboard anzeigen", + "trug": "4d52ebf21e33b65d" + }, + "route:get /admin/documents": { + "abdruck": "254afcc7302b5bb0", + "funktion": "Dokumente auflisten", + "trug": "0f9da42877f59cbe" + }, + "route:get /admin/enterprise": { + "abdruck": "b9d858b5471e2275", + "funktion": "Betrieb einsehen", + "trug": "0b34c0dd4f914b6b" + }, + "route:get /admin/enterprise/backup/download/latest": { + "abdruck": "ed97e58d3ce006f5", + "funktion": "Backup herunterladen", + "trug": "98261892ea9d3263" + }, + "route:get /admin/enterprise/backup/download/{backupId}": { + "abdruck": "284a03d7c9c86a3d", + "funktion": "Backup herunterladen", + "trug": "98261892ea9d3263" + }, + "route:get /admin/evals": { + "abdruck": "894a59095781a388", + "funktion": "Eval-Berichte anzeigen", + "trug": "2f9bb8b3d22f8dbe" + }, + "route:get /admin/guides": { + "abdruck": "a6767af48c103041", + "funktion": "Anleitungsübersicht öffnen", + "trug": "98c240aa62e2af02" + }, + "route:get /admin/ingest-profiles": { + "abdruck": "bd4481affd92aaf9", + "funktion": "Ingest-Profile anzeigen", + "trug": "2a45a43dfa6f7271" + }, + "route:get /admin/knowledge-batches": { + "abdruck": "6d68dc146b79f1b1", + "funktion": "Berichte auflisten", + "trug": "1e1adebd6a533d9b" + }, + "route:get /admin/knowledge-spaces": { + "abdruck": "1f5bfdfaca51004d", + "funktion": "Knowledge-Räume anzeigen", + "trug": "e04105aad7265aec" + }, + "route:get /admin/logout": { + "abdruck": "cebcf3109c609638", + "funktion": "Logout einleiten", + "trug": "9326b36641217583" + }, + "route:get /admin/mcp": { + "abdruck": "3174b0ae81ed2d20", + "funktion": "Diagnose anzeigen", + "trug": "653ae3c6bc6a5ac7" + }, + "route:get /admin/model-config": { + "abdruck": "182f6a72c678582a", + "funktion": "Konfigurationen anzeigen", + "trug": "a4cd0821c5ab3b91" + }, + "route:get /admin/system-logs": { + "abdruck": "6c4c049808bfb725", + "funktion": "Logdateien auflisten", + "trug": "e23662d3a0a4fc26" + }, + "route:get /admin/system/agent": { + "abdruck": "1ff3e3c48256b456", + "funktion": "Agentenaktivität anzeigen", + "trug": "512d3700573a9356" + }, + "route:get /admin/system/prompt": { + "abdruck": "0f2a1947d023e2b0", + "funktion": "Promptversionen verwalten", + "trug": "3ec1e92103f00c9a" + }, + "route:get /admin/tags": { + "abdruck": "dadb6db0fce78a59", + "funktion": "Tags auflisten", + "trug": "a6bcaa4a541749b0" + }, + "route:get /admin/tags/rebuild/stream": { + "abdruck": "da90a04cfab9e7bc", + "funktion": "Tags neu indizieren", + "trug": "aad224c33efd3415" + }, + "route:get /admin/users": { + "abdruck": "451ceac42e573fda", + "funktion": "Benutzer auflisten", + "trug": "200ddcbf1533c973" + }, + "route:get /admin/vector": { + "abdruck": "3762d40b703820f7", + "funktion": "Logdatei anzeigen", + "karten": "69d65c7a24056348", + "trug": "a9d4ceb635037c40" + }, + "route:get /ask-jobs/{jobId}": { + "abdruck": "0477abfc17efcd4b", + "funktion": "Auftragsstatus prüfen", + "trug": "bf711e7620e0bc96" + }, + "route:get /ask-jobs/{jobId}/events": { + "abdruck": "b035aad4da5a9b84", + "funktion": "Auftragsereignisse abrufen", + "trug": "5ec31a2942302b5d" + }, + "route:get /ask-sse/{jobId}": { + "abdruck": "2ae6d3b6ab22ee94", + "funktion": "Chat streamen", + "trug": "3af6f0591b337739" + }, + "route:get /cases/new": { + "abdruck": "d73c3f7105356e98", + "funktion": "Fall anlegen", + "trug": "d302a36967935d71" + }, + "route:get /cases/wizard": { + "abdruck": "55b87c4c5f6edabb", + "funktion": "Assistent anzeigen", + "trug": "804b6b42634c7a25" + }, + "route:get /chat": { + "abdruck": "8af834421de8e8ef", + "funktion": "Chatseite anzeigen", + "trug": "7ef27e2f05c8c346" + }, + "route:get /chat-messages/frontend": { + "abdruck": "ac5ca7be22f54fb2", + "funktion": "Konfiguration bereitstellen", + "trug": "df981d6e3375bcdc" + }, + "route:get /chat-uploads": { + "abdruck": "ccfaa51e5a843676", + "funktion": "Uploads auflisten", + "trug": "09d17a795ce6d016" + }, + "route:get /chat/login": { + "abdruck": "dbc0f1ab46c63065", + "funktion": "", + "karten": "69d65c7a24056348", + "trug": "" + }, + "route:get /chat/logout": { + "abdruck": "8c143d7ed8bb19f1", + "funktion": "Abmelden ermöglichen", + "trug": "b10bdd01f2407daf" + }, + "route:get /create": { + "abdruck": "fb24a0a1b5de52ef", + "funktion": "Ingest-Profil anlegen", + "trug": "ea489ce2cac0eaf7" + }, + "route:get /health": { + "abdruck": "f027e5524a192d02", + "funktion": "Dienststatus melden", + "trug": "161408c208cf7559" + }, + "route:get /history": { + "abdruck": "1a45e95056f2e9ec", + "funktion": "Verlauf abrufen", + "trug": "9867e39b79854b64" + }, + "route:get /log": { + "abdruck": "d174343fa1d615b0", + "funktion": "Logdatei anzeigen", + "karten": "69d65c7a24056348", + "trug": "a9d4ceb635037c40" + }, + "route:get /new": { + "abdruck": "fb14d5f8ec1a4eaa", + "funktion": "Dokument erstellen", + "trug": "22f98a663b531e62" + }, + "route:get /version/{versionId}/chunk-quality": { + "abdruck": "3d9010c730e6ec8d", + "funktion": "Abschnittsqualität laden", + "trug": "3cb1468222207d3a" + }, + "route:get /version/{versionId}/derive": { + "abdruck": "cdf85b729cf231dd", + "funktion": "Version ableiten", + "trug": "0dd44cc05ad88501" + }, + "route:get /version/{versionId}/preview": { + "abdruck": "058dec3bb1d45c3d", + "funktion": "Versionvorschau anzeigen", + "trug": "a0bf7fb5ea225b8c" + }, + "route:get /view/{date}": { + "abdruck": "9e6084cb57091b03", + "funktion": "Logdatei anzeigen", + "trug": "a9d4ceb635037c40" + }, + "route:get /{batchId}/download/{format}": { + "abdruck": "a6452842849c08bf", + "funktion": "Bericht als JSON herunterladen", + "trug": "22375d7e87b48c7a" + }, + "route:get /{id}": { + "abdruck": "ee95293ff6fa8c1e", + "funktion": "Dokument anzeigen", + "trug": "f8dbff8484664fa3" + }, + "route:get /{id}/assign": { + "abdruck": "104594e54aef3de9", + "funktion": "", + "karten": "69d65c7a24056348", + "trug": "" + }, + "route:get /{id}/edit": { + "abdruck": "8884a169ccea6f64", + "funktion": "Benutzer bearbeiten", + "trug": "8915fc3934e98aeb" + }, + "route:get /{id}/status": { + "abdruck": "8ea057327ee0827e", + "funktion": "Auftragsstatus anzeigen", + "trug": "28f625fb14170c58" + }, + "route:get /{id}/test-retrieval": { + "abdruck": "2ba055d91fdcc948", + "funktion": "Retrieval-Qualität testen", + "trug": "ebe624f4ef848daa" + }, + "route:get /{id}/version/new": { + "abdruck": "c690365b95e860d1", + "funktion": "Version erstellen", + "trug": "99e905871d2af5b8" + }, + "route:get /{slug}": { + "abdruck": "44a679fcb574ce62", + "funktion": "Anleitung anzeigen", + "trug": "1abf113dd0ca51b5" + }, + "route:patch /chat-uploads/{uploadId}/authority-mode": { + "abdruck": "9887f2123af2c793", + "funktion": "Berechtigungsmodus ändern", + "trug": "1b7c2db95a58e7b4" + }, + "route:post /activate/{id}": { + "abdruck": "c9636625aae80c95", + "funktion": "post activate {id} bereitstellen", + "trug": "8cea29a4826cdd6a" + }, + "route:post /admin/chat-feedback/batch/review-status": { + "abdruck": "be6a181dc679b11f", + "funktion": "Feedback-Status aktualisieren", + "trug": "4422d06808d2e980" + }, + "route:post /admin/chat-feedback/{id}/delete": { + "abdruck": "6893b0aa4d8eab87", + "funktion": "Feedback löschen", + "trug": "394b01bbb9e78c64" + }, + "route:post /admin/chat-feedback/{id}/review-status": { + "abdruck": "e25459719748b78c", + "funktion": "Feedback-Status aktualisieren", + "trug": "4422d06808d2e980" + }, + "route:post /admin/enterprise/backup/dry-run": { + "abdruck": "cc7a6cb84b283232", + "funktion": "", + "karten": "69d65c7a24056348", + "trug": "" + }, + "route:post /admin/enterprise/backup/start": { + "abdruck": "c26f0e1b8ec48387", + "funktion": "Backup starten", + "trug": "a80ee1ac8d09feef" + }, + "route:post /admin/enterprise/check/backup-restore": { + "abdruck": "60189cb65f15f7c4", + "funktion": "Backup-Wiederherstellung prüfen", + "trug": "2f43d33d76a1b5fd" + }, + "route:post /admin/enterprise/check/deployment-scheduler": { + "abdruck": "5a0199bcefb3aafe", + "funktion": "Deployment prüfen", + "trug": "72e96ff15688afb5" + }, + "route:post /admin/enterprise/check/security": { + "abdruck": "b626d367ee88e80d", + "funktion": "post admin enterprise check security bereitstellen", + "trug": "ae4ec899a0ed87f9" + }, + "route:post /admin/enterprise/restore/dry-run/latest": { + "abdruck": "4233f9927778bb02", + "funktion": "Backup-Trockenlauf prüfen", + "trug": "38cceaaa7e618c63" + }, + "route:post /admin/enterprise/restore/dry-run/{backupId}": { + "abdruck": "9a80fdd8dd1ce713", + "funktion": "Wiederherstellung testen", + "trug": "bffab37148aca377" + }, + "route:post /admin/knowledge-spaces/chat-availability": { + "abdruck": "5846f32d223c395c", + "funktion": "Chat-Verfügbarkeit prüfen", + "trug": "5bfe9a138fa7a344" + }, + "route:post /admin/knowledge-spaces/diagnostics/run": { + "abdruck": "d36a6a72518706c9", + "funktion": "Wissensräume prüfen", + "trug": "00428abe5d12a1a6" + }, + "route:post /admin/knowledge-spaces/provider-candidate-select": { + "abdruck": "70273cbf7942e934", + "funktion": "Kandidaten wählen", + "trug": "1b400e58e9b9ffa1" + }, + "route:post /admin/knowledge-spaces/provider-resource-chat": { + "abdruck": "94af13df841dd297", + "funktion": "Chat-Freigabe umschalten", + "trug": "ba7f9fdd0f377d82" + }, + "route:post /admin/knowledge-spaces/provider-resource-live-preview": { + "abdruck": "59ce57e712f49f67", + "funktion": "Live-Vorschau laden", + "trug": "60f5dcce03a7be18" + }, + "route:post /admin/knowledge-spaces/provider-resource-review": { + "abdruck": "3d9e1c18d8d90b91", + "funktion": "Kandidaten wählen", + "trug": "1b400e58e9b9ffa1" + }, + "route:post /admin/knowledge-spaces/provider-tool-allowlist": { + "abdruck": "bfb807bb4464c1fc", + "funktion": "Tool-Freigaben aktualisieren", + "trug": "71c29c88725cc001" + }, + "route:post /admin/runtime-cache/clear": { + "abdruck": "b70129f6aca03fad", + "funktion": "Cache leeren", + "trug": "5117399da510e8d0" + }, + "route:post /admin/system/prompt/{id}/activate": { + "abdruck": "dd98f9404f17be0a", + "funktion": "Promptversion aktivieren", + "trug": "7f1b7c10cfc78ea1" + }, + "route:post /admin/system/prompt/{id}/delete": { + "abdruck": "47cc4c8359701df5", + "funktion": "Promptversion löschen", + "trug": "69954cb2aa7826c8" + }, + "route:post /ask-jobs": { + "abdruck": "86dc2f6802845aad", + "funktion": "Auftrag starten", + "trug": "82c4f207a44eed63" + }, + "route:post /ask-sse": { + "abdruck": "87998efb193f5a13", + "funktion": "Chat streamen", + "trug": "3af6f0591b337739" + }, + "route:post /cases": { + "abdruck": "891fb74ed011cee0", + "funktion": "Fall erstellen", + "trug": "b2eeeb327760069a" + }, + "route:post /cases/delete": { + "abdruck": "f7d1df8c1239a344", + "funktion": "Fälle löschen bereitstellen", + "trug": "1644004910ad89e4" + }, + "route:post /cases/wizard": { + "abdruck": "f30980daf2c898a1", + "funktion": "Fall erstellen", + "trug": "b2eeeb327760069a" + }, + "route:post /chat-feedback/status": { + "abdruck": "58df216dabd44e95", + "funktion": "Feedback-Status prüfen", + "trug": "f633724f8d81bf1d" + }, + "route:post /chat-uploads": { + "abdruck": "29d717ceaaf86caa", + "funktion": "Datei hochladen", + "trug": "cf32f652744b3bce" + }, + "route:post /chat-uploads/clear": { + "abdruck": "62df3634844e6b6c", + "funktion": "Upload entfernen", + "trug": "eeec4fdfa3e38511" + }, + "route:post /cleanup": { + "abdruck": "e63b808d97ff109c", + "funktion": "Verzeichnis bereinigen", + "trug": "e4bdd1b6abc28e16" + }, + "route:post /clear-cache": { + "abdruck": "ee57c19a44d92c93", + "funktion": "Performance-Cache leeren", + "trug": "46d7cac0b9f2f79c" + }, + "route:post /create": { + "abdruck": "1c4155cf5a5a761e", + "funktion": "Tags bearbeiten", + "trug": "3a6a4c0fb9c8c0e2" + }, + "route:post /global-reindex": { + "abdruck": "0fbbf88bea2405f9", + "funktion": "Neuindizierung starten", + "trug": "ecd57c4d2d8030b3" + }, + "route:post /history/delete": { + "abdruck": "6e0556a3d3ba517a", + "funktion": "Verlauf löschen", + "trug": "9e769103ea5134a6" + }, + "route:post /reload": { + "abdruck": "79600beee79f0e3f", + "funktion": "Daten neu laden", + "trug": "148a6c4d4edb318d" + }, + "route:post /reports/cleanup": { + "abdruck": "8562351bb6f08c43", + "funktion": "Berichte bereinigen", + "trug": "0f19d3d7b9b076c8" + }, + "route:post /reset": { + "abdruck": "fb1f8b79658c653b", + "funktion": "Systemzustand zurücksetzen", + "trug": "bdfc7ede2fdab0cc" + }, + "route:post /run": { + "abdruck": "cf1ec8908428c705", + "funktion": "Evaluation ausführen", + "trug": "ad158b97138fdfd5" + }, + "route:post /search-chunks": { + "abdruck": "76d40589251fcbcd", + "funktion": "Textteile suchen", + "trug": "f12b4b68064135a4" + }, + "route:post /search-tags": { + "abdruck": "3b82c9af379b43c2", + "funktion": "Tags suchen", + "trug": "c28826e98ccf4488" + }, + "route:post /version/{versionId}/ingest": { + "abdruck": "d219584b34c5cf59", + "funktion": "Abschnitte laden", + "trug": "1fdbb25d131c9241" + }, + "route:post /version/{versionId}/markdown-normalize": { + "abdruck": "84b4594ebade4f10", + "funktion": "Markdown bereinigen", + "trug": "3b52c219a579635d" + }, + "route:post /{batchId}/delete": { + "abdruck": "5cc03440260bd2c2", + "funktion": "Bericht löschen", + "trug": "da18d390ddee9f9e" + }, + "route:post /{id}/activate": { + "abdruck": "f57b82e8c822e3a9", + "funktion": "Konfiguration aktivieren", + "trug": "1de4ccbe029cd746" + }, + "route:post /{id}/delete": { + "abdruck": "b39fd9ea4063eef6", + "funktion": "Dokument entfernen", + "trug": "9cfe41d491014a02" + }, + "route:post /{id}/tags/save": { + "abdruck": "daf6d63a0d9dac6f", + "funktion": "post {id} tags save bereitstellen", + "trug": "bfe4c204d790784c" + }, + "route:post /{id}/title": { + "abdruck": "5f4a8a89a24220e5", + "funktion": "Titel aktualisieren", + "trug": "43eca51f9fdc858b" + }, + "route:post /{id}/title-suggestions": { + "abdruck": "fc54786daea4cb86", + "funktion": "Titelvorschläge laden", + "trug": "bdd02c15d128d3e7" + }, + "route:post /{id}/toggle-active": { + "abdruck": "9317d97fb76431ce", + "funktion": "Benutzer aktivieren", + "trug": "ef44f89122814a30" + } + }, + "belege": { + "[\"admin\", \"Dashboard anzeigen\"]": { + "abdruck": "88c7b9f422dc8eb8", + "beleg": "#[Route('/admin/dashboard', name: 'admin_dashboard', methods: ['GET'])]", + "datei": "src/Controller/Admin/DashboardController.php" + }, + "[\"admin\", \"Logout einleiten\"]": { + "abdruck": "22b7a2529dbafa62", + "beleg": "throw new \\LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');", + "datei": "src/Controller/Admin/SecurityController.php" + }, + "[\"admin\", \"Wiederherstellung testen\"]": { + "abdruck": "50b702083d4b3b49", + "beleg": "#[Route('/admin/enterprise/restore/dry-run/{backupId}', name: 'admin_enterprise_restore_dry_run', requirements: ['backupId' => 'retriex-backup-[0-9]{8}-[0-9]{6}(?:-[a-f0-9]{6})?'], methods: ['POST'])]", + "datei": "src/Controller/Admin/EnterpriseOperationsController.php" + }, + "[\"admin\", \"Zum Dashboard weiterleiten\"]": { + "abdruck": "868c59b96819addc", + "beleg": "return $this->redirectToRoute('admin_dashboard');", + "datei": "src/Controller/Admin/DashboardController.php" + }, + "[\"agenten\", \"Agentenaktivität anzeigen\"]": { + "abdruck": "2e27daae10412580", + "beleg": "$limit = max(1, min(200, (int) $request->query->get('limit', 50)));", + "datei": "src/Controller/Admin/SystemAgentController.php" + }, + "[\"agenten\", \"Chat-Auswahl-Guard testen\"]": { + "abdruck": "3f5ad7d5b139a81c", + "beleg": "return ($report['status'] ?? '') === 'OK' ? Command::SUCCESS : Command::FAILURE;", + "datei": "src/Command/KnowledgeSpaceChatSelectionGuardSelfTestCommand.php" + }, + "[\"agenten\", \"Fähigkeiten ermitteln\"]": { + "abdruck": "82e0eb0d75ca0c79", + "beleg": "/** @return array */\n public function discover(string $serverKey, ?int $resourceIndex = null, bool $includeResourceRead = false): array", + "datei": "src/Mcp/McpAdminSourceRegistryBridge.php" + }, + "[\"agenten\", \"Hybrid-Tool-Auswahl testen\"]": { + "abdruck": "05bb4dd7e9a30b1a", + "beleg": "$cases = [\n $this->case('planner_self_test_is_green', [($plannerReport['status'] ?? '') === 'OK'], $plannerReport),\n $this->case('agent_runner_uses_llm_only_as_planner_before_retriex_validation', [\n str_contains($agentRunner, 'buildLlmSelectionPrompt($prompt, $spaceId, $serverKey, $allowlistedTools)'),\n str_contains($agentRunner, 'parseLlmSelectionResponse($rawToolSelection)'),\n str_contains($agentRunner, 'planFromLlmSuggestion($prompt, $spaceId, $serverKey, $allowlistedTools, $toolSuggestion)'),\n str_contains($agentRunner, \"llmCallModel('mcp_tool_selection')\"),\n str_contains($agentRunner, 'deterministic_fallback_allowed'),\n ], ['agent_runner_contains_hybrid_selection' => true]),\n $this->case('loader_exposes_tool_selection_latency', [\n str_contains($agentRunner, 'Passendes Tool wird ausgewählt'),\n str_contains($chatMessages, 'loader_mcp_selecting_tool'),\n str_contains($chatJs, 'loader_mcp_selecting_tool'),\n ], ['loader_status' => 'selecting_tool']),\n $this->case('model_config_has_dedicated_optional_call_model', [\n str_contains($modelConfig, 'mcp_tool_selection:'),\n ], ['model_config' => 'mcp_tool_selection']),\n ];", + "datei": "src/Command/McpHybridToolSelectionPlannerSelfTestCommand.php" + }, + "[\"agenten\", \"MCP-Gateway trocken ausführen\"]": { + "abdruck": "ab8dcf1eaaeba5a5", + "beleg": "return $result['status'] === 'ready' ? Command::SUCCESS : Command::FAILURE;", + "datei": "src/Command/McpGatewayDryRunCommand.php" + }, + "[\"agenten\", \"MCP-Laufzeit-Gate prüfen\"]": { + "abdruck": "a610bdc0e1f1b6e2", + "beleg": "$result = (bool) $input->getOption('fixture')\n ? $this->gate->checkResourceForServers(\n $this->fixtureServers(),\n $request,\n (bool) $input->getOption('assume-enabled'),\n )->toArray()\n : $this->gate->checkResource($request)->toArray();", + "datei": "src/Command/McpRuntimeGateCheckCommand.php" + }, + "[\"agenten\", \"MCP-Laufzeitgrenze testen\"]": { + "abdruck": "a644cd0877293b21", + "beleg": "#[AsCommand(\n name: 'mto:agent:mcp:runtime-boundary-self-test',\n description: 'Validate that MCP stays admin-controlled and bounded for answer runtime'\n)]", + "datei": "src/Command/McpRuntimeBoundarySelfTestCommand.php" + }, + "[\"agenten\", \"MCP-Quelle prüfen\"]": { + "abdruck": "af9e24b774af1592", + "beleg": "#[AsCommand(\n name: 'mto:agent:mcp:admin-source-check',\n description: 'Check one stored Admin MCP source as a registry-compatible read-only test policy'\n)]", + "datei": "src/Command/McpAdminSourceCheckCommand.php" + }, + "[\"agenten\", \"Mit Agent chatten\"]": { + "abdruck": "e74a0245ad75018b", + "beleg": "foreach ($this->agentRunner->run($prompt, $userId) as $token) {\n $output->write($token);\n }", + "datei": "src/Command/AgentCliCommand.php" + }, + "[\"agenten\", \"Performance-Cache leeren\"]": { + "abdruck": "42a53bc0d0dd9e2f", + "beleg": "$result = $this->runtimeCacheClearService->clearAll(!((bool) $input->getOption('skip-vector-service')));", + "datei": "src/Command/RuntimeCacheClearCommand.php" + }, + "[\"agenten\", \"Produktlabel-Formatierer testen\"]": { + "abdruck": "e8e2412ddcf623eb", + "beleg": "private function containsRuntimeSideEffectMarker(string $source): bool\n {\n return false;\n }", + "datei": "src/Command/ProductLabelFormatterExtractionSelfTestCommand.php" + }, + "[\"agenten\", \"Release-Selbsttest bereitstellen\"]": { + "abdruck": "7f9423f2d5b36480", + "beleg": "private const REQUIRED_RELEASE_FILES = [", + "datei": "src/Command/RetriexV1108ReleaseLockSelfTestCommand.php" + }, + "[\"agenten\", \"Ressource abrufen\"]": { + "abdruck": "fe6f6babdb73587a", + "beleg": "$result = (bool) $input->getOption('fixture')\n ? $this->client->readForServers($this->fixtureServers(), $request, (bool) $input->getOption('assume-enabled'))\n : $this->client->read($request, (bool) $input->getOption('assume-enabled'));", + "datei": "src/Command/McpResourceReadCommand.php" + }, + "[\"agenten\", \"Ressource validieren\"]": { + "abdruck": "5fd85436d1302f70", + "beleg": "return $decision->allowed ? Command::SUCCESS : Command::FAILURE;", + "datei": "src/Command/McpResourceCheckCommand.php" + }, + "[\"agenten\", \"Rollencode-Zuweisung prüfen\"]": { + "abdruck": "3ccada3f8950af23", + "beleg": "private function buildReport(): array", + "datei": "src/Command/ProductRoleCodeAssignmentRegressionGuardSelfTestCommand.php" + }, + "[\"agenten\", \"Stabilitäts-Selbsttest bereitstellen\"]": { + "abdruck": "e100bf5436bb7888", + "beleg": "final class ShopFollowupAnchorStabilitySelfTestCommand extends Command", + "datei": "src/Command/ShopFollowupAnchorStabilitySelfTestCommand.php" + }, + "[\"agenten\", \"System rebuild bereitstellen\"]": { + "abdruck": "4a94da2e8f5631d7", + "beleg": "#[AsCommand(\n name: 'mto:agent:system:rebuild',\n description: 'Hard rebuild: global reindex (chunks+vector), rebuild tag index, then reload vector service'\n)]", + "datei": "src/Command/SystemRebuildCommand.php" + }, + "[\"agenten\", \"Vektordienst steuern\"]": { + "abdruck": "81ff7d5a3425664b", + "beleg": "private readonly int $timeoutSeconds = 300,", + "datei": "src/Command/VectorControlCommand.php" + }, + "[\"agenten\", \"Wissensbatch finalisieren testen\"]": { + "abdruck": "fc30904681203405", + "beleg": "protected function execute(InputInterface $input, OutputInterface $output): int", + "datei": "src/Command/KnowledgeBatchFinalizeSelfTestCommand.php" + }, + "[\"anleitungen\", \"Anleitung anzeigen\"]": { + "abdruck": "7638a294a35eaedb", + "beleg": "'html' => $renderer->render($content),", + "datei": "src/Controller/Admin/GuideController.php" + }, + "[\"anleitungen\", \"Anleitungsübersicht öffnen\"]": { + "abdruck": "2335ab051c43a64d", + "beleg": "usort($guides, fn ($a, $b) => strcasecmp($a['title'], $b['title']));", + "datei": "src/Controller/Admin/GuideController.php" + }, + "[\"auftraege\", \"Auftrag starten\"]": { + "abdruck": "b2dc7effa8028795", + "beleg": "#[Route('/ask-jobs', name: 'ask_job_start', methods: ['POST'])]", + "datei": "src/Controller/AskSseController.php" + }, + "[\"auftraege\", \"Auftragsereignisse abrufen\"]": { + "abdruck": "eccbb5871ebf164c", + "beleg": "return new JsonResponse([\n 'status' => (string) ($job['status'] ?? ''),\n 'message' => is_string($job['message'] ?? null) ? (string) $job['message'] : '',\n 'lastEventId' => max(0, (int) ($job['lastEventId'] ?? 0)),\n 'updatedAt' => max(0, (int) ($job['updatedAt'] ?? 0)),\n 'completedAt' => max(0, (int) ($job['completedAt'] ?? 0)),\n 'events' => $this->readJobOutputAfter($jobId, $afterEventId),\n ]);", + "datei": "src/Controller/AskSseController.php" + }, + "[\"auftraege\", \"Auftragsstatus anzeigen\"]": { + "abdruck": "96e47a6fc65c461f", + "beleg": "return $this->json([\n 'id' => (string) $job->getId(),\n 'type' => $job->getType(),\n 'status' => $job->getStatus(),\n 'startedAt' => $job->getStartedAt()->format(DATE_ATOM),\n 'finishedAt' => $job->getFinishedAt()?->format(DATE_ATOM),\n 'errorMessage' => $job->getErrorMessage(),\n 'logPath' => $job->getLogPath(),\n ]);", + "datei": "src/Controller/Admin/IngestJobController.php" + }, + "[\"auftraege\", \"Auftragsstatus prüfen\"]": { + "abdruck": "d8926247da5b90fa", + "beleg": "public function jobStatus(string $jobId): JsonResponse", + "datei": "src/Controller/AskSseController.php" + }, + "[\"auftraege\", \"Ingest-Job starten\"]": { + "abdruck": "e52af5fba6df161f", + "beleg": "protected function execute(InputInterface $input, OutputInterface $output): int", + "datei": "src/Command/IngestRunJobCommand.php" + }, + "[\"backup\", \"Backup herunterladen\"]": { + "abdruck": "8c2bbb210875e413", + "beleg": "#[Route('/admin/enterprise/backup/download/{backupId}', name: 'admin_enterprise_backup_download', requirements: ['backupId' => 'retriex-backup-[0-9]{8}-[0-9]{6}(?:-[a-f0-9]{6})?'], methods: ['GET'])]", + "datei": "src/Controller/Admin/EnterpriseOperationsController.php" + }, + "[\"backup\", \"Backup starten\"]": { + "abdruck": "863cdc2fa384bd3b", + "beleg": "$report = $rollingBackup->createBackup(false, null, false, $includeDatabaseDump);", + "datei": "src/Controller/Admin/EnterpriseOperationsController.php" + }, + "[\"backup\", \"Backup-Tauglichkeit prüfen\"]": { + "abdruck": "7f32db860c7e3cf4", + "beleg": "return ($report['status'] ?? '') === 'OK' ? Command::SUCCESS : Command::FAILURE;", + "datei": "src/Command/EnterpriseBackupRestoreReadinessCheckCommand.php" + }, + "[\"backup\", \"Backup-Trockenlauf prüfen\"]": { + "abdruck": "1a3a2e4963e023bc", + "beleg": "$report = $restoreDryRun->buildDryRunReport();\n $operatorCheckProtocol->recordCheck('restore_dry_run', 'Restore pruefen', $report, ['backup_id' => (string) ($report['backup_id'] ?? ''), 'dry_run' => true]);\n $this->addRestoreDryRunFlash($report);", + "datei": "src/Controller/Admin/EnterpriseOperationsController.php" + }, + "[\"backup\", \"Backup-Wiederherstellung prüfen\"]": { + "abdruck": "b06b798f0cdc03dc", + "beleg": "#[Route('/admin/enterprise/check/backup-restore', name: 'admin_enterprise_check_backup_restore', methods: ['POST'])]", + "datei": "src/Controller/Admin/EnterpriseOperationsController.php" + }, + "[\"benutzer\", \"Benutzer aktivieren\"]": { + "abdruck": "7bc70cb331b3a2ac", + "beleg": "#[Route('/{id}/toggle-active', name: 'admin_users_toggle_active', requirements: ['id' => '[0-9a-fA-F\\-]{36}'], methods: ['POST'])]", + "datei": "src/Controller/Admin/UserController.php" + }, + "[\"benutzer\", \"Benutzer anlegen\"]": { + "abdruck": "93125c82911d2de0", + "beleg": "if (strlen(trim($plainPassword)) < 8) {", + "datei": "src/Command/CreateUserCommand.php" + }, + "[\"benutzer\", \"Benutzer auflisten\"]": { + "abdruck": "d527fa14409a6978", + "beleg": "public function listUsers(string $query = '', string $status = 'all', string $role = 'all'): array", + "datei": "src/Service/Admin/UserAdminService.php" + }, + "[\"benutzer\", \"Benutzer bearbeiten\"]": { + "abdruck": "63f9b60fe54af1c2", + "beleg": "#[Route('/{id}/edit', name: 'admin_users_edit', requirements: ['id' => '[0-9a-fA-F\\-]{36}'], methods: ['GET', 'POST'])]\n public function edit(string $id, Request $request, UserAdminService $users): Response", + "datei": "src/Controller/Admin/UserController.php" + }, + "[\"berichte\", \"Akzeptanzbericht generieren\"]": { + "abdruck": "202ceb031a05333e", + "beleg": "$io->table(['Zeitpunkt', 'Pruefung', 'Status', 'Ergebnis'], array_map(", + "datei": "src/Command/EnterpriseOperatorAcceptanceReportCommand.php" + }, + "[\"berichte\", \"Bericht als JSON herunterladen\"]": { + "abdruck": "cca47a8c490854b4", + "beleg": "public function download(string $batchId, string $format, KnowledgeBatchReportReadService $reports): BinaryFileResponse", + "datei": "src/Controller/Admin/KnowledgeBatchReportController.php" + }, + "[\"berichte\", \"Bericht löschen\"]": { + "abdruck": "94555049b4fa8aa5", + "beleg": "public function deleteReport(string $batchId, Request $request, KnowledgeBatchReportReadService $reports): Response", + "datei": "src/Controller/Admin/KnowledgeBatchReportController.php" + }, + "[\"berichte\", \"Übersicht rendern\"]": { + "abdruck": "17f97a67c55bc85f", + "beleg": "$overview = $this->operationsOverview->buildOverview($backupRestoreReport, $securityReport, $deploymentReport, $acceptanceReport, $backupOverview);", + "datei": "src/Command/EnterpriseOperationsOverviewCommand.php" + }, + "[\"chat\", \"Abmelden ermöglichen\"]": { + "abdruck": "8178f115f5e6d301", + "beleg": "#[Route('/chat/logout', name: 'chat_logout', methods: ['GET'])]", + "datei": "src/Controller/Chat/SecurityController.php" + }, + "[\"chat\", \"Chat streamen\"]": { + "abdruck": "8973369a0ffbb6c6", + "beleg": "return new StreamedResponse(\n function () use ($prompt, $clientId, $cookieResponse, $includeFullContext, $requestContextHint, $dataSourceMode, $finalAnswerModelMode, $temporaryUploadIds, $knowledgeSpaceEffectiveSpaceId): void {\n $this->streamAgentResponse(\n prompt: $prompt,\n clientId: $clientId,\n includeFullContext: $includeFullContext,\n cookieResponse: $cookieResponse,\n jobId: null,\n requestContextHint: $requestContextHint,\n dataSourceMode: $dataSourceMode,\n finalAnswerModelOverride: $this->finalAnswerModelOverride($finalAnswerModelMode),\n temporaryUploadIds: $temporaryUploadIds,\n knowledgeSpaceEffectiveSpaceId: $knowledgeSpaceEffectiveSpaceId\n );\n },\n Response::HTTP_OK,\n $this->streamHeaders()\n );", + "datei": "src/Controller/AskSseController.php" + }, + "[\"chat\", \"Chatseite anzeigen\"]": { + "abdruck": "32f2c858efb14e67", + "beleg": "return $this->render('chat/index.html.twig', [\n 'chat_prompt_user_name' => $this->resolvePromptUserName(),\n 'chat_knowledge_space_selector' => $knowledgeSpaceSelector->build(),\n 'chat_handbook_available' => $chatHandbookMarkdown !== null,\n 'chat_handbook_markdown' => $chatHandbookMarkdown ?? '',\n ]);", + "datei": "src/Controller/Chat/ChatController.php" + }, + "[\"diagnose\", \"Abdeckung prüfen\"]": { + "abdruck": "48d3b0d8a7011a70", + "beleg": "usort($rows, function (array $a, array $b): int {", + "datei": "src/Command/IngestFactsCoverageCommand.php" + }, + "[\"diagnose\", \"Abrufgrenzen prüfen\"]": { + "abdruck": "a37984380c253a68", + "beleg": "final class AgentRetrievalBoundaryPlanSelfTestCommand extends Command", + "datei": "src/Command/AgentRetrievalBoundaryPlanSelfTestCommand.php" + }, + "[\"diagnose\", \"Bereitschaftsbericht ausgeben\"]": { + "abdruck": "a09f986af89eaacd", + "beleg": "return ($report['status'] ?? '') === 'OK' ? Command::SUCCESS : Command::FAILURE;", + "datei": "src/Command/EnterpriseDeploymentSchedulerReadinessCheckCommand.php" + }, + "[\"diagnose\", \"Datenqualität prüfen\"]": { + "abdruck": "ca2c74c205e880ff", + "beleg": "#[AsCommand(\n name: 'mto:agent:ingest:chunk-quality',\n description: 'Compare original and derived Markdown ingest chunk quality in dry-run diagnostics'\n)]", + "datei": "src/Command/IngestChunkQualityCommand.php" + }, + "[\"diagnose\", \"Diagnose anzeigen\"]": { + "abdruck": "a44b68c6167f4548", + "beleg": "#[Route('/admin/mcp', name: 'admin_mcp_diagnostics', methods: ['GET', 'POST'])]", + "datei": "src/Controller/Admin/McpDiagnosticsController.php" + }, + "[\"diagnose\", \"Genre-Hotspots prüfen\"]": { + "abdruck": "83a0e5f5a3d81804", + "beleg": "public function audit(?callable $progress = null): array", + "datei": "src/Genre/CoreNeutralityAuditProvider.php" + }, + "[\"diagnose\", \"Guard-Mechanismus prüfen\"]": { + "abdruck": "428aec0b4471fc87", + "beleg": "private function buildReport(): array", + "datei": "src/Command/UnsupportedToolTermGuardSelfTestCommand.php" + }, + "[\"diagnose\", \"Hygieneregeln prüfen\"]": { + "abdruck": "d0a1488af78eb9a4", + "beleg": "private function buildReport(): array", + "datei": "src/Command/KnowledgeBatchHygieneSelfTestCommand.php" + }, + "[\"diagnose\", \"Indizierungszustand prüfen\"]": { + "abdruck": "5c404523842d6af0", + "beleg": "final class IngestDeferredReindexStateSelfTestCommand extends Command", + "datei": "src/Command/IngestDeferredReindexStateSelfTestCommand.php" + }, + "[\"diagnose\", \"Konfiguration prüfen\"]": { + "abdruck": "0258b188bf0a71d8", + "beleg": "#[AsCommand(\n name: 'mto:agent:config:validate',\n description: 'Validate the effective RetrieX configuration'\n)]", + "datei": "src/Command/ConfigValidateCommand.php" + }, + "[\"diagnose\", \"Provenienz prüfen\"]": { + "abdruck": "3ef13c4717f68df6", + "beleg": "$cases[] = $this->case(\n 'chunk_records_receive_provenance_metadata',\n str_contains($ingestService, 'source_file_extension')\n && str_contains($ingestService, 'source_version_id')\n && str_contains($ingestService, 'derived_from_version_id')\n && str_contains($ingestService, 'derived_format')\n && str_contains($ingestService, 'normalization_prompt_version')\n && str_contains($ingestService, 'normalization_model')\n && str_contains($ingestService, 'normalization_status'),\n 'NDJSON metadata includes source and derived Markdown provenance keys'\n );", + "datei": "src/Command/IngestMarkdownDerivedChunkDiagnosticsSelfTestCommand.php" + }, + "[\"diagnose\", \"Retrieval-Pipeline testen\"]": { + "abdruck": "a2bda82b3cf0c287", + "beleg": "final class TestHybridRetrievalCommand extends Command", + "datei": "src/Command/TestHybridRetrievalCommand.php" + }, + "[\"diagnose\", \"Segmentierung prüfen\"]": { + "abdruck": "2ddb19d3004bb42b", + "beleg": "$service = $this->read($root . '/src/Ingest/MarkdownNormalization/DocumentMarkdownNormalizationService.php');", + "datei": "src/Command/IngestSegmentedMarkdownNormalizationExecutionSelfTestCommand.php" + }, + "[\"diagnose\", \"Shop-Suche testen\"]": { + "abdruck": "ed98c9737930f464", + "beleg": "'zeige mir produkte unter 5000 euro'", + "datei": "src/Command/TestShopSearchCommand.php" + }, + "[\"diagnose\", \"Sicherheitsstatus prüfen\"]": { + "abdruck": "003f893fb9cea617", + "beleg": "return ($report['status'] ?? '') === 'OK' ? Command::SUCCESS : Command::FAILURE;", + "datei": "src/Command/EnterpriseSecurityDataProtectionReadinessCheckCommand.php" + }, + "[\"diagnose\", \"Stapel-Upload verifizieren\"]": { + "abdruck": "fff1582bd8e5bf3f", + "beleg": "final class KnowledgeBatchAdminUploadSelfTestCommand extends Command", + "datei": "src/Command/KnowledgeBatchAdminUploadSelfTestCommand.php" + }, + "[\"diagnose\", \"Systemzustand prüfen\"]": { + "abdruck": "7045932ec8f4d9ce", + "beleg": "return str_starts_with($result['status'], 'OK')\n ? Command::SUCCESS\n : Command::FAILURE;", + "datei": "src/Command/VectorHealthCheckCommand.php" + }, + "[\"diagnose\", \"Tag-Index-Gesundheit prüfen\"]": { + "abdruck": "79248caf983173f9", + "beleg": "private function isHealthy(string $status): bool\n {\n return in_array($status, ['OK', 'OK_EMPTY'], true);\n }", + "datei": "src/Command/TagHealthCheckCommand.php" + }, + "[\"diagnose\", \"Tags neu indizieren\"]": { + "abdruck": "411663e63cc97ed3", + "beleg": "while (!connection_aborted()) {", + "datei": "src/Controller/Admin/TagRebuildStreamController.php" + }, + "[\"diagnose\", \"Verankerung testen\"]": { + "abdruck": "73de227779d46c5f", + "beleg": "if ((bool) $input->getOption('sample')) {\n [$prompt, $history] = $this->samplePromptAndHistory();\n } elseif ($historyFile !== '') {", + "datei": "src/Command/TestFollowUpAnchorResolverDryRunCommand.php" + }, + "[\"diagnose\", \"Vergleichsgrenzen validieren\"]": { + "abdruck": "669f27f21e0c7cbc", + "beleg": "private function buildReport(): array\n {\n $root = rtrim($this->kernel->getProjectDir(), '/\\\\');\n $service = $this->read($root . '/src/Service/Admin/DocumentChunkQualityComparisonService.php');\n $command = $this->read($root . '/src/Command/IngestChunkQualityCommand.php');\n $controller = $this->read($root . '/src/Controller/Admin/DocumentController.php');\n $template = $this->read($root . '/templates/admin/document/show.html.twig');\n $styles = $this->read($root . '/public/assets/styles/base.css');\n $segmentationPlanService = $this->read($root . '/src/Ingest/MarkdownNormalization/DocumentMarkdownSegmentationPlanService.php');\n $agentRunner = $this->read($root . '/src/Agent/AgentRunner.php');\n $ingestService = $this->read($root . '/src/Knowledge/Ingest/KnowledgeIngestService.php');", + "datei": "src/Command/IngestChunkQualityComparisonSelfTestCommand.php" + }, + "[\"dokumente\", \"Abschnitte laden\"]": { + "abdruck": "6be09cd85989675b", + "beleg": "$version->setIngestStatus(DocumentVersion::INGEST_PENDING);", + "datei": "src/Controller/Admin/DocumentController.php" + }, + "[\"dokumente\", \"Abschnittsqualität laden\"]": { + "abdruck": "ff648f1bf4dd8875", + "beleg": "public function versionChunkQuality(", + "datei": "src/Controller/Admin/DocumentController.php" + }, + "[\"dokumente\", \"Dokument entfernen\"]": { + "abdruck": "b30e86c7c0afc914", + "beleg": "public function deleteDocument(", + "datei": "src/Controller/Admin/DocumentController.php" + }, + "[\"dokumente\", \"Dokument erstellen\"]": { + "abdruck": "216bdc467154f33a", + "beleg": "#[Route('/new', name: 'admin_document_new', methods: ['GET', 'POST'])]", + "datei": "src/Controller/Admin/DocumentController.php" + }, + "[\"dokumente\", \"Dokumente auflisten\"]": { + "abdruck": "d0fc65218aa9ccd3", + "beleg": "#[Route('', name: 'admin_documents', methods: ['GET'])]", + "datei": "src/Controller/Admin/DocumentController.php" + }, + "[\"dokumente\", \"Markdown bereinigen\"]": { + "abdruck": "9e0e8ea0de452f7f", + "beleg": "$newVersion = $documentService->addVersion($document, $result['file_path'], $this->requireUser());", + "datei": "src/Controller/Admin/DocumentController.php" + }, + "[\"evaluation\", \"Berichte bereinigen\"]": { + "abdruck": "ab28043e52bdafa3", + "beleg": "public function cleanupReportHistory(string $scope, string $mode = 'trim'): array", + "datei": "src/Service/Admin/EvalAdminService.php" + }, + "[\"evaluation\", \"Eval-Berichte anzeigen\"]": { + "abdruck": "7c5a683645081b79", + "beleg": "#[Route('/', name: 'admin_evals_index', methods: ['GET'])]", + "datei": "src/Controller/Admin/AdminEvalController.php" + }, + "[\"evaluation\", \"Eval-Fälle ausführen\"]": { + "abdruck": "130685562e3eff09", + "beleg": "return $failed > 0 ? Command::FAILURE : Command::SUCCESS;", + "datei": "src/Command/AgentEvalRunCommand.php" + }, + "[\"evaluation\", \"Eval-Fälle parallelisieren\"]": { + "abdruck": "2d6d1b790ca8f991", + "beleg": "while (!$stopScheduling && $nextIndex < $caseCount && count($running) < $jobs) {", + "datei": "src/Command/AgentEvalParallelCommand.php" + }, + "[\"evaluation\", \"Evaluation ausführen\"]": { + "abdruck": "5b2305d1f3727b25", + "beleg": "#[Route('/run', name: 'admin_evals_run', methods: ['POST'])]", + "datei": "src/Controller/Admin/AdminEvalController.php" + }, + "[\"faelle\", \"Assistent anzeigen\"]": { + "abdruck": "d34e5813e73074d3", + "beleg": "public function caseWizard(Request $request, EvalAdminService $evals): Response", + "datei": "src/Controller/Admin/AdminEvalController.php" + }, + "[\"faelle\", \"Fall anlegen\"]": { + "abdruck": "c29d7fd91f3232df", + "beleg": "#[Route('/cases/new', name: 'admin_evals_case_new', methods: ['GET'])]", + "datei": "src/Controller/Admin/AdminEvalController.php" + }, + "[\"faelle\", \"Fall erstellen\"]": { + "abdruck": "52edb0d34124f34b", + "beleg": "#[Route('/cases', name: 'admin_evals_case_create', methods: ['POST'])]", + "datei": "src/Controller/Admin/AdminEvalController.php" + }, + "[\"faelle\", \"Fälle löschen bereitstellen\"]": { + "abdruck": "d3a7338ca875abcd", + "beleg": "#[Route('/cases/delete', name: 'admin_evals_case_delete', methods: ['POST'])]\n public function deleteCase(Request $request, EvalAdminService $evals): Response\n {\n $this->denyAccessUnlessGranted(ApplicationRoles::ROLE_KNOWLEDGE_ADMIN);", + "datei": "src/Controller/Admin/AdminEvalController.php" + }, + "[\"feedback\", \"Chat-Feedback anzeigen\"]": { + "abdruck": "380650cd110c8613", + "beleg": "#[Route('/admin/chat-feedback', name: 'admin_chat_feedback_index', methods: ['GET'])]", + "datei": "src/Controller/Admin/AdminChatFeedbackController.php" + }, + "[\"feedback\", \"Feedback exportieren\"]": { + "abdruck": "f4168bfa7d6e819a", + "beleg": "#[Route('/admin/chat-feedback/export', name: 'admin_chat_feedback_export', methods: ['GET'])]\n public function export(Request $request, ChatAnswerFeedbackRepository $repository): StreamedResponse\n {\n $this->denyAccessUnlessGranted(ApplicationRoles::ROLE_KNOWLEDGE_ADMIN);", + "datei": "src/Controller/Admin/AdminChatFeedbackController.php" + }, + "[\"feedback\", \"Feedback klassifizieren\"]": { + "abdruck": "722b8e9be1eda83d", + "beleg": "if ($processed % 100 === 0) {", + "datei": "src/Command/ChatFeedbackClassifyCommand.php" + }, + "[\"feedback\", \"Feedback löschen\"]": { + "abdruck": "774f9c113b07b54c", + "beleg": "public function delete(string $id, Request $request, ChatAnswerFeedbackRepository $repository, EntityManagerInterface $entityManager): Response", + "datei": "src/Controller/Admin/AdminChatFeedbackController.php" + }, + "[\"feedback\", \"Feedback-Details anzeigen\"]": { + "abdruck": "5ccfb944dd8353de", + "beleg": "#[Route('/admin/chat-feedback/{id}', name: 'admin_chat_feedback_show', requirements: ['id' => '[0-9a-fA-F-]{36}'], methods: ['GET'])]", + "datei": "src/Controller/Admin/AdminChatFeedbackController.php" + }, + "[\"feedback\", \"Feedback-Status aktualisieren\"]": { + "abdruck": "107aa5d09bbfd64c", + "beleg": "$status = trim((string) $request->request->get('status', ChatAnswerFeedback::REVIEW_STATUS_DONE));\n if ($status === ChatAnswerFeedback::REVIEW_STATUS_DONE) {\n $feedback->markReviewDone(trim((string) $request->request->get('reviewNote', '')) ?: null);\n $this->addFlash('success', 'Feedback wurde als erledigt markiert.');\n } else {\n $feedback->reopenReview();\n $this->addFlash('success', 'Feedback wurde wieder geöffnet.');\n }", + "datei": "src/Controller/Admin/AdminChatFeedbackController.php" + }, + "[\"feedback\", \"Feedback-Status prüfen\"]": { + "abdruck": "e08595a775786488", + "beleg": "$response = new JsonResponse([\n 'status' => 'ok',\n 'stored' => $feedback !== null,\n 'feedbackId' => $feedback !== null ? (string) $feedback->getId() : null,\n 'rating' => $feedback !== null ? $feedback->getRating() : null,\n ]);", + "datei": "src/Controller/ChatFeedbackController.php" + }, + "[\"knowledge-raeume\", \"Batch-Import durchführen\"]": { + "abdruck": "ed8e53ee87a33ecd", + "beleg": "final class KnowledgeBatchImportCommand extends Command", + "datei": "src/Command/KnowledgeBatchImportCommand.php" + }, + "[\"knowledge-raeume\", \"Chat-Freigabe umschalten\"]": { + "abdruck": "b0459d69691cd838", + "beleg": "#[Route('/admin/knowledge-spaces/provider-resource-chat', name: 'admin_knowledge_spaces_provider_resource_chat_update', methods: ['POST'])]", + "datei": "src/Controller/Admin/KnowledgeSpaceOverviewController.php" + }, + "[\"knowledge-raeume\", \"Chat-Verfügbarkeit prüfen\"]": { + "abdruck": "07ac7926675dc356", + "beleg": "#[Route('/admin/knowledge-spaces/chat-availability', name: 'admin_knowledge_spaces_chat_availability_update', methods: ['POST'])]", + "datei": "src/Controller/Admin/KnowledgeSpaceOverviewController.php" + }, + "[\"knowledge-raeume\", \"Facts prüfen\"]": { + "abdruck": "0150181090352e46", + "beleg": "$io->warning('No chunks with diagnostic ingest facts matched the current filter. Run a global reindex after extractor changes so index.ndjson contains the current fact schema.');", + "datei": "src/Command/IngestFactsInspectCommand.php" + }, + "[\"knowledge-raeume\", \"Kandidaten wählen\"]": { + "abdruck": "f3cfe523ec5c3401", + "beleg": "#[Route('/admin/knowledge-spaces/provider-candidate-select', name: 'admin_knowledge_spaces_provider_candidate_select', methods: ['POST'])]", + "datei": "src/Controller/Admin/KnowledgeSpaceOverviewController.php" + }, + "[\"knowledge-raeume\", \"Knowledge-Räume anzeigen\"]": { + "abdruck": "651989a1820b87cf", + "beleg": "#[Route('/admin/knowledge-spaces', name: 'admin_knowledge_spaces_overview', methods: ['GET'])]\n public function index(McpKnowledgeSpaceReadModel $readModel, KnowledgeSpaceAdminOverviewReadModel $adminOverviewReadModel, KnowledgeSpaceAvailabilityReadModel $availabilityReadModel, KnowledgeSpaceChatSelectorReadModel $chatSelectorReadModel, KnowledgeSpaceProviderResourceCandidateReadModel $providerResourceCandidateReadModel): Response\n {\n return $this->render('admin/knowledge_spaces/index.html.twig', [\n 'knowledgeSpaceReadModel' => $readModel->build(),\n 'knowledgeSpaceAdminOverview' => $adminOverviewReadModel->build(),\n 'knowledgeSpaceAvailability' => $availabilityReadModel->build(),\n 'chatKnowledgeSpaceSelector' => $chatSelectorReadModel->build(),\n 'knowledgeSpaceProviderResourceCandidates' => $providerResourceCandidateReadModel->build(),\n ]);\n }", + "datei": "src/Controller/Admin/KnowledgeSpaceOverviewController.php" + }, + "[\"knowledge-raeume\", \"Live-Vorschau laden\"]": { + "abdruck": "581e01a64ada02e6", + "beleg": "#[Route('/admin/knowledge-spaces/provider-resource-live-preview', name: 'admin_knowledge_spaces_provider_resource_live_preview', methods: ['POST'])]", + "datei": "src/Controller/Admin/KnowledgeSpaceOverviewController.php" + }, + "[\"knowledge-raeume\", \"Ressourcenprüfung durchführen\"]": { + "abdruck": "1d6a2b8d376cce22", + "beleg": "public function check(string $serverKey, string $resourceUri, string $mimeType = ''): McpResourcePolicyDecision", + "datei": "src/Mcp/McpResourcePolicyChecker.php" + }, + "[\"knowledge-raeume\", \"Textteile suchen\"]": { + "abdruck": "cb366acdc584d3cd", + "beleg": "@app.post(\"/search-chunks\")\ndef search_chunks(req: SearchRequest) -> List[Dict[str, Any]]:", + "datei": "python/vector/vector_service.py" + }, + "[\"knowledge-raeume\", \"Wissensräume prüfen\"]": { + "abdruck": "f329f8b7d149443c", + "beleg": "#[Route('/admin/knowledge-spaces/diagnostics/run', name: 'admin_knowledge_spaces_diagnostics_run', methods: ['POST'])]\n public function runDiagnostics(", + "datei": "src/Controller/Admin/KnowledgeSpaceOverviewController.php" + }, + "[\"konfiguration\", \"Ingest-Profil anlegen\"]": { + "abdruck": "88d9ebf11cc65de1", + "beleg": "#[Route('/create', name: 'admin_ingest_profile_create', methods: ['GET', 'POST'])]", + "datei": "src/Controller/Admin/IngestProfileController.php" + }, + "[\"konfiguration\", \"Ingest-Profile anzeigen\"]": { + "abdruck": "3bcd4f2eecf9e04d", + "beleg": "{% if p.active %}\n Aktiv\n {% else %}\n \n Inaktiv\n \n {% endif %}", + "datei": "templates/admin/ingest_profile/list.html.twig" + }, + "[\"konfiguration\", \"Konfiguration aktivieren\"]": { + "abdruck": "3cdcaacb5c30935e", + "beleg": "#[Route('/{id}/activate', name: 'admin_model_config_activate', methods: ['POST'])]", + "datei": "src/Controller/Admin/ModelGenerationConfigController.php" + }, + "[\"konfiguration\", \"Konfiguration anzeigen\"]": { + "abdruck": "be665b176d285ec7", + "beleg": "$json = json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);", + "datei": "src/Command/ConfigDumpEffectiveCommand.php" + }, + "[\"konfiguration\", \"Konfiguration bereitstellen\"]": { + "abdruck": "d726bc00b770d39d", + "beleg": "#[Route('/chat-messages/frontend', name: 'chat_messages_frontend', methods: ['GET'])]", + "datei": "src/Controller/ChatMessagesController.php" + }, + "[\"konfiguration\", \"Konfigurationen anzeigen\"]": { + "abdruck": "4d0677e36928af2f", + "beleg": "#[Route('/', name: 'admin_model_config_list')]\n public function list(ModelGenerationConfigAdminService $svc): Response\n {\n $this->denyAccessUnlessGranted(ApplicationRoles::ROLE_KNOWLEDGE_ADMIN);", + "datei": "src/Controller/Admin/ModelGenerationConfigController.php" + }, + "[\"konfiguration\", \"Konfigurationsmuster prüfen\"]": { + "abdruck": "0e0bc4972945d622", + "beleg": "$calls = $this->matchingCalls((string) $line, $suspiciousCalls);", + "datei": "src/Config/CorePatternAuditProvider.php" + }, + "[\"konfiguration\", \"Tool-Freigaben aktualisieren\"]": { + "abdruck": "564123f595ea652e", + "beleg": "#[Route('/admin/knowledge-spaces/provider-tool-allowlist', name: 'admin_knowledge_spaces_provider_tool_allowlist_update', methods: ['POST'])]\n public function updateProviderToolAllowlist(Request $request, McpAdminSourceStore $sourceStore): RedirectResponse", + "datei": "src/Controller/Admin/KnowledgeSpaceOverviewController.php" + }, + "[\"logs\", \"Logdatei anzeigen\"]": { + "abdruck": "e5823ed4e9f28bf2", + "beleg": "$content = $this->readLastLines($path, 1000);", + "datei": "src/Controller/Admin/AdminSystemLogController.php" + }, + "[\"logs\", \"Logdateien auflisten\"]": { + "abdruck": "65b9c55ff9cc0246", + "beleg": "foreach (\\glob($this->logDir . '/system*.log') ?: [] as $file) {", + "datei": "src/Controller/Admin/AdminSystemLogController.php" + }, + "[\"sonstiges\", \"post activate {id} bereitstellen\"]": { + "abdruck": "77751e07c0ac66e6", + "beleg": "if (!$this->isCsrfTokenValid('activate_ingest_profile_' . $profile->getId(), (string) $request->request->get('_token'))) {", + "datei": "src/Controller/Admin/IngestProfileController.php" + }, + "[\"sonstiges\", \"post admin enterprise check security bereitstellen\"]": { + "abdruck": "6fde0d762ab1f63a", + "beleg": "#[Route('/admin/enterprise/check/security', name: 'admin_enterprise_check_security', methods: ['POST'])]", + "datei": "src/Controller/Admin/EnterpriseOperationsController.php" + }, + "[\"sonstiges\", \"post {id} tags save bereitstellen\"]": { + "abdruck": "4b25cdb131288705", + "beleg": "#[Route('/{id}/tags/save', name: 'admin_document_tags_save', methods: ['POST'])]", + "datei": "src/Controller/Admin/DocumentTagController.php" + }, + "[\"system\", \"Access-Denied-Fehler bereitstellen\"]": { + "abdruck": "82cd2269b409655e", + "beleg": "if ($targetHomeRoute === 'admin_dashboard' && $this->security->isGranted(ApplicationRoles::ROLE_ADMIN_AREA)) {", + "datei": "src/Security/AccessDeniedPageRenderer.php" + }, + "[\"system\", \"Betriebsbereitschaft prüfen\"]": { + "abdruck": "447f0da9c71ca14d", + "beleg": "$report = $this->buildReport();", + "datei": "src/Command/EnterpriseOperationsReadinessCheckCommand.php" + }, + "[\"system\", \"Cache leeren\"]": { + "abdruck": "5fa28d5145b77c72", + "beleg": "if (!$this->isCsrfTokenValid('runtime_cache_clear', (string) $request->request->get('_token'))) {", + "datei": "src/Controller/Admin/DashboardController.php" + }, + "[\"system\", \"Daten neu laden\"]": { + "abdruck": "37040fd380c7eb93", + "beleg": "@app.post(\"/reload\")\ndef reload() -> Dict[str, str]:\n try:\n load_all()\n return {\"status\": \"reloaded\", \"stamp\": SERVICE_STAMP}\n except Exception as exc:\n logger.exception(\"reload failed\")\n raise HTTPException(status_code=500, detail=str(exc))", + "datei": "python/vector/vector_service.py" + }, + "[\"system\", \"Daten sichern\"]": { + "abdruck": "7ccd1004eac1418a", + "beleg": "protected function execute(InputInterface $input, OutputInterface $output): int", + "datei": "src/Command/EnterpriseRollingBackupCommand.php" + }, + "[\"system\", \"Deployment prüfen\"]": { + "abdruck": "2e5833bfbb397dfc", + "beleg": "if (!$this->isCsrfTokenValid('enterprise_check_deployment_scheduler', (string) $request->request->get('_token', ''))) {", + "datei": "src/Controller/Admin/EnterpriseOperationsController.php" + }, + "[\"system\", \"Dienststatus melden\"]": { + "abdruck": "f03c81a271cb0eb9", + "beleg": "@app.get(\"/health\")", + "datei": "python/vector/vector_service.py" + }, + "[\"system\", \"Flow-Grenze sperren\"]": { + "abdruck": "4e90cc73b0837ac4", + "beleg": "private function buildReport(): array\n {\n $root = rtrim($this->kernel->getProjectDir(), '/\\\\');\n $boundaries = AgentRunFlowBoundaryContract::boundaries();\n $actualSections = array_keys($boundaries);\n $missingFiles = $this->missingFiles($root, self::REQUIRED_FILES);\n $flowFiles = glob($root . '/src/Agent/Run/*Flow.php') ?: [];\n $flowSources = $this->combinedReadableSource($flowFiles);\n $agentRunner = $this->read($root . '/src/Agent/AgentRunner.php');\n $sourceLeakTrace = $this->buildSensitiveTraceLeakReport();\n $missingOwnerTokens = $this->missingTokens($agentRunner, self::AGENTRUNNER_CRITICAL_OWNER_TOKENS);\n $forbiddenFlowTokens = $this->presentTokens($flowSources, self::FORBIDDEN_FLOW_TOKENS);\n $badBoundaryContracts = $this->badBoundaryContracts($boundaries);\n $badSectionFlows = $this->badSectionFlows($boundaries);\n $debugTraceBuilderFindings = $this->debugTraceBuilderFindings($agentRunner, $this->read($root . '/src/Agent/Run/AgentRunDebugTracePayloadBuilder.php'));\n $capabilityBoundaryFindings = $this->capabilityBoundaryFindings(\n $this->read($root . '/src/Agent/Run/CapabilityContextFlow.php'),\n $this->read($root . '/src/Agent/Run/CapabilityContextResult.php')\n );\n $followUpActionBuilderFindings = $this->followUpActionBuilderFindings(\n $agentRunner,\n $this->read($root . '/src/Agent/Support/FollowUpActionBuilder.php')\n );\n $evidenceDiagnosticMetaBuilderFindings = $this->evidenceDiagnosticMetaBuilderFindings(\n $agentRunner,\n $this->read($root . '/src/Agent/Support/EvidenceDiagnosticMetaMessageBuilder.php')\n );\n $claimEvidencePresentationBuilderFindings = $this->claimEvidencePresentationBuilderFindings(\n $agentRunner,\n $this->read($root . '/src/Agent/Support/ClaimEvidencePresentationMessageBuilder.php')\n );", + "datei": "src/Command/AgentRunFlowBoundaryLockSelfTestCommand.php" + }, + "[\"system\", \"Neuindizierung starten\"]": { + "abdruck": "b4519b8d45b5d080", + "beleg": "#[Route('/global-reindex', name: 'admin_global_reindex', methods: ['POST'])]", + "datei": "src/Controller/Admin/IngestJobController.php" + }, + "[\"system\", \"Normalisierung prüfen\"]": { + "abdruck": "36bcb0a013c43f30", + "beleg": "/** @var list */\n private const REQUIRED_FILES = [\n 'src/Ingest/MarkdownNormalization/DocumentMarkdownNormalizationService.php',\n 'src/Ingest/MarkdownNormalization/DocumentMarkdownNormalizationPromptBuilder.php',\n 'src/Ingest/MarkdownNormalization/DocumentMarkdownNormalizationValidator.php',\n 'src/Ingest/MarkdownNormalization/DocumentMarkdownSourceTextCleaner.php',\n 'src/Ingest/MarkdownNormalization/DocumentDerivedMarkdownVersionWriter.php',\n 'src/Ingest/MarkdownNormalization/DocumentMarkdownSegmentationPlanService.php',\n 'src/Command/IngestMarkdownNormalizationFoundationSelfTestCommand.php',\n 'docs/retriex/ingest-markdown-normalization-foundation.md',\n 'README.md',\n 'PATCH_MANIFEST.md',\n 'GENRE_NEUTRAL_CORE_PATCHLINE.md',\n ];", + "datei": "src/Command/IngestMarkdownNormalizationFoundationSelfTestCommand.php" + }, + "[\"system\", \"Preview prüfen\"]": { + "abdruck": "175111522fc5db0e", + "beleg": "#[AsCommand(\n name: 'mto:agent:ingest:markdown-normalization-preview-self-test',\n description: 'Validate the admin Markdown normalization preview wiring without LLM, DB, ingest or answer side effects'\n)]", + "datei": "src/Command/IngestMarkdownNormalizationPreviewSelfTestCommand.php" + }, + "[\"system\", \"Promptversion aktivieren\"]": { + "abdruck": "2bd24ab6b032d071", + "beleg": "$svc->activate($prompt);", + "datei": "src/Controller/Admin/SystemPromptController.php" + }, + "[\"system\", \"Promptversion löschen\"]": { + "abdruck": "5dd7729167e2c812", + "beleg": "#[Route('/admin/system/prompt/{id}/delete', name: 'admin_system_prompt_delete', methods: ['POST'])]", + "datei": "src/Controller/Admin/SystemPromptController.php" + }, + "[\"system\", \"Promptversionen verwalten\"]": { + "abdruck": "35608f50dcb84951", + "beleg": "'all' => $this->repo->findBy([], ['version' => 'DESC']),", + "datei": "src/Service/Admin/SystemPromptAdminService.php" + }, + "[\"system\", \"Restore-Vorschau prüfen\"]": { + "abdruck": "1e0c758c14cafbd5", + "beleg": "private function addRestoreDryRunFlash(array $report): void", + "datei": "src/Controller/Admin/EnterpriseOperationsController.php" + }, + "[\"system\", \"Simulation ausführen\"]": { + "abdruck": "c50566f7d0f432ba", + "beleg": "if ($payloadJson !== '' && $payloadFile !== '') {\n throw new \\InvalidArgumentException('Use either --payload-json or --payload-file, not both.');\n }", + "datei": "src/Command/McpEvidenceDryRunCommand.php" + }, + "[\"system\", \"Systemzustand zurücksetzen\"]": { + "abdruck": "ec8e8511801fc5ca", + "beleg": "#[Route('/reset', name: 'admin_document_reset', methods: ['POST'])]", + "datei": "src/Controller/Admin/DocumentController.php" + }, + "[\"system\", \"Verzeichnis bereinigen\"]": { + "abdruck": "cacd399eaef94143", + "beleg": "#[Route('/cleanup', name: 'admin_knowledge_batch_cleanup', methods: ['POST'])]", + "datei": "src/Controller/Admin/KnowledgeBatchReportController.php" + }, + "[\"tags\", \"Tag-Rebuild-Auftrag ausführen\"]": { + "abdruck": "08bdc2dfadebb29a", + "beleg": "$job->markCompleted();", + "datei": "src/Command/TagRebuildRunJobCommand.php" + }, + "[\"tags\", \"Tags auflisten\"]": { + "abdruck": "f35e569340543788", + "beleg": "#[Route('', name: 'admin_tags_index', methods: ['GET'])]", + "datei": "src/Controller/Admin/TagController.php" + }, + "[\"tags\", \"Tags bearbeiten\"]": { + "abdruck": "a75df6fbceed8e9d", + "beleg": "#[Route('/{id}/tags', name: 'admin_document_tags_edit', methods: ['GET'])]", + "datei": "src/Controller/Admin/DocumentTagController.php" + }, + "[\"tags\", \"Tags suchen\"]": { + "abdruck": "d507a2144565b9a9", + "beleg": "@app.post(\"/search-tags\")\ndef search_tags(req: SearchRequest) -> List[Dict[str, Any]]:", + "datei": "python/vector/vector_service.py" + }, + "[\"titel\", \"Titel aktualisieren\"]": { + "abdruck": "f4226daad62eb2a6", + "beleg": "$document->updateTitle($title, Document::TITLE_SOURCE_MANUAL, false);", + "datei": "src/Controller/Admin/DocumentController.php" + }, + "[\"titel\", \"Titelvorschläge laden\"]": { + "abdruck": "09506400afa4f506", + "beleg": "$result = $titleSuggestionService->suggest($document);", + "datei": "src/Controller/Admin/DocumentController.php" + }, + "[\"uploads\", \"Berechtigungsmodus ändern\"]": { + "abdruck": "ec7ba210bc22e0ee", + "beleg": "#[Route('/chat-uploads/{uploadId}/authority-mode', name: 'chat_upload_authority_mode', requirements: ['uploadId' => '[a-f0-9]{32}'], methods: ['PATCH', 'POST'])]\n public function setAuthorityMode(Request $request, string $uploadId): JsonResponse", + "datei": "src/Controller/ChatUploadController.php" + }, + "[\"uploads\", \"Datei hochladen\"]": { + "abdruck": "abda7a007e492357", + "beleg": "$status = $this->isSizeError($e->getMessage())\n ? Response::HTTP_REQUEST_ENTITY_TOO_LARGE\n : Response::HTTP_BAD_REQUEST;", + "datei": "src/Controller/ChatUploadController.php" + }, + "[\"uploads\", \"Upload entfernen\"]": { + "abdruck": "c12063ad4ea6504a", + "beleg": "public function delete(Request $request, string $uploadId): JsonResponse", + "datei": "src/Controller/ChatUploadController.php" + }, + "[\"uploads\", \"Uploads auflisten\"]": { + "abdruck": "f715c27aaa2efe0b", + "beleg": "#[Route('/chat-uploads', name: 'chat_upload_list', methods: ['GET'])]", + "datei": "src/Controller/ChatUploadController.php" + }, + "[\"verlauf\", \"Verankerungen extrahieren\"]": { + "abdruck": "07982f2a65cfc9a3", + "beleg": "$anchors = $this->extractor->extractRecentAnchors($history, $maxTurns);", + "datei": "src/Command/TestStructuredHistoryAnchorsCommand.php" + }, + "[\"verlauf\", \"Verlauf abrufen\"]": { + "abdruck": "5245760a2672d725", + "beleg": "#[Route('/history', name: 'chat_history', methods: ['GET'])]", + "datei": "src/Controller/HistoryController.php" + }, + "[\"verlauf\", \"Verlauf löschen\"]": { + "abdruck": "a1e4bd366e494634", + "beleg": "$this->contextService->deleteHistory($clientId);", + "datei": "src/Controller/HistoryController.php" + }, + "[\"versionen\", \"Version ableiten\"]": { + "abdruck": "9d7b531eafa6b4db", + "beleg": "public function deriveVersion(\n string $versionId,\n Request $request,\n EntityManagerInterface $em,\n DocumentService $documentService,\n ParameterBagInterface $params,\n FormatText $formatText,\n DocumentVersionPreviewService $previewService,\n ): Response {", + "datei": "src/Controller/Admin/DocumentController.php" + }, + "[\"versionen\", \"Version einlesen\"]": { + "abdruck": "e104d93b6d3ca473", + "beleg": "#[Route(\n '/version/{versionId}/preview',\n name: 'admin_document_version_preview',\n requirements: ['versionId' => '[0-9a-fA-F\\-]{36}'],\n methods: ['GET']\n )]\n public function previewVersion(", + "datei": "src/Controller/Admin/DocumentController.php" + }, + "[\"versionen\", \"Version erstellen\"]": { + "abdruck": "e91ce1c1c6094cf1", + "beleg": "$documentService->addVersion($document, $filePath, $user);", + "datei": "src/Controller/Admin/DocumentController.php" + }, + "[\"versionen\", \"Versionvorschau anzeigen\"]": { + "abdruck": "a974b2f0fc1570d9", + "beleg": "return $this->json([\n 'ok' => true,\n 'preview' => $previewService->buildPreview(\n $version,\n max(0, (int) $request->query->get('offset', 0)),\n (int) $request->query->get('limit', 0) ?: null,\n ),\n ]);", + "datei": "src/Controller/Admin/DocumentController.php" + } + }, + "ohne_code": {}, + "ohne_karte": { + "befehl:mto:agent:admin:title-suggestions-batch-ux-self-test": { + "abdruck": "843d5ca642b321bb", + "beleg": "src/Command/AdminTitleSuggestionsBatchUxSelfTestCommand.php:13", + "feature": "diagnose", + "karten": "69d65c7a24056348", + "stelle": "befehl:mto:agent:admin:title-suggestions-batch-ux-self-test", + "titel": "Titelvorschläge-Selbsttest bereitstellen" + }, + "befehl:mto:agent:config:audit-source": { + "abdruck": "6230151689bef31c", + "beleg": "src/Command/ConfigSourceAuditCommand.php:16", + "feature": "diagnose", + "karten": "69d65c7a24056348", + "stelle": "befehl:mto:agent:config:audit-source", + "titel": "Konfigurationsquellen prüfen" + }, + "befehl:mto:agent:knowledge:batch-markdown-normalization-self-test": { + "abdruck": "3e48335eb38ac843", + "beleg": "src/Command/KnowledgeBatchMarkdownNormalizationSelfTestCommand.php:15", + "feature": "diagnose", + "karten": "69d65c7a24056348", + "stelle": "befehl:mto:agent:knowledge:batch-markdown-normalization-self-test", + "titel": "Batch-Markdown-Normalisierung testen" + }, + "befehl:mto:agent:mcp:policy-check": { + "abdruck": "8110a377aeb90a72", + "beleg": "src/Command/McpPolicyCheckCommand.php:15", + "feature": "agenten", + "karten": "69d65c7a24056348", + "stelle": "befehl:mto:agent:mcp:policy-check", + "titel": "MCP-Allowlist prüfen" + }, + "befehl:mto:agent:system:rebuild": { + "abdruck": "338b6ba198206984", + "beleg": "src/Command/SystemRebuildCommand.php:23", + "feature": "agenten", + "karten": "69d65c7a24056348", + "stelle": "befehl:mto:agent:system:rebuild", + "titel": "System rebuild bereitstellen" + }, + "einbinden:erweitert error/layout.html.twig": { + "abdruck": "7e0ec1ba9d60dfc2", + "beleg": "templates/bundles/TwigBundle/Exception/error.html.twig:1", + "feature": "system", + "karten": "69d65c7a24056348", + "stelle": "einbinden:erweitert error/layout.html.twig", + "titel": "Fehlerseite anzeigen" + }, + "route:get /admin/enterprise/operator-report.json": { + "abdruck": "f80c52683806f557", + "beleg": "src/Controller/Admin/EnterpriseOperationsController.php:222", + "feature": "backup", + "karten": "69d65c7a24056348", + "stelle": "route:get /admin/enterprise/operator-report.json", + "titel": "Operatorbericht als JSON exportieren" + }, + "route:get /admin/enterprise/operator-report.md": { + "abdruck": "013cf5bf01f75995", + "beleg": "src/Controller/Admin/EnterpriseOperationsController.php:233", + "feature": "berichte", + "karten": "69d65c7a24056348", + "stelle": "route:get /admin/enterprise/operator-report.md", + "titel": "Operatorbericht als Markdown herunterladen" + }, + "route:get /admin/jobs": { + "abdruck": "bb7ffeb8ab6206d7", + "beleg": "src/Controller/Admin/IngestJobController.php:19", + "feature": "auftraege", + "karten": "69d65c7a24056348", + "stelle": "route:get /admin/jobs", + "titel": "Ingest-Jobs auflisten" + }, + "route:get /admin/login": { + "abdruck": "26892f59f58a1343", + "beleg": "src/Controller/Admin/SecurityController.php:17", + "feature": "system", + "karten": "69d65c7a24056348", + "stelle": "route:get /admin/login", + "titel": "Admin-Login bereitstellen" + }, + "route:get /tags/status": { + "abdruck": "563ca03e6e7d0168", + "beleg": "src/Controller/Admin/DocumentTagController.php:64", + "feature": "tags", + "karten": "69d65c7a24056348", + "stelle": "route:get /tags/status", + "titel": "Tag-Rebuild-Status abfragen" + }, + "route:get /version/{versionId}/chunks": { + "abdruck": "5912e8ad04dff0b9", + "beleg": "src/Controller/Admin/DocumentController.php:362", + "feature": "dokumente", + "karten": "69d65c7a24056348", + "stelle": "route:get /version/{versionId}/chunks", + "titel": "Version-Chunks abrufen" + }, + "route:get /{batchId}": { + "abdruck": "aff9a8b22d9a3898", + "beleg": "src/Controller/Admin/KnowledgeBatchReportController.php:120", + "feature": "berichte", + "karten": "69d65c7a24056348", + "stelle": "route:get /{batchId}", + "titel": "Batch-Bericht anzeigen" + }, + "route:get /{id}/tags": { + "abdruck": "647012ad65e4e903", + "beleg": "src/Controller/Admin/DocumentTagController.php:20", + "feature": "tags", + "karten": "69d65c7a24056348", + "stelle": "route:get /{id}/tags", + "titel": "Tag-Zuordnung bearbeiten" + }, + "route:post /chat-feedback": { + "abdruck": "3580073b0c13af05", + "beleg": "src/Controller/ChatFeedbackController.php:58", + "feature": "feedback", + "karten": "69d65c7a24056348", + "stelle": "route:post /chat-feedback", + "titel": "Feedback speichern" + }, + "route:post /remove/{id}": { + "abdruck": "a1713c7060f2b0aa", + "beleg": "src/Controller/Admin/IngestProfileController.php:76", + "feature": "konfiguration", + "karten": "69d65c7a24056348", + "stelle": "route:post /remove/{id}", + "titel": "Ingest-Profil entfernen" + }, + "route:post /upload": { + "abdruck": "4dc0d28cbc695b67", + "beleg": "src/Controller/Admin/KnowledgeBatchReportController.php:65", + "feature": "berichte", + "karten": "69d65c7a24056348", + "stelle": "route:post /upload", + "titel": "Batch-Bericht hochladen" + }, + "route:post /version/{versionId}/activate": { + "abdruck": "19e7d9844ad77ac3", + "beleg": "src/Controller/Admin/DocumentController.php:549", + "feature": "versionen", + "karten": "69d65c7a24056348", + "stelle": "route:post /version/{versionId}/activate", + "titel": "Version aktivieren" + } + }, + "paare": { + "[\"[\\\"diagnose\\\", \\\"Konfiguration prüfen\\\"]\", \"[\\\"konfiguration\\\", \\\"Konfigurationsmuster prüfen\\\"]\"]": { + "abdruck": "15337f18a6737c8c", + "gleich": false + }, + "[\"[\\\"knowledge-raeume\\\", \\\"Batch-Import durchführen\\\"]\", \"[\\\"knowledge-raeume\\\", \\\"Ressourcenprüfung durchführen\\\"]\"]": { + "abdruck": "2986858d481560bc", + "gleich": false + }, + "[\"[\\\"knowledge-raeume\\\", \\\"Chat-Verfügbarkeit prüfen\\\"]\", \"[\\\"knowledge-raeume\\\", \\\"Ressourcenprüfung durchführen\\\"]\"]": { + "abdruck": "152316f10336728c", + "gleich": false + }, + "[\"[\\\"knowledge-raeume\\\", \\\"Facts prüfen\\\"]\", \"[\\\"knowledge-raeume\\\", \\\"Ressourcenprüfung durchführen\\\"]\"]": { + "abdruck": "b4dbd1bd2cdfad59", + "gleich": false + }, + "[\"[\\\"knowledge-raeume\\\", \\\"Live-Vorschau laden\\\"]\", \"[\\\"knowledge-raeume\\\", \\\"Ressourcenprüfung durchführen\\\"]\"]": { + "abdruck": "6bd6037f86a8638b", + "gleich": false + }, + "[\"[\\\"konfiguration\\\", \\\"Ingest-Profil anlegen\\\"]\", \"[\\\"konfiguration\\\", \\\"Ingest-Profile anzeigen\\\"]\"]": { + "abdruck": "54fa5dc37e4bce7b", + "gleich": false + }, + "[\"[\\\"konfiguration\\\", \\\"Konfiguration anzeigen\\\"]\", \"[\\\"konfiguration\\\", \\\"Konfigurationen anzeigen\\\"]\"]": { + "abdruck": "1a2b3ae854024ca6", + "gleich": false + } + }, + "stil": { + "[\"admin\", \"\"]": { + "abdruck": "a203875bd41900c1", + "probleme": [] + }, + "[\"admin\", \"Betrieb einsehen\"]": { + "abdruck": "92a486ddfff5158e", + "probleme": [] + }, + "[\"admin\", \"Dashboard anzeigen\"]": { + "abdruck": "54e5d6299d132ede", + "probleme": [ + { + "feature": "admin", + "feld": "regeln", + "funktion": "Dashboard anzeigen", + "ganzes_feld": true, + "original": "Rendered admin dashboard index html twig\nEnthält Chunk-Zähler und Chunk-Limit\nEnthält Vektor- und Tag-Gesundheitsdaten\nEnthält Reset-Konfiguration", + "problem": "Template-Pfad kein Feature-Inhalt. Chunk-Zähler und Limit sowie Vektor- und Tag-Daten sind je zwei Inhalte in einer Zeile", + "regel": "Genau eine Aussage je Zeile; zwei Aussagen werden zu zwei Regeln", + "vorschlag": "Chunk-Zähler und Chunk-Limit anzeigen\nVektor- und Tag-Gesundheitsdaten anzeigen\nReset-Konfiguration anzeigen" + } + ] + }, + "[\"admin\", \"Logout einleiten\"]": { + "abdruck": "42dcd7e9064bcbbf", + "probleme": [] + }, + "[\"admin\", \"Wiederherstellung testen\"]": { + "abdruck": "0a40315eeece5b67", + "probleme": [] + }, + "[\"admin\", \"Zum Dashboard weiterleiten\"]": { + "abdruck": "7b834b643e67b940", + "probleme": [] + }, + "[\"agenten\", \"\"]": { + "abdruck": "901c385fec70b938", + "probleme": [] + }, + "[\"agenten\", \"Agentenaktivität anzeigen\"]": { + "abdruck": "cd9f8ffc4b1305b9", + "probleme": [] + }, + "[\"agenten\", \"Chat-Auswahl-Guard testen\"]": { + "abdruck": "64ce9ac9cfcff1dc", + "probleme": [] + }, + "[\"agenten\", \"Fähigkeiten ermitteln\"]": { + "abdruck": "785628cbe59d669a", + "probleme": [] + }, + "[\"agenten\", \"Hybrid-Tool-Auswahl testen\"]": { + "abdruck": "ee09ee5102072416", + "probleme": [] + }, + "[\"agenten\", \"MCP-Allowlist prüfen\"]": { + "abdruck": "853ccb3f4e4aa8d4", + "probleme": [] + }, + "[\"agenten\", \"MCP-Gateway trocken ausführen\"]": { + "abdruck": "1439df287c8150b2", + "probleme": [] + }, + "[\"agenten\", \"MCP-Laufzeit-Gate prüfen\"]": { + "abdruck": "b3293656f686ae09", + "probleme": [ + { + "feature": "agenten", + "feld": "regeln", + "funktion": "MCP-Laufzeit-Gate prüfen", + "ganzes_feld": false, + "original": "Gate ohne Transport öffnen", + "problem": "Erste Regel ist Ablaufschritt statt Eigenschaft", + "regel": "Beschreibt eine Eigenschaft oder Bedingung, keinen Ablaufschritt", + "vorschlag": "Gate ohne Transport verfügbar" + }, + { + "feature": "agenten", + "feld": "testen", + "funktion": "MCP-Laufzeit-Gate prüfen", + "ganzes_feld": false, + "original": "JSON auf Status ready und Fehler prüfen", + "problem": "Letzte Zeile enthält Handlung statt Endzustand", + "regel": "Letzte Zeile beschreibt den Endzustand, keine Handlung", + "vorschlag": "JSON zeigt Status ready ohne Fehler" + } + ] + }, + "[\"agenten\", \"MCP-Laufzeitgrenze testen\"]": { + "abdruck": "080b368f6b310470", + "probleme": [] + }, + "[\"agenten\", \"MCP-Quelle prüfen\"]": { + "abdruck": "c1558584859c0dec", + "probleme": [] + }, + "[\"agenten\", \"Mit Agent chatten\"]": { + "abdruck": "00eafdf90dab665a", + "probleme": [] + }, + "[\"agenten\", \"Performance-Cache leeren\"]": { + "abdruck": "97e48547004e559b", + "probleme": [] + }, + "[\"agenten\", \"Produktlabel-Formatierer testen\"]": { + "abdruck": "c5831a681dbce9d2", + "probleme": [] + }, + "[\"agenten\", \"Release-Selbsttest bereitstellen\"]": { + "abdruck": "4d0951f85d841836", + "probleme": [] + }, + "[\"agenten\", \"Ressource abrufen\"]": { + "abdruck": "f41b71225f818920", + "probleme": [] + }, + "[\"agenten\", \"Ressource validieren\"]": { + "abdruck": "3d7999723f74822d", + "probleme": [] + }, + "[\"agenten\", \"Rollencode-Zuweisung prüfen\"]": { + "abdruck": "287ee050cc63c85a", + "probleme": [ + { + "feature": "agenten", + "feld": "testen", + "funktion": "Rollencode-Zuweisung prüfen", + "ganzes_feld": false, + "original": "Ausgabe auf Status OK prüfen", + "problem": "Zweiter Ablauf in einer Funktion", + "regel": "Genau ein Ablauf: handeln, handeln, Ergebnis", + "vorschlag": "" + } + ] + }, + "[\"agenten\", \"Stabilitäts-Selbsttest bereitstellen\"]": { + "abdruck": "3db549d48f744d79", + "probleme": [ + { + "feature": "agenten", + "feld": "testen", + "funktion": "Stabilitäts-Selbsttest bereitstellen", + "ganzes_feld": true, + "original": "Binconsole mto:agent:shop-followup-anchor-stability-self-test\nStatus OK prüfen\npassed größer 0 prüfen\nfailed gleich 0 prüfen\nBinconsole mit --json\nJSON-Status OK prüfen", + "problem": "Zweiter Ablauf für menschenlesbare Ausgabe", + "regel": "Zwei Abläufe in einer Funktion", + "vorschlag": "Binconsole mto:agent:shop-followup-anchor-stability-self-test --json ausführen\nExit-Code 0 prüfen\nJSON-Status OK prüfen\nJSON failed gleich 0 prüfen\nJSON passed größer 0 prüfen" + } + ] + }, + "[\"agenten\", \"System rebuild bereitstellen\"]": { + "abdruck": "5bfdef4e50e34918", + "probleme": [ + { + "feature": "agenten", + "feld": "testen", + "funktion": "System rebuild bereitstellen", + "ganzes_feld": true, + "original": "", + "problem": "Funktion benötigt Testschritte, Feld fehlt", + "regel": "Feld testen. Gibt es nur bei Funktionen, nie auf Kartenebene.", + "vorschlag": "System rebuild Befehl ausführen\nRebuild abgeschlossen" + } + ] + }, + "[\"agenten\", \"Vektordienst steuern\"]": { + "abdruck": "ac9028407142447d", + "probleme": [] + }, + "[\"agenten\", \"Wissensbatch finalisieren testen\"]": { + "abdruck": "ff209274e8194d00", + "probleme": [] + }, + "[\"anleitungen\", \"\"]": { + "abdruck": "cd6d903356c7e46e", + "probleme": [] + }, + "[\"anleitungen\", \"Anleitung anzeigen\"]": { + "abdruck": "899edf023676bec8", + "probleme": [] + }, + "[\"anleitungen\", \"Anleitungsübersicht öffnen\"]": { + "abdruck": "806b26a376c96a30", + "probleme": [] + }, + "[\"auftraege\", \"\"]": { + "abdruck": "af6f7983d90efdc8", + "probleme": [] + }, + "[\"auftraege\", \"Auftrag starten\"]": { + "abdruck": "b6eab1ba718ae1a4", + "probleme": [] + }, + "[\"auftraege\", \"Auftragsereignisse abrufen\"]": { + "abdruck": "c4b50cdc890f64a5", + "probleme": [] + }, + "[\"auftraege\", \"Auftragsstatus anzeigen\"]": { + "abdruck": "3b24cdd657d277e3", + "probleme": [] + }, + "[\"auftraege\", \"Auftragsstatus prüfen\"]": { + "abdruck": "00a4cdd2990b0add", + "probleme": [] + }, + "[\"auftraege\", \"Ingest-Job starten\"]": { + "abdruck": "72aec88bb6eff241", + "probleme": [] + }, + "[\"auftraege\", \"Ingest-Jobs auflisten\"]": { + "abdruck": "f7d0895bcadf912d", + "probleme": [] + }, + "[\"backup\", \"\"]": { + "abdruck": "45e98250435d775b", + "probleme": [] + }, + "[\"backup\", \"Backup herunterladen\"]": { + "abdruck": "e2f3abc461d9c194", + "probleme": [] + }, + "[\"backup\", \"Backup starten\"]": { + "abdruck": "566508ee6bfb61bc", + "probleme": [] + }, + "[\"backup\", \"Backup-Tauglichkeit prüfen\"]": { + "abdruck": "6eb57d4ef14f886c", + "probleme": [] + }, + "[\"backup\", \"Backup-Trockenlauf prüfen\"]": { + "abdruck": "0690893ed788267b", + "probleme": [] + }, + "[\"backup\", \"Backup-Wiederherstellung prüfen\"]": { + "abdruck": "dbc11a271214f791", + "probleme": [] + }, + "[\"backup\", \"Operatorbericht als JSON exportieren\"]": { + "abdruck": "14bef84729eaadf1", + "probleme": [] + }, + "[\"benutzer\", \"\"]": { + "abdruck": "32420f60cbf635b1", + "probleme": [] + }, + "[\"benutzer\", \"Benutzer aktivieren\"]": { + "abdruck": "96f95d98b60ce655", + "probleme": [] + }, + "[\"benutzer\", \"Benutzer anlegen\"]": { + "abdruck": "f05fc2e1c4187019", + "probleme": [] + }, + "[\"benutzer\", \"Benutzer auflisten\"]": { + "abdruck": "8321758658996847", + "probleme": [ + { + "feature": "benutzer", + "feld": "testen", + "funktion": "Benutzer auflisten", + "ganzes_feld": true, + "original": "Seite /admin/users aufrufen\nSeite zeigt Benutzerliste mit Rollen und Status\nFilter auf Status \"aktiv\" setzen\nListe zeigt nur aktive Benutzer", + "problem": "Schrägstrich in Pfad entfernt", + "regel": "Keine Klammern und keine Schrägstriche", + "vorschlag": "Seite admin Benutzer aufrufen\nFilter auf Status \"aktiv\" setzen\nListe zeigt nur aktive Benutzer" + } + ] + }, + "[\"benutzer\", \"Benutzer bearbeiten\"]": { + "abdruck": "f127b29c9c5bc74e", + "probleme": [] + }, + "[\"berichte\", \"\"]": { + "abdruck": "0f4156c5fc44424d", + "probleme": [] + }, + "[\"berichte\", \"Akzeptanzbericht generieren\"]": { + "abdruck": "f04707b53e234402", + "probleme": [] + }, + "[\"berichte\", \"Batch-Bericht anzeigen\"]": { + "abdruck": "f38e641b3339b8ab", + "probleme": [] + }, + "[\"berichte\", \"Batch-Bericht hochladen\"]": { + "abdruck": "9030b692a0e36c2a", + "probleme": [] + }, + "[\"berichte\", \"Bericht als JSON herunterladen\"]": { + "abdruck": "ddc360bbfd90df78", + "probleme": [] + }, + "[\"berichte\", \"Bericht löschen\"]": { + "abdruck": "469932b04c26e284", + "probleme": [] + }, + "[\"berichte\", \"Berichte auflisten\"]": { + "abdruck": "9080b473520828ed", + "probleme": [] + }, + "[\"berichte\", \"Operatorbericht als Markdown herunterladen\"]": { + "abdruck": "7c7899d0d1d192c9", + "probleme": [ + { + "feature": "berichte", + "feld": "testen", + "funktion": "Operatorbericht als Markdown herunterladen", + "ganzes_feld": true, + "original": "", + "problem": "Funktion ohne Ziel, Regeln und Testen", + "regel": "Jede Funktion hat Ziel, Regeln oder Testschritte — nie nur einen Titel", + "vorschlag": "Operatorbericht herunterladen\nDownload der Markdown-Datei" + } + ] + }, + "[\"berichte\", \"Übersicht rendern\"]": { + "abdruck": "6dc46bd6fede91df", + "probleme": [] + }, + "[\"chat\", \"\"]": { + "abdruck": "a1447aea8aded8a8", + "probleme": [] + }, + "[\"chat\", \"Abmelden ermöglichen\"]": { + "abdruck": "c0f05ddcafaea075", + "probleme": [] + }, + "[\"chat\", \"Chat streamen\"]": { + "abdruck": "e1e9cb8c9053e37b", + "probleme": [] + }, + "[\"chat\", \"Chatseite anzeigen\"]": { + "abdruck": "11e80969e49bdcba", + "probleme": [] + }, + "[\"diagnose\", \"\"]": { + "abdruck": "dabf1d8c23deb380", + "probleme": [] + }, + "[\"diagnose\", \"Abdeckung prüfen\"]": { + "abdruck": "329d2b8accf37a8c", + "probleme": [] + }, + "[\"diagnose\", \"Abrufgrenzen prüfen\"]": { + "abdruck": "2e96c8c9e81d5c08", + "probleme": [] + }, + "[\"diagnose\", \"Batch-Markdown-Normalisierung testen\"]": { + "abdruck": "e2381c7b61403312", + "probleme": [ + { + "feature": "diagnose", + "feld": "testen", + "funktion": "Batch-Markdown-Normalisierung testen", + "ganzes_feld": true, + "original": "", + "problem": "Testen fehlt, Funktion benötigt Testschritte", + "regel": "Jede Funktion hat Ziel, Regeln oder Testschritte — nie nur einen Titel", + "vorschlag": "Batch-Markdown-Dateien auswählen\nNormalisierung starten\nMarkdown-Dateien nach Regeln formatiert" + } + ] + }, + "[\"diagnose\", \"Bereitschaftsbericht ausgeben\"]": { + "abdruck": "08760e3d3d8b51db", + "probleme": [] + }, + "[\"diagnose\", \"Datenqualität prüfen\"]": { + "abdruck": "c511b22c8c39db86", + "probleme": [] + }, + "[\"diagnose\", \"Diagnose anzeigen\"]": { + "abdruck": "5c04af7f55f567b2", + "probleme": [] + }, + "[\"diagnose\", \"Genre-Hotspots prüfen\"]": { + "abdruck": "e030f3ee1c29b26b", + "probleme": [] + }, + "[\"diagnose\", \"Guard-Mechanismus prüfen\"]": { + "abdruck": "3b18f616a3db9276", + "probleme": [ + { + "feature": "diagnose", + "feld": "testen", + "funktion": "Guard-Mechanismus prüfen", + "ganzes_feld": true, + "original": "Befehl ausführen: mto:agent:proofing:unsupported-tool-term-guard-self-test\nStatus OK in JSON-Ausgabe prüfen\nAlle 8 Testfälle bestanden", + "problem": "Zwei getrennte Ergebnisse statt einem Ablauf", + "regel": "Genau ein Ablauf: handeln, handeln, Ergebnis", + "vorschlag": "Befehl ausführen: mto:agent:proofing:unsupported-tool-term-guard-self-test\nJSON-Ausgabe enthält Status OK und 8 bestandene Testfälle" + } + ] + }, + "[\"diagnose\", \"Hygieneregeln prüfen\"]": { + "abdruck": "ddfb86db54bf0bef", + "probleme": [] + }, + "[\"diagnose\", \"Indizierungszustand prüfen\"]": { + "abdruck": "208a457fe1c0d0b7", + "probleme": [] + }, + "[\"diagnose\", \"Konfiguration prüfen\"]": { + "abdruck": "8a8ce42e5d2051e8", + "probleme": [ + { + "feature": "diagnose", + "feld": "testen", + "funktion": "Konfiguration prüfen", + "ganzes_feld": true, + "original": "php bin/console mto:agent:config:validate ausführen\nErgebnis auf Fehler und Warnungen prüfen\nExitcode prüfen\nKonfiguration gültig: Exitcode 0\nphp bin/console mto:agent:config:validate --json ausführen\nJSON-Ausgabe enthält status, errors, warnings", + "problem": "Schrägstrich im Konsolenbefehl entfernt", + "regel": "Keine Klammern und keine Schrägstriche", + "vorschlag": "Konsolenbefehl mto:agent:config:validate ausführen\nErgebnis auf Fehler und Warnungen prüfen\nExitcode prüfen\nKonfiguration gültig: Exitcode 0" + } + ] + }, + "[\"diagnose\", \"Konfigurationsquellen prüfen\"]": { + "abdruck": "53ba45d064f6433a", + "probleme": [ + { + "feature": "diagnose", + "feld": "testen", + "funktion": "Konfigurationsquellen prüfen", + "ganzes_feld": true, + "original": "", + "problem": "Pflichtfelder bei Funktion fehlen", + "regel": "Jede Funktion hat Ziel, Regeln oder Testschritte — nie nur einen Titel", + "vorschlag": "Testschritte erforderlich" + } + ] + }, + "[\"diagnose\", \"Provenienz prüfen\"]": { + "abdruck": "82bbe9fc8808a6a8", + "probleme": [] + }, + "[\"diagnose\", \"Retrieval-Pipeline testen\"]": { + "abdruck": "c7469a1ab52e339a", + "probleme": [] + }, + "[\"diagnose\", \"Retrieval-Qualität testen\"]": { + "abdruck": "7b133381f3194f4f", + "probleme": [] + }, + "[\"diagnose\", \"Segmentierung prüfen\"]": { + "abdruck": "9c80d823344ee85b", + "probleme": [] + }, + "[\"diagnose\", \"Shop-Suche testen\"]": { + "abdruck": "86201015e42388f0", + "probleme": [] + }, + "[\"diagnose\", \"Sicherheitsstatus prüfen\"]": { + "abdruck": "763e7ad0e8d96136", + "probleme": [ + { + "feature": "diagnose", + "feld": "testen", + "funktion": "Sicherheitsstatus prüfen", + "ganzes_feld": true, + "original": "php bin/console mto:agent:enterprise:security-data-protection-readiness\nTabelle mit Cases wird ausgegeben\nphp bin/console mto:agent:enterprise:security-data-protection-readiness --json\nJSON-Objekt wird ausgegeben", + "problem": "Schrägstrich im Befehlspfad verboten", + "regel": "Keine Klammern und keine Schrägstriche", + "vorschlag": "mto:agent:enterprise:security-data-protection-readiness im Terminal ausführen\nTabelle mit Cases wird ausgegeben\nmto:agent:enterprise:security-data-protection-readiness mit JSON-Option im Terminal ausführen\nJSON-Objekt wird ausgegeben" + } + ] + }, + "[\"diagnose\", \"Stapel-Upload verifizieren\"]": { + "abdruck": "1d26cafba701a598", + "probleme": [ + { + "feature": "diagnose", + "feld": "regeln", + "funktion": "Stapel-Upload verifizieren", + "ganzes_feld": true, + "original": "Trockenlauf ohne Dokumentenimport\nRuft kein LLM auf\nÄndert keine Daten im Wissensspeicher\nGibt maschinenlesbares JSON aus\nPrüft CSRF-Schutz, Dienstintegration und Fortschrittsanzeige\nPrüft PDF-Schutz, Speichergrenzen und Leerraum-Bereinigung\nPrüft CLI-Progress und keine Agent-Verschaltung", + "problem": "Zeilen 5 6 7 enthalten jeweils mehrere Aussagen", + "regel": "Genau eine Aussage je Zeile; zwei Aussagen werden zu zwei Regeln", + "vorschlag": "Trockenlauf ohne Dokumentenimport\nRuft kein LLM auf\nÄndert keine Daten im Wissensspeicher\nGibt maschinenlesbares JSON aus\nPrüft CSRF-Schutz\nPrüft Dienstintegration\nPrüft Fortschrittsanzeige\nPrüft PDF-Schutz\nPrüft Speichergrenzen\nPrüft Leerraum-Bereinigung\nPrüft CLI-Progress\nPrüft keine Agent-Verschaltung" + } + ] + }, + "[\"diagnose\", \"Systemzustand prüfen\"]": { + "abdruck": "d28aa2acfe9cfac4", + "probleme": [] + }, + "[\"diagnose\", \"Tag-Index-Gesundheit prüfen\"]": { + "abdruck": "a48e532486b4c2b5", + "probleme": [] + }, + "[\"diagnose\", \"Tags neu indizieren\"]": { + "abdruck": "a037e610d8d69c42", + "probleme": [] + }, + "[\"diagnose\", \"Titelvorschläge-Selbsttest bereitstellen\"]": { + "abdruck": "86b944b2266d2b37", + "probleme": [] + }, + "[\"diagnose\", \"Verankerung testen\"]": { + "abdruck": "8ca4a84d17efdfa2", + "probleme": [] + }, + "[\"diagnose\", \"Vergleichsgrenzen validieren\"]": { + "abdruck": "bc540e615d0d5bd7", + "probleme": [] + }, + "[\"dokumente\", \"\"]": { + "abdruck": "4becdb2142c5bd23", + "probleme": [] + }, + "[\"dokumente\", \"Abschnitte laden\"]": { + "abdruck": "63a90ebf0595d865", + "probleme": [] + }, + "[\"dokumente\", \"Abschnittsqualität laden\"]": { + "abdruck": "c62844c88eabc50e", + "probleme": [] + }, + "[\"dokumente\", \"Dokument anzeigen\"]": { + "abdruck": "d6b054833ea79af3", + "probleme": [] + }, + "[\"dokumente\", \"Dokument entfernen\"]": { + "abdruck": "e64c95dd87a82000", + "probleme": [] + }, + "[\"dokumente\", \"Dokument erstellen\"]": { + "abdruck": "8e01d7cbd5a0a8a4", + "probleme": [] + }, + "[\"dokumente\", \"Dokumente auflisten\"]": { + "abdruck": "b7c2416d7d4cbbae", + "probleme": [ + { + "feature": "dokumente", + "feld": "testen", + "funktion": "Dokumente auflisten", + "ganzes_feld": true, + "original": "admin/documents öffnet die Übersicht\nDokumente werden mit Titeln angezeigt\nLMB auf Filterfeld\nFilterkriterium auswählen\nErgebnis zeigt gefilterte Dokumente", + "problem": "Schrägstrich in admin/documents und vermischte Abläufe", + "regel": "Keine Klammern und keine Schrägstriche", + "vorschlag": "admin Dokumente Übersicht öffnen\nDokumentenübersicht zeigt Dokumente mit Titeln\nLMB auf Filterfeld\nFilterkriterium auswählen\nGefilterte Dokumente anzeigen" + } + ] + }, + "[\"dokumente\", \"Markdown bereinigen\"]": { + "abdruck": "06b80c5a0e87b0a2", + "probleme": [] + }, + "[\"dokumente\", \"Version-Chunks abrufen\"]": { + "abdruck": "121d643dfeaa9d06", + "probleme": [] + }, + "[\"evaluation\", \"\"]": { + "abdruck": "594221238c11b947", + "probleme": [] + }, + "[\"evaluation\", \"Berichte bereinigen\"]": { + "abdruck": "a7042dc676807598", + "probleme": [] + }, + "[\"evaluation\", \"Eval-Berichte anzeigen\"]": { + "abdruck": "e5bef4df8f06ec4c", + "probleme": [] + }, + "[\"evaluation\", \"Eval-Fälle ausführen\"]": { + "abdruck": "d6df9edb6f759315", + "probleme": [] + }, + "[\"evaluation\", \"Eval-Fälle parallelisieren\"]": { + "abdruck": "27acbff82a31da6a", + "probleme": [] + }, + "[\"evaluation\", \"Evaluation ausführen\"]": { + "abdruck": "2b308fa2f538a538", + "probleme": [] + }, + "[\"faelle\", \"\"]": { + "abdruck": "e38157c616482b1c", + "probleme": [] + }, + "[\"faelle\", \"Assistent anzeigen\"]": { + "abdruck": "4e8e66ff7acfb7c0", + "probleme": [] + }, + "[\"faelle\", \"Fall anlegen\"]": { + "abdruck": "bce7e877c144ea9d", + "probleme": [] + }, + "[\"faelle\", \"Fall erstellen\"]": { + "abdruck": "ec52ed76fbd9d12b", + "probleme": [] + }, + "[\"faelle\", \"Fälle löschen bereitstellen\"]": { + "abdruck": "69713f6beacefbcc", + "probleme": [] + }, + "[\"feedback\", \"\"]": { + "abdruck": "4b64525f442c4972", + "probleme": [] + }, + "[\"feedback\", \"Chat-Feedback anzeigen\"]": { + "abdruck": "69466ab1f54c2cb9", + "probleme": [] + }, + "[\"feedback\", \"Feedback exportieren\"]": { + "abdruck": "ddb61be881c2bbff", + "probleme": [] + }, + "[\"feedback\", \"Feedback klassifizieren\"]": { + "abdruck": "9d766ebb18ca02c5", + "probleme": [] + }, + "[\"feedback\", \"Feedback löschen\"]": { + "abdruck": "d60ec5bc507ba562", + "probleme": [] + }, + "[\"feedback\", \"Feedback speichern\"]": { + "abdruck": "d48bb573cdb9705d", + "probleme": [] + }, + "[\"feedback\", \"Feedback-Details anzeigen\"]": { + "abdruck": "d6b5bce8fb06d510", + "probleme": [] + }, + "[\"feedback\", \"Feedback-Status aktualisieren\"]": { + "abdruck": "b403e18917069070", + "probleme": [] + }, + "[\"feedback\", \"Feedback-Status prüfen\"]": { + "abdruck": "b26f6d469ab858d2", + "probleme": [] + }, + "[\"knowledge-raeume\", \"\"]": { + "abdruck": "25228e3324851fe7", + "probleme": [] + }, + "[\"knowledge-raeume\", \"Batch-Import durchführen\"]": { + "abdruck": "31019ec87c246d93", + "probleme": [] + }, + "[\"knowledge-raeume\", \"Chat-Freigabe umschalten\"]": { + "abdruck": "080f4432ef5b203c", + "probleme": [] + }, + "[\"knowledge-raeume\", \"Chat-Verfügbarkeit prüfen\"]": { + "abdruck": "603b7775de757a04", + "probleme": [] + }, + "[\"knowledge-raeume\", \"Facts prüfen\"]": { + "abdruck": "3896b29ce690ad30", + "probleme": [] + }, + "[\"knowledge-raeume\", \"Kandidaten wählen\"]": { + "abdruck": "d964a18b84dad74d", + "probleme": [] + }, + "[\"knowledge-raeume\", \"Knowledge-Räume anzeigen\"]": { + "abdruck": "562a038e69aa6f0e", + "probleme": [] + }, + "[\"knowledge-raeume\", \"Live-Vorschau laden\"]": { + "abdruck": "f728e6193791be38", + "probleme": [] + }, + "[\"knowledge-raeume\", \"Ressourcenprüfung durchführen\"]": { + "abdruck": "b1a1ebfc2a7a3ee9", + "probleme": [] + }, + "[\"knowledge-raeume\", \"Textteile suchen\"]": { + "abdruck": "e17ffa8ad1243dc9", + "probleme": [] + }, + "[\"knowledge-raeume\", \"Wissensräume prüfen\"]": { + "abdruck": "3a41f11618fa60df", + "probleme": [] + }, + "[\"konfiguration\", \"\"]": { + "abdruck": "92cf0d92545eb7ff", + "probleme": [ + { + "feature": "konfiguration", + "feld": "regeln", + "funktion": "", + "ganzes_feld": true, + "original": "ROLE_SUPER_ADMIN darf alle Funktionen aufrufen\nROLE_KNOWLEDGE_ADMIN darf Konfigurationen lesen\nPOST erfordert gültiges CSRF-Token\nFlash-Nachrichten zeigen Erfolg und Fehler\nJsonResponse ohne Browser-Cache-Header\nDefault-Ausgabe ist JSON\nIngest-Profil entfernen fehlt\nModel-Konfiguration löschen fehlt\nModel-Konfiguration Retrieval testen fehlt", + "problem": "Drei Zeilen beschreiben fehlende Features", + "regel": "Beschreibt eine Eigenschaft oder Bedingung, keinen Ablaufschritt", + "vorschlag": "ROLE_SUPER_ADMIN darf alle Funktionen aufrufen\nROLE_KNOWLEDGE_ADMIN darf Konfigurationen lesen\nPOST erfordert gültiges CSRF-Token\nFlash-Nachrichten zeigen Erfolg und Fehler\nJsonResponse ohne Browser-Cache-Header\nDefault-Ausgabe ist JSON" + } + ] + }, + "[\"konfiguration\", \"Ingest-Profil anlegen\"]": { + "abdruck": "9e5b29256daf2c06", + "probleme": [] + }, + "[\"konfiguration\", \"Ingest-Profil entfernen\"]": { + "abdruck": "0c1b8c259154ef6c", + "probleme": [ + { + "feature": "konfiguration", + "feld": "testen", + "funktion": "Ingest-Profil entfernen", + "ganzes_feld": true, + "original": "", + "problem": "Leer, widerspricht Regel Jede Funktion hat Ziel, Regeln oder Testschritte", + "regel": "Kein Satzzeichen am Zeilenende, kein Punkt und kein Semikolon", + "vorschlag": "Ingest-Profil auswählen\nLöschen betätigen\nIngest-Profil nicht mehr vorhanden" + } + ] + }, + "[\"konfiguration\", \"Ingest-Profile anzeigen\"]": { + "abdruck": "caf3406830504a3d", + "probleme": [] + }, + "[\"konfiguration\", \"Konfiguration aktivieren\"]": { + "abdruck": "d0348c558413f373", + "probleme": [] + }, + "[\"konfiguration\", \"Konfiguration anzeigen\"]": { + "abdruck": "c5e60cea343fde20", + "probleme": [] + }, + "[\"konfiguration\", \"Konfiguration bereitstellen\"]": { + "abdruck": "26a2e49c0ad08c5d", + "probleme": [] + }, + "[\"konfiguration\", \"Konfigurationen anzeigen\"]": { + "abdruck": "b99bbc6dc1dbb85b", + "probleme": [] + }, + "[\"konfiguration\", \"Konfigurationsmuster prüfen\"]": { + "abdruck": "548417111961dff3", + "probleme": [] + }, + "[\"konfiguration\", \"Tool-Freigaben aktualisieren\"]": { + "abdruck": "6a817eb0259e5a15", + "probleme": [] + }, + "[\"logs\", \"\"]": { + "abdruck": "8973dbd63027cc8d", + "probleme": [] + }, + "[\"logs\", \"Logdatei anzeigen\"]": { + "abdruck": "5cb3a44df5954a83", + "probleme": [] + }, + "[\"logs\", \"Logdateien auflisten\"]": { + "abdruck": "a99c8ae34ebbf477", + "probleme": [] + }, + "[\"sonstiges\", \"\"]": { + "abdruck": "1b9e9b354b4e4eb6", + "probleme": [] + }, + "[\"sonstiges\", \"Sicherheitsnachweis bereitstellen\"]": { + "abdruck": "4f9581ea69437237", + "probleme": [] + }, + "[\"sonstiges\", \"post activate {id} bereitstellen\"]": { + "abdruck": "97cd9a4ee22b4c8e", + "probleme": [] + }, + "[\"sonstiges\", \"post {id} tags save bereitstellen\"]": { + "abdruck": "c70846fc95f332de", + "probleme": [] + }, + "[\"system\", \"\"]": { + "abdruck": "cd76c21c32180982", + "probleme": [] + }, + "[\"system\", \"Access-Denied-Fehler bereitstellen\"]": { + "abdruck": "0c4867fdd18e405f", + "probleme": [] + }, + "[\"system\", \"Admin-Login bereitstellen\"]": { + "abdruck": "90977c98a07c9372", + "probleme": [] + }, + "[\"system\", \"Betriebsbereitschaft prüfen\"]": { + "abdruck": "875a43396ab59856", + "probleme": [ + { + "feature": "system", + "feld": "testen", + "funktion": "Betriebsbereitschaft prüfen", + "ganzes_feld": true, + "original": "Command ausführen ohne Option\nTabelle zeigt Status, Case und Details\nAlle Cases mit PASS erscheinen\nCommand mit --json ausführen\nJSON-Objekt mit status, summary und cases erscheint", + "problem": "Zweiter Ablauf entfernt, nur ein Ablauf erlaubt", + "regel": "Genau ein Ablauf: handeln, handeln, Ergebnis", + "vorschlag": "Command ausführen ohne Option\nTabelle zeigt Status, Case und Details" + } + ] + }, + "[\"system\", \"Cache leeren\"]": { + "abdruck": "fb93b62747244c97", + "probleme": [] + }, + "[\"system\", \"Daten neu laden\"]": { + "abdruck": "7b1bde58f2c6be89", + "probleme": [] + }, + "[\"system\", \"Daten sichern\"]": { + "abdruck": "a346f050ca9ca3dd", + "probleme": [] + }, + "[\"system\", \"Deployment prüfen\"]": { + "abdruck": "58f45050c3d6ddf2", + "probleme": [] + }, + "[\"system\", \"Dienststatus melden\"]": { + "abdruck": "53692da8a39ee4ee", + "probleme": [] + }, + "[\"system\", \"Fehlerseite anzeigen\"]": { + "abdruck": "ac91cfa7c4443a2c", + "probleme": [ + { + "feature": "system", + "feld": "testen", + "funktion": "Fehlerseite anzeigen", + "ganzes_feld": true, + "original": "", + "problem": "Funktion ohne Ziel, Regeln und Testen", + "regel": "Jede Funktion hat Ziel, Regeln oder Testschritte — nie nur einen Titel", + "vorschlag": "Fehlerseite auslösen\nFehlerseite prüft Inhalt\nFehlerseite angezeigt" + } + ] + }, + "[\"system\", \"Flow-Grenze sperren\"]": { + "abdruck": "7f8f2ff111578aee", + "probleme": [] + }, + "[\"system\", \"Neuindizierung starten\"]": { + "abdruck": "baab3281c00716ea", + "probleme": [] + }, + "[\"system\", \"Normalisierung prüfen\"]": { + "abdruck": "1d078a8c8739dce7", + "probleme": [] + }, + "[\"system\", \"Preview prüfen\"]": { + "abdruck": "36bfb9af2c395881", + "probleme": [] + }, + "[\"system\", \"Promptversion aktivieren\"]": { + "abdruck": "cf621d5db06669cd", + "probleme": [] + }, + "[\"system\", \"Promptversion löschen\"]": { + "abdruck": "4831087ddffa3a02", + "probleme": [] + }, + "[\"system\", \"Promptversionen verwalten\"]": { + "abdruck": "271419aa16b295c1", + "probleme": [] + }, + "[\"system\", \"Restore-Vorschau prüfen\"]": { + "abdruck": "79007d6f20f9f259", + "probleme": [] + }, + "[\"system\", \"Simulation ausführen\"]": { + "abdruck": "872c7daa285566a6", + "probleme": [] + }, + "[\"system\", \"Systemzustand zurücksetzen\"]": { + "abdruck": "aad55d89505af36e", + "probleme": [] + }, + "[\"system\", \"Verzeichnis bereinigen\"]": { + "abdruck": "c3a169bd14fc72ff", + "probleme": [] + }, + "[\"tags\", \"\"]": { + "abdruck": "0137270973dfabae", + "probleme": [] + }, + "[\"tags\", \"Tag-Rebuild-Auftrag ausführen\"]": { + "abdruck": "84922f94b261c3aa", + "probleme": [] + }, + "[\"tags\", \"Tag-Rebuild-Status abfragen\"]": { + "abdruck": "3b7cd1dfa6cce19b", + "probleme": [] + }, + "[\"tags\", \"Tag-Zuordnung bearbeiten\"]": { + "abdruck": "2c07ad450bffd805", + "probleme": [ + { + "feature": "tags", + "feld": "testen", + "funktion": "Tag-Zuordnung bearbeiten", + "ganzes_feld": true, + "original": "", + "problem": "Testen leer stattTestschritte zu enthalten", + "regel": "Jede Funktion hat Ziel, Regeln oder Testschritte — nie nur einen Titel", + "vorschlag": "[Tag auswählen]\n[Zuweisung ändern]\n[Änderung bestätigen]" + } + ] + }, + "[\"tags\", \"Tags auflisten\"]": { + "abdruck": "b9eeaa47d21451b3", + "probleme": [] + }, + "[\"tags\", \"Tags bearbeiten\"]": { + "abdruck": "b499aeba37fc4762", + "probleme": [] + }, + "[\"tags\", \"Tags suchen\"]": { + "abdruck": "bc800e0107e9e99e", + "probleme": [] + }, + "[\"titel\", \"\"]": { + "abdruck": "b771a18e13aba81c", + "probleme": [] + }, + "[\"titel\", \"Titel aktualisieren\"]": { + "abdruck": "5fd71fcaa6cf86b1", + "probleme": [] + }, + "[\"titel\", \"Titelvorschläge laden\"]": { + "abdruck": "7c5913d783929e93", + "probleme": [] + }, + "[\"uploads\", \"\"]": { + "abdruck": "bfee1441da40c5ca", + "probleme": [] + }, + "[\"uploads\", \"Berechtigungsmodus ändern\"]": { + "abdruck": "fe6824d5e74aa716", + "probleme": [] + }, + "[\"uploads\", \"Datei hochladen\"]": { + "abdruck": "097eed6431a3436c", + "probleme": [] + }, + "[\"uploads\", \"Upload entfernen\"]": { + "abdruck": "9743e4d26d8c92e4", + "probleme": [] + }, + "[\"uploads\", \"Uploads auflisten\"]": { + "abdruck": "5b8d1649c1128f87", + "probleme": [] + }, + "[\"verlauf\", \"\"]": { + "abdruck": "1ad061f8898591f2", + "probleme": [] + }, + "[\"verlauf\", \"Verankerungen extrahieren\"]": { + "abdruck": "c8b5823dc343a021", + "probleme": [] + }, + "[\"verlauf\", \"Verlauf abrufen\"]": { + "abdruck": "512f74a4d7093956", + "probleme": [] + }, + "[\"verlauf\", \"Verlauf löschen\"]": { + "abdruck": "3cd576b5811fc821", + "probleme": [] + }, + "[\"versionen\", \"\"]": { + "abdruck": "a2ff5a390898eadf", + "probleme": [] + }, + "[\"versionen\", \"Version ableiten\"]": { + "abdruck": "23c5eaf21b66893b", + "probleme": [] + }, + "[\"versionen\", \"Version aktivieren\"]": { + "abdruck": "f8c322e31e37620c", + "probleme": [] + }, + "[\"versionen\", \"Version einlesen\"]": { + "abdruck": "7a8b97e289a62d9e", + "probleme": [] + }, + "[\"versionen\", \"Version erstellen\"]": { + "abdruck": "0c0a4c71ade40480", + "probleme": [] + }, + "[\"versionen\", \"Versionvorschau anzeigen\"]": { + "abdruck": "eab759a8abfc20e7", + "probleme": [] + } + }, + "verworfen": {} +} diff --git a/daten/MtoRagSystem/.verzeichnis b/daten/MtoRagSystem/.verzeichnis new file mode 100644 index 0000000..22ab7ba --- /dev/null +++ b/daten/MtoRagSystem/.verzeichnis @@ -0,0 +1 @@ +/home/arbeit/arbeit/MtoRagSystem diff --git a/daten/MtoRagSystem/anbindung.md b/daten/MtoRagSystem/anbindung.md new file mode 100644 index 0000000..1f301e8 --- /dev/null +++ b/daten/MtoRagSystem/anbindung.md @@ -0,0 +1,157 @@ + +Anbindung +---------------------------------------- + +optional +---------------------------------------- + +Bindet einen externen Server kontrolliert an +---------------------------------------- + +- Ein Token wird nie gespeichert, nur sein Name +- Eine Anbindung startet eingeschaltet, ohne Chatfreigabe +- Eine Anbindung wirkt erst nach Freigabe +- Ein Import führt nie ein Werkzeug aus +- Ein Import liest keine Inhalte +- Anweisungen fremder Inhalte werden entfernt +- Ein Transport über Standardeingabe ist gesperrt +- Nur verschlüsselte Verbindungen sind erlaubt +- Interne Netze sind gesperrt +- Weiterleitungen werden nicht verfolgt +- Protokolle enthalten nur Metadaten +- Der Bereich braucht die höchste Rolle +---------------------------------------- + +Anbindung anlegen + +- Speichern folgt einer bestandenen Prüfung +- Ein Speichern ändert keine Antwort +- Ein Formulartoken ist Pflicht + +- Menüeintrag MCP Quellen wählen +- Reiter Anbindung anlegen wählen +- Formular ausfüllen +- Anbindung speichern +- Anbindung in der Übersicht +---------------------------------------- + +Anbindung prüfen + +Testet die Angaben gegen Erlaubnisliste und Regeln + +- Ohne Onlinetest entstehen keine Abrufe +- Das Ergebnis nennt den Grund +- Die Prüfung speichert nicht + +- Formular ausfüllen +- LMB auf Anbindung prüfen +- Prüfergebnis mit Begründung +---------------------------------------- + +Anbindung bearbeiten + +- Änderungen wirken erst nach dem Speichern +- Werkzeugdaten bleiben erhalten +- Zugewiesene Inhalte bleiben am Kurznamen gebunden + +- Übersicht öffnen +- LMB auf Bearbeiten +- Formular vorbefüllt +---------------------------------------- + +Anbindung umschalten + +Legt eine Anbindung vorübergehend still + +- Ausgewählte Inhalte bleiben gespeichert +- Eine stillgelegte Anbindung wirkt nicht +- Wiedereinschalten braucht keine neue Freigabe + +- Übersicht öffnen +- LMB auf Deaktivieren +- Zustandsmarke wechselt +---------------------------------------- + +Anbindung entfernen + +- Der Raum wird zuvor abgeschaltet +- Eine Rückfrage geht voraus + +- Übersicht öffnen +- LMB auf Entfernen +- Bestätigen +- Anbindung verschwindet +---------------------------------------- + +Ressource übernehmen + +Schreibt eine gefundene Ressource in die Anbindung + +- Nur erkannte Ressourcen sind übernehmbar +- Die Übernahme schaltet den Chat nicht ein + +- Serverinhalte aktualisieren +- LMB auf Ressource übernehmen +- Ressource in der Anbindung +---------------------------------------- + +Serverinhalte aktualisieren + +Erkennt Ressourcen, Werkzeuge und Vorlagen als Metadaten + +- Kein Werkzeug wird ausgeführt +- Vorlagen werden erkannt, nie ausgeführt +- Ressourcen werden nicht gelesen +- Gefundene Werkzeuge sind zunächst gesperrt + +- Übersicht öffnen +- LMB auf Inhalte aktualisieren +- Gefundene Inhalte sichtbar +---------------------------------------- + +Anbindung online prüfen + +Prüft eine gespeicherte Anbindung im Terminal + +- Geprüft werden Freigabe und ein Inhalt +- Ohne prüfbaren Inhalt bricht der Lauf ab +- Ein fehlendes Geheimnis blockt vorher +- Anfragen werden bereinigt protokolliert + +- Kommando mit Servernamen aufrufen +- Prüfbericht sichtbar +---------------------------------------- + +Schutzregeln ansehen + +Zeigt Grenzen und Systemprüfung der Anbindungen + +- Die Anzeige ruft nichts extern ab +- Freie Werkzeugnutzung ist gesperrt + +- Menüeintrag Quellen wählen +- Reiter Sicherheit wählen +- Grenzen und Prüfstand sichtbar +---------------------------------------- + +Freigaben prüfen + +Prüft die Serverliste der Grundeinstellung + +- Kein Transport wird geöffnet +- Das Ergebnis nennt Server, Fehler und Warnungen + +- Kommando aufrufen +- Prüfstand je Regel sichtbar +---------------------------------------- + +Brücke trocken testen + +Prüft Bereinigung und Belegbrücke ohne Serverkontakt + +- Nur lokale Nutzlasten werden geprüft +- Kein Transport, keine Chatwirkung +- Fremde Anweisungsmarker fallen weg + +- Kommando aufrufen +- Bereinigte Nutzlast sichtbar diff --git a/daten/MtoRagSystem/antwort.md b/daten/MtoRagSystem/antwort.md new file mode 100644 index 0000000..3fb4237 --- /dev/null +++ b/daten/MtoRagSystem/antwort.md @@ -0,0 +1,115 @@ + +Antwort +---------------------------------------- + +kern +---------------------------------------- + +Beantwortet eine Frage aus geprüften Quellen +---------------------------------------- + +- Nur Aussagen aus den Quellen +- Fehlende Werte werden nicht erfunden +- Keine Schätzung ersetzt einen fehlenden Wert +- Fakten und Ableitungen bleiben getrennt +- Ableitungen sind als solche markiert +- Eignung gilt als belegpflichtige Aussage +- Negativaussagen brauchen einen Quellenbeleg +- Werbesprache ist untersagt +- Sprache der Frage gilt für die Antwort +- Interne Belegkennungen bleiben auf Nachfrage beschränkt +- Interne Denktexte erreichen niemanden +- Die genutzte Datenbasis steht an der Antwort +- Trefferzahl aus Wissen und Shop liegt bei +- Die Antwortdauer wird ausgewiesen +- Ein Vertrauensabzeichen steht an der Antwort +- Wiederholungsschleifen werden sichtbar abgeschnitten +- Transparente Unsicherheit schlägt sichere Falschaussage +---------------------------------------- + +Frage stellen + +Sendet eine Frage und empfängt die Antwort laufend + +- Leere Frage wird abgewiesen +- Höchstens 10000 Zeichen +- Warnung ab 7500 Zeichen +- Erneutes Senden bleibt bis zum Ende gesperrt +- Entwurf überlebt einen Neuladen +- Unterbrochener Empfang wird fortgesetzt +- Ein Lauf verfällt nach 900 Sekunden +- Ein stehender Lauf wird beendet + +- Text eingeben +- Enter drücken +- Frage im Verlauf +- Antwort läuft ein +---------------------------------------- + +Antwort abbrechen + +Beendet eine laufende Antwort vorzeitig + +- Nur während des Empfangs möglich +- Der Serverlauf arbeitet weiter +- Der Vermerk gilt nur in der laufenden Ansicht +- Nach dem Neuladen steht die volle Antwort + +- Frage stellen +- LMB auf Abbrechen +- Abbruchvermerk im Verlauf +---------------------------------------- + +Frage erneut senden + +Wiederholt die Frage mit anderer Einstellung + +- Angeboten sind nur ungenutzte Varianten +- Der Klick setzt die Einstellung passend +- Während des Empfangs gesperrt + +- Frage stellen +- LMB auf eine Variante +- Frage erneut im Verlauf +---------------------------------------- + +Antwortmodus wählen + +Wählt zwischen gründlicher und schneller Antwort + +- Zwei Werte: Standard und schnell +- Ungültiger Wert fällt auf Standard +- Der schnelle Modus nutzt ein anderes Modell +- Der schnelle Modus antwortet ungenauer +- Die Wahl gilt für die ganze Unterhaltung + +- Chat-Einstellungen öffnen +- Antwortmodus wählen +- Modus an der nächsten Antwort +---------------------------------------- + +Datenbasis wählen + +Legt fest, ob Wissen oder Shopdaten zählen + +- Vier Werte: automatisch, Wissen, Shop, beides +- Unbekannter Wert fällt auf automatisch +- Nur Wissen löst keine Shopsuche aus +- Die genutzte Basis steht in der Antwort + +- Chat-Einstellungen öffnen +- Datenbasis wählen +- Basis in der Zusammenfassung +---------------------------------------- + +Folgeaktion auslösen + +Sendet eine vorgeschlagene Folgefrage sofort + +- Der Fragetext kommt vom Server +- Angebot entfällt bei ablehnender Antwort +- Während des Empfangs passiert nichts + +- Frage stellen +- LMB auf eine Folgeaktion +- Folgefrage im Verlauf diff --git a/daten/MtoRagSystem/auftrag.md b/daten/MtoRagSystem/auftrag.md new file mode 100644 index 0000000..6d78ced --- /dev/null +++ b/daten/MtoRagSystem/auftrag.md @@ -0,0 +1,85 @@ + +Auftrag +---------------------------------------- + +kern +---------------------------------------- + +Führt Indexierung und Neuaufbau nachvollziehbar aus +---------------------------------------- + +- Jeder Lauf hinterlässt einen Auftrag +- Der Auftrag nennt Typ, Zustand, Zeiten und Person +- Fünf Zustände bis zum Abbruch +- Nur der Neuaufbau schreibt eine Protokolldatei +- Nur ein Indexlauf läuft gleichzeitig +- Ein Strukturwechsel erzwingt einen sichtbaren Neuaufbau +- Ein unvollständiger Aufbau bricht ab +---------------------------------------- + +Aufträge einsehen + +Zeigt den Verlauf aller Indexläufe + +- Neueste Aufträge stehen oben +- Der Fehlertext endet in der Liste bei 120 Zeichen + +- Menüeintrag Aufträge wählen +- Auftragsliste sichtbar +---------------------------------------- + +Auftrag verfolgen + +Beobachtet einen einzelnen Lauf bis zum Ende + +- Die Kennung muss dem Kennungsformat folgen +- Der Stand wird zweisekündlich nachgeladen +- Geliefert werden Typ, Zustand, Zeiten und Fehler +- Das Nachladen endet mit dem Auftrag + +- Auftragsliste öffnen +- LMB auf eine Kennung +- Zustandsmarke wechselt +---------------------------------------- + +Index neu aufbauen + +Überführt vorgemerkte Änderungen in den Index + +- Nur die höchste Rolle darf starten +- Der Auftrag beginnt wartend +- Die Arbeit läuft im Hintergrund +- Ein Fehlstart markiert den Auftrag als gescheitert +- Nach Erfolg wird der Zwischenspeicher geleert + +- Dokumentliste öffnen +- LMB auf Index neu aufbauen +- Bestätigen +- Auftragsseite sichtbar +---------------------------------------- + +Auftrag ausführen + +Startet einen vorhandenen Auftrag im Terminal + +- Unbekannte Kennung wird abgewiesen +- Abgeschlossene Aufträge laufen nicht erneut +- Ein Trockenlauf vermeidet schwere Schritte + +- Kommando mit Kennung aufrufen +- Zustandszeile sichtbar +---------------------------------------- + +Index hart neu aufbauen + +Baut Chunks, Vektoren und Tags vollständig neu + +- Ohne Erzwingen bricht der Lauf ab +- Vier Schritte laufen in fester Reihenfolge +- Einzelne Schritte lassen sich überspringen +- Ein gescheiterter Schritt beendet den Lauf +- Ein Trockenlauf schreibt keine Indexdatei + +- Kommando mit Erzwingen aufrufen +- Vier Schritte sichtbar +- Gesundheitsstand am Ende diff --git a/daten/MtoRagSystem/batch.md b/daten/MtoRagSystem/batch.md new file mode 100644 index 0000000..82f685c --- /dev/null +++ b/daten/MtoRagSystem/batch.md @@ -0,0 +1,118 @@ + +Batch +---------------------------------------- + +optional +---------------------------------------- + +Importiert viele Dokumente in einem Lauf +---------------------------------------- + +- Höchstens 250 Dateien je Upload +- Erlaubt sind PDF, Text, Markdown und Word +- Geschützte PDF gelten als nicht verarbeitbar +- Doppelte Prüfsummen werden übersprungen +- Höchstens ein Neuaufbau je Lauf +- Ohne Indexwirkung entfällt der Neuaufbau +- Der Eingang wird nach dem Lauf geräumt +- Je gelungener Lauf entsteht ein Bericht +---------------------------------------- + +Batch hochladen + +Lädt viele Dateien gesammelt und verarbeitet sie + +- Ohne Datei bricht der Lauf ab +- Titel entstehen aus Dateinamen oder Manifest +- Schwache Titel werden markiert +- Wissenskarten entstehen nur auf Wunsch +- Aktivierung ohne Wissenskarte wird verworfen + +- Menüeintrag Batch wählen +- Dateien wählen +- Batch starten +- Ergebniszahlen sichtbar +---------------------------------------- + +Batch vorab prüfen + +Prüft einen Eingang ohne jede Schreibwirkung + +- Kein Dokument wird importiert +- Kein Modell wird aufgerufen +- Dateityp, Prüfsumme und Dubletten werden geprüft +- Zusatzschalter erzeugen eine Warnung + +- Kommando im Trockenlauf aufrufen +- Bericht mit Dateiliste sichtbar +---------------------------------------- + +Batch importieren + +Importiert einen Eingang im Terminal + +- Der Import ist über Prüfsummen wiederholbar +- Ohne eindeutigen Benutzer bricht der Lauf ab +- Der Kommandolauf hat keine Dateigrenze +- Erfolgreiche Quellen verlassen den Eingang +- Fehler und Übersprungenes landen getrennt +- Abgeleitete Versionen bleiben ohne Schalter inaktiv + +- Kommando mit Eingang aufrufen +- Bericht als Datei geschrieben +---------------------------------------- + +Berichte auflisten + +- Höchstens 100 Berichte, neueste oben +- Defekte Berichte werden übersprungen + +- Menüeintrag Batch wählen +- Berichtsliste sichtbar +---------------------------------------- + +Bericht ansehen + +Zeigt einen Lauf je Datei und Schritt + +- Die Kennung darf keine Sonderzeichen tragen +- Ein unbekannter Bericht meldet einen Fehler +- Die Ansicht startet keine Verarbeitung + +- Berichtsliste öffnen +- LMB auf Anzeigen +- Schritte und Dateien sichtbar +---------------------------------------- + +Bericht herunterladen + +- Zwei Formate: JSON und Markdown +- Eine fehlende Datei meldet einen Fehler + +- Berichtsliste öffnen +- LMB auf ein Format +- Datei im Download +---------------------------------------- + +Bericht löschen + +- Beide Formate fallen zusammen weg +- Dokumente und Index bleiben unberührt + +- Berichtsliste öffnen +- LMB auf Löschen +- Bestätigen +- Bericht verschwindet +---------------------------------------- + +Eingang bereinigen + +Räumt leere Ordner und falsche Ablagen auf + +- Die Bereinigung wirkt nur im Importverzeichnis +- Namenskollisionen bekommen einen Zähler +- Kein Einfluss auf Suche oder Antwort + +- Menüeintrag Batch wählen +- LMB auf Eingang bereinigen +- Zahl geräumter Ordner sichtbar diff --git a/daten/MtoRagSystem/beleg.md b/daten/MtoRagSystem/beleg.md new file mode 100644 index 0000000..a2e1565 --- /dev/null +++ b/daten/MtoRagSystem/beleg.md @@ -0,0 +1,71 @@ + +Beleg +---------------------------------------- + +kern +---------------------------------------- + +Weist nach, worauf eine Aussage sich stützt +---------------------------------------- + +- Belegquellen sind Wissen, Shop und URL-Inhalte +- Frühere Antworten belegen keine Fachwerte +- Jede Antwort erhält genau einen Belegzustand +- Direkt belegt gilt nur bei einem tragenden Beleg +- Verstreute Anforderungen ergeben schwach belegt +- Fehlende Pflichtangabe ergibt nicht vollständig belegt +- Ohne Quelle gilt nicht geprüft +- Jeder Beleg trägt eine Stärke +- Fehlende Pflichtmerkmale werden einzeln benannt +- Direkte Dokumentquellen stehen unter der Antwort +- Höchstens vier Quellentitel erscheinen +- Eine genutzte Uploaddatei bleibt in der Quellenliste +---------------------------------------- + +Belegdetails aufklappen + +Zeigt Prüfsignale hinter der Vertrauenslage + +- Ohne echte Signale erscheint keine Belegkarte +- Konflikte werden gesondert benannt +- Die Anzeige gilt für alle sichtbaren Antworten + +- Frage stellen +- LMB auf technische Details +- Claims und Belege sichtbar +---------------------------------------- + +Zusatzinfos umschalten + +Blendet Quellen und Folgeaktionen ein + +- Nur genutzte Quellen werden gelistet +- Die Einstellung überlebt einen Neuladen + +- Chat-Einstellungen öffnen +- Zusatzinfos umschalten +- Quellenblock verschwindet +---------------------------------------- + +Statusprotokoll einschalten + +Macht Prüf- und Quellenschritte sichtbar + +- Der Bereich öffnet sich beim Einschalten +- Statusinfos stehen neben dem Verlauf +- Fehlermeldungen bleiben immer sichtbar +- Prompts und Geheimnisse erscheinen nie + +- Chat-Einstellungen öffnen +- Statusprotokoll einschalten +- Seitenbereich mit Zeitleiste sichtbar +---------------------------------------- + +Statusprotokoll schließen + +- Schließen schaltet die Einstellung aus +- Der Zustand überlebt einen Neuladen + +- Statusprotokoll einschalten +- LMB auf Schließen im Bereich +- Bereich verschwindet diff --git a/daten/MtoRagSystem/benutzer.md b/daten/MtoRagSystem/benutzer.md new file mode 100644 index 0000000..4b34aa4 --- /dev/null +++ b/daten/MtoRagSystem/benutzer.md @@ -0,0 +1,82 @@ + +Benutzer +---------------------------------------- + +kern +---------------------------------------- + +Regelt Zugang und Rollen der Menschen +---------------------------------------- + +- Ein Passwort wird nur verschlüsselt gespeichert +- Eine E-Mail ist eindeutig +- Ein deaktiviertes Konto wird abgewiesen +- Niemand deaktiviert sich selbst +- Der letzte oberste Verwalter bleibt geschützt +- Die Verwaltung braucht die höchste Rolle +- Ein Konto lässt sich nicht löschen +- Deaktivierung beendet die laufende Sitzung +---------------------------------------- + +Benutzer filtern + +- Filter nach Text, Zustand und Rolle +- Die Suche trifft Namen, E-Mail und Abteilung +- Ein ungültiger Wert fällt auf alle +- Die Gesamtzahlen bleiben ungefiltert + +- Menüeintrag Benutzer wählen +- Filter setzen +- LMB auf Filtern +- Trefferzahl sichtbar +---------------------------------------- + +Benutzer erstellen + +- Das Passwort braucht acht Zeichen +- Die Wiederholung muss übereinstimmen +- Mindestens eine Rolle ist Pflicht +- Unbekannte Rollen werden abgewiesen +- Die Grundrolle ist nicht vergebbar + +- Benutzerliste öffnen +- Formular ausfüllen +- Rollen ankreuzen +- Erstellen +- Benutzer in der Liste +---------------------------------------- + +Benutzer bearbeiten + +- Leeres Passwortfeld ändert nichts +- Die oberste Rolle entzieht sich niemand selbst +- Namen enden bei 100 Zeichen +- Abteilung endet bei 120 Zeichen + +- Benutzerliste öffnen +- LMB auf Bearbeiten +- Felder ändern +- Speichern +- Änderung in der Liste +---------------------------------------- + +Benutzer umschalten + +Sperrt oder öffnet den Zugang sofort + +- Bestehende Rollen bleiben erhalten + +- Benutzerliste öffnen +- LMB auf Zustand +- Bestätigen +- Zustandsspalte wechselt +---------------------------------------- + +Benutzer im Terminal anlegen + +- Doppelte E-Mail wird abgewiesen +- Die Eingabe erfolgt abgefragt + +- Kommando aufrufen +- Angaben eintragen +- Benutzer angelegt diff --git a/daten/MtoRagSystem/betriebspruefung.md b/daten/MtoRagSystem/betriebspruefung.md new file mode 100644 index 0000000..229cd66 --- /dev/null +++ b/daten/MtoRagSystem/betriebspruefung.md @@ -0,0 +1,117 @@ + +Betriebsprüfung +---------------------------------------- + +optional +---------------------------------------- + +Bewertet Betriebsreife vor der Abnahme +---------------------------------------- + +- Jede Prüfung liest nur lokale Angaben +- Kein Chat, kein Shop, kein Modell läuft +- Ein Fehler setzt den Gesamtstand +- Ein fehlender Nachweis wird zur Warnung +- Ein Nachweis wird nie stillschweigend angenommen +- Geheimnisse bleiben Verweise +- Der Restore-Nachweis bleibt Betreiberaufgabe +- Das System richtet keine Zeitsteuerung ein +- Jedes Ergebnis landet bereinigt im Protokoll +---------------------------------------- + +Betrieb überblicken + +Fasst alle Prüfstände und die letzte Sicherung + +- Die Seite bewertet bei jedem Aufruf neu +- Nur ausgelöste Prüfungen landen im Protokoll +- Der nächste sinnvolle Schritt steht dabei + +- Menüeintrag Betrieb wählen +- Gesamtstand und Teilstände sichtbar +---------------------------------------- + +Sicherheit prüfen + +Prüft Rollen, Geheimnisse und Grenzen + +- Die Prüfung ersetzt kein externes Audit +- Geheimniswerte werden nicht gelesen + +- Betriebsseite öffnen +- LMB auf Sicherheit prüfen +- Fallliste mit Ständen sichtbar +---------------------------------------- + +Sicherungsweg prüfen + +Bewertet Pfad, Umfang und Restore-Nachweis + +- Es entsteht keine Sicherung +- Ein Restore-Erfolg wird nicht behauptet + +- Betriebsseite öffnen +- LMB auf Sicherungsweg prüfen +- Prüfpunkte sichtbar +---------------------------------------- + +Zeitsteuerung prüfen + +Bewertet Automatik, Turnus und Betreibernachweise + +- Der Betreiber dokumentiert Automatik selbst +- Nicht beschreibbare Pfade erzeugen Hinweise + +- Betriebsseite öffnen +- LMB auf Zeitsteuerung prüfen +- Nachweistabelle sichtbar +---------------------------------------- + +Protokoll einsehen + +Zeigt die zuletzt ausgelösten Prüfungen + +- Keine Prompts und keine Rohantworten +- Keine Geheimnisse und keine Zugangsdaten +- Der Text endet bei 220 Zeichen +- Höchstens 50 Einträge bleiben erhalten +- Die Anzeige zeigt die letzten acht + +- Betriebsseite öffnen +- Protokollbereich lesen +- Letzte Prüfungen sichtbar +---------------------------------------- + +Abnahmebericht ausgeben + +Lädt den bereinigten Bericht zur Abnahme + +- Zwei Formate: JSON und Markdown +- Die Datengrenze steht im Bericht +- Erledigte Aufgaben fallen weg +- Der Export startet keine Prüfung + +- Betriebsseite öffnen +- Format wählen +- Bericht im Download +---------------------------------------- + +Betriebsreife im Terminal prüfen + +- Nur ein grüner Stand endet ohne Fehler +- Warnungen ändern den Ausgang nicht + +- Kommando aufrufen +- Fallliste sichtbar +---------------------------------------- + +Unterlagen öffnen + +Zeigt Runbook und Checklisten im Adminbereich + +- Nur Markdown aus dem Projektverzeichnis +- Die Anzeige ist rein lesend + +- Menüeintrag Leitfäden wählen +- Dokument wählen +- Inhalt sichtbar diff --git a/daten/MtoRagSystem/claim.md b/daten/MtoRagSystem/claim.md new file mode 100644 index 0000000..3b790d7 --- /dev/null +++ b/daten/MtoRagSystem/claim.md @@ -0,0 +1,51 @@ + +Claim +---------------------------------------- + +kern +---------------------------------------- + +Prüft einzelne Aussagen der Antwort gegen Belege +---------------------------------------- + +- Geprüft werden Werte, Preise und Artikelnummern +- Geprüft werden URLs und Rollencodes +- Geprüft werden Relationen und Kompatibilitätsaussagen +- Ein Claim ohne Quelle gilt als unbelegt +- Ein unbelegter Claim setzt ein Prüfsignal +- Unbelegte Claims werden benannt +- Höchstens fünf Beispiele erscheinen +- Rollencodes gelten nur bei genauer Übereinstimmung +- Relationen brauchen beide Partner in einem Dokument +- Eine leere Antwort gilt als ungeprüft +- Sieben Claim-Arten stehen fest +---------------------------------------- + +Antwort bewerten + +Meldet falsche Zuordnung oder Quellenfehler zurück + +- Zwei Werte: zustimmend und ablehnend +- Ablehnung erlaubt einen Kommentar +- Kommentar wird auf 2000 Zeichen gekürzt +- Bewertung braucht eine fertige Antwort +- Eine fremde Antwort wird abgewiesen +- Die Oberfläche sperrt nach dem Speichern +- Ein erneuter Aufruf überschreibt die Bewertung +- Frage und Antwort werden mitgespeichert + +- Frage stellen +- LMB auf eine Bewertung +- Bestätigung sichtbar +---------------------------------------- + +Prompt kopieren + +Übernimmt die eigene Frage in die Zwischenablage + +- Kopiert wird nur der Fragetext +- Erfolg wird kurz gemeldet + +- Frage stellen +- LMB auf Kopieren +- Rückmeldung an der Schaltfläche diff --git a/daten/MtoRagSystem/diagnose.md b/daten/MtoRagSystem/diagnose.md new file mode 100644 index 0000000..59ca8f0 --- /dev/null +++ b/daten/MtoRagSystem/diagnose.md @@ -0,0 +1,84 @@ + +Diagnose +---------------------------------------- + +optional +---------------------------------------- + +Untersucht einzelne Teile des Antwortwegs +---------------------------------------- + +- Diagnosen ändern Antwortgüte und Wahrheitssicherung nicht +- Prompts und Rohantworten werden nie ausgegeben +- Betriebsfunktionen beeinflussen die Antwort nicht +---------------------------------------- + +Im Terminal fragen + +Stellt Fragen an das System ohne Oberfläche + +- Die Antwort läuft in Stücken ein +- Statusmeldungen stehen dazwischen +- Der Lauf löst echte Modellaufrufe aus + +- Kommando aufrufen +- Frage eintragen +- Antwort läuft ein +---------------------------------------- + +Suchweg testen + +Prüft den hybriden Suchweg zu einer Frage + +- Leere Frage wird abgewiesen +- Die Ausgabe nennt Dauer und Trefferzahl + +- Kommando mit Frage aufrufen +- Trefferliste sichtbar +---------------------------------------- + +Faktenabdeckung prüfen + +Prüft, wie gut Fakten eine Frage abdecken + +- Eine leere Frage wird abgewiesen +- Eine Mindestgüte ist wählbar + +- Kommando mit Frage aufrufen +- Abdeckung mit Zusammenfassung sichtbar +---------------------------------------- + +Ankerauflösung testen + +Prüft die Auflösung einer Folgefrage trocken + +- Kein Eingriff in die Laufzeit +- Mehrdeutige Anker werden verworfen +- Eine genannte Artikelnummer schlägt jeden Anker + +- Kommando mit Folgefrage aufrufen +- Auflösungsbericht sichtbar +---------------------------------------- + +Verlaufsanker auslesen + +Zieht Bezugsanker aus einem Gesprächsverlauf + +- Anker belegen keine Fachwerte +- Eingabe per Argument, Datei oder Strom +- Ein eingebauter Rauchtest ist wählbar + +- Kommando mit Rauchtest aufrufen +- Ankerliste sichtbar +---------------------------------------- + +Fakten inspizieren + +Untersucht gespeicherte Fakten der Chunkdatei + +- Eine fehlende Chunkdatei meldet einen Fehler +- Nur lesender Zugriff auf den Index +- Filter nach Text, Typ und Anzahl + +- Kommando mit Suchtext aufrufen +- Trefferliste sichtbar diff --git a/daten/MtoRagSystem/dokument.md b/daten/MtoRagSystem/dokument.md new file mode 100644 index 0000000..a4ae5a2 --- /dev/null +++ b/daten/MtoRagSystem/dokument.md @@ -0,0 +1,107 @@ + +Dokument +---------------------------------------- + +kern +---------------------------------------- + +Führt eine Wissensquelle über ihre Versionen +---------------------------------------- + +- Ein Dokument hält mehrere Versionen +- Genau eine Version ist aktiv +- Tags hängen am Dokument, nicht an der Version +- Schreiben an Dokument oder Version ändert den Index nicht +---------------------------------------- + +Dokumente filtern + +Grenzt die Liste nach Zustand und Pflege ein + +- Sechs Filter: Suche, Status, Index, Version, Titel, Tags +- Unbekannter Filterwert fällt auf alle +- Die Suche trifft Titel, Kennung und Dateiname +- Kennzahlen zählen immer den Gesamtbestand + +- Dokumentliste öffnen +- Filter setzen +- LMB auf Filtern +- Trefferzahl sichtbar +---------------------------------------- + +Dokument hochladen + +Legt eine Wissensquelle mit erster Version an + +- Die Datei ist Pflicht +- Ohne Titel dient der Dateiname als Titel +- Ein schwacher Titel bekommt einen Prüfhinweis +- Version eins entsteht aktiv +- Je Version wird eine Prüfsumme gespeichert +- Der Index bleibt bis zum Neuaufbau unverändert + +- Dokumentliste öffnen +- LMB auf neues Dokument +- Datei wählen +- Speichern +- Dokumentseite sichtbar +---------------------------------------- + +Titel ändern + +Ersetzt einen schwachen Titel fachlich + +- Leerer Titel wird abgewiesen +- Höchstens 255 Zeichen +- Der Prüfhinweis entfällt danach +- Index und Antwortlogik bleiben unberührt + +- Dokumentseite öffnen +- Titel ändern +- Speichern +- Titel als geprüft markiert +---------------------------------------- + +Titel vorschlagen lassen + +Erzeugt Titelkandidaten aus dem Dokumentanfang + +- Der Ausschnitt endet bei 9000 Zeichen +- Höchstens sechs Vorschläge +- Höchstens 120 Zeichen je Vorschlag +- Zu kurze Kandidaten fallen weg +- Ein Klick füllt nur das Feld +- Dokument, Version und Index bleiben unberührt + +- Dokumentseite öffnen +- LMB auf Titel vorschlagen +- Kandidat wählen +- Titelfeld gefüllt +---------------------------------------- + +Indexbereitschaft ansehen + +Zeigt, was den Index bisher nicht erreicht hat + +- Offene Änderungen werden gezählt +- Gelöschte Dokumente im Index werden benannt + +- Dokumentliste öffnen +- Bereitschaftsblock lesen +- Zahl offener Änderungen sichtbar +---------------------------------------- + +Dokument löschen + +Entfernt Dokument, Versionen und Dateien endgültig + +- Nur die höchste Rolle darf löschen +- Ein laufender Neuaufbau verhindert das Löschen +- Versionsdateien werden mitgelöscht +- Ein Auftrag hält den Vorgang fest +- Der Index ändert sich beim nächsten Neuaufbau + +- Dokumentliste öffnen +- LMB auf Löschen +- Bestätigen +- Dokument verschwindet diff --git a/daten/MtoRagSystem/evalfall.md b/daten/MtoRagSystem/evalfall.md new file mode 100644 index 0000000..7438a6b --- /dev/null +++ b/daten/MtoRagSystem/evalfall.md @@ -0,0 +1,77 @@ + +Evalfall +---------------------------------------- + +optional +---------------------------------------- + +Beschreibt einen prüfbaren Fall für die Antwortgüte +---------------------------------------- + +- Neun Falltypen stehen im Adminbereich +- Ein zehnter Typ läuft nur im Terminal +- Eine Fallkennung ist projektweit eindeutig +- Pflichtfelder sind Kennung, Typ und Frage +- Fälle liegen als Zeilendatei je Typ und Bereich +- Schreiben erfolgt mit ausschließender Sperre +---------------------------------------- + +Bereich wählen + +Schaltet zwischen Systembasis und Fachbereich + +- Der Bereich prägt jede weitere Handlung +- Fachbereiche liegen in eigenen Ordnern + +- Menüeintrag Eval Suite wählen +- LMB auf einen Bereichsreiter +- Fälle des Bereichs sichtbar +---------------------------------------- + +Evalfall anlegen + +- Doppelte Kennung wird abgewiesen +- Erwartung muss ein Objekt sein +- Verlauf muss eine Liste sein +- Ein Fehler verhindert jede Änderung + +- Menüeintrag Eval Suite wählen +- LMB auf neuer Test +- Formular ausfüllen +- Absenden +- Fall in der Datei +---------------------------------------- + +Evalfall geführt anlegen + +Legt einen Fall über einen Assistenten an + +- Eigener Entwurf mit eigener Fehlerprüfung + +- Menüeintrag Eval Suite wählen +- LMB auf Assistent +- Schritte ausfüllen +- Fall in der Datei +---------------------------------------- + +Evalfall ableiten + +Übernimmt einen gescheiterten Lauf als Fall + +- Kennung und Frage werden vorbelegt + +- Lauf mit Fehlschlag öffnen +- LMB auf Fall übernehmen +- Formular vorbefüllt +---------------------------------------- + +Evalfall löschen + +- Eine defekte Zeile verhindert die Änderung +- Unbekannte Kennung meldet einen Fehler +- Eine Rückfrage geht voraus + +- Seite neuer Test öffnen +- LMB auf Löschen +- Bestätigen +- Fall verschwindet diff --git a/daten/MtoRagSystem/evallauf.md b/daten/MtoRagSystem/evallauf.md new file mode 100644 index 0000000..aae1024 --- /dev/null +++ b/daten/MtoRagSystem/evallauf.md @@ -0,0 +1,100 @@ + +Evallauf +---------------------------------------- + +optional +---------------------------------------- + +Prüft die Antwortpipeline gegen gespeicherte Fälle +---------------------------------------- + +- Ein gescheiterter Fall setzt den Gesamtstand +- Eine leere Auswahl gilt nicht als Fehlschlag +- Berichte entstehen unteilbar +- Evals messen Fälle, nicht jede mögliche Frage +- Fünf Falltypen rufen das Modell +- Vier Falltypen laufen ohne Modell +---------------------------------------- + +Evallauf starten + +Führt Fälle aus dem Adminbereich aus + +- Der Lauf braucht die Wissensrolle +- Der Bericht wird zusätzlich archiviert +- Der Lauf blockiert die Anfrage bis zum Ende + +- Menüeintrag Eval Suite wählen +- Auswahl treffen +- Lauf starten +- Ergebnis je Fall sichtbar +---------------------------------------- + +Einzelfall erneut testen + +Wiederholt genau einen gescheiterten Fall + +- Nur der gewählte Fall läuft + +- Lauf mit Fehlschlag öffnen +- LMB auf erneut testen +- Ergebnis des Falls sichtbar +---------------------------------------- + +Läufe vergleichen + +Stellt zwei Berichte als Unterschied gegenüber + +- Der Vergleich nennt behoben, neu und entfernt + +- Menüeintrag Eval Suite wählen +- Vergleichsbasis wählen +- Unterschied sichtbar +---------------------------------------- + +Evallauf im Terminal ausführen + +- Die Auswahl folgt Typ und Bereich +- Ein Abbruch nach dem ersten Fehler ist wählbar +- Ein Lauf ohne Schreiben ist wählbar +- Fälle lassen sich nur auflisten + +- Kommando mit Typ aufrufen +- Ergebnis je Fall sichtbar +---------------------------------------- + +Evallauf parallelisieren + +Verteilt Fälle auf mehrere Kindprozesse + +- Zwischen einem und 32 Prozessen +- Vorgabe sind zwei Prozesse +- Ein Zeitlimit je Prozess ist wählbar +- Das Ergebnis ist ein Sammelbericht + +- Kommando mit Prozesszahl aufrufen +- Sammelbericht sichtbar +---------------------------------------- + +Berichte aufräumen + +- Nur erzeugte Dateinamen fallen weg +- Aufräumen behält 20 Läufe je Bereich +- Die Liste zeigt zehn Läufe + +- Menüeintrag Eval Suite wählen +- LMB auf Aufräumen +- Berichtszahl sinkt +---------------------------------------- + +Berichte löschen + +Entfernt alle Läufe eines Bereichs + +- Der aktuelle Lauf fällt mit weg +- Eine Rückfrage geht voraus + +- Menüeintrag Eval Suite wählen +- LMB auf alle löschen +- Bestätigen +- Berichtsliste leer diff --git a/daten/MtoRagSystem/fremdinhalt.md b/daten/MtoRagSystem/fremdinhalt.md new file mode 100644 index 0000000..e100caf --- /dev/null +++ b/daten/MtoRagSystem/fremdinhalt.md @@ -0,0 +1,138 @@ + +Fremdinhalt +---------------------------------------- + +optional +---------------------------------------- + +Prüft externe Inhalte vor jeder Nutzung +---------------------------------------- + +- Geprüft wird der ausgewählte Inhalt +- Ein Lesen führt kein Werkzeug aus +- Ein Lesen ändert die Antwortpipeline nicht +- Vorschauen sind gekürzt und bereinigt +- Externe Inhalte heben ihren Rang nicht selbst +- Der Bereich braucht die höchste Rolle +- Keine Übernahme ins Standardwissen erfolgt automatisch +---------------------------------------- + +Inhalt live prüfen + +Liest den ausgewählten Inhalt einmalig online + +- Nur der gewählte Inhalt wird gelesen +- Ohne Zutun wird nichts gespeichert + +- Übersicht öffnen +- LMB auf Inhalt prüfen +- Bestätigen +- Vorschau mit Abrufzahl +---------------------------------------- + +Inhalt bereitstellen + +Merkt einen gelesenen Inhalt als Kandidat vor + +- Chat und Antwortnutzung bleiben aus +- Der Kandidat startet ohne Freigabe +- Eine Rückfrage geht voraus + +- Inhalt live prüfen +- LMB auf bereitstellen +- Bestätigen +- Kandidat in der Liste +---------------------------------------- + +Inhalt auswählen + +Ordnet einen Inhalt einem Raum zur Prüfung zu + +- Zwei Arten: eigener Raum und Ergänzung +- Die Auswahl gilt schon als geprüft +- Die Auswahl schaltet den Chat nicht ein +- Standardwissen wird dadurch nicht ergänzt + +- Räume überblicken +- LMB auf Inhalt auswählen +- Bestätigen +- Inhalt im Freigabebereich +---------------------------------------- + +Inhalt entscheiden + +Gibt einen geprüften Inhalt frei oder stellt zurück + +- Fünf Wege bis zum Zurücksetzen +- Eine unbekannte Entscheidung wird abgewiesen +- Eine Freigabe schaltet den Chat nicht ein +- Die Notiz endet bei 1000 Zeichen + +- Freigabebereich öffnen +- LMB auf Inhalt ansehen +- Entscheidung wählen +- Zustandsmarke wechselt +---------------------------------------- + +Inhalt im Chat einschalten + +Fügt einen freigegebenen Inhalt dem Raum zu + +- Nur geprüfte Inhalte eines eigenen Raums +- Nicht vorbereitete Inhalte werden abgewiesen +- Suche und Belege bleiben unberührt +- Es entsteht kein gespeichertes Wissen + +- Freigabebereich öffnen +- LMB auf im Chat einschalten +- Inhalt als aktiv markiert +---------------------------------------- + +Kandidaten filtern + +Grenzt vorbereitete Inhalte nach Zustand ein + +- Filter nach Zustand, Anbindung, Art und Zeit +- Das Filtern ruft nichts extern ab + +- Vorbereitete Inhalte öffnen +- Filter setzen +- Trefferliste eingegrenzt +---------------------------------------- + +Kandidat entfernen + +Löscht einen vorbereiteten Inhalt endgültig + +- Die Vorschau fällt mit weg + +- Vorbereitete Inhalte öffnen +- LMB auf Entfernen +- Kandidat verschwindet +---------------------------------------- + +Kandidaten ausgeben + +Lädt vorbereitete Inhalte als Datei herunter + +- Zwei Formate: Markdown und JSONL +- Der Export gibt die gefilterte Menge aus +- Der Export wirkt nicht als Freigabe + +- Vorbereitete Inhalte öffnen +- Format wählen +- Herunterladen +- Datei im Download +---------------------------------------- + +Ressource lesen + +Liest eine freigegebene Ressource im Terminal + +- Nur erlaubte Server und Adressen +- Der Inhalt wird bereinigt +- Ausgegeben werden nur Metadaten und Prüfsumme +- Eine Kürzung wird gekennzeichnet + +- Kommando mit Adresse aufrufen +- Metadaten und Prüfsumme sichtbar diff --git a/daten/MtoRagSystem/indexprofil.md b/daten/MtoRagSystem/indexprofil.md new file mode 100644 index 0000000..51e6894 --- /dev/null +++ b/daten/MtoRagSystem/indexprofil.md @@ -0,0 +1,64 @@ + +Indexprofil +---------------------------------------- + +optional +---------------------------------------- + +Legt Struktur für Chunking und Einbettung fest +---------------------------------------- + +- Ein Profil ist unveränderlich +- Genau ein Profil ist aktiv +- Einsehen braucht die Wissensrolle +- Ändern braucht die höchste Rolle +- Die Version zählt beim Anlegen hoch +- Ein neues Profil entsteht inaktiv +---------------------------------------- + +Profile prüfen + +Gleicht das aktive Profil gegen den Index ab + +- Der Vergleich läuft gegen die Indexmetadaten +- Eine abweichende Zeile setzt den Gesamtstand +- Fehlende Metadaten gelten als Strukturabweichung +- Die Ansicht startet keinen Neuaufbau + +- Menüeintrag Indexprofile wählen +- Abweichungen je Zeile sichtbar +---------------------------------------- + +Profil anlegen + +- Chunkgröße von 50 bis 1000 in Schritten von 25 +- Überlappung von 25 bis 200 in Schritten von 25 +- Das Einbettungsmodell ist Pflicht +- Fehlende Pflichtwerte nennen das Feld +- Nur die höchste Rolle darf anlegen + +- Indexprofile öffnen +- Werte eintragen +- Profil erstellen +- Inaktives Profil sichtbar +---------------------------------------- + +Profil aktivieren + +- Das bisherige Profil wird deaktiviert +- Die Aktivierung startet keinen Neuaufbau + +- Indexprofile öffnen +- LMB auf Aktivieren +- Bestätigen +- Profil als aktiv markiert +---------------------------------------- + +Profil löschen + +- Der Löschweg erscheint nur bei inaktiven Profilen + +- Indexprofile öffnen +- LMB auf Löschen +- Bestätigen +- Profil verschwindet diff --git a/daten/MtoRagSystem/konfiguration.md b/daten/MtoRagSystem/konfiguration.md new file mode 100644 index 0000000..45db7ca --- /dev/null +++ b/daten/MtoRagSystem/konfiguration.md @@ -0,0 +1,46 @@ + +Konfiguration +---------------------------------------- + +optional +---------------------------------------- + +Prüft die wirksamen Einstellungen vor dem Betrieb +---------------------------------------- + +- Fachsemantik gehört in die Konfiguration +- Harte Sonderpfade im Antwortkern sind verboten +- Geänderter Kataloginhalt wirkt ohne Codeänderung +---------------------------------------- + +Konfiguration validieren + +- Fehler und Warnungen erscheinen getrennt +- Warnungen ändern den Ausgang nicht +- Regressionswächter melden nur Warnungen + +- Kommando aufrufen +- Fehler- und Warnliste sichtbar +---------------------------------------- + +Konfiguration ausgeben + +Zeigt die aufgelöste Einstellung zur Diagnose + +- Die Ausgabe ist nicht bereinigt +- Pfade und Adressen stehen darin +- Nur der Shopschlüssel bleibt verborgen + +- Kommando aufrufen +- Vollständige Ausgabe sichtbar +---------------------------------------- + +Quellen auditieren + +Prüft Herkunft, Muster und Fachneutralität + +- Reine Quelltextanalyse ohne Laufzeitwirkung +- Ein Fehlerstand beendet den Lauf + +- Kommando aufrufen +- Kennzahlen und Funde sichtbar diff --git a/daten/MtoRagSystem/modellprofil.md b/daten/MtoRagSystem/modellprofil.md new file mode 100644 index 0000000..8497f9a --- /dev/null +++ b/daten/MtoRagSystem/modellprofil.md @@ -0,0 +1,68 @@ + +Modellprofil +---------------------------------------- + +optional +---------------------------------------- + +Stellt Modell und Suchparameter der Antwort ein +---------------------------------------- + +- Höchstens ein Profil ist systemweit aktiv +- Ohne aktives Profil greifen die Vorgabewerte +- Die Version zählt je Modellname hoch +- Ein neues Profil entsteht inaktiv +- Ein aktives Profil lässt sich nicht löschen +- Nur fehlende Felder erben die Vorgabewerte +- Wertebereiche greifen erst beim Aktivieren +- Suchwerte werden still auf 1 bis 200 begrenzt +---------------------------------------- + +Profile auflisten + +- Das aktive Profil steht oben +- Die Anzeige startet keine Erzeugung + +- Menüeintrag Modellsetup wählen +- Profilliste sichtbar +---------------------------------------- + +Profil erstellen + +- Der Modellname ist Pflicht +- Nur die höchste Rolle darf anlegen + +- Profilliste öffnen +- Werte eintragen +- Absenden +- Inaktives Profil sichtbar +---------------------------------------- + +Profil aktivieren + +- Profilliste öffnen +- LMB auf Aktivieren +- Bestätigen +- Profil als aktiv markiert +---------------------------------------- + +Profil löschen + +- Profilliste öffnen +- LMB auf Löschen +- Bestätigen +- Profil verschwindet +---------------------------------------- + +Suche testen + +Prüft das Trefferverhalten eines Profils + +- Leere Frage liefert kein Ergebnis +- Der Test ändert das Profil nicht +- Der Test aktiviert das Profil nicht + +- Profilliste öffnen +- LMB auf Testen +- Frage eintragen +- Trefferliste sichtbar diff --git a/daten/MtoRagSystem/protokoll.md b/daten/MtoRagSystem/protokoll.md new file mode 100644 index 0000000..24dfe5d --- /dev/null +++ b/daten/MtoRagSystem/protokoll.md @@ -0,0 +1,43 @@ + +Protokoll +---------------------------------------- + +optional +---------------------------------------- + +Zeigt Betriebsmeldungen der Dienste +---------------------------------------- + +- Nur die höchste Rolle darf lesen +- Die Anzeige ist rein lesend +- Kein Löschen ist vorgesehen +---------------------------------------- + +Protokolle auflisten + +- Nur Dateien nach festem Namensmuster +- Neueste Änderung steht oben + +- Menüeintrag Protokolle wählen +- Dateiliste mit Größe sichtbar +---------------------------------------- + +Protokoll anzeigen + +- Höchstens 1000 Zeilen +- Gelesen wird vom Dateiende +- Eine fehlende Datei meldet einen Fehler + +- Protokollliste öffnen +- LMB auf Anzeigen +- Letzte Zeilen sichtbar +---------------------------------------- + +Vektorprotokoll anzeigen + +- Feste Quelle im Protokollverzeichnis +- Höchstens 500 Zeilen +- Eine fehlende Datei meldet einen Hinweis + +- Menüeintrag Vektorprotokoll wählen +- Letzte Zeilen sichtbar diff --git a/daten/MtoRagSystem/rueckmeldung.md b/daten/MtoRagSystem/rueckmeldung.md new file mode 100644 index 0000000..c1d4115 --- /dev/null +++ b/daten/MtoRagSystem/rueckmeldung.md @@ -0,0 +1,99 @@ + +Rückmeldung +---------------------------------------- + +optional +---------------------------------------- + +Sammelt Nutzerkritik für die Verbesserung +---------------------------------------- + +- Eine Rückmeldung hängt an einer Antwort +- Die Adminsicht braucht die Wissensrolle +- Ein Löschen ist endgültig +- Der Export enthält Frage und Antwort im Klartext +- Der Export folgt den gesetzten Filtern +---------------------------------------- + +Rückmeldungen filtern + +Grenzt Fälle nach zehn Merkmalen ein + +- Filter nach Bewertung und Bearbeitungsstand +- Filter nach Einordnung und Fehlerverdacht +- Filter nach Vorrang und Referenzwert +- Seitengröße wählbar mit 25, 50 oder 100 + +- Menüeintrag Chat-Feedback wählen +- Filter setzen +- Trefferliste sichtbar +---------------------------------------- + +Rückmeldung ansehen + +Zeigt einen Fall mit Frage und Antwort + +- Rückmeldungen filtern +- LMB auf einen Fall +- Frage und Antwort sichtbar +---------------------------------------- + +Rückmeldung erledigen + +- Eine Notiz ist möglich + +- Rückmeldung ansehen +- LMB auf erledigt +- Zustand wechselt +---------------------------------------- + +Rückmeldung wieder öffnen + +- Erledigte Rückmeldung ansehen +- LMB auf wieder öffnen +- Zustand wechselt +---------------------------------------- + +Rückmeldungen gesammelt erledigen + +Setzt den Stand für die ganze Auswahl + +- Auswahl über Kästchen oder Filter +- Höchstens 5000 Fälle je Aktion + +- Rückmeldungen filtern +- Auswahl treffen +- LMB auf Auswahl erledigen +- Zustände wechseln +---------------------------------------- + +Rückmeldung löschen + +- Rückmeldung ansehen +- LMB auf Löschen +- Bestätigen +- Eintrag verschwindet +---------------------------------------- + +Rückmeldungen ausgeben + +- Zwei Formate: Markdown und JSONL +- Der Export ist nicht bereinigt +- Vorgefertigte Auszüge je Vorrang + +- Rückmeldungen filtern +- Format wählen +- Datei im Download +---------------------------------------- + +Rückmeldungen einordnen + +Bestimmt Typ, Risiko und Vorrang im Terminal + +- Ohne Erzwingen nur ungeordnete Einträge +- Höchstens 5000 Einträge je Lauf +- Vorgabe sind 500 Einträge +- Zwischenstände werden gespeichert + +- Kommando aufrufen +- Zähler je Risiko sichtbar diff --git a/daten/MtoRagSystem/selbsttest.md b/daten/MtoRagSystem/selbsttest.md new file mode 100644 index 0000000..ac14084 --- /dev/null +++ b/daten/MtoRagSystem/selbsttest.md @@ -0,0 +1,76 @@ + +Selbsttest +---------------------------------------- + +optional +---------------------------------------- + +Sichert Grenzen des Systems gegen Rückschritte +---------------------------------------- + +- 23 Selbsttests decken die Regressionsfläche +- Jeder Test hat sein eigenes Kommando +- Es gibt kein Sammelkommando +- Jeder Test liefert Fallliste und Ausgang +- Jeder Test kennt eine maschinenlesbare Ausgabe +- 15 Tests prüfen nur den Quelltext +- Sechs Tests prüfen gemischt +- Zwei Tests prüfen nur Verhalten +---------------------------------------- + +Einzeltest ausführen + +Prüft eine benannte Grenze des Systems + +- Kein Modell, kein Netz, keine Antwort +- Keine Datenbank und kein Import +- Ein gescheiterter Fall beendet den Lauf + +- Kommandonamen aus der Übersicht holen +- Kommando aufrufen +- Fallliste mit Ständen sichtbar +---------------------------------------- + +Ingestgrenzen prüfen + +Sichert Markdown, Chunks und Batchgrenzen ab + +- Zwölf Kommandos decken diesen Bereich +- Ein Test räumt sein Verzeichnis selbst auf + +- Kommando aus der Ingestgruppe aufrufen +- Fallliste mit Ständen sichtbar +---------------------------------------- + +Anbindungsgrenzen prüfen + +Sichert Fremddaten und Werkzeuggrenzen ab + +- Drei Kommandos decken diesen Bereich +- Verbotene Zeichenketten gelten als Fall + +- Kommando aus der Anbindungsgruppe aufrufen +- Fallliste mit Ständen sichtbar +---------------------------------------- + +Architekturgrenzen prüfen + +Sichert Flussgrenzen und Produktregeln ab + +- Fünf Kommandos decken diesen Bereich +- Ein Test hängt an einer Freigabeversion + +- Kommando aus der Architekturgruppe aufrufen +- Fallliste mit Ständen sichtbar +---------------------------------------- + +Antwortgrenzen prüfen + +Sichert Anker, Prüfung und Raumauswahl ab + +- Drei Kommandos decken diesen Bereich +- Keine Chatantwort und kein Shopzugriff +- Unbelegte Begriffe bleiben unrepariert + +- Kommando aus der Antwortgruppe aufrufen +- Fallliste mit Ständen sichtbar diff --git a/daten/MtoRagSystem/shoptreffer.md b/daten/MtoRagSystem/shoptreffer.md new file mode 100644 index 0000000..a386971 --- /dev/null +++ b/daten/MtoRagSystem/shoptreffer.md @@ -0,0 +1,75 @@ + +Shoptreffer +---------------------------------------- + +optional +---------------------------------------- + +Liefert Preis und Verfügbarkeit aus dem Shop +---------------------------------------- + +- Der Preis stammt allein aus dem Shopdatensatz +- Ohne Shoppreis erscheint kein Preis +- Ein fehlender Preis wird nicht zu null +- Kostenlos gilt nur mit Quellenbeleg +- Verfügbarkeit stammt allein aus dem Shopfeld +- Die Produktadresse stammt aus dem Shoppfad +- Reine Wissensantworten tragen keine Shopadressen +- Ein Shoptreffer belegt keine technische Eignung +- Zubehör wird nicht als Hauptgerät ausgegeben +- Bündelangaben bleiben unzerlegt +- Gefilterte Treffer sind keine fehlenden Treffer +- Kein Treffer bedeutet nicht: gibt es nicht +- Ein Shopausfall wird gemeldet +- Bei automatischer Basis startet sie nur bei Kaufbezug +- Die Basis Shop erzwingt die Suche +- Die gesendete Suchanfrage wird offengelegt +- Bilder stammen aus dem Bildfeld desselben Datensatzes +---------------------------------------- + +Shopsuche auslösen + +Sucht aus einer Wissensantwort passende Produkte + +- Angebot entfällt bei gleicher Suche +- Angebot entfällt bei ablehnender Antwort +- Eine erweiterte Suche wird ausgewiesen + +- Frage stellen +- LMB auf Shopsuche +- Trefferliste sichtbar +---------------------------------------- + +Preis nachfragen + +Ruft Handelsdaten zum genannten Produkt ab + +- Angebot entfällt bei genanntem Preis +- Die Folgeantwort bleibt am Produkt + +- Frage nach einem Produkt stellen +- LMB auf Preis anzeigen +- Preis und Artikelnummer sichtbar +---------------------------------------- + +Treffer filtern + +Grenzt die Liste auf Zubehör oder Geräte ein + +- Angebot erscheint nur bei Wirkung +- Mehrdeutige Rollen gelten nicht als Gerät + +- Shopsuche auslösen +- LMB auf eine Rolle +- Liste eingegrenzt +---------------------------------------- + +Shopsuche diagnostizieren + +Prüft eine Suchanfrage samt Reparatur im Terminal + +- Der Zugriff läuft live gegen den Shop +- Die Reparatursuche bevorzugt den angefragten Code + +- Kommando mit Suchtext aufrufen +- Suchanfrage und Treffer sichtbar diff --git a/daten/MtoRagSystem/sicherung.md b/daten/MtoRagSystem/sicherung.md new file mode 100644 index 0000000..0595250 --- /dev/null +++ b/daten/MtoRagSystem/sicherung.md @@ -0,0 +1,90 @@ + +Sicherung +---------------------------------------- + +optional +---------------------------------------- + +Sichert Anwendung und Datenbank nachvollziehbar +---------------------------------------- + +- Geheimnisse werden nie mitkopiert +- Fremdbibliotheken und Zwischenspeicher bleiben draußen +- Ein Datenbankabzug entsteht auf Anforderung oder Vorgabe +- Eine Sperrdatei verhindert parallele Läufe +- Sieben Stände bleiben rollierend erhalten +- Symlinks werden übersprungen +- Ein Verzeichnis nennt Umfang und Kennung +- Eine gelungene Sicherung beweist keinen Restore +---------------------------------------- + +Sicherung testen + +Prüft den geplanten Umfang ohne Schreibvorgang + +- Keine Sicherungsdatei entsteht +- Keine alte Sicherung fällt weg +- Fehlende Pflichtquellen erscheinen als Warnung +- Fehlende Zusatzquellen zählen getrennt + +- Betriebsseite öffnen +- LMB auf Sicherung testen +- Umfang und Warnungen sichtbar +---------------------------------------- + +Sicherung starten + +- Ein Datenbankabzug braucht Schalter oder Vorgabe +- Das Verzeichnis nennt keinen Zugang +- Geräumte Sicherungen werden benannt +- Eine Rückfrage geht voraus + +- Betriebsseite öffnen +- LMB auf Sicherung starten +- Bestätigen +- Sicherung in der Liste +---------------------------------------- + +Sicherung herunterladen + +Holt ein Archiv für den Restore-Test + +- Nur die höchste Rolle darf herunterladen +- Nur gültige lokale Kennungen +- Der Abruf startet keine Sicherung + +- Betriebsseite öffnen +- LMB auf Herunterladen +- Archiv im Download +---------------------------------------- + +Restore prüfen + +Bewertet eine Sicherung als Wiederherstellungsgrundlage + +- Nur die höchste Rolle darf prüfen +- Es läuft keine Wiederherstellung +- Kein Datenbankimport erfolgt +- Gelesen werden Verzeichnis und Bestandteile +- Das Ergebnis liefert einen Plan + +- Betriebsseite öffnen +- LMB auf Restore prüfen +- Prüfpunkte und Plan sichtbar +---------------------------------------- + +Sicherung im Terminal erstellen + +- Ein Trockenlauf schreibt keine Datei +- Die Aufbewahrung ist wählbar + +- Kommando aufrufen +- Kennung und Umfang sichtbar +---------------------------------------- + +Restore im Terminal prüfen + +- Kein Netz, kein Modell, kein Chat + +- Kommando mit Kennung aufrufen +- Prüfpunkte und Plan sichtbar diff --git a/daten/MtoRagSystem/sitzung.md b/daten/MtoRagSystem/sitzung.md new file mode 100644 index 0000000..241fbe9 --- /dev/null +++ b/daten/MtoRagSystem/sitzung.md @@ -0,0 +1,83 @@ + +Sitzung +---------------------------------------- + +kern +---------------------------------------- + +Hält Zugang und Verlauf einer Unterhaltung +---------------------------------------- + +- Chat und Adminbereich teilen eine Anmeldung +- Ein Abmelden beendet beide Bereiche +- Der Verlauf hängt an einem Browserkennzeichen +- Ein Abmelden löscht dieses Kennzeichen nicht +- Deaktivierte Konten werden abgewiesen +- Der Verlauf löst nur Bezüge auf +- Der Verlauf belegt keine Fachwerte +- Ein Hinweis nennt Fehlerrisiko und Datennutzung +---------------------------------------- + +Am Chat anmelden + +- E-Mail und Passwort sind Pflicht +- Ohne Chatrolle erscheint eine Verbotsseite +- Falscher Zugang behält die E-Mail +- Angemeldete landen sofort im Chat + +- Anmeldeseite aufrufen +- E-Mail und Passwort eintragen +- Bestätigen +- Chat mit Verlauf sichtbar +---------------------------------------- + +Vom Chat abmelden + +- Gemerkte Einstellungen bleiben erhalten + +- LMB auf Abmelden +- Anmeldeseite sichtbar +---------------------------------------- + +Am Adminbereich anmelden + +- Ohne Adminrolle erscheint eine Verbotsseite +- Berechtigte landen auf der Systemübersicht +- Der letzte Benutzername ist vorbelegt + +- Adminanmeldung aufrufen +- E-Mail und Passwort eintragen +- Bestätigen +- Systemübersicht sichtbar +---------------------------------------- + +Vom Adminbereich abmelden + +- LMB auf Abmelden +- Anmeldeseite sichtbar +---------------------------------------- + +Verlauf löschen + +Entfernt Gespräch, Produktbezüge und Uploads + +- Während des Empfangs gesperrt +- Löscht alle temporären Uploads mit +- Keine Rückfrage, keine Wiederherstellung +- Danach fehlen alle Bezugsanker + +- LMB auf Verlauf löschen +- Verlauf leer +- Uploadliste leer +---------------------------------------- + +Hilfe öffnen + +Zeigt das Bedienhandbuch im Chat + +- Nur bei vorhandener Handbuchdatei +- Höchstens 512 KB werden gelesen +- Die Hilfe ändert keine Antwortlogik + +- LMB auf Hilfe +- Handbuch im Fenster sichtbar diff --git a/daten/MtoRagSystem/systemprompt.md b/daten/MtoRagSystem/systemprompt.md new file mode 100644 index 0000000..3827769 --- /dev/null +++ b/daten/MtoRagSystem/systemprompt.md @@ -0,0 +1,46 @@ + +Systemprompt +---------------------------------------- + +optional +---------------------------------------- + +Steuert die Grundanweisung an das Modell +---------------------------------------- + +- Genau eine Version ist aktiv +- Die Version zählt fortlaufend hoch +- Eine neue Version überschreibt keine alte +- Nur die höchste Rolle darf ändern +---------------------------------------- + +Version speichern + +- Leerer Inhalt wird abgewiesen +- Die neue Version wird sofort aktiv +- Die bisherige Version wird abgeschaltet + +- Menüeintrag Systemprompt wählen +- Text eintragen +- Speichern +- Neue aktive Version oben +---------------------------------------- + +Version aktivieren + +Schaltet auf eine frühere Version zurück + +- Systemprompt öffnen +- LMB auf Aktivieren +- Bestätigen +- Kennzeichnung wechselt +---------------------------------------- + +Version löschen + +- Eine aktive Version bleibt geschützt + +- Systemprompt öffnen +- LMB auf Löschen +- Bestätigen +- Version verschwindet diff --git a/daten/MtoRagSystem/tag.md b/daten/MtoRagSystem/tag.md new file mode 100644 index 0000000..6351030 --- /dev/null +++ b/daten/MtoRagSystem/tag.md @@ -0,0 +1,92 @@ + +Tag +---------------------------------------- + +optional +---------------------------------------- + +Lenkt die Suche über gepflegte Signale +---------------------------------------- + +- Drei Typen: allgemein, Katalogobjekt, Vertriebssignal +- Unbekannter Typ fällt auf allgemein +- Ein Slug ist eindeutig +- Jede Änderung stößt einen Neuaufbau an +- Ein laufender Neuaufbau verhindert einen zweiten +---------------------------------------- + +Tag anlegen + +- Slug und Bezeichnung sind Pflicht +- Der Slug wird kleingeschrieben +- Leerzeichen werden zu Bindestrichen +- Ein doppelter Slug wird abgewiesen + +- Tagliste öffnen +- Bezeichnung und Slug eintragen +- Anlegen +- Tag in der Liste +---------------------------------------- + +Tag löschen + +- Alle Zuweisungen fallen mit weg + +- Tagliste öffnen +- LMB auf Löschen +- Bestätigen +- Tag verschwindet +---------------------------------------- + +Dokumente zuweisen + +Ordnet einem Tag mehrere Dokumente zu + +- Nur aktive Dokumente stehen zur Wahl +- Doppelte Kennungen werden entfernt +- Nur Unterschiede werden geschrieben + +- Tagliste öffnen +- LMB auf Zuweisen +- Dokumente ankreuzen +- Speichern +- Zähler angepasst +---------------------------------------- + +Dokument-Tags bearbeiten + +Setzt die Tags eines einzelnen Dokuments + +- Tags erscheinen nach Typ sortiert +- Nicht angekreuzte Tags fallen weg + +- Dokumentliste öffnen +- LMB auf Tags +- Tags ankreuzen +- Speichern +- Neuaufbau angestoßen +---------------------------------------- + +Neuaufbau verfolgen + +Zeigt den Fortschritt des Tag-Neuaufbaus laufend + +- Der Stand wird zweisekündlich abgefragt +- Ein Lebenszeichen kommt zehnsekündlich +- Vier Zustände: wartend, laufend, fertig, gescheitert +- Das Zusehen stößt keinen Neuaufbau an + +- Tagliste öffnen +- Statuszeile beobachten +- Zustand wechselt bis fertig +---------------------------------------- + +Tagindex neu aufbauen + +Baut Tagexport und Tagvektoren im Terminal neu + +- Entweder Auftragskennung oder Neuanlage +- Eine Sperrdatei verhindert Parallelläufe + +- Kommando mit Neuanlage aufrufen +- Kennzahlen sichtbar diff --git a/daten/MtoRagSystem/upload.md b/daten/MtoRagSystem/upload.md new file mode 100644 index 0000000..963d239 --- /dev/null +++ b/daten/MtoRagSystem/upload.md @@ -0,0 +1,68 @@ + +Upload +---------------------------------------- + +kern +---------------------------------------- + +Stellt eine Datei als Quelle der Sitzung bereit +---------------------------------------- + +- Erlaubt sind PDF, Markdown und Text +- Höchstens drei Dateien je Sitzung +- Höchstens 10 MB je Datei +- Ein Upload verfällt nach 60 Minuten +- Uploads ändern die Wissensbasis nie +- Ein Upload beginnt nachrangig +- Ein Upload lässt sich auf vorrangig stellen +- Der ausgewertete Text endet bei 60000 Zeichen +- Der Client prüft, der Server prüft erneut +---------------------------------------- + +Datei hochladen + +- Eine leere Datei weist erst der Server ab +- Übergroße Datei wird abgewiesen +- Bei erreichtem Maximum ist der Zugang gesperrt +- Ein Upload beginnt nachrangig + +- LMB auf Hinzufügen +- Datei wählen +- Datei mit Größe sichtbar +---------------------------------------- + +Nutzung wählen + +Legt fest, ob der Upload allein zählt + +- Abfrage erscheint nach dem Hochladen +- Als eigener Raum zählt nur der Upload +- Als Ergänzung bleibt Standardwissen führend +- Ohne Freigabe bleibt Standardwissen wirksam + +- Datei hochladen +- Eine Nutzungsart wählen +- Wissensraum passt sich an +---------------------------------------- + +Upload priorisieren + +Hebt den Upload gegenüber dem Wissen an + +- Zwei Modi: nachrangig und vorrangig +- Als eigener Raum entfällt der Schalter +- Ein Widerspruch bleibt sichtbar ausgewiesen + +- Datei hochladen +- LMB auf den Rangvermerk +- Vermerk zeigt vorrangig +---------------------------------------- + +Upload entfernen + +- Wirkt nur auf eigene Uploads +- Ohne Upload fällt der Raum zurück + +- Datei hochladen +- LMB auf Entfernen +- Datei verschwindet diff --git a/daten/MtoRagSystem/version.md b/daten/MtoRagSystem/version.md new file mode 100644 index 0000000..678a70c --- /dev/null +++ b/daten/MtoRagSystem/version.md @@ -0,0 +1,135 @@ + +Version +---------------------------------------- + +kern +---------------------------------------- + +Hält einen unveränderlichen Stand eines Dokuments +---------------------------------------- + +- Eine Version wird nie überschrieben +- Jede Version trägt eine Prüfsumme +- Eine neue Version entsteht inaktiv +- Nur die aktive Version speist den Index +---------------------------------------- + +Version hochladen + +Legt einen Nachfolgestand als neue Version ab + +- Die Datei ist Pflicht +- Die Nummer zählt vom höchsten Stand hoch +- Die aktive Version bleibt unverändert + +- Dokumentseite öffnen +- LMB auf neue Version +- Datei wählen +- Hochladen +- Inaktive Version sichtbar +---------------------------------------- + +Originaltext ansehen + +Zeigt die Textbasis vor der Chunk-Erzeugung + +- Die Anzeige ändert die Datei nicht +- Jede Seite liefert 40000 Zeichen +- Eine angeforderte Seitengröße endet bei 80000 +- Weitere Seiten laden beim Blättern nach +- Nicht lesbare Formate melden einen Fehler + +- Dokumentseite öffnen +- LMB auf Original ansehen +- Text im Fenster sichtbar +---------------------------------------- + +Version ableiten + +Speichert korrigierten Text als neue Version + +- Die Arbeitskopie endet bei 180000 Zeichen +- Leerer Inhalt wird abgewiesen +- Der Dateiname nennt die Quellversion +- Quelle und aktive Version bleiben unberührt +- Die neue Version ist inaktiv + +- Originaltext ansehen +- Text anpassen +- Als neue Version speichern +- Inaktive Version sichtbar +---------------------------------------- + +Wissenskarte erzeugen + +Erstellt eine strukturierte Markdown-Fassung der Version + +- Die Quelle wird segmentiert verarbeitet +- Ein unvollständiger Plan bricht ab +- Der Zusammenbau erfolgt durch das System +- Der Nachweis nennt Modell und Segmentzahl +- Kein Index wird geschrieben +- Doppelklicks bleiben während des Laufs gesperrt + +- Dokumentseite öffnen +- LMB auf Wissenskarte erzeugen +- Bestätigen +- Neue inaktive Version sichtbar +---------------------------------------- + +Version aktivieren + +Wählt eine Version als künftige Antwortbasis + +- Genau eine Version bleibt aktiv +- Die Version wird zum Neuaufbau vorgemerkt +- Kein Auftrag und kein Neuaufbau startet +- Bis dahin gilt der letzte stabile Index + +- Dokumentseite öffnen +- LMB auf Version aktivieren +- Bestätigen +- Warnung zum Neuaufbau sichtbar +---------------------------------------- + +Version vormerken + +Markiert die aktive Version für den Neuaufbau + +- Nur die aktive Version lässt sich vormerken +- Es startet kein Einzellauf + +- Dokumentseite öffnen +- LMB auf vormerken +- Bestätigen +- Version als vorgemerkt markiert +---------------------------------------- + +Chunks lesen + +Zeigt die Chunks einer Version aus dem Index + +- Die Anzeige ändert keine Antwortlogik +- Höchstens 300 Chunks je Version +- Je Chunk höchstens 1400 Zeichen +- Je Chunk höchstens 30 Fakten +- Ohne Indexeinträge erscheint eine Warnung + +- Dokumentseite öffnen +- LMB auf Chunks lesen +- Chunkliste sichtbar +---------------------------------------- + +Chunkgüte vergleichen + +Stellt Original und Wissenskarte gegenüber + +- Die Prüfung läuft nur im Speicher +- Kein Index wird geschrieben +- Kein Modell wird aufgerufen +- Ein fehlendes Gegenstück meldet einen Hinweis +- Der Vergleich nennt Chunks, Tabellen und Fakten + +- Dokumentseite öffnen +- LMB auf Güte vergleichen +- Vergleich sichtbar diff --git a/daten/MtoRagSystem/vision.md b/daten/MtoRagSystem/vision.md new file mode 100644 index 0000000..62a5b93 --- /dev/null +++ b/daten/MtoRagSystem/vision.md @@ -0,0 +1,72 @@ + +Vision +---------------------------------------- + +vision +---------------------------------------- + +Antworten sollen nicht nur plausibel klingen, sondern nachprüfbar sein. +---------------------------------------- + +Beleggeführt antworten + +Jede Aussage bekommt einen nachvollziehbaren Belegzustand +- Was nicht in den Quellen steht, wird nicht behauptet +- Belegzustand und Abdeckung sind ablesbar +- Einzelne Aussagen werden gegen die Belege geprüft +---------------------------------------- + +Grenzen zeigen + +Fehlendes, Schwaches und Widersprüchliches bleibt sichtbar +- Fehlende Quellen werden benannt, nicht ersetzt +- Quellenkonflikte werden gezeigt statt zusammengeführt +- Transparente Unsicherheit schlägt sichere Falschaussage +---------------------------------------- + +Quellen trennen + +Fachwissen, Handelsdaten und Uploads bleiben unterscheidbar +- Ein Shoppreis belegt keine technische Eignung +- Wissensräume trennen die Bestände sichtbar +- Ein Upload bleibt temporär und nachrangig +---------------------------------------- + +Wissen pflegen + +Dokumente werden antwortfähig, nicht nur abgelegt +- Versionen bleiben einzeln nachvollziehbar +- Struktur, Chunks und Fakten sind einsehbar +- Ein Neuaufbau ist eine bewusste Entscheidung +---------------------------------------- + +Fremddaten kontrollieren + +Externe Quellen wirken nur nach bewusster Freigabe +- Nichts wird automatisch zu Standardwissen +- Nur lesende Werkzeuge, nie Schreibaktionen +- Jede Freigabe ist eine eigene Entscheidung +---------------------------------------- + +Fachfrei bleiben + +Fachsemantik gehört in Konfiguration, nicht in den Kern +- Harte Sonderpfade im Antwortkern sind verboten +- Ein Fachpaket ist pflegbar ohne Codeänderung +- Diagnosen verändern die Antwortgüte nicht +---------------------------------------- + +Betrieb nachweisen + +Der Betreiber kann belegen, dass das System trägt +- Prüfungen, Sicherungen und Berichte sind abrufbar +- Berichte enthalten keine Geheimnisse +- Ein Restore-Nachweis bleibt Aufgabe des Betreibers +---------------------------------------- + +Grenzen des Systems anerkennen + +Das System ersetzt keine Prüfung durch Menschen +- Es gibt keine Rechteverwaltung im Wissen +- Kein Ersatz für Audit, Rechtsrat oder Abkommen +- Evals messen Fälle, nicht universelle Wahrheit diff --git a/daten/MtoRagSystem/werkzeug.md b/daten/MtoRagSystem/werkzeug.md new file mode 100644 index 0000000..a14db82 --- /dev/null +++ b/daten/MtoRagSystem/werkzeug.md @@ -0,0 +1,56 @@ + +Werkzeug +---------------------------------------- + +optional +---------------------------------------- + +Erlaubt ein lesendes Werkzeug im Anbindungsraum +---------------------------------------- + +- Nur eindeutig lesende Werkzeuge sind erlaubt +- Werkzeuge mit Schreibrisiko bleiben gesperrt +- Eine Freigabe gilt nur für ihren Raum +- Das Modell schlägt vor, das System führt aus +- Ein freigegebenes Werkzeug läuft ohne Rückfrage +- Höchstens ein Werkzeug je Antwort +- Jede Nutzung erhält einen Nachweis +- Ein Werkzeugfehler wird sichtbar gemeldet +- Standardwissen und Shop bleiben ausgeschlossen +- Der Bereich braucht die höchste Rolle +---------------------------------------- + +Werkzeug freigeben + +- Nicht eindeutig lesende Werkzeuge bleiben gesperrt +- Der Grund für eine Sperre steht dabei +- Die Freigabe führt kein Werkzeug aus + +- Räume überblicken +- Abschnitt Werkzeuge aufklappen +- LMB auf freigeben +- Werkzeug als freigegeben markiert +---------------------------------------- + +Werkzeugfreigabe zurücknehmen + +- Die Rücknahme wirkt sofort + +- Räume überblicken +- Abschnitt Werkzeuge aufklappen +- LMB auf Freigabe entfernen +- Werkzeug wieder gesperrt +---------------------------------------- + +Werkzeugergebnis auswählen + +Ordnet ein gespeichertes Ergebnis einem Raum zu + +- Kein Werkzeug läuft dabei +- Ergebnisse bleiben gespeicherte Prüfinformationen +- Ergebnisse sind nicht live lesbar + +- Räume überblicken +- Abschnitt Ergebnisse aufklappen +- LMB auf auswählen +- Ergebnis im Freigabebereich diff --git a/daten/MtoRagSystem/wissensindex.md b/daten/MtoRagSystem/wissensindex.md new file mode 100644 index 0000000..5b682fc --- /dev/null +++ b/daten/MtoRagSystem/wissensindex.md @@ -0,0 +1,90 @@ + +Wissensindex +---------------------------------------- + +kern +---------------------------------------- + +Hält die durchsuchbare Fassung des Wissens +---------------------------------------- + +- Treffer unter der Mindestgüte fallen weg +- Jeder Treffer trägt eine Chunkkennung +- Dokument und Abschnitt kommen mit, sofern vorhanden +- Eine nicht erreichbare Suche liefert keine Treffer +- Ein veralteter Index wird gemeldet +- Ein unvollständiger Aufbau bricht ab +---------------------------------------- + +Systemstand ansehen + +Zeigt Chunkzahl und Gesundheit der Dienste + +- Die Anzeige schreibt nichts +- Die harte Chunkgrenze liegt bei 25000 + +- Menüeintrag Systemübersicht wählen +- Chunkzahl und Gesundheit sichtbar +---------------------------------------- + +Chunkindex einsehen + +- Nur die höchste Rolle darf einsehen +- Vorgabe 50, höchstens 200 Einträge je Seite +- Die Anzeige startet keinen Neuaufbau + +- Menüeintrag Wissensbasis wählen +- Metadaten und Einträge sichtbar +---------------------------------------- + +Zwischenspeicher leeren + +Verwirft kurzlebige Zwischenstände nach Wartung + +- Der Dienst kennt keine Antwortlogik +- Ein nicht erreichbarer Vektordienst ergibt eine Warnung +- Eine Rückfrage geht voraus + +- Systemübersicht öffnen +- LMB auf Zwischenspeicher leeren +- Bestätigen +- Ergebnismeldung sichtbar +---------------------------------------- + +Gesundheit prüfen + +Prüft Vektor- und Tagindex im Terminal + +- Gesund ist jeder Zustand mit Vorsilbe OK +- Es entsteht kein Schreibzugriff + +- Kommando aufrufen +- Prüfbericht sichtbar +---------------------------------------- + +Vektordienst steuern + +Startet, stoppt oder lädt den Vektordienst neu + +- Die Steuerung läuft über das Kontrollskript +- Das Zeitlimit beträgt 600 Sekunden + +- Kommando mit Aktion aufrufen +- Ausgabe des Skripts sichtbar +---------------------------------------- + +Wissen zurücksetzen + +Löscht Dokumente, Versionen, Tags und Indexdateien + +- Nur die höchste Rolle darf ausführen +- Die Funktion ist standardmäßig gesperrt +- Der Bestätigungstext muss wörtlich stimmen +- Zuvor entsteht eine Sicherung +- Ein Fehlschlag der Sicherung bricht ab + +- Systemübersicht öffnen +- Bestätigungstext eintippen +- Absenden +- Bestätigen +- Sicherungspfad sichtbar diff --git a/daten/MtoRagSystem/wissensraum.md b/daten/MtoRagSystem/wissensraum.md new file mode 100644 index 0000000..58c7074 --- /dev/null +++ b/daten/MtoRagSystem/wissensraum.md @@ -0,0 +1,97 @@ + +Wissensraum +---------------------------------------- + +kern +---------------------------------------- + +Bestimmt, welcher Bestand eine Antwort trägt +---------------------------------------- + +- Standardwissen ist immer verfügbar +- Standardwissen lässt sich nicht abschalten +- Ein Uploadraum antwortet nur aus dem Upload +- Ein Uploadraum kennt keinen stillen Rückfall +- Ein Anbindungsraum liest nur Freigegebenes +- Ein Anbindungsraum mischt kein Standardwissen +- Ein unbekannter Raum fällt auf Standardwissen +- Freigegebene Inhalte und Werkzeugergebnisse sind nachrangig +- Beide bleiben vom Rangvorteil ausgenommen +---------------------------------------- + +Wissensraum wählen + +Legt die Antwortgrundlage der Unterhaltung fest + +- Der Uploadraum braucht einen gültigen Upload +- Gesperrte Räume sind nicht wählbar +- Während des Empfangs gesperrt + +- Chat-Einstellungen öffnen +- Wissensraum wählen +- Raum in der Zusammenfassung +---------------------------------------- + +Räume überblicken + +Zeigt, welche Räume arbeiten und angeboten werden + +- Der Zugang braucht die höchste Rolle +- Anbindungen sind erst nach Freigabe wirksam + +- Menüeintrag Wissensräume wählen +- Räume mit Zählern sichtbar +---------------------------------------- + +Chatauswahl umschalten + +Gibt einen Raum für die Chatauswahl frei + +- Standardwissen bleibt gesperrt +- Ausschalten löscht keine Freigaben +- Wiedereinschalten braucht keine neue Freigabe +- Nicht vorgesehene Räume werden abgewiesen + +- Räume überblicken +- LMB auf Einschalten +- Raum als aktiv markiert +---------------------------------------- + +Freigegebenen Inhalt vorschauen + +Liest einen freigegebenen Inhalt vor der Entscheidung + +- Der Dialog liest nur auf Klick +- Kein Standardwissen und kein Werkzeug +- Es wird nichts gespeichert + +- Räume überblicken +- Freigabebereich öffnen +- LMB auf live lesen +- Textvorschau sichtbar +---------------------------------------- + +Herkunft ansehen + +Zeigt, welche Inhalte welchem Raum gehören + +- Reine Anzeige ohne Freigabe +- Kein externer Abruf entsteht + +- Räume überblicken +- Abschnitt Herkunft aufklappen +- Zuordnungen je Raum sichtbar +---------------------------------------- + +Raumgrenzen prüfen + +Führt sechs Selbsttests zu den Raumgrenzen aus + +- Es entsteht keine Chatantwort +- Kein Werkzeug wird ausgeführt +- Kein Inhalt wird live gelesen +- Netz und Speicher werden je Test ausgewiesen + +- Räume überblicken +- LMB auf Prüfungen ausführen +- Sammelergebnis sichtbar diff --git a/daten/MtoVariantConfigurator/.planung/.pruefung.json b/daten/MtoVariantConfigurator/.planung/.pruefung.json deleted file mode 100644 index f578988..0000000 --- a/daten/MtoVariantConfigurator/.planung/.pruefung.json +++ /dev/null @@ -1,537 +0,0 @@ -{ - "abdeckung": { - "einbinden:VariantConfiguratorPlugin": { - "abdruck": "823481507a44729d", - "funktion": "Konfigurationsdaten bereitstellen", - "trug": "5fbc8363b7cffe59" - }, - "einbinden:erweitert @Storefront/storefront/component/buy-widget/configurator.html.twig": { - "abdruck": "c6d031d6bc598089", - "funktion": "Konfigurator aktivieren", - "trug": "6cf5a2b08ce2371a" - }, - "einbinden:override sw-product-detail-variants": { - "abdruck": "2fcf518e7333458a", - "funktion": "", - "trug": "" - }, - "einbinden:register mto-vc-variants-card": { - "abdruck": "c472feadaac5ac71", - "funktion": "", - "trug": "" - }, - "hoeren:[data-mto-vc-gallery-next].click": { - "abdruck": "c402ad6f114e8c3d", - "funktion": "Galerie blättern", - "trug": "bacf45ebf9dd77b8" - }, - "hoeren:[data-mto-vc-gallery-prev].click": { - "abdruck": "f50d4f7effc60a06", - "funktion": "Galerie blättern", - "trug": "bacf45ebf9dd77b8" - }, - "hoeren:[data-mto-vc-lightbox-close].click": { - "abdruck": "89a22850af7694bb", - "funktion": "Galerie blättern", - "trug": "bacf45ebf9dd77b8" - }, - "hoeren:document.keydown": { - "abdruck": "7c018ebbfa346bee", - "funktion": "Schritt öffnen", - "trug": "efe9634e3080c073" - }, - "hoeren:el.click": { - "abdruck": "6a423a062267755c", - "funktion": "Nächsten Schritt anzeigen", - "trug": "f6b276e3fedf287d" - }, - "hoeren:info.click": { - "abdruck": "7a5a70dfb792bf19", - "funktion": "Optionsdetail öffnen", - "trug": "39fed29af6734cd4" - }, - "hoeren:info.keydown": { - "abdruck": "409cecf6fb3bbb4a", - "funktion": "Optionsdetail öffnen", - "trug": "39fed29af6734cd4" - }, - "hoeren:lightboxSelect.click": { - "abdruck": "9add2d2c77b440b5", - "funktion": "Ansicht schließen", - "trug": "24d52cc6d249d4f5" - }, - "hoeren:next.click": { - "abdruck": "d5b0cdcce40afcff", - "funktion": "Konfigurator schließen", - "trug": "1cc1a6b5fc943e03" - }, - "hoeren:prev.click": { - "abdruck": "6b8db8d885c0d6f8", - "funktion": "Konfigurator schließen", - "trug": "1cc1a6b5fc943e03" - }, - "hoeren:row.click": { - "abdruck": "b4ec6f63c613c35f", - "funktion": "Option wählen", - "trug": "80df89cf0c129387" - }, - "hoeren:thumb.click": { - "abdruck": "b4aa2111971f6886", - "funktion": "Bild wählen", - "trug": "0604a0a6875489b8" - }, - "hoeren:trigger.click": { - "abdruck": "e219933925adc81a", - "funktion": "Schritt öffnen", - "trug": "efe9634e3080c073" - }, - "reaktion:ProductPageLoadedEvent": { - "abdruck": "6f808b91c1a0c4f5", - "funktion": "Konfigurationsdaten bereitstellen", - "trug": "5fbc8363b7cffe59" - }, - "route:get /mto-variant-configurator/resolve/{productId}": { - "abdruck": "b14355d6007564a1", - "funktion": "Konfigurationsdaten bereitstellen", - "trug": "5fbc8363b7cffe59" - } - }, - "belege": { - "[\"auswahl-anstossen\", \"Gewählte Option anzeigen\"]": { - "abdruck": "626af3ee300b610a", - "beleg": "\n {{ mtoVcSelected ? mtoVcSelected.translated.name : 'mto.variantConfigurator.choose'|trans }}\n ", - "datei": "src/Resources/views/storefront/component/buy-widget/configurator.html.twig" - }, - "[\"auswahl-anstossen\", \"Hinweistext anzeigen\"]": { - "abdruck": "b9baf394ca99d4e6", - "beleg": "{% if mtoVcBubble != mtoVcBubbleKey and mtoVcBubble is not empty %}\n

{{ mtoVcBubble|sw_sanitize }}

\n {% endif %}", - "datei": "src/Resources/views/storefront/component/buy-widget/configurator.html.twig" - }, - "[\"auswahl-anstossen\", \"Schrittnummer anzeigen\"]": { - "abdruck": "b9e4deada2c3a6f1", - "beleg": "{{ 'mto.variantConfigurator.step'|trans({ '%step%': mtoVcStep })|sw_sanitize }}", - "datei": "src/Resources/views/storefront/component/buy-widget/configurator.html.twig" - }, - "[\"beratung-anbieten\", \"Beratung erreichen\"]": { - "abdruck": "fa513f8d265ad713", - "beleg": "{% if ctaPhone is not empty %}\n \n {{ ctaPhone|sw_sanitize }}\n {% endif %}", - "datei": "src/Resources/views/storefront/component/buy-widget/mto-variant-configurator-modal.html.twig" - }, - "[\"beratung-anbieten\", \"Optionsübersicht öffnen\"]": { - "abdruck": "8aba7fb9bf50281b", - "beleg": "{% if pdfUrl %}\n \n {{ 'mto.variantConfigurator.allOptions'|trans|sw_sanitize }}\n \n {% else %}\n \n {% endif %}", - "datei": "src/Resources/views/storefront/component/buy-widget/mto-variant-configurator-modal.html.twig" - }, - "[\"beratung-anbieten\", \"Vertrauen zeigen\"]": { - "abdruck": "5b204dff7de6f96d", - "beleg": "{% if trustLogo %}\n \"\"\n{% endif %}", - "datei": "src/Resources/views/storefront/component/buy-widget/mto-variant-configurator-modal.html.twig" - }, - "[\"layout-zuweisen\", \"Konfigurator aktivieren\"]": { - "abdruck": "60a65511f06ae7fe", - "beleg": "", - "datei": "src/Resources/app/administration/src/component/mto-vc-variants-card/mto-vc-variants-card.html.twig" - }, - "[\"layout-zuweisen\", \"Optionsübersicht hinterlegen\"]": { - "abdruck": "97b421cf540a6cc2", - "beleg": "{% if pdfUrl %}\n \n {{ 'mto.variantConfigurator.allOptions'|trans|sw_sanitize }}\n \n {% else %}\n \n {% endif %}", - "datei": "src/Resources/views/storefront/component/buy-widget/mto-variant-configurator-modal.html.twig" - }, - "[\"layout-zuweisen\", \"Trust-Logo hinterlegen\"]": { - "abdruck": "1954311a4c3a9cc1", - "beleg": "$mediaId = $this->systemConfigService->get(\n MtoVariantConfigurator::CONFIG_TRUST_LOGO,\n $salesChannelId,\n );", - "datei": "src/Core/Content/Product/VariantResolveService.php" - }, - "[\"option-ansehen\", \"Ansicht schließen\"]": { - "abdruck": "6eac493d9a481e30", - "beleg": "if (!this._nodes.lightbox.hidden) {\n this._closeLightbox();\n } else {\n this._close();\n }", - "datei": "src/Resources/app/storefront/src/js/variant-configurator.plugin.js" - }, - "[\"option-ansehen\", \"Option aus Ansicht wählen\"]": { - "abdruck": "b4223f8cf3e2456e", - "beleg": "this._nodes.lightboxSelect?.addEventListener('click', () => {\n if (this._lightboxOption) {\n this._selectOption(this.options.groups[this._currentStep], this._lightboxOption.id);\n }\n this._closeLightbox();\n });", - "datei": "src/Resources/app/storefront/src/js/variant-configurator.plugin.js" - }, - "[\"option-ansehen\", \"Optionsdetail öffnen\"]": { - "abdruck": "59faab581e0fac7f", - "beleg": "info.addEventListener('click', open);\n info.addEventListener('keydown', (event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n open(event);\n }\n });", - "datei": "src/Resources/app/storefront/src/js/variant-configurator.plugin.js" - }, - "[\"schritt-zeigen\", \"Eigenschaft benennen\"]": { - "abdruck": "dd54064a67689e2c", - "beleg": "this._nodes.title.textContent = group.name;", - "datei": "src/Resources/app/storefront/src/js/variant-configurator.plugin.js" - }, - "[\"schritt-zeigen\", \"Optionen auflisten\"]": { - "abdruck": "a71af321f056608d", - "beleg": "if (option.media) {\n const visual = document.createElement('span');\n visual.className = 'mto-vc-option-media';\n const img = document.createElement('img');\n img.src = option.media;\n img.alt = '';\n img.loading = 'lazy';\n visual.appendChild(img);\n row.appendChild(visual);\n } else if (option.color) {\n const visual = document.createElement('span');\n visual.className = 'mto-vc-option-swatch';\n visual.style.backgroundColor = option.color;\n row.appendChild(visual);\n } else {\n row.classList.add('has-no-visual');\n }", - "datei": "src/Resources/app/storefront/src/js/variant-configurator.plugin.js" - }, - "[\"schritt-zeigen\", \"Schrittstand anzeigen\"]": { - "abdruck": "aa7b8888103f8bd0", - "beleg": "this._nodes.counter.textContent = (this._snippets.stepCount || '__step__ / __total__')\n .replace('__step__', String(step))\n .replace('__total__', String(total));\n this._nodes.progress.style.width = `${(step / total) * 100}%`;", - "datei": "src/Resources/app/storefront/src/js/variant-configurator.plugin.js" - }, - "[\"varianten-waehlen\", \"Auswahl übernehmen\"]": { - "abdruck": "21ccf5bc0286c95c", - "beleg": "if (optionId && select.value !== optionId) {\n select.value = optionId;\n lastChanged = select;\n }", - "datei": "src/Resources/app/storefront/src/js/variant-configurator.plugin.js" - }, - "[\"varianten-waehlen\", \"Konfigurationsdaten bereitstellen\"]": { - "abdruck": "e6e5848381fce5aa", - "beleg": "$page->assign([", - "datei": "src/Subscriber/ProductPageSubscriber.php" - }, - "[\"varianten-waehlen\", \"Konfigurator schließen\"]": { - "abdruck": "1b7d4aea18cdb896", - "beleg": "_close() {\n this._closeLightbox();\n this._modalEl.hidden = true;\n document.body.classList.remove('mto-vc-modal-open');\n document.removeEventListener('keydown', this._keydownHandler);\n this._lastFocus?.focus();\n }", - "datei": "src/Resources/app/storefront/src/js/variant-configurator.plugin.js" - }, - "[\"varianten-waehlen\", \"Nächsten Schritt anzeigen\"]": { - "abdruck": "3deee97595984a3e", - "beleg": "const isLast = this._nextUsableStep(this._currentStep + 1, 1) === null;\n this._nodes.next.textContent = isLast\n ? this._nodes.next.dataset.finishLabel\n : this._nodes.next.dataset.nextLabel;", - "datei": "src/Resources/app/storefront/src/js/variant-configurator.plugin.js" - }, - "[\"varianten-waehlen\", \"Option wählen\"]": { - "abdruck": "4b9f7dc844cf7aac", - "beleg": "this._selected[group.id] = optionId;", - "datei": "src/Resources/app/storefront/src/js/variant-configurator.plugin.js" - }, - "[\"varianten-waehlen\", \"Schritt öffnen\"]": { - "abdruck": "94b3aa8d50c53fc8", - "beleg": "this._triggers.forEach((trigger) => {\n trigger.addEventListener('click', (event) => {\n event.preventDefault();\n this._open(parseInt(trigger.dataset.mtoVcStepIndex, 10));\n });\n });", - "datei": "src/Resources/app/storefront/src/js/variant-configurator.plugin.js" - }, - "[\"varianten-waehlen\", \"Vorherigen Schritt anzeigen\"]": { - "abdruck": "df5e60fe148da5e6", - "beleg": "this._nodes.prev.disabled = this._nextUsableStep(this._currentStep - 1, -1) === null;", - "datei": "src/Resources/app/storefront/src/js/variant-configurator.plugin.js" - }, - "[\"vorschau-zeigen\", \"Bild wählen\"]": { - "abdruck": "ab1e74251036541a", - "beleg": "thumb.className = `mto-vc-thumb${index === this._galleryIndex ? ' is-active' : ''}`;", - "datei": "src/Resources/app/storefront/src/js/variant-configurator.plugin.js" - }, - "[\"vorschau-zeigen\", \"Galerie blättern\"]": { - "abdruck": "6b28a5866629b878", - "beleg": "_stepGallery(delta) {\n if (this._gallery.length < 2) {\n return;\n }\n const count = this._gallery.length;\n this._galleryIndex = (this._galleryIndex + delta + count) % count;\n this._renderGallery();\n }", - "datei": "src/Resources/app/storefront/src/js/variant-configurator.plugin.js" - }, - "[\"vorschau-zeigen\", \"Vorschau laden\"]": { - "abdruck": "413024bc244f7770", - "beleg": "return new JsonResponse($this->variantResolveService->resolveVariant($variantId, $context));", - "datei": "src/Storefront/Controller/VariantConfiguratorController.php" - } - }, - "ohne_code": {}, - "ohne_karte": {}, - "paare": { - "[\"[\\\"auswahl-anstossen\\\", \\\"Gewählte Option anzeigen\\\"]\", \"[\\\"auswahl-anstossen\\\", \\\"Hinweistext anzeigen\\\"]\"]": { - "abdruck": "450345e8a27f5695", - "gleich": false - }, - "[\"[\\\"auswahl-anstossen\\\", \\\"Gewählte Option anzeigen\\\"]\", \"[\\\"auswahl-anstossen\\\", \\\"Schrittnummer anzeigen\\\"]\"]": { - "abdruck": "60008fdb6d69349b", - "gleich": false - }, - "[\"[\\\"auswahl-anstossen\\\", \\\"Hinweistext anzeigen\\\"]\", \"[\\\"auswahl-anstossen\\\", \\\"Schrittnummer anzeigen\\\"]\"]": { - "abdruck": "3eaf19062d6d53a3", - "gleich": false - }, - "[\"[\\\"beratung-anbieten\\\", \\\"Beratung erreichen\\\"]\", \"[\\\"beratung-anbieten\\\", \\\"Optionsübersicht öffnen\\\"]\"]": { - "abdruck": "9d3da3bf8c127ae1", - "gleich": false - }, - "[\"[\\\"beratung-anbieten\\\", \\\"Beratung erreichen\\\"]\", \"[\\\"beratung-anbieten\\\", \\\"Vertrauen zeigen\\\"]\"]": { - "abdruck": "2c3c62cb4b935c56", - "gleich": false - }, - "[\"[\\\"beratung-anbieten\\\", \\\"Optionsübersicht öffnen\\\"]\", \"[\\\"beratung-anbieten\\\", \\\"Vertrauen zeigen\\\"]\"]": { - "abdruck": "bf601d5dc7c6c507", - "gleich": false - }, - "[\"[\\\"beratung-anbieten\\\", \\\"Optionsübersicht öffnen\\\"]\", \"[\\\"layout-zuweisen\\\", \\\"Optionsübersicht hinterlegen\\\"]\"]": { - "abdruck": "bc9dc09e54b78a75", - "gleich": false - }, - "[\"[\\\"layout-zuweisen\\\", \\\"Konfigurator aktivieren\\\"]\", \"[\\\"layout-zuweisen\\\", \\\"Optionsbild am Datensatz pflegen\\\"]\"]": { - "abdruck": "5a4d802d668ddd55", - "gleich": false - }, - "[\"[\\\"layout-zuweisen\\\", \\\"Konfigurator aktivieren\\\"]\", \"[\\\"layout-zuweisen\\\", \\\"Optionsübersicht hinterlegen\\\"]\"]": { - "abdruck": "eeed78a6284711f1", - "gleich": false - }, - "[\"[\\\"layout-zuweisen\\\", \\\"Konfigurator aktivieren\\\"]\", \"[\\\"layout-zuweisen\\\", \\\"Trust-Logo hinterlegen\\\"]\"]": { - "abdruck": "b4944e5aa4df871a", - "gleich": false - }, - "[\"[\\\"layout-zuweisen\\\", \\\"Optionsbild am Datensatz pflegen\\\"]\", \"[\\\"layout-zuweisen\\\", \\\"Optionsübersicht hinterlegen\\\"]\"]": { - "abdruck": "b91bdff82a120a8d", - "gleich": false - }, - "[\"[\\\"layout-zuweisen\\\", \\\"Optionsbild am Datensatz pflegen\\\"]\", \"[\\\"layout-zuweisen\\\", \\\"Trust-Logo hinterlegen\\\"]\"]": { - "abdruck": "97268714e2b5d989", - "gleich": false - }, - "[\"[\\\"layout-zuweisen\\\", \\\"Optionsübersicht hinterlegen\\\"]\", \"[\\\"layout-zuweisen\\\", \\\"Trust-Logo hinterlegen\\\"]\"]": { - "abdruck": "b52cedd4106ee837", - "gleich": false - }, - "[\"[\\\"option-ansehen\\\", \\\"Ansicht schließen\\\"]\", \"[\\\"option-ansehen\\\", \\\"Option aus Ansicht wählen\\\"]\"]": { - "abdruck": "caa5ce4c5ff31774", - "gleich": false - }, - "[\"[\\\"option-ansehen\\\", \\\"Ansicht schließen\\\"]\", \"[\\\"option-ansehen\\\", \\\"Optionsdetail öffnen\\\"]\"]": { - "abdruck": "462a46d7a2030874", - "gleich": false - }, - "[\"[\\\"option-ansehen\\\", \\\"Option aus Ansicht wählen\\\"]\", \"[\\\"option-ansehen\\\", \\\"Optionsdetail öffnen\\\"]\"]": { - "abdruck": "8f695dfd90060204", - "gleich": false - }, - "[\"[\\\"schritt-zeigen\\\", \\\"Eigenschaft benennen\\\"]\", \"[\\\"schritt-zeigen\\\", \\\"Optionen auflisten\\\"]\"]": { - "abdruck": "5372df6b482e9a5c", - "gleich": false - }, - "[\"[\\\"schritt-zeigen\\\", \\\"Eigenschaft benennen\\\"]\", \"[\\\"schritt-zeigen\\\", \\\"Schrittstand anzeigen\\\"]\"]": { - "abdruck": "732d371c2135b53f", - "gleich": false - }, - "[\"[\\\"schritt-zeigen\\\", \\\"Optionen auflisten\\\"]\", \"[\\\"schritt-zeigen\\\", \\\"Schrittstand anzeigen\\\"]\"]": { - "abdruck": "590d6974e948c69c", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Auswahl übernehmen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Konfigurationsdaten bereitstellen\\\"]\"]": { - "abdruck": "34e23fca918e5dc0", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Auswahl übernehmen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Konfigurator schließen\\\"]\"]": { - "abdruck": "eb521941a5dc979a", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Auswahl übernehmen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Nächsten Schritt anzeigen\\\"]\"]": { - "abdruck": "271109c8b42cf5d5", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Auswahl übernehmen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Option wählen\\\"]\"]": { - "abdruck": "618d3c213492555a", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Auswahl übernehmen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Schritt öffnen\\\"]\"]": { - "abdruck": "b45252ce7cc39ed9", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Auswahl übernehmen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Vorherigen Schritt anzeigen\\\"]\"]": { - "abdruck": "d7ade9bdd7d0c66e", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Konfigurationsdaten bereitstellen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Konfigurator schließen\\\"]\"]": { - "abdruck": "97ceded85ca2035c", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Konfigurationsdaten bereitstellen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Nächsten Schritt anzeigen\\\"]\"]": { - "abdruck": "ba83ab596b72af22", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Konfigurationsdaten bereitstellen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Option wählen\\\"]\"]": { - "abdruck": "6f23248b5fbd7be4", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Konfigurationsdaten bereitstellen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Schritt öffnen\\\"]\"]": { - "abdruck": "7350e93a2a368ac1", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Konfigurationsdaten bereitstellen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Vorherigen Schritt anzeigen\\\"]\"]": { - "abdruck": "50753ef9f3d5c8b5", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Konfigurator schließen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Nächsten Schritt anzeigen\\\"]\"]": { - "abdruck": "b49e65e1c60b5307", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Konfigurator schließen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Option wählen\\\"]\"]": { - "abdruck": "b165f28b36fc3637", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Konfigurator schließen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Schritt öffnen\\\"]\"]": { - "abdruck": "0bf509fed71f1c25", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Konfigurator schließen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Vorherigen Schritt anzeigen\\\"]\"]": { - "abdruck": "de5acdbf92511e14", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Nächsten Schritt anzeigen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Option wählen\\\"]\"]": { - "abdruck": "7c9a06867c701267", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Nächsten Schritt anzeigen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Schritt öffnen\\\"]\"]": { - "abdruck": "f45378da83876bae", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Nächsten Schritt anzeigen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Vorherigen Schritt anzeigen\\\"]\"]": { - "abdruck": "9fc4c9cf8ae1d7fb", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Option wählen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Schritt öffnen\\\"]\"]": { - "abdruck": "a71f8b8b92d1025c", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Option wählen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Vorherigen Schritt anzeigen\\\"]\"]": { - "abdruck": "e3270a7176c63620", - "gleich": false - }, - "[\"[\\\"varianten-waehlen\\\", \\\"Schritt öffnen\\\"]\", \"[\\\"varianten-waehlen\\\", \\\"Vorherigen Schritt anzeigen\\\"]\"]": { - "abdruck": "44e775b8e8b106d1", - "gleich": false - }, - "[\"[\\\"vorschau-zeigen\\\", \\\"Bild wählen\\\"]\", \"[\\\"vorschau-zeigen\\\", \\\"Galerie blättern\\\"]\"]": { - "abdruck": "19851d2901c309a1", - "gleich": false - }, - "[\"[\\\"vorschau-zeigen\\\", \\\"Bild wählen\\\"]\", \"[\\\"vorschau-zeigen\\\", \\\"Vorschau laden\\\"]\"]": { - "abdruck": "508415e6500f9fca", - "gleich": false - }, - "[\"[\\\"vorschau-zeigen\\\", \\\"Galerie blättern\\\"]\", \"[\\\"vorschau-zeigen\\\", \\\"Vorschau laden\\\"]\"]": { - "abdruck": "86aa1f412d5a5dcd", - "gleich": false - } - }, - "stil": { - "[\"auswahl-anstossen\", \"\"]": { - "abdruck": "aeec25973dafe92f", - "probleme": [] - }, - "[\"auswahl-anstossen\", \"Gewählte Option anzeigen\"]": { - "abdruck": "59058982f7989af8", - "probleme": [] - }, - "[\"auswahl-anstossen\", \"Hinweistext anzeigen\"]": { - "abdruck": "b3568e0a2585d71c", - "probleme": [] - }, - "[\"auswahl-anstossen\", \"Schrittnummer anzeigen\"]": { - "abdruck": "117d58f0d4b21973", - "probleme": [] - }, - "[\"beratung-anbieten\", \"\"]": { - "abdruck": "4b0267b165360857", - "probleme": [] - }, - "[\"beratung-anbieten\", \"Beratung erreichen\"]": { - "abdruck": "cfdb65d682c3e068", - "probleme": [] - }, - "[\"beratung-anbieten\", \"Optionsübersicht öffnen\"]": { - "abdruck": "28d5587c78199c54", - "probleme": [] - }, - "[\"beratung-anbieten\", \"Vertrauen zeigen\"]": { - "abdruck": "8c00dec8d3ebf751", - "probleme": [] - }, - "[\"layout-zuweisen\", \"\"]": { - "abdruck": "1e0d2ca5296aabea", - "probleme": [] - }, - "[\"layout-zuweisen\", \"Konfigurator aktivieren\"]": { - "abdruck": "dca9bbf7361f5520", - "probleme": [] - }, - "[\"layout-zuweisen\", \"Optionsbild am Datensatz pflegen\"]": { - "abdruck": "cc0701aafd02ac3a", - "probleme": [] - }, - "[\"layout-zuweisen\", \"Optionsübersicht hinterlegen\"]": { - "abdruck": "de6c0e3e80d47496", - "probleme": [] - }, - "[\"layout-zuweisen\", \"Trust-Logo hinterlegen\"]": { - "abdruck": "ebd1a72ece157e69", - "probleme": [] - }, - "[\"option-ansehen\", \"\"]": { - "abdruck": "ace46c77101e26b3", - "probleme": [] - }, - "[\"option-ansehen\", \"Ansicht schließen\"]": { - "abdruck": "6bdaf5e60fb3baa9", - "probleme": [] - }, - "[\"option-ansehen\", \"Option aus Ansicht wählen\"]": { - "abdruck": "cc10af5dda4a7857", - "probleme": [] - }, - "[\"option-ansehen\", \"Optionsdetail öffnen\"]": { - "abdruck": "e00d07ce7b75d8fc", - "probleme": [] - }, - "[\"schritt-zeigen\", \"\"]": { - "abdruck": "f0d53ef421968759", - "probleme": [] - }, - "[\"schritt-zeigen\", \"Eigenschaft benennen\"]": { - "abdruck": "ec4828e2e9197083", - "probleme": [] - }, - "[\"schritt-zeigen\", \"Optionen auflisten\"]": { - "abdruck": "d8e6daed0f36098f", - "probleme": [] - }, - "[\"schritt-zeigen\", \"Schrittstand anzeigen\"]": { - "abdruck": "42a1c7f94c30f72d", - "probleme": [] - }, - "[\"varianten-waehlen\", \"\"]": { - "abdruck": "0835908894fa892c", - "probleme": [] - }, - "[\"varianten-waehlen\", \"Auswahl übernehmen\"]": { - "abdruck": "6683956c63370244", - "probleme": [] - }, - "[\"varianten-waehlen\", \"Konfigurationsdaten bereitstellen\"]": { - "abdruck": "498f3141e86f8db0", - "probleme": [] - }, - "[\"varianten-waehlen\", \"Konfigurator schließen\"]": { - "abdruck": "866918b327061449", - "probleme": [] - }, - "[\"varianten-waehlen\", \"Nächsten Schritt anzeigen\"]": { - "abdruck": "8d810a760dfec037", - "probleme": [] - }, - "[\"varianten-waehlen\", \"Option wählen\"]": { - "abdruck": "ac4eae399ac3a15e", - "probleme": [] - }, - "[\"varianten-waehlen\", \"Schritt öffnen\"]": { - "abdruck": "40f795456747214e", - "probleme": [] - }, - "[\"varianten-waehlen\", \"Vorherigen Schritt anzeigen\"]": { - "abdruck": "a63a26a8baea9c07", - "probleme": [] - }, - "[\"vorschau-zeigen\", \"\"]": { - "abdruck": "52976631fd09993a", - "probleme": [] - }, - "[\"vorschau-zeigen\", \"Bild wählen\"]": { - "abdruck": "a3e980ef7678a446", - "probleme": [] - }, - "[\"vorschau-zeigen\", \"Galerie blättern\"]": { - "abdruck": "47ccb441120c1470", - "probleme": [] - }, - "[\"vorschau-zeigen\", \"Vorschau laden\"]": { - "abdruck": "29e5951f170dba26", - "probleme": [] - } - }, - "verworfen": {} -} diff --git a/daten/MtoVariantConfigurator/.planung/.verlauf.json b/daten/MtoVariantConfigurator/.planung/.verlauf.json deleted file mode 100644 index 1135079..0000000 --- a/daten/MtoVariantConfigurator/.planung/.verlauf.json +++ /dev/null @@ -1,122 +0,0 @@ -[ - { - "titel": "„Lightbox“ geändert", - "dateien": { - "lightbox": "\nLightbox\n----------------------------------------\n\nkern\n----------------------------------------\n\nZeigt eine vergrößerte Ansicht der Optionsabbildung mit ihrem Namen\n----------------------------------------\n\n- lightboxSelect bestätigt Auswahl und schließt\n- Escape und x-Icon schließen\n- Tab und Shift-Tab zirkulieren im Fokusring\n- Geschlossen kehrt Fokus zum Auslöser zurück\n- hidden-Attribut entfernt aus dem Barrierefreiheitsbaum\n----------------------------------------\n\nAuswahl bestätigen\n\nWählt eine Option im aktuellen Schritt und berechnet die gültigen Folgeschritte neu\n\n- Bleibt im aktuellen Schritt\n- Invalidiert Folgeschritte mit ungültigen Kombinationen\n- Setzt Fokus auf die gewählte Option\n- Aktualisiert Galerie und Preis\n\n- Lightbox mit Option öffnen\n- LMB auf Auswahl bestätigen\n- Option ist markiert\n- Lightbox geschlossen\n----------------------------------------\n\nKonfigurator schließen\n\n- Schließt die Lightbox, ohne den Konfigurator zu schließen\n- x-Icon oder Escape beenden die Lightbox\n- Fokus kehrt zum Auslöser in der Optionsliste zurück\n\n- Option mit Bildauswahl öffnet die Lightbox\n- Escape drücken\n- Lightbox geschlossen, Modal offen\n----------------------------------------\n\nLightbox schließen\n\nEntfernt die vergrößerte Produktansicht wieder\n\n- x-Icon oder Escape schließt\n- Zurück zum Dialog gibt Focus\n\n- Modal öffnen\n- Option mit Bild wählen\n- Leinwand-Icon klicken\n- Lightbox sichtbar\n- Escape drücken\n- Lightbox geschlossen, Dialog fokussiert\n----------------------------------------\n\nLightbox öffnen\n\nZeigt das Produktfoto einer Variante option in Originalgröße\n\n- lightboxImage zeigt option.media\n- lightboxCaption zeigt option.name\n- lightboxSelect erhält Fokus\n\n- Modal öffnen\n- Auf Option mit Bild klicken\n- Info-Button der Option klicken\n- Lightbox zeigt das Foto in Originalgröße\n----------------------------------------\n\nTastatur verwenden\n\nBedient Modal und Lightbox per Tastatur\n\n- Escape schließt Lightbox oder Modal\n- Tab zirkuliert im Fokusring vorwärts\n- Shift-Tab zirkuliert im Fokusring rückwärts\n\n- Modal öffnen\n- Lightbox öffnen\n- Escape drücken\n- Lightbox geschlossen\n- Escape drücken\n- Modal geschlossen\n" - } - }, - { - "titel": "„Konfigurator“ geändert", - "dateien": { - "konfigurator": "\nKonfigurator\n----------------------------------------\n\nkern\n----------------------------------------\n\nFührt durch Variantenkonfiguration in Einzelschritten mit Live-Vorschau\n----------------------------------------\n\n- Aktiv nur wenn Produkt mto_variant_configurator_active gesetzt hat\n- Optionen-Bilder nur bis zwei Schritte\n- Galerie und Preis aktualisieren live ohne Seitenreload\n- Body erhält CSS-Klasse mto-vc-modal-open solange Modal offen\n- Escape schließt Modal\n- Schließen stellt Fokus auf vorheriges Element\n- Registriert als mto-vc-variants-card in swProductDetail\n- Einstellungen in customFields des Produkts gespeichert\n- Falls inaktiv: Fallback auf Standard-Konfigurator von Shopware\n- Natives Select pro Gruppe im DOM\n- Schritte ohne gültige Optionen werden beim Navigieren übersprungen\n- Ungültige Kombinationen für Folgeschritte werden beim Wählen verworfen\n- Unbesuchte Schritte werden beim Bestätigen mit erster gültiger Option aufgefüllt\n- Deaktivierte Optionen sind nicht auswählbar\n- Gallery-Container erhält CSS-Klasse has-no-gallery wenn keine Bilder vorhanden\n- Schließen bei Lightbox: fokus auf Lightbox-Auswahl-Button\n----------------------------------------\n\nGeführte Konfiguration aktivieren\n\nFührt Kunden schrittweise durch die Variantenauswahl mit Hinweisen und Modal\n\n- Aktiviert bei Produkten mit aktivem Konfigurator-Layout\n- Zeigt jeden Konfigurationsschritt mit Beschriftung\n- Blendentext je Gruppe über Modal aus\n- Inkrementelle Variantenauflösung über resolveUrl\n\n- Produktseite mit aktivem Konfigurator öffnen\n- LMB auf ersten Konfigurationsschritt\n- Option im Modal wählen\n- Modal schließt und nächster Schritt markiert\n----------------------------------------\n\nKonfigurationsdaten abrufen\n\nLiefert Variantendaten für eine Live-Aktualisierung im Konfigurator.\n\n- GET /mto-variant-configurator/resolve/{productId}\n- Query-Parameter switched enthält die aktuell gewechselte Gruppe\n- Query-Parameter options enthält ein JSON-Array gewählter Optionen\n- Ungültiges JSON führt zu leerem options-Array\n- VariantNotFoundException hält productId als Fallback\n- Rückgabe enthält variantId, gallery media und Preis\n- Kein HTTP-Cache wegen kundenspezifischer Preise\n\n- GET /mto-variant-configurator/resolve/STRG-PRODUKT-ID?options=[{\"optionId\":\"farbe\",\"option\":\"rot\"}]\n- Antwort enthält variantId\n- Antwort enthält gallery media\n- Antwort enthält Preis\n----------------------------------------\n\nKonfigurator öffnen\n\nÖffnet den Konfigurator ab einem gewählten Schritt\n\n- Erster Aufruf zeigt das Modal\n- Weiterer Aufruf wechselt den Schritt\n- Fokus vorheriges Element wird gespeichert\n- Body erhält CSS-Klasse mto-vc-modal-open\n- Escape-Schließen wird registriert\n- Galerie und Preis werden aktualisiert\n- Fokus springt auf den Next-Button\n\n- LMB auf Konfigurator-Trigger klicken\n- Modal erscheint im gewählten Schritt\n----------------------------------------\n\nKonfigurator-Karte registrieren\n\nMacht die Einstellungen des Varianten-Konfigurators auf der Produktdetail-Seite verfügbar\n\n- Registriert als mto-vc-variants-card\n- Nutzt Produkt aus swProductDetail\n- Speichert Einstellungen in customFields des Produkts\n\n- Produktdetail-Seite eines Produkts öffnen\n- Tab Variants aufrufen\n- Registrierte mto-vc-variants-card wird angezeigt\n----------------------------------------\n\nPlugin registrieren\n\nMacht das Plugin für Elemente mit dem Selektor verfügbar\n\n- Registriert unter VariantConfiguratorPlugin\n- Nutzt window.PluginManager\n- Bindet an [data-mto-variant-configurator]\n\n- PluginManager.register aufrufen\n- Element mit data-mto-variant-configurator erstellen\n- Plugin auf Element angewendet\n" - } - }, - { - "titel": "„Konfigurator“ geändert", - "dateien": { - "konfigurator": "\nKonfigurator\n----------------------------------------\n\nkern\n----------------------------------------\n\nFührt durch Variantenkonfiguration in Einzelschritten mit Live-Vorschau\n----------------------------------------\n\n- Aktiv nur wenn Produkt mto_variant_configurator_active gesetzt hat\n- Optionen-Bilder nur bis zwei Schritte\n- Galerie und Preis aktualisieren live ohne Seitenreload\n- Body erhält CSS-Klasse mto-vc-modal-open solange Modal offen\n- Escape schließt Modal\n- Schließen stellt Fokus auf vorheriges Element\n- Registriert als mto-vc-variants-card in swProductDetail\n- Einstellungen in customFields des Produkts gespeichert\n- Falls inaktiv: Fallback auf Standard-Konfigurator von Shopware\n- Natives Select pro Gruppe im DOM\n- Schritte ohne gültige Optionen werden beim Navigieren übersprungen\n- Ungültige Kombinationen für Folgeschritte werden beim Wählen verworfen\n- Unbesuchte Schritte werden beim Bestätigen mit erster gültiger Option aufgefüllt\n- Deaktivierte Optionen sind nicht auswählbar\n- Gallery-Container erhält CSS-Klasse has-no-gallery wenn keine Bilder vorhanden\n- Schließen bei Lightbox: fokus auf Lightbox-Auswahl-Button\n----------------------------------------\n\nGeführte Konfiguration aktivieren\n\nFührt Kunden schrittweise durch die Variantenauswahl mit Hinweisen und Modal\n\n- Aktiviert bei Produkten mit aktivem Konfigurator-Layout\n- Zeigt jeden Konfigurationsschritt mit Beschriftung\n- Blendentext je Gruppe über Modal aus\n- Inkrementelle Variantenauflösung über resolveUrl\n\n- Produktseite mit aktivem Konfigurator öffnen\n- LMB auf ersten Konfigurationsschritt\n- Option im Modal wählen\n- Modal schließt und nächster Schritt markiert\n----------------------------------------\n\nKonfigurationsdaten abrufen\n\nLiefert Variantendaten für eine Live-Aktualisierung im Konfigurator\n\n- GET /mto-variant-configurator/resolve/{productId}\n- Query-Parameter switched enthält die aktuell gewechselte Gruppe\n- Query-Parameter options enthält ein JSON-Array gewählter Optionen\n- Ungültiges JSON führt zu leerem options-Array\n- VariantNotFoundException hält productId als Fallback\n- Rückgabe enthält variantId, gallery media und Preis\n- Kein HTTP-Cache wegen kundenspezifischer Preise\n\n- GET /mto-variant-configurator/resolve/STRG-PRODUKT-ID?options=[{\"optionId\":\"farbe\",\"option\":\"rot\"}]\n- Antwort enthält variantId\n- Antwort enthält gallery media\n- Antwort enthält Preis\n----------------------------------------\n\nKonfigurator öffnen\n\nÖffnet den Konfigurator ab einem gewählten Schritt\n\n- Erster Aufruf zeigt das Modal\n- Weiterer Aufruf wechselt den Schritt\n- Fokus vorheriges Element wird gespeichert\n- Body erhält CSS-Klasse mto-vc-modal-open\n- Escape-Schließen wird registriert\n- Galerie und Preis werden aktualisiert\n- Fokus springt auf den Next-Button\n\n- LMB auf Konfigurator-Trigger klicken\n- Modal erscheint im gewählten Schritt\n----------------------------------------\n\nKonfigurator-Karte registrieren\n\nMacht die Einstellungen des Varianten-Konfigurators auf der Produktdetail-Seite verfügbar\n\n- Registriert als mto-vc-variants-card\n- Nutzt Produkt aus swProductDetail\n- Speichert Einstellungen in customFields des Produkts\n\n- Produktdetail-Seite eines Produkts öffnen\n- Tab Variants aufrufen\n- Registrierte mto-vc-variants-card wird angezeigt\n----------------------------------------\n\nPlugin registrieren\n\nMacht das Plugin für Elemente mit dem Selektor verfügbar\n\n- Registriert unter VariantConfiguratorPlugin\n- Nutzt window.PluginManager\n- Bindet an [data-mto-variant-configurator]\n\n- PluginManager.register aufrufen\n- Element mit data-mto-variant-configurator erstellen\n- Plugin auf Element angewendet\n" - } - }, - { - "titel": "„Konfigurator“ geändert", - "dateien": { - "konfigurator": "\nKonfigurator\n----------------------------------------\n\nkern\n----------------------------------------\n\nFührt durch Variantenkonfiguration in Einzelschritten mit Live-Vorschau\n----------------------------------------\n\n- Aktiv nur wenn Produkt mto_variant_configurator_active gesetzt hat\n- Optionen-Bilder nur bis zwei Schritte\n- Galerie und Preis aktualisieren live ohne Seitenreload\n- Body erhält CSS-Klasse mto-vc-modal-open solange Modal offen\n- Escape schließt Modal\n- Schließen stellt Fokus auf vorheriges Element\n- Registriert als mto-vc-variants-card in swProductDetail\n- Einstellungen in customFields des Produkts gespeichert\n- Falls inaktiv: Fallback auf Standard-Konfigurator von Shopware\n- Natives Select pro Gruppe im DOM\n- Schritte ohne gültige Optionen werden beim Navigieren übersprungen\n- Ungültige Kombinationen für Folgeschritte werden beim Wählen verworfen\n- Unbesuchte Schritte werden beim Bestätigen mit erster gültiger Option aufgefüllt\n- Deaktivierte Optionen sind nicht auswählbar\n- Gallery-Container erhält CSS-Klasse has-no-gallery wenn keine Bilder vorhanden\n- Schließen bei Lightbox: fokus auf Lightbox-Auswahl-Button\n----------------------------------------\n\nGeführte Konfiguration aktivieren\n\nFührt Kunden schrittweise durch die Variantenauswahl mit Hinweisen und Modal\n\n- Aktiviert bei Produkten mit aktivem Konfigurator-Layout\n- Zeigt jeden Konfigurationsschritt mit Beschriftung\n- Blendentext je Gruppe über Modal aus\n- Inkrementelle Variantenauflösung über resolveUrl\n\n- Produktseite mit aktivem Konfigurator öffnen\n- LMB auf ersten Konfigurationsschritt\n- Option im Modal wählen\n- Modal schließt und nächster Schritt markiert\n----------------------------------------\n\nKonfigurationsdaten abrufen\n\nLiefert Variantendaten für eine Live-Aktualisierung im Konfigurator\n\n- Endpoint mto-variant-configurator resolve\n- Query-Parameter switched enthält die aktuell gewechselte Gruppe\n- Query-Parameter options enthält ein JSON-Array gewählter Optionen\n- Ungültiges JSON führt zu leerem options-Array\n- VariantNotFoundException hält productId als Fallback\n- Rückgabe enthält variantId, gallery media und Preis\n- Kein HTTP-Cache wegen kundenspezifischer Preise\n\n- GET /mto-variant-configurator/resolve/STRG-PRODUKT-ID?options=[{\"optionId\":\"farbe\",\"option\":\"rot\"}]\n- Antwort enthält variantId\n- Antwort enthält gallery media\n- Antwort enthält Preis\n----------------------------------------\n\nKonfigurator öffnen\n\nÖffnet den Konfigurator ab einem gewählten Schritt\n\n- Erster Aufruf zeigt das Modal\n- Weiterer Aufruf wechselt den Schritt\n- Fokus vorheriges Element wird gespeichert\n- Body erhält CSS-Klasse mto-vc-modal-open\n- Escape-Schließen wird registriert\n- Galerie und Preis werden aktualisiert\n- Fokus springt auf den Next-Button\n\n- LMB auf Konfigurator-Trigger klicken\n- Modal erscheint im gewählten Schritt\n----------------------------------------\n\nKonfigurator-Karte registrieren\n\nMacht die Einstellungen des Varianten-Konfigurators auf der Produktdetail-Seite verfügbar\n\n- Registriert als mto-vc-variants-card\n- Nutzt Produkt aus swProductDetail\n- Speichert Einstellungen in customFields des Produkts\n\n- Produktdetail-Seite eines Produkts öffnen\n- Tab Variants aufrufen\n- Registrierte mto-vc-variants-card wird angezeigt\n----------------------------------------\n\nPlugin registrieren\n\nMacht das Plugin für Elemente mit dem Selektor verfügbar\n\n- Registriert unter VariantConfiguratorPlugin\n- Nutzt window.PluginManager\n- Bindet an [data-mto-variant-configurator]\n\n- PluginManager.register aufrufen\n- Element mit data-mto-variant-configurator erstellen\n- Plugin auf Element angewendet\n" - } - }, - { - "titel": "„Galerie“ geändert", - "dateien": { - "galerie": "\nGalerie\n----------------------------------------\n\nkern\n----------------------------------------\n\nErmöglicht das Anzeigen und Durchblättern von Produktbildern im Konfigurator-Modal\n----------------------------------------\n\n- Einzelne Galerie pro Modal\n- Navigiert zyklisch\n- Ein Bild deaktiviert Navigation\n- Hauptbild über thumbnails aktualisierbar\n----------------------------------------\n\nGalerie nächste anzeigen\n\nZeigt das nächste Bild der Galerie\n\n- Mindestens 2 Bilder vorhanden\n- Zyklisch von letztem zu erstem Bild\n\n- Auf next-Button klicken\n- Nächstes Bild wird angezeigt\n----------------------------------------\n\nGalerie rückwärts blättern\n\nVorheriges Bild der Galerie anzeigen\n\n- Nur mit mindestens zwei Bildern\n- Springt von erstem zum letzten Bild\n- Aktualisiert Miniaturansicht\n\n- Vollmodus öffnen\n- Klick auf Vorheriges-Bild-Icon\n- Erstes Bild zeigt\n----------------------------------------\n\nGalerie vorherige anzeigen\n\nBlendet das vorherige Bild der Galerie ein\n\n- mto-vc-gallery-prev-Icon\n- Bei nur einem Bild keine Wirkung\n\n- Galerie mit mindestens zwei Bildern öffnen\n- LMB auf mto-vc-gallery-prev-Icon\n- Vorheriges Bild im Stage-Image angezeigt\n----------------------------------------\n\nGalerie vorwärts blättern\n\nZeigt das nächste Bild der Galerie\n\n- Geht bei weniger als zwei Bildern nicht\n- Springt vom letzten zum ersten Bild\n\n- Modal öffnen\n- Klick auf gallery-next\n- Nächstes Bild wird angezeigt\n- Klick erneut bei letztem Bild\n- Erstes Bild wird angezeigt\n----------------------------------------\n\nThumbnail auswählen\n\nGreift direkt auf ein Produktbild zu, ohne durch die Galerie zu blättern\n\n- Aktives Thumbnail zeigt x-Icon\n- Klick aktualisiert Hauptbild und Aktivzustand\n\n- Galerie mit mehreren Thumbnails öffnen\n- Klick auf Thumbnail\n- Hauptbild entspricht geklicktem Thumbnail\n" - } - }, - { - "titel": "„Lightbox“ geändert", - "dateien": { - "lightbox": "\nLightbox\n----------------------------------------\n\nkern\n----------------------------------------\n\nZeigt eine vergrößerte Ansicht der Optionsabbildung mit ihrem Namen\n----------------------------------------\n\n- lightboxSelect bestätigt Auswahl und schließt\n- Escape und x-Icon schließen\n- Tab und Shift-Tab zirkulieren im Fokusring\n- Geschlossen kehrt Fokus zum Auslöser zurück\n- hidden-Attribut entfernt aus dem Barrierefreiheitsbaum\n----------------------------------------\n\nAuswahl bestätigen\n\nWählt eine Option im aktuellen Schritt und berechnet die gültigen Folgeschritte neu\n\n- Bleibt im aktuellen Schritt\n- Invalidiert Folgeschritte mit ungültigen Kombinationen\n- Setzt Fokus auf die gewählte Option\n- Aktualisiert Galerie und Preis\n\n- Lightbox mit Option öffnen\n- LMB auf Auswahl bestätigen\n- Option markiert\n----------------------------------------\n\nKonfigurator schließen\n\n- Schließt die Lightbox, ohne den Konfigurator zu schließen\n- x-Icon oder Escape beenden die Lightbox\n- Fokus kehrt zum Auslöser in der Optionsliste zurück\n\n- Option mit Bildauswahl öffnet die Lightbox\n- Escape drücken\n- Lightbox geschlossen, Modal offen\n----------------------------------------\n\nLightbox schließen\n\nEntfernt die vergrößerte Produktansicht wieder\n\n- x-Icon oder Escape schließt\n- Zurück zum Dialog gibt Focus\n\n- Modal öffnen\n- Option mit Bild wählen\n- Leinwand-Icon klicken\n- Lightbox sichtbar\n- Escape drücken\n- Lightbox geschlossen, Dialog fokussiert\n----------------------------------------\n\nLightbox öffnen\n\nZeigt das Produktfoto einer Variante option in Originalgröße\n\n- lightboxImage zeigt option.media\n- lightboxCaption zeigt option.name\n- lightboxSelect erhält Fokus\n\n- Modal öffnen\n- Auf Option mit Bild klicken\n- Info-Button der Option klicken\n- Lightbox zeigt das Foto in Originalgröße\n----------------------------------------\n\nTastatur verwenden\n\nBedient Modal und Lightbox per Tastatur\n\n- Escape schließt Lightbox oder Modal\n- Tab zirkuliert im Fokusring vorwärts\n- Shift-Tab zirkuliert im Fokusring rückwärts\n\n- Modal öffnen\n- Lightbox öffnen\n- Escape drücken\n- Lightbox geschlossen\n- Escape drücken\n- Modal geschlossen\n" - } - }, - { - "titel": "„Produkt“ geändert", - "dateien": { - "produkt": "\nProdukt\n----------------------------------------\n\nkern\n----------------------------------------\n\nStellt dem Produkttemplate Daten des Variantenkonfigurators bereit\n----------------------------------------\n\n- Inaktiver Konfigurator setzt mtoVariantConfiguratorActive auf false\n- Aktiver Konfigurator weist alle Konfigurator-Variablen zu\n- sw-product-detail-variants wird mit eigener Template-Datei überschrieben\n- mtoVariantConfiguratorTrustLogo fehlt in Regeln und Funktion\n- Produktseite laden: Testschritte beschreiben Ergebnis statt Handlung\n- Variantenansicht erweitern: Funktion hat keine Testschritte, nur Regeln\n----------------------------------------\n\nProduktseite laden\n\nBereitet Variant-Konfigurationsdaten für die Produktseite vor\n\n- mtoVariantConfiguratorActive false bei inaktivem Konfigurator\n- Alle Variablen bei aktivem Konfigurator zugewiesen\n- Initial-Variante für vorausgefülltes Modal geladen\n\n- Produkt mit aktivem Konfigurator öffnen\n- Seite vollständig laden\n- Template-Variablen prüfen\n- Seite ohne Konfigurator öffnen\n- mtoVariantConfiguratorActive ist false\n----------------------------------------\n\nVariantenansicht erweitern\n\nFügt der Produktdetail-Variantenansicht zusätzliche Felder oder Funktionen hinzu\n\n- Überschreibt sw-product-detail-variants\n- Eigene Template-Datei wird geladen\n\n- Produktdetailseite öffnen\n- Varianten-Bereich aufrufen\n- Erweiterte Felder oder Funktionen sichtbar\n" - } - }, - { - "titel": "„Lightbox“ geändert", - "dateien": { - "lightbox": "\nLightbox\n----------------------------------------\n\nkern\n----------------------------------------\n\nZeigt eine vergrößerte Ansicht der Optionsabbildung mit ihrem Namen\n----------------------------------------\n\n- lightboxSelect bestätigt Auswahl und schließt\n- Escape und x-Icon schließen\n- Tab und Shift-Tab zirkulieren im Fokusring\n- Geschlossen kehrt Fokus zum Auslöser zurück\n- hidden-Attribut entfernt aus dem Barrierefreiheitsbaum\n----------------------------------------\n\nAuswahl bestätigen\n\nWählt eine Option im aktuellen Schritt und berechnet die gültigen Folgeschritte neu\n\n- Bleibt im aktuellen Schritt\n- Invalidiert Folgeschritte mit ungültigen Kombinationen\n- Setzt Fokus auf die gewählte Option\n- Aktualisiert Galerie und Preis\n\n- Lightbox mit Option öffnen\n- LMB auf Auswahl bestätigen\n- Option markiert\n----------------------------------------\n\nKonfigurator schließen\n\n- Schließt die Lightbox, ohne den Konfigurator zu schließen\n- x-Icon oder Escape beenden die Lightbox\n- Fokus kehrt zum Auslöser in der Optionsliste zurück\n\n- Option mit Bildauswahl öffnet die Lightbox\n- Escape drücken\n- Lightbox geschlossen, Modal offen\n----------------------------------------\n\nLightbox schließen\n\nEntfernt die vergrößerte Produktansicht wieder\n\n- x-Icon oder Escape schließt\n- Zurück zum Dialog gibt Focus\n\n- Lightbox öffnen\n- Escape drücken\n- Lightbox geschlossen, Dialog fokussiert\n----------------------------------------\n\nLightbox öffnen\n\nZeigt das Produktfoto einer Variante option in Originalgröße\n\n- lightboxImage zeigt option.media\n- lightboxCaption zeigt option.name\n- lightboxSelect erhält Fokus\n\n- Modal öffnen\n- Auf Option mit Bild klicken\n- Info-Button der Option klicken\n- Lightbox zeigt das Foto in Originalgröße\n----------------------------------------\n\nTastatur verwenden\n\nBedient Modal und Lightbox per Tastatur\n\n- Escape schließt Lightbox oder Modal\n- Tab zirkuliert im Fokusring vorwärts\n- Shift-Tab zirkuliert im Fokusring rückwärts\n\n- Modal öffnen\n- Lightbox öffnen\n- Escape drücken\n- Lightbox geschlossen\n- Escape drücken\n- Modal geschlossen\n" - } - }, - { - "titel": "„Galerie“ geändert", - "dateien": { - "galerie": "\nGalerie\n----------------------------------------\n\nkern\n----------------------------------------\n\nErmöglicht das Anzeigen und Durchblättern von Produktbildern im Konfigurator-Modal\n----------------------------------------\n\n- Einzelne Galerie pro Modal\n- Navigiert zyklisch\n- Ein Bild deaktiviert Navigation\n- Hauptbild über thumbnails aktualisierbar\n----------------------------------------\n\nGalerie nächste anzeigen\n\nZeigt das nächste Bild der Galerie\n\n- Mindestens 2 Bilder vorhanden\n- Zyklisch von letztem zu erstem Bild\n\n- Auf next-Button klicken\n- Nächstes Bild wird angezeigt\n----------------------------------------\n\nGalerie rückwärts blättern\n\nVorheriges Bild der Galerie anzeigen\n\n- Nur mit mindestens zwei Bildern\n- Springt von erstem zum letzten Bild\n- Aktualisiert Miniaturansicht\n\n- Vollmodus öffnen\n- Klick auf Vorheriges-Bild-Icon\n- Erstes Bild zeigt\n----------------------------------------\n\nGalerie vorherige anzeigen\n\nBlendet das vorherige Bild der Galerie ein\n\n- mto-vc-gallery-prev-Icon\n- Bei nur einem Bild keine Wirkung\n\n- Galerie mit mindestens zwei Bildern öffnen\n- LMB auf mto-vc-gallery-prev-Icon\n- Vorheriges Bild im Stage-Image angezeigt\n----------------------------------------\n\nGalerie vorwärts blättern\n\nZeigt das nächste Bild der Galerie\n\n- Geht bei weniger als zwei Bildern nicht\n- Springt vom letzten zum ersten Bild\n\n- Modal öffnen\n- Klick auf gallery-next\n- Nächstes Bild wird angezeigt\n----------------------------------------\n\nThumbnail auswählen\n\nGreift direkt auf ein Produktbild zu, ohne durch die Galerie zu blättern\n\n- Aktives Thumbnail zeigt x-Icon\n- Klick aktualisiert Hauptbild und Aktivzustand\n\n- Galerie mit mehreren Thumbnails öffnen\n- Klick auf Thumbnail\n- Hauptbild entspricht geklicktem Thumbnail\n" - } - }, - { - "titel": "„Lightbox“ geändert", - "dateien": { - "lightbox": "\nLightbox\n----------------------------------------\n\nkern\n----------------------------------------\n\nZeigt eine vergrößerte Ansicht der Optionsabbildung mit ihrem Namen\n----------------------------------------\n\n- lightboxSelect bestätigt Auswahl und schließt\n- Escape und x-Icon schließen\n- Tab und Shift-Tab zirkulieren im Fokusring\n- Geschlossen kehrt Fokus zum Auslöser zurück\n- hidden-Attribut entfernt aus dem Barrierefreiheitsbaum\n----------------------------------------\n\nAuswahl bestätigen\n\nWählt eine Option im aktuellen Schritt und berechnet die gültigen Folgeschritte neu\n\n- Bleibt im aktuellen Schritt\n- Invalidiert Folgeschritte mit ungültigen Kombinationen\n- Setzt Fokus auf die gewählte Option\n- Aktualisiert Galerie und Preis\n\n- Lightbox mit Option öffnen\n- LMB auf Auswahl bestätigen\n- Option markiert\n----------------------------------------\n\nKonfigurator schließen\n\n- Schließt die Lightbox, ohne den Konfigurator zu schließen\n- x-Icon oder Escape beenden die Lightbox\n- Fokus kehrt zum Auslöser in der Optionsliste zurück\n\n- LMB auf Option mit Bildauswahl\n- Escape drücken\n- Lightbox geschlossen, Modal offen\n----------------------------------------\n\nLightbox schließen\n\nEntfernt die vergrößerte Produktansicht wieder\n\n- x-Icon oder Escape schließt\n- Zurück zum Dialog gibt Focus\n\n- Lightbox öffnen\n- Escape drücken\n- Lightbox geschlossen, Dialog fokussiert\n----------------------------------------\n\nLightbox öffnen\n\nZeigt das Produktfoto einer Variante option in Originalgröße\n\n- lightboxImage zeigt option.media\n- lightboxCaption zeigt option.name\n- lightboxSelect erhält Fokus\n\n- Modal öffnen\n- Auf Option mit Bild klicken\n- Info-Button der Option klicken\n- Lightbox zeigt das Foto in Originalgröße\n----------------------------------------\n\nTastatur verwenden\n\nBedient Modal und Lightbox per Tastatur\n\n- Escape schließt Lightbox oder Modal\n- Tab zirkuliert im Fokusring vorwärts\n- Shift-Tab zirkuliert im Fokusring rückwärts\n\n- Modal öffnen\n- Lightbox öffnen\n- Escape drücken\n- Lightbox geschlossen\n- Escape drücken\n- Modal geschlossen\n" - } - }, - { - "titel": "„Lightbox“ geändert", - "dateien": { - "lightbox": "\nLightbox\n----------------------------------------\n\nkern\n----------------------------------------\n\nZeigt eine vergrößerte Ansicht der Optionsabbildung mit ihrem Namen\n----------------------------------------\n\n- lightboxSelect bestätigt Auswahl\n- lightboxSelect schließt\n- Escape schließt\n- x-Icon schließt\n- Geschlossen kehrt Fokus zum Auslöser zurück\n- hidden-Attribut entfernt aus dem Barrierefreiheitsbaum\n----------------------------------------\n\nAuswahl bestätigen\n\nWählt eine Option im aktuellen Schritt und berechnet die gültigen Folgeschritte neu\n\n- Bleibt im aktuellen Schritt\n- Invalidiert Folgeschritte mit ungültigen Kombinationen\n- Setzt Fokus auf die gewählte Option\n- Aktualisiert Galerie und Preis\n\n- Lightbox mit Option öffnen\n- LMB auf Auswahl bestätigen\n- Option markiert\n----------------------------------------\n\nKonfigurator schließen\n\n- Schließt die Lightbox, ohne den Konfigurator zu schließen\n- x-Icon oder Escape beenden die Lightbox\n- Fokus kehrt zum Auslöser in der Optionsliste zurück\n\n- LMB auf Option mit Bildauswahl\n- Escape drücken\n- Lightbox geschlossen, Modal offen\n----------------------------------------\n\nLightbox schließen\n\nEntfernt die vergrößerte Produktansicht wieder\n\n- x-Icon oder Escape schließt\n- Zurück zum Dialog gibt Focus\n\n- Lightbox öffnen\n- Escape drücken\n- Lightbox geschlossen, Dialog fokussiert\n----------------------------------------\n\nLightbox öffnen\n\nZeigt das Produktfoto einer Variante option in Originalgröße\n\n- lightboxImage zeigt option.media\n- lightboxCaption zeigt option.name\n- lightboxSelect erhält Fokus\n\n- Modal öffnen\n- Auf Option mit Bild klicken\n- Info-Button der Option klicken\n- Lightbox zeigt das Foto in Originalgröße\n----------------------------------------\n\nTastatur verwenden\n\nBedient Modal und Lightbox per Tastatur\n\n- Escape schließt Lightbox oder Modal\n- Tab zirkuliert im Fokusring vorwärts\n- Shift-Tab zirkuliert im Fokusring rückwärts\n\n- Modal öffnen\n- Lightbox öffnen\n- Escape drücken\n- Lightbox geschlossen\n- Escape drücken\n- Modal geschlossen\n" - } - }, - { - "titel": "„Konfigurator“ geändert", - "dateien": { - "konfigurator": "\nKonfigurator\n----------------------------------------\n\nkern\n----------------------------------------\n\nFührt durch Variantenkonfiguration in Einzelschritten mit Live-Vorschau\n----------------------------------------\n\n- Aktiv nur wenn Produkt mto_variant_configurator_active gesetzt hat\n- Optionen-Bilder nur bis zwei Schritte\n- Galerie und Preis aktualisieren live ohne Seitenreload\n- Body erhält CSS-Klasse mto-vc-modal-open solange Modal offen\n- Escape schließt Modal\n- Schließen stellt Fokus auf vorheriges Element\n- Registriert als mto-vc-variants-card in swProductDetail\n- Einstellungen in customFields des Produkts gespeichert\n- Falls inaktiv: Fallback auf Standard-Konfigurator von Shopware\n- Natives Select pro Gruppe im DOM\n- Schritte ohne gültige Optionen werden beim Navigieren übersprungen\n- Ungültige Kombinationen für Folgeschritte werden beim Wählen verworfen\n- Unbesuchte Schritte werden beim Bestätigen mit erster gültiger Option aufgefüllt\n- Deaktivierte Optionen sind nicht auswählbar\n- Gallery-Container erhält CSS-Klasse has-no-gallery wenn keine Bilder vorhanden\n- Schließen bei Lightbox: fokus auf Lightbox-Auswahl-Button\n----------------------------------------\n\nGeführte Konfiguration aktivieren\n\nFührt Kunden schrittweise durch die Variantenauswahl mit Hinweisen und Modal\n\n- Aktiviert bei Produkten mit aktivem Konfigurator-Layout\n- Zeigt jeden Konfigurationsschritt mit Beschriftung\n- Blendentext je Gruppe über Modal aus\n- Inkrementelle Variantenauflösung über resolveUrl\n\n- Produktseite mit aktivem Konfigurator öffnen\n- LMB auf ersten Konfigurationsschritt\n- Option im Modal wählen\n- Modal schließt und nächster Schritt markiert\n----------------------------------------\n\nKonfigurationsdaten abrufen\n\nLiefert Variantendaten für eine Live-Aktualisierung im Konfigurator\n\n- Endpoint mto-variant-configurator resolve\n- Query-Parameter switched enthält die aktuell gewechselte Gruppe\n- Query-Parameter options enthält ein JSON-Array gewählter Optionen\n- Ungültiges JSON führt zu leerem options-Array\n- VariantNotFoundException hält productId als Fallback\n- Rückgabe enthält variantId, gallery media und Preis\n- Kein HTTP-Cache wegen kundenspezifischer Preise\n\n- Resolve-Endpunkt mit Produkt-ID und Option aufrufen\n- Antwort enthält variantId\n- Antwort enthält gallery media\n- Antwort enthält Preis\n----------------------------------------\n\nKonfigurator öffnen\n\nÖffnet den Konfigurator ab einem gewählten Schritt\n\n- Erster Aufruf zeigt das Modal\n- Weiterer Aufruf wechselt den Schritt\n- Fokus vorheriges Element wird gespeichert\n- Body erhält CSS-Klasse mto-vc-modal-open\n- Escape-Schließen wird registriert\n- Galerie und Preis werden aktualisiert\n- Fokus springt auf den Next-Button\n\n- LMB auf Konfigurator-Trigger klicken\n- Modal erscheint im gewählten Schritt\n----------------------------------------\n\nKonfigurator-Karte registrieren\n\nMacht die Einstellungen des Varianten-Konfigurators auf der Produktdetail-Seite verfügbar\n\n- Registriert als mto-vc-variants-card\n- Nutzt Produkt aus swProductDetail\n- Speichert Einstellungen in customFields des Produkts\n\n- Produktdetail-Seite eines Produkts öffnen\n- Tab Variants aufrufen\n- Registrierte mto-vc-variants-card wird angezeigt\n----------------------------------------\n\nPlugin registrieren\n\nMacht das Plugin für Elemente mit dem Selektor verfügbar\n\n- Registriert unter VariantConfiguratorPlugin\n- Nutzt window.PluginManager\n- Bindet an [data-mto-variant-configurator]\n\n- PluginManager.register aufrufen\n- Element mit data-mto-variant-configurator erstellen\n- Plugin auf Element angewendet\n" - } - }, - { - "titel": "„Lightbox“ geändert", - "dateien": { - "lightbox": "\nLightbox\n----------------------------------------\n\nkern\n----------------------------------------\n\nZeigt eine vergrößerte Ansicht der Optionsabbildung mit ihrem Namen\n----------------------------------------\n\n- lightboxSelect bestätigt Auswahl\n- lightboxSelect schließt\n- Escape schließt\n- x-Icon schließt\n- Geschlossen kehrt Fokus zum Auslöser zurück\n- hidden-Attribut entfernt aus dem Barrierefreiheitsbaum\n----------------------------------------\n\nAuswahl bestätigen\n\nWählt eine Option im aktuellen Schritt und berechnet die gültigen Folgeschritte neu\n\n- Bleibt im aktuellen Schritt\n- Invalidiert Folgeschritte mit ungültigen Kombinationen\n- Setzt Fokus auf die gewählte Option\n- Aktualisiert Galerie und Preis\n\n- Lightbox mit Option öffnen\n- LMB auf Auswahl bestätigen\n- Option markiert\n----------------------------------------\n\nKonfigurator schließen\n\n- Schließt die Lightbox, ohne den Konfigurator zu schließen\n- x-Icon oder Escape beenden die Lightbox\n- Fokus kehrt zum Auslöser in der Optionsliste zurück\n\n- LMB auf Option mit Bildauswahl\n- Escape drücken\n- Lightbox geschlossen, Modal offen\n----------------------------------------\n\nLightbox schließen\n\nEntfernt die vergrößerte Produktansicht wieder\n\n- x-Icon schließt\n- Escape schließt\n- Zurück zum Dialog gibt Focus\n\n- Lightbox öffnen\n- Escape drücken\n- Lightbox geschlossen, Dialog fokussiert\n----------------------------------------\n\nLightbox öffnen\n\nZeigt das Produktfoto einer Variante option in Originalgröße\n\n- lightboxImage zeigt option.media\n- lightboxCaption zeigt option.name\n- lightboxSelect erhält Fokus\n\n- Modal öffnen\n- Auf Option mit Bild klicken\n- Info-Button der Option klicken\n- Lightbox zeigt das Foto in Originalgröße\n----------------------------------------\n\nTastatur verwenden\n\nBedient Modal und Lightbox per Tastatur\n\n- Escape schließt Lightbox oder Modal\n- Tab zirkuliert im Fokusring vorwärts\n- Shift-Tab zirkuliert im Fokusring rückwärts\n\n- Modal öffnen\n- Lightbox öffnen\n- Escape drücken\n- Lightbox geschlossen\n- Escape drücken\n- Modal geschlossen\n" - } - }, - { - "titel": "„Option ansehen“ geändert", - "dateien": { - "option-ansehen": "\nOption ansehen\n----------------------------------------\n\nkern\n----------------------------------------\n\nDer Kunde prüft eine Option groß, bevor er sie nimmt\n----------------------------------------\n\n- Nur Optionen mit Bild tragen den Hinweis\n- Optionsbilder erscheinen bis zwei Schritte\n- Ansicht liegt über dem Konfigurator\n----------------------------------------\n\nOptionsdetail öffnen\n\nZeigt Bild und Namen einer Option in voller Größe\n\n- i-Icon öffnet die Ansicht\n- Enter öffnet die Ansicht\n- Leertaste öffnet die Ansicht\n\n- Konfigurator öffnen\n- LMB auf i-Icon einer Option\n- Große Ansicht erscheint\n----------------------------------------\n\nOption aus Ansicht wählen\n\nÜbernimmt die betrachtete Option in die Auswahl\n\n- Knopf übernimmt und schließt die Ansicht\n- Schritt bleibt derselbe\n\n- Optionsdetail öffnen\n- LMB auf Wählen-Knopf\n- Option ist gewählt\n----------------------------------------\n\nAnsicht schließen\n\nKehrt zur Optionsliste zurück ohne Auswahl\n\n- x-Icon schließt die Ansicht\n- Escape schließt die Ansicht\n- Konfigurator bleibt offen\n\n- Optionsdetail öffnen\n- Escape drücken\n- Optionsliste erscheint wieder\n" - } - }, - { - "titel": "„Varianten wählen“ geändert", - "dateien": { - "varianten-waehlen": "\nVarianten wählen\n----------------------------------------\n\nkern\n----------------------------------------\n\nDer Kunde findet Schritt für Schritt eine bestellbare Kombination\n----------------------------------------\n\n- Erster Schritt zeigt alle Optionen seiner Eigenschaft\n- Folgeschritte zeigen nur kombinierbare Optionen\n- Reihenfolge der Schritte kommt aus dem Backend\n- Ohne Auswahl greifen die Standardvarianten des Elternartikels\n- Schritte ohne gültige Option werden übersprungen\n- Eine Auswahl wechselt den Schritt nicht\n- Ungültige Folgeauswahl fällt beim Wechsel weg\n- Escape schließt den Konfigurator\n- Tabulator bleibt im Dialog\n----------------------------------------\n\nSchritt öffnen\n\nÖffnet den Konfigurator beim angeklickten Schritt\n\n- LMB auf einen Schritt öffnet das Modal\n- Offener Konfigurator wechselt nur den Schritt\n- Modal hängt am Seitenkörper\n\n- Produktseite öffnen\n- LMB auf zweiten Schritt\n- Modal öffnet bei Schritt 2\n----------------------------------------\n\nOption wählen\n\nÜbernimmt eine Option in die laufende Auswahl\n\n- Gewählte Option ist hervorgehoben\n- Nicht kombinierbare Optionen sind gesperrt\n- Auswahl verwirft ungültige Folgeschritte\n\n- Konfigurator öffnen\n- LMB auf eine Option\n- Option ist hervorgehoben\n----------------------------------------\n\nNächsten Schritt anzeigen\n\nFührt zum nächsten Schritt mit gültigen Optionen\n\n- Weiter-Knopf heißt am letzten Schritt Fertig\n- Leere Schritte werden übersprungen\n\n- Konfigurator öffnen\n- LMB auf Weiter-Knopf\n- Nächster Schritt erscheint\n----------------------------------------\n\nVorherigen Schritt anzeigen\n\nFührt zurück zum letzten Schritt mit Optionen\n\n- Zurück-Knopf ist am ersten Schritt gesperrt\n- Leere Schritte werden übersprungen\n\n- Zum zweiten Schritt gehen\n- LMB auf Zurück-Knopf\n- Erster Schritt erscheint\n----------------------------------------\n\nAuswahl übernehmen\n\nWechselt das Produkt auf die gewählte Variante\n\n- Fertig schreibt die Auswahl in die Auswahlfelder\n- Unbesuchte Schritte bekommen die erste gültige Option\n- Der Variantenwechsel von Shopware führt den Wechsel aus\n\n- Alle Schritte durchgehen\n- LMB auf Fertig-Knopf\n- Seite zeigt die gewählte Variante\n----------------------------------------\n\nKonfigurator schließen\n\nBeendet die Auswahl ohne Wechsel der Variante\n\n- x-Icon schließt das Modal\n- Escape schließt das Modal\n- Fokus kehrt zum Auslöser zurück\n\n- Konfigurator öffnen\n- Escape drücken\n- Modal ist geschlossen\n" - } - }, - { - "titel": "„Vorschau zeigen“ geändert", - "dateien": { - "vorschau-zeigen": "\nVorschau zeigen\n----------------------------------------\n\nkern\n----------------------------------------\n\nDer Kunde sieht Bild und Preis der gewählten Kombination\n----------------------------------------\n\n- Preis stimmt mit dem Preis der Produktseite überein\n- Antwort wird nicht zwischengespeichert\n- Späte Antworten überholter Anfragen werden verworfen\n- Ohne eigene Bilder greifen die Bilder des Elternartikels\n----------------------------------------\n\nVorschau laden\n\nHolt Bilder und Preis zur laufenden Auswahl\n\n- Jede Auswahl löst eine neue Anfrage aus\n- Ohne Treffer bleibt die Produkt-ID als Rückfall\n- Erstes Bild ist das Titelbild der Variante\n\n- Konfigurator öffnen\n- Andere Option wählen\n- Bild und Preis ändern sich\n----------------------------------------\n\nGalerie blättern\n\nZeigt weitere Bilder der gewählten Variante\n\n- Pfeil-Icons blättern vor und zurück\n- Nach dem letzten Bild folgt das erste\n- Bei einem Bild bleibt die Navigation aus\n\n- Konfigurator öffnen\n- LMB auf Vor-Icon\n- Nächstes Bild erscheint\n----------------------------------------\n\nBild wählen\n\nWechselt das große Bild über die Vorschaubilder\n\n- Aktives Vorschaubild ist hervorgehoben\n- Großes Bild folgt der Wahl\n\n- Konfigurator öffnen\n- LMB auf drittes Vorschaubild\n- Großes Bild zeigt dieses Motiv\n" - } - }, - { - "titel": "„Varianten wählen“ geändert", - "dateien": { - "varianten-waehlen": "\nVarianten wählen\n----------------------------------------\n\nkern\n----------------------------------------\n\nDer Kunde findet Schritt für Schritt eine bestellbare Kombination\n----------------------------------------\n\n- Erster Schritt zeigt alle Optionen seiner Eigenschaft\n- Folgeschritte zeigen nur kombinierbare Optionen\n- Der Ablauf trägt beliebig viele Eigenschaften\n- Reihenfolge der Schritte kommt aus dem Backend\n- Ohne Auswahl greifen die Standardvarianten des Elternartikels\n- Schritte ohne gültige Option werden übersprungen\n- Eine Auswahl wechselt den Schritt nicht\n- Ungültige Folgeauswahl fällt beim Wechsel weg\n- Auf kleinen Bildschirmen bleibt der Ablauf derselbe\n- Escape schließt den Konfigurator\n- Tabulator bleibt im Dialog\n----------------------------------------\n\nSchritt öffnen\n\nÖffnet den Konfigurator beim angeklickten Schritt\n\n- LMB auf einen Schritt öffnet das Modal\n- Offener Konfigurator wechselt nur den Schritt\n- Modal hängt am Seitenkörper\n\n- Produktseite öffnen\n- LMB auf zweiten Schritt\n- Modal öffnet bei Schritt 2\n----------------------------------------\n\nOption wählen\n\nÜbernimmt eine Option in die laufende Auswahl\n\n- Gewählte Option ist hervorgehoben\n- Nicht kombinierbare Optionen sind gesperrt\n- Auswahl verwirft ungültige Folgeschritte\n- Schritt bleibt nach der Wahl derselbe\n\n- Konfigurator öffnen\n- LMB auf eine Option\n- Option ist hervorgehoben\n----------------------------------------\n\nNächsten Schritt anzeigen\n\nFührt zum nächsten Schritt mit gültigen Optionen\n\n- Weiter-Knopf heißt am letzten Schritt Fertig\n- Leere Schritte werden übersprungen\n\n- Konfigurator öffnen\n- LMB auf Weiter-Knopf\n- Nächster Schritt erscheint\n----------------------------------------\n\nVorherigen Schritt anzeigen\n\nFührt zurück zum letzten Schritt mit Optionen\n\n- Zurück-Knopf ist am ersten Schritt gesperrt\n- Leere Schritte werden übersprungen\n\n- Zum zweiten Schritt gehen\n- LMB auf Zurück-Knopf\n- Erster Schritt erscheint\n----------------------------------------\n\nAuswahl übernehmen\n\nWechselt das Produkt auf die gewählte Variante\n\n- Fertig schreibt die Auswahl in die Auswahlfelder\n- Unbesuchte Schritte bekommen die erste gültige Option\n- Der Variantenwechsel von Shopware führt den Wechsel aus\n- Die Seite zeigt danach die Adresse der Variante\n\n- Alle Schritte durchgehen\n- LMB auf Fertig-Knopf\n- Produktseite zeigt die gewählte Variante\n----------------------------------------\n\nKonfigurator schließen\n\nBeendet die Auswahl ohne Wechsel der Variante\n\n- x-Icon schließt das Modal\n- Escape schließt das Modal\n- Fokus kehrt zum Auslöser zurück\n\n- Konfigurator öffnen\n- Escape drücken\n- Modal ist geschlossen\n" - } - }, - { - "titel": "„Layout zuweisen“ geändert", - "dateien": { - "layout-zuweisen": "\nLayout zuweisen\n----------------------------------------\n\nkern\n----------------------------------------\n\nEin Händler entscheidet je Produkt, ob die geführte Auswahl erscheint\n----------------------------------------\n\n- Einstellungen liegen auf dem Varianten-Tab des Produkts\n- Werte stehen in den customFields des Produkts\n- Bearbeiten erfordert das Recht product.editor\n- Ohne Zuweisung bleibt das Standardlayout aktiv\n----------------------------------------\n\nKonfigurator aktivieren\n\nSchaltet die geführte Variantenauswahl für ein Produkt frei\n\n- Schalter steht auf dem Varianten-Tab\n- Aktiv ersetzt die Buybox des Produkts\n- Inaktiv zeigt das Standardlayout von Shopware\n\n- Produkt im Admin öffnen\n- Varianten-Tab öffnen\n- Schalter aktivieren und speichern\n- Buybox zeigt die geführte Auswahl\n----------------------------------------\n\nOptionsübersicht hinterlegen\n\nHinterlegt ein PDF mit allen Varianten und Kombinationen\n\n- Medienfeld steht auf dem Varianten-Tab\n- Feld hängt am Hauptartikel\n- Ohne PDF bleibt der Knopf unsichtbar\n\n- Varianten-Tab öffnen\n- PDF im Medienfeld wählen\n- Produkt speichern\n- Modal zeigt den Knopf für Optionen\n----------------------------------------\n\nTrust-Logo hinterlegen\n\nZeigt ein Vertrauenssiegel neben dem Gesamtpreis\n\n- Logo steht in der Plugin-Konfiguration\n- Gilt für den ganzen Verkaufskanal\n- Ohne Logo erscheint nur der Text\n\n- Plugin-Konfiguration öffnen\n- Logo im Medienfeld wählen\n- Modal zeigt das Logo am Preis\n----------------------------------------\n\nOptionsbild zuordnen\n\noffen\n\nHinterlegt je Variante ein Farbbild oder Materialbild\n\n- Zuordnung erfolgt auf Variantenebene\n- Bild erscheint neben der Option im Modal\n\n- Variante im Admin öffnen\n- Bild der Variante zuordnen\n- Modal zeigt das Bild an der Option\n" - } - }, - { - "titel": "„Varianten wählen“ geändert", - "dateien": { - "varianten-waehlen": "\nVarianten wählen\n----------------------------------------\n\nkern\n----------------------------------------\n\nDer Kunde findet Schritt für Schritt eine bestellbare Kombination\n----------------------------------------\n\n- Erster Schritt zeigt alle Optionen seiner Eigenschaft\n- Folgeschritte zeigen nur kombinierbare Optionen\n- Der Ablauf trägt beliebig viele Eigenschaften\n- Reihenfolge der Schritte kommt aus dem Backend\n- Ohne Auswahl greifen die Standardvarianten des Elternartikels\n- Schritte ohne gültige Option werden übersprungen\n- Eine Auswahl wechselt den Schritt nicht\n- Ungültige Folgeauswahl fällt beim Wechsel weg\n- Auf kleinen Bildschirmen bleibt der Ablauf derselbe\n- Escape schließt den Konfigurator\n- Tabulator bleibt im Dialog\n----------------------------------------\n\nSchritt öffnen\n\nÖffnet den Konfigurator beim angeklickten Schritt\n\n- LMB auf einen Schritt öffnet das Modal\n- Offener Konfigurator wechselt nur den Schritt\n- Modal hängt am Seitenkörper\n\n- Produktseite öffnen\n- LMB auf zweiten Schritt\n- Modal öffnet bei Schritt 2\n----------------------------------------\n\nOption wählen\n\nÜbernimmt eine Option in die laufende Auswahl\n\n- Gewählte Option ist hervorgehoben\n- Nicht kombinierbare Optionen sind gesperrt\n- Auswahl verwirft ungültige Folgeschritte\n- Schritt bleibt nach der Wahl derselbe\n\n- Konfigurator öffnen\n- LMB auf eine Option\n- Option ist hervorgehoben\n----------------------------------------\n\nNächsten Schritt anzeigen\n\nFührt zum nächsten Schritt mit gültigen Optionen\n\n- Weiter-Knopf heißt am letzten Schritt Fertig\n- Leere Schritte werden übersprungen\n\n- Konfigurator öffnen\n- LMB auf Weiter-Knopf\n- Nächster Schritt erscheint\n----------------------------------------\n\nVorherigen Schritt anzeigen\n\nFührt zurück zum letzten Schritt mit Optionen\n\n- Zurück-Knopf ist am ersten Schritt gesperrt\n- Leere Schritte werden übersprungen\n\n- Zum zweiten Schritt gehen\n- LMB auf Zurück-Knopf\n- Erster Schritt erscheint\n----------------------------------------\n\nAuswahl übernehmen\n\nWechselt das Produkt auf die gewählte Variante\n\n- Fertig überträgt die Auswahl in die Auswahlfelder\n- Unbesuchte Schritte bekommen die erste gültige Option\n- Shopware führt den Variantenwechsel aus\n\n- Alle Schritte durchgehen\n- LMB auf Fertig-Knopf\n- Produktseite zeigt die gewählte Variante\n----------------------------------------\n\nKonfigurator schließen\n\nBeendet die Auswahl ohne Wechsel der Variante\n\n- x-Icon schließt das Modal\n- Escape schließt das Modal\n- Fokus kehrt zum Auslöser zurück\n\n- Konfigurator öffnen\n- Escape drücken\n- Modal ist geschlossen\n" - } - }, - { - "titel": "„Schritt zeigen“ geändert", - "dateien": { - "schritt-zeigen": "\nSchritt zeigen\n----------------------------------------\n\nkern\n----------------------------------------\n\nDer Kunde weiß im Modal, wo er steht und was er wählt\n----------------------------------------\n\n- Optionen stehen rechts, die Bilder links\n- Lange Optionslisten lassen sich scrollen\n----------------------------------------\n\nEigenschaft benennen\n\nZeigt den Namen der Eigenschaft des aktuellen Schritts\n\n- Name steht als Überschrift über der Liste\n- Name kommt aus der Eigenschaftsgruppe\n\n- Konfigurator öffnen\n- Überschrift nennt die erste Eigenschaft\n----------------------------------------\n\nSchrittstand anzeigen\n\nZeigt den aktuellen Schritt und die Gesamtzahl\n\n- Zähler nennt Schritt und Gesamtzahl\n- Balken wächst mit dem Fortschritt\n- Text kommt aus einem Textbaustein\n\n- Konfigurator öffnen\n- Zähler zeigt 1 von 3\n----------------------------------------\n\nOptionen auflisten\n\nZeigt alle Optionen der Eigenschaft mit Namen und Bild\n\n- Jede Option nennt ihren Namen\n- Bild erscheint nur bis zwei Schritte\n- Ohne Bild erscheint der Farbwert\n- Ohne Farbwert bleibt die Zeile ohne Zeichen\n\n- Konfigurator öffnen\n- Jede Option zeigt ihren Namen\n" - } - } -] diff --git a/daten/MtoVariantConfigurator/.planung/auswahl-anstossen.md b/daten/MtoVariantConfigurator/.planung/auswahl-anstossen.md deleted file mode 100644 index 665f2fa..0000000 --- a/daten/MtoVariantConfigurator/.planung/auswahl-anstossen.md +++ /dev/null @@ -1,49 +0,0 @@ - -Auswahl anstoßen ----------------------------------------- - -kern ----------------------------------------- - -Der Kunde erkennt in der Buybox die Reihenfolge der Schritte ----------------------------------------- - -- Jede Eigenschaft bildet einen eigenen Schritt -- Natives Auswahlfeld bleibt für den Variantenwechsel erhalten -- Eigene Darstellung gilt unabhängig vom Anzeigetyp der Eigenschaft -- Ohne aktives Layout erscheint die Standard-Buybox ----------------------------------------- - -Schrittnummer anzeigen - -Zeigt neben jeder Eigenschaft ihre Position im Ablauf - -- Beschriftung nennt das Wort Schritt und die Nummer -- Nummer folgt der Reihenfolge aus dem Backend - -- Produktseite öffnen -- Erste Eigenschaft zeigt Schritt 1 ----------------------------------------- - -Hinweistext anzeigen - -Erklärt dem Kunden, worauf er im Schritt achtet - -- Text kommt aus einem Textbaustein je Schritt -- Leerer Textbaustein blendet den Hinweis aus -- Hinweis hängt an der Nummer statt an der Eigenschaft - -- Textbaustein für Schritt 1 füllen -- Produktseite öffnen -- Hinweis steht unter der Überschrift ----------------------------------------- - -Gewählte Option anzeigen - -Zeigt am Schritt, welche Option gerade gilt - -- Ohne Auswahl steht dort Bitte wählen -- Vorbelegung erscheint ohne Zutun des Kunden - -- Hauptartikel ohne Variante öffnen -- Jeder Schritt nennt eine Option diff --git a/daten/MtoVariantConfigurator/.planung/beratung-anbieten.md b/daten/MtoVariantConfigurator/.planung/beratung-anbieten.md deleted file mode 100644 index c0beeb5..0000000 --- a/daten/MtoVariantConfigurator/.planung/beratung-anbieten.md +++ /dev/null @@ -1,47 +0,0 @@ - -Beratung anbieten ----------------------------------------- - -optional ----------------------------------------- - -Der Kunde findet im Konfigurator Vertrauen und einen Kontakt ----------------------------------------- - -- Alle Texte kommen aus Textbausteinen -- Leerer Textbaustein blendet den Bereich aus ----------------------------------------- - -Vertrauen zeigen - -Zeigt Siegel und Zusage neben dem Gesamtpreis - -- Logo stammt aus der Plugin-Konfiguration -- Ohne Logo bleibt der Text stehen - -- Konfigurator öffnen -- Siegel steht neben dem Preis ----------------------------------------- - -Beratung erreichen - -Bietet eine Telefonnummer für Fragen zur Konfiguration - -- Nummer ist als Telefonlink klickbar -- Leere Nummer blendet den Bereich aus - -- Konfigurator öffnen -- LMB auf die Nummer -- Telefon-App öffnet sich ----------------------------------------- - -Optionsübersicht öffnen - -Öffnet das hinterlegte PDF mit allen Optionen - -- Knopf erscheint nur mit hinterlegtem PDF -- PDF öffnet in einem neuen Tab - -- Konfigurator öffnen -- LMB auf Optionen-Knopf -- PDF öffnet in neuem Tab diff --git a/daten/MtoVariantConfigurator/.planung/layout-zuweisen.md b/daten/MtoVariantConfigurator/.planung/layout-zuweisen.md deleted file mode 100644 index 1e06c7a..0000000 --- a/daten/MtoVariantConfigurator/.planung/layout-zuweisen.md +++ /dev/null @@ -1,69 +0,0 @@ - -Layout zuweisen ----------------------------------------- - -kern ----------------------------------------- - -Ein Händler entscheidet je Produkt, ob die geführte Auswahl erscheint ----------------------------------------- - -- Einstellungen liegen auf dem Varianten-Tab des Produkts -- Werte stehen in den customFields des Produkts -- Bearbeiten erfordert das Recht product.editor -- Ohne Zuweisung bleibt das Standardlayout aktiv ----------------------------------------- - -Konfigurator aktivieren - -Schaltet die geführte Variantenauswahl für ein Produkt frei - -- Schalter steht auf dem Varianten-Tab -- Aktiv ersetzt die Buybox des Produkts -- Inaktiv zeigt das Standardlayout von Shopware - -- Produkt im Admin öffnen -- Varianten-Tab öffnen -- Schalter aktivieren und speichern -- Buybox zeigt die geführte Auswahl ----------------------------------------- - -Optionsübersicht hinterlegen - -Hinterlegt ein PDF mit allen Varianten und Kombinationen - -- Medienfeld steht auf dem Varianten-Tab -- Feld hängt am Hauptartikel -- Ohne PDF bleibt der Knopf unsichtbar - -- Varianten-Tab öffnen -- PDF im Medienfeld wählen -- Produkt speichern -- Modal zeigt den Knopf für Optionen ----------------------------------------- - -Trust-Logo hinterlegen - -Zeigt ein Vertrauenssiegel neben dem Gesamtpreis - -- Logo steht in der Plugin-Konfiguration -- Gilt für den ganzen Verkaufskanal -- Ohne Logo erscheint nur der Text - -- Plugin-Konfiguration öffnen -- Logo im Medienfeld wählen -- Modal zeigt das Logo am Preis ----------------------------------------- - -Optionsbild am Datensatz pflegen - -offen - -Hinterlegt das Bild einer Option am Datensatz der Variante - -- Feld liegt im Formular der einzelnen Variante -- Heute stammt das Bild aus der Eigenschaftsgruppe - -- Variante im Admin öffnen -- Bildfeld der Variante füllen -- Variante speichern diff --git a/daten/MtoVariantConfigurator/.planung/option-ansehen.md b/daten/MtoVariantConfigurator/.planung/option-ansehen.md deleted file mode 100644 index bda54d3..0000000 --- a/daten/MtoVariantConfigurator/.planung/option-ansehen.md +++ /dev/null @@ -1,51 +0,0 @@ - -Option ansehen ----------------------------------------- - -kern ----------------------------------------- - -Der Kunde prüft eine Option groß, bevor er sie nimmt ----------------------------------------- - -- Nur Optionen mit Bild tragen den Hinweis -- Ansicht liegt über dem Konfigurator ----------------------------------------- - -Optionsdetail öffnen - -Zeigt Bild und Namen einer Option in voller Größe - -- i-Icon öffnet die Ansicht -- Enter öffnet die Ansicht -- Leertaste öffnet die Ansicht - -- Konfigurator öffnen -- LMB auf i-Icon einer Option -- Große Ansicht erscheint ----------------------------------------- - -Option aus Ansicht wählen - -Übernimmt die betrachtete Option in die Auswahl - -- Knopf übernimmt die Option -- Knopf schließt die Ansicht -- Schritt bleibt derselbe - -- Optionsdetail öffnen -- LMB auf Wählen-Knopf -- Option ist gewählt ----------------------------------------- - -Ansicht schließen - -Kehrt zur Optionsliste zurück ohne Auswahl - -- x-Icon schließt die Ansicht -- Escape schließt die Ansicht -- Konfigurator bleibt offen - -- Optionsdetail öffnen -- Escape drücken -- Optionsliste erscheint wieder diff --git a/daten/MtoVariantConfigurator/.planung/schritt-zeigen.md b/daten/MtoVariantConfigurator/.planung/schritt-zeigen.md deleted file mode 100644 index 3ceb620..0000000 --- a/daten/MtoVariantConfigurator/.planung/schritt-zeigen.md +++ /dev/null @@ -1,49 +0,0 @@ - -Schritt zeigen ----------------------------------------- - -kern ----------------------------------------- - -Der Kunde weiß im Modal, wo er steht und was er wählt ----------------------------------------- - -- Optionen stehen rechts -- Bilder links -- Lange Optionslisten lassen sich scrollen ----------------------------------------- - -Eigenschaft benennen - -Zeigt den Namen der Eigenschaft des aktuellen Schritts - -- Name steht als Überschrift über der Liste -- Name kommt aus der Eigenschaftsgruppe - -- Konfigurator öffnen -- Überschrift nennt die erste Eigenschaft ----------------------------------------- - -Schrittstand anzeigen - -Zeigt den aktuellen Schritt und die Gesamtzahl - -- Zähler nennt Schritt und Gesamtzahl -- Balken wächst mit dem Fortschritt -- Text kommt aus einem Textbaustein - -- Konfigurator öffnen -- Zähler zeigt 1 von 3 ----------------------------------------- - -Optionen auflisten - -Zeigt alle Optionen der Eigenschaft mit Namen und Bild - -- Jede Option nennt ihren Namen -- Bild erscheint nur bis zwei Schritte -- Ohne Bild erscheint der Farbwert -- Ohne Farbwert bleibt die Zeile ohne Zeichen - -- Konfigurator öffnen -- Jede Option zeigt ihren Namen diff --git a/daten/MtoVariantConfigurator/.planung/varianten-waehlen.md b/daten/MtoVariantConfigurator/.planung/varianten-waehlen.md deleted file mode 100644 index c732ab7..0000000 --- a/daten/MtoVariantConfigurator/.planung/varianten-waehlen.md +++ /dev/null @@ -1,109 +0,0 @@ - -Varianten wählen ----------------------------------------- - -kern ----------------------------------------- - -Der Kunde findet Schritt für Schritt eine bestellbare Kombination ----------------------------------------- - -- Erster Schritt zeigt alle Optionen seiner Eigenschaft -- Folgeschritte zeigen nur kombinierbare Optionen -- Der Ablauf trägt beliebig viele Eigenschaften -- Reihenfolge der Schritte kommt aus dem Backend -- Ohne Auswahl greifen die Standardvarianten des Elternartikels -- Schritte ohne gültige Option werden übersprungen -- Eine Auswahl wechselt den Schritt nicht -- Ungültige Folgeauswahl fällt beim Wechsel weg -- Auf kleinen Bildschirmen bleibt der Ablauf derselbe -- Escape schließt den Konfigurator -- Tabulator bleibt im Dialog ----------------------------------------- - -Schritt öffnen - -Öffnet den Konfigurator beim angeklickten Schritt - -- LMB auf einen Schritt öffnet das Modal -- Offener Konfigurator wechselt nur den Schritt -- Modal hängt am Seitenkörper - -- Produktseite öffnen -- LMB auf zweiten Schritt -- Modal öffnet bei Schritt 2 ----------------------------------------- - -Option wählen - -Übernimmt eine Option in die laufende Auswahl - -- Gewählte Option ist hervorgehoben -- Nicht kombinierbare Optionen sind gesperrt -- Auswahl verwirft ungültige Folgeschritte -- Schritt bleibt nach der Wahl derselbe - -- Konfigurator öffnen -- LMB auf eine Option -- Option ist hervorgehoben ----------------------------------------- - -Nächsten Schritt anzeigen - -Führt zum nächsten Schritt mit gültigen Optionen - -- Weiter-Knopf heißt am letzten Schritt Fertig -- Leere Schritte werden übersprungen - -- Konfigurator öffnen -- LMB auf Weiter-Knopf -- Nächster Schritt erscheint ----------------------------------------- - -Vorherigen Schritt anzeigen - -Führt zurück zum letzten Schritt mit Optionen - -- Zurück-Knopf ist am ersten Schritt gesperrt -- Leere Schritte werden übersprungen - -- Zum zweiten Schritt gehen -- LMB auf Zurück-Knopf -- Erster Schritt erscheint ----------------------------------------- - -Auswahl übernehmen - -Wechselt das Produkt auf die gewählte Variante - -- Fertig überträgt die Auswahl in die Auswahlfelder -- Unbesuchte Schritte bekommen die erste gültige Option -- Shopware führt den Variantenwechsel aus - -- Alle Schritte durchgehen -- LMB auf Fertig-Knopf -- Produktseite zeigt die gewählte Variante ----------------------------------------- - -Konfigurator schließen - -Beendet die Auswahl ohne Wechsel der Variante - -- x-Icon schließt das Modal -- Escape schließt das Modal -- Fokus kehrt zum Auslöser zurück - -- Konfigurator öffnen -- Escape drücken -- Modal ist geschlossen ----------------------------------------- - -Konfigurationsdaten bereitstellen - -Legt der Produktseite alles bei, was der Konfigurator braucht - -- Kombinationen stammen vom Hauptartikel -- Ohne aktives Layout bleibt die Beilage aus - -- Produktseite mit aktivem Layout öffnen -- Seite trägt Kombinationen und Vorbelegung diff --git a/daten/MtoVariantConfigurator/.planung/vorschau-zeigen.md b/daten/MtoVariantConfigurator/.planung/vorschau-zeigen.md deleted file mode 100644 index d4704fd..0000000 --- a/daten/MtoVariantConfigurator/.planung/vorschau-zeigen.md +++ /dev/null @@ -1,53 +0,0 @@ - -Vorschau zeigen ----------------------------------------- - -kern ----------------------------------------- - -Der Kunde sieht Bild und Preis der gewählten Kombination ----------------------------------------- - -- Preis stimmt mit dem Preis der Produktseite überein -- Antwort wird nicht zwischengespeichert -- Späte Antworten überholter Anfragen werden verworfen -- Ohne eigene Bilder greifen die Bilder des Elternartikels ----------------------------------------- - -Vorschau laden - -Holt Bilder und Preis zur laufenden Auswahl - -- Jede Auswahl löst eine neue Anfrage aus -- Titelbild der Variante steht an erster Stelle -- Ohne Treffer bleibt die Produkt-ID als Rückfall - -- Konfigurator öffnen -- Andere Option wählen -- Bild und Preis ändern sich ----------------------------------------- - -Galerie blättern - -Zeigt weitere Bilder der gewählten Variante - -- Pfeil-Icons blättern vor -- Pfeil-Icons blättern zurück -- Nach dem letzten Bild folgt das erste -- Bei einem Bild bleibt die Navigation aus - -- Konfigurator öffnen -- LMB auf Vor-Icon -- Nächstes Bild erscheint ----------------------------------------- - -Bild wählen - -Wechselt das große Bild über die Vorschaubilder - -- Aktives Vorschaubild ist hervorgehoben -- Großes Bild folgt der Wahl - -- Konfigurator öffnen -- LMB auf drittes Vorschaubild -- Großes Bild zeigt dieses Motiv diff --git a/daten/MtoVariantConfigurator/.verzeichnis b/daten/MtoVariantConfigurator/.verzeichnis new file mode 100644 index 0000000..6a49a44 --- /dev/null +++ b/daten/MtoVariantConfigurator/.verzeichnis @@ -0,0 +1 @@ +/home/arbeit/arbeit/BeckhuisSwag6/custom/static-plugins/MtoVariantConfigurator diff --git a/daten/MtoVariantConfigurator/auswahl-anstossen.md b/daten/MtoVariantConfigurator/auswahl-anstossen.md deleted file mode 100644 index 665f2fa..0000000 --- a/daten/MtoVariantConfigurator/auswahl-anstossen.md +++ /dev/null @@ -1,49 +0,0 @@ - -Auswahl anstoßen ----------------------------------------- - -kern ----------------------------------------- - -Der Kunde erkennt in der Buybox die Reihenfolge der Schritte ----------------------------------------- - -- Jede Eigenschaft bildet einen eigenen Schritt -- Natives Auswahlfeld bleibt für den Variantenwechsel erhalten -- Eigene Darstellung gilt unabhängig vom Anzeigetyp der Eigenschaft -- Ohne aktives Layout erscheint die Standard-Buybox ----------------------------------------- - -Schrittnummer anzeigen - -Zeigt neben jeder Eigenschaft ihre Position im Ablauf - -- Beschriftung nennt das Wort Schritt und die Nummer -- Nummer folgt der Reihenfolge aus dem Backend - -- Produktseite öffnen -- Erste Eigenschaft zeigt Schritt 1 ----------------------------------------- - -Hinweistext anzeigen - -Erklärt dem Kunden, worauf er im Schritt achtet - -- Text kommt aus einem Textbaustein je Schritt -- Leerer Textbaustein blendet den Hinweis aus -- Hinweis hängt an der Nummer statt an der Eigenschaft - -- Textbaustein für Schritt 1 füllen -- Produktseite öffnen -- Hinweis steht unter der Überschrift ----------------------------------------- - -Gewählte Option anzeigen - -Zeigt am Schritt, welche Option gerade gilt - -- Ohne Auswahl steht dort Bitte wählen -- Vorbelegung erscheint ohne Zutun des Kunden - -- Hauptartikel ohne Variante öffnen -- Jeder Schritt nennt eine Option diff --git a/daten/MtoVariantConfigurator/beratung-anbieten.md b/daten/MtoVariantConfigurator/beratung-anbieten.md deleted file mode 100644 index c0beeb5..0000000 --- a/daten/MtoVariantConfigurator/beratung-anbieten.md +++ /dev/null @@ -1,47 +0,0 @@ - -Beratung anbieten ----------------------------------------- - -optional ----------------------------------------- - -Der Kunde findet im Konfigurator Vertrauen und einen Kontakt ----------------------------------------- - -- Alle Texte kommen aus Textbausteinen -- Leerer Textbaustein blendet den Bereich aus ----------------------------------------- - -Vertrauen zeigen - -Zeigt Siegel und Zusage neben dem Gesamtpreis - -- Logo stammt aus der Plugin-Konfiguration -- Ohne Logo bleibt der Text stehen - -- Konfigurator öffnen -- Siegel steht neben dem Preis ----------------------------------------- - -Beratung erreichen - -Bietet eine Telefonnummer für Fragen zur Konfiguration - -- Nummer ist als Telefonlink klickbar -- Leere Nummer blendet den Bereich aus - -- Konfigurator öffnen -- LMB auf die Nummer -- Telefon-App öffnet sich ----------------------------------------- - -Optionsübersicht öffnen - -Öffnet das hinterlegte PDF mit allen Optionen - -- Knopf erscheint nur mit hinterlegtem PDF -- PDF öffnet in einem neuen Tab - -- Konfigurator öffnen -- LMB auf Optionen-Knopf -- PDF öffnet in neuem Tab diff --git a/daten/MtoVariantConfigurator/hilfe.md b/daten/MtoVariantConfigurator/hilfe.md new file mode 100644 index 0000000..9fcc6be --- /dev/null +++ b/daten/MtoVariantConfigurator/hilfe.md @@ -0,0 +1,40 @@ + +Hilfe +---------------------------------------- + +optional +---------------------------------------- + +Bietet Unterstützung während der Auswahl an +---------------------------------------- + +- Ein Übersichtsdokument ist je Produkt pflegbar +- Ohne Dokument entfällt der Zugang +- Ein Vertrauenslogo ist je Verkaufskanal pflegbar +- Ohne Logo bleibt nur der Text +- Ohne Vertrauenstext bleibt das Logo verborgen +- Alle Texte liegen als Textbausteine bei +- Textbausteine gelten shopweit je Sprache +- Deutsch, Englisch und Niederländisch liegen bei +- Ohne Rufnummer entfällt der Anrufweg +---------------------------------------- + +Übersicht öffnen + +Zeigt alle Kombinationen als Dokument + +- Das Dokument öffnet in einem neuen Reiter + +- Konfigurator öffnen +- LMB auf alle Optionen ansehen +- Dokument im neuen Reiter +---------------------------------------- + +Beratung anrufen + +- Die Rufnummer wird als Anrufweg gesetzt +- Leerzeichen, Striche und Klammern fallen weg + +- Konfigurator öffnen +- LMB auf die Rufnummer +- Anrufweg geöffnet diff --git a/daten/MtoVariantConfigurator/konfigurator.md b/daten/MtoVariantConfigurator/konfigurator.md new file mode 100644 index 0000000..8ec990f --- /dev/null +++ b/daten/MtoVariantConfigurator/konfigurator.md @@ -0,0 +1,100 @@ + +Konfigurator +---------------------------------------- + +kern +---------------------------------------- + +Führt Schritt für Schritt zur passenden Variante +---------------------------------------- + +- Nur bei aktivem Konfigurator-Layout +- Ein Schritt je Eigenschaftsgruppe +- Die Reihenfolge folgt den Gruppen des Produkts +- Ohne Gruppen bleibt der Konfigurator aus +- Nur die Produktdetailseite nutzt ihn +- Ohne Fenster wirken die Schrittzeilen nicht +- Das Fenster hängt am Seitenkörper +- Ein veraltetes Fenster wird entfernt +- Die Seite hinter dem Fenster scrollt nicht +- Ohne Bilder klappt der Bildbereich weg +---------------------------------------- + +Konfigurator öffnen + +Startet die Auswahl bei einem gewählten Schritt + +- Jede Schrittzeile öffnet ihren eigenen Schritt +- Der vorherige Fokus wird gemerkt +- Der Fokus springt auf Weiter +- Die Vorschau wird beim Öffnen geholt + +- Produktseite mit Konfigurator öffnen +- LMB auf eine Schrittzeile +- Fenster mit diesem Schritt sichtbar +---------------------------------------- + +Konfigurator schließen + +- Escape schließt das Fenster +- Ein Klick auf den Hintergrund schließt +- Der Fokus kehrt zum Auslöser zurück +- Die Wahl wird dabei verworfen + +- Konfigurator öffnen +- LMB auf Schließen +- Produktseite wieder sichtbar +---------------------------------------- + +Schritt wechseln + +Bewegt sich vorwärts und rückwärts durch die Schritte + +- Ein Schritt ohne gültige Option wird übersprungen +- Zurück bleibt am ersten Schritt gesperrt +- Der letzte Schritt beschriftet die Schaltfläche um + +- Konfigurator öffnen +- LMB auf Weiter +- Nächster Schritt sichtbar +---------------------------------------- + +Fortschritt ablesen + +Zeigt, an welcher Stelle der Auswahl man steht + +- Der Zähler nennt Schritt und Gesamtzahl +- Der Balken wächst mit dem Schritt +- Beide zählen übersprungene Schritte mit + +- Konfigurator öffnen +- LMB auf Weiter +- Zähler und Balken gewachsen +---------------------------------------- + +Auswahl abschließen + +Übergibt die Auswahl an den Variantenwechsel + +- Ein ausgelassener Schritt wird ergänzt +- Ergänzt wird die erste gültige Option +- Der Wechsel läuft über die Auswahlfelder +- Das Fenster schließt vor dem Wechsel + +- Konfigurator öffnen +- Bis zum letzten Schritt gehen +- LMB auf Fertig +- Produktseite zeigt die Variante +---------------------------------------- + +Mit der Tastatur bedienen + +Hält die Bedienung ohne Maus geschlossen + +- Der Fokus bleibt im Fenster +- Escape schließt zuerst die Großansicht +- Die Steuerung liegt am Dokument + +- Konfigurator öffnen +- Mehrfach Tab drücken +- Fokus bleibt im Fenster diff --git a/daten/MtoVariantConfigurator/layout-zuweisen.md b/daten/MtoVariantConfigurator/layout-zuweisen.md deleted file mode 100644 index 1e06c7a..0000000 --- a/daten/MtoVariantConfigurator/layout-zuweisen.md +++ /dev/null @@ -1,69 +0,0 @@ - -Layout zuweisen ----------------------------------------- - -kern ----------------------------------------- - -Ein Händler entscheidet je Produkt, ob die geführte Auswahl erscheint ----------------------------------------- - -- Einstellungen liegen auf dem Varianten-Tab des Produkts -- Werte stehen in den customFields des Produkts -- Bearbeiten erfordert das Recht product.editor -- Ohne Zuweisung bleibt das Standardlayout aktiv ----------------------------------------- - -Konfigurator aktivieren - -Schaltet die geführte Variantenauswahl für ein Produkt frei - -- Schalter steht auf dem Varianten-Tab -- Aktiv ersetzt die Buybox des Produkts -- Inaktiv zeigt das Standardlayout von Shopware - -- Produkt im Admin öffnen -- Varianten-Tab öffnen -- Schalter aktivieren und speichern -- Buybox zeigt die geführte Auswahl ----------------------------------------- - -Optionsübersicht hinterlegen - -Hinterlegt ein PDF mit allen Varianten und Kombinationen - -- Medienfeld steht auf dem Varianten-Tab -- Feld hängt am Hauptartikel -- Ohne PDF bleibt der Knopf unsichtbar - -- Varianten-Tab öffnen -- PDF im Medienfeld wählen -- Produkt speichern -- Modal zeigt den Knopf für Optionen ----------------------------------------- - -Trust-Logo hinterlegen - -Zeigt ein Vertrauenssiegel neben dem Gesamtpreis - -- Logo steht in der Plugin-Konfiguration -- Gilt für den ganzen Verkaufskanal -- Ohne Logo erscheint nur der Text - -- Plugin-Konfiguration öffnen -- Logo im Medienfeld wählen -- Modal zeigt das Logo am Preis ----------------------------------------- - -Optionsbild am Datensatz pflegen - -offen - -Hinterlegt das Bild einer Option am Datensatz der Variante - -- Feld liegt im Formular der einzelnen Variante -- Heute stammt das Bild aus der Eigenschaftsgruppe - -- Variante im Admin öffnen -- Bildfeld der Variante füllen -- Variante speichern diff --git a/daten/MtoVariantConfigurator/option-ansehen.md b/daten/MtoVariantConfigurator/option-ansehen.md deleted file mode 100644 index bda54d3..0000000 --- a/daten/MtoVariantConfigurator/option-ansehen.md +++ /dev/null @@ -1,51 +0,0 @@ - -Option ansehen ----------------------------------------- - -kern ----------------------------------------- - -Der Kunde prüft eine Option groß, bevor er sie nimmt ----------------------------------------- - -- Nur Optionen mit Bild tragen den Hinweis -- Ansicht liegt über dem Konfigurator ----------------------------------------- - -Optionsdetail öffnen - -Zeigt Bild und Namen einer Option in voller Größe - -- i-Icon öffnet die Ansicht -- Enter öffnet die Ansicht -- Leertaste öffnet die Ansicht - -- Konfigurator öffnen -- LMB auf i-Icon einer Option -- Große Ansicht erscheint ----------------------------------------- - -Option aus Ansicht wählen - -Übernimmt die betrachtete Option in die Auswahl - -- Knopf übernimmt die Option -- Knopf schließt die Ansicht -- Schritt bleibt derselbe - -- Optionsdetail öffnen -- LMB auf Wählen-Knopf -- Option ist gewählt ----------------------------------------- - -Ansicht schließen - -Kehrt zur Optionsliste zurück ohne Auswahl - -- x-Icon schließt die Ansicht -- Escape schließt die Ansicht -- Konfigurator bleibt offen - -- Optionsdetail öffnen -- Escape drücken -- Optionsliste erscheint wieder diff --git a/daten/MtoVariantConfigurator/option.md b/daten/MtoVariantConfigurator/option.md new file mode 100644 index 0000000..cc0015e --- /dev/null +++ b/daten/MtoVariantConfigurator/option.md @@ -0,0 +1,63 @@ + +Option +---------------------------------------- + +kern +---------------------------------------- + +Bietet je Schritt nur passende Ausprägungen an +---------------------------------------- + +- Der erste Schritt bietet alles an +- Spätere Schritte hängen an der bisherigen Wahl +- Spätere Schritte sperren unerreichbare Optionen +- Ein Schritt ohne Auswahlfeld wirkt nicht +- Gesperrte Optionen bleiben sichtbar +- Optionsbilder gibt es nur bis zwei Schritte +- Das Bild stammt aus der Konfiguratoreinstellung +- Sonst dient das Bild der Ausprägung +- Ohne Bild dient die Farbe als Merkmal +- Ohne Bild und Farbe steht nur der Name +---------------------------------------- + +Option wählen + +Legt die Ausprägung des aktuellen Schritts fest + +- Die Wahl wechselt den Schritt nicht +- Spätere unpassende Wahlen fallen weg +- Der Fokus bleibt auf der gewählten Zeile + +- Konfigurator öffnen +- LMB auf eine Option +- Option als gewählt markiert +---------------------------------------- + +Option vergrößern + +Zeigt das Optionsbild groß mit Namen + +- Nur Optionen mit Bild sind vergrößerbar +- Enter und Leertaste öffnen ebenfalls + +- Konfigurator öffnen +- LMB auf Mehr Info +- Großansicht mit Bild sichtbar +---------------------------------------- + +Großansicht schließen + +- Escape schließt zuerst die Großansicht + +- Option vergrößern +- LMB auf Schließen +- Optionsliste wieder sichtbar +---------------------------------------- + +Option aus Großansicht wählen + +- Die Großansicht schließt danach + +- Option vergrößern +- LMB auf Option wählen +- Option als gewählt markiert diff --git a/daten/MtoVariantConfigurator/produkt.md b/daten/MtoVariantConfigurator/produkt.md new file mode 100644 index 0000000..9076cee --- /dev/null +++ b/daten/MtoVariantConfigurator/produkt.md @@ -0,0 +1,60 @@ + +Produkt +---------------------------------------- + +kern +---------------------------------------- + +Legt fest, welches Produkt den Konfigurator nutzt +---------------------------------------- + +- Die Einstellung liegt in den Zusatzfeldern +- Die Zusatzfelder bleiben importierbar +- Die Karte sitzt im Reiter Varianten +- Ohne Bearbeitungsrecht bleiben die Felder gesperrt +- Die Felder erscheinen nicht im allgemeinen Bereich +- Installieren und Aktualisieren tun dasselbe +- Eine alte Produktzuordnung wird entfernt +- Deinstallieren räumt die Felder nicht auf +---------------------------------------- + +Konfigurator aktivieren + +Schaltet das geführte Layout für ein Produkt frei + +- Ohne Freischaltung greift das Standardlayout + +- Produkt im Verwaltungsbereich öffnen +- Reiter Varianten wählen +- Schalter umlegen +- Speichern +- Konfigurator auf der Produktseite sichtbar +---------------------------------------- + +Übersichtsdokument hinterlegen + +Verknüpft ein Dokument mit allen Kombinationen + +- Gespeichert wird die Kennung als Text +- Es gibt keine Beziehung zum Medium +- Ein gelöschtes Medium lässt den Zugang verschwinden +- Ein leeres Feld entfernt die Verknüpfung + +- Produkt im Verwaltungsbereich öffnen +- Reiter Varianten wählen +- Dokument wählen +- Speichern +- Zugang im Konfigurator sichtbar +---------------------------------------- + +Vertrauenslogo hinterlegen + +Setzt das Logo neben dem Gesamtpreis + +- Die Einstellung gilt je Verkaufskanal +- Das Logo stammt aus der Medienverwaltung + +- Plugin-Einstellungen öffnen +- Logo wählen +- Speichern +- Logo im Konfigurator sichtbar diff --git a/daten/MtoVariantConfigurator/schritt-zeigen.md b/daten/MtoVariantConfigurator/schritt-zeigen.md deleted file mode 100644 index 3ceb620..0000000 --- a/daten/MtoVariantConfigurator/schritt-zeigen.md +++ /dev/null @@ -1,49 +0,0 @@ - -Schritt zeigen ----------------------------------------- - -kern ----------------------------------------- - -Der Kunde weiß im Modal, wo er steht und was er wählt ----------------------------------------- - -- Optionen stehen rechts -- Bilder links -- Lange Optionslisten lassen sich scrollen ----------------------------------------- - -Eigenschaft benennen - -Zeigt den Namen der Eigenschaft des aktuellen Schritts - -- Name steht als Überschrift über der Liste -- Name kommt aus der Eigenschaftsgruppe - -- Konfigurator öffnen -- Überschrift nennt die erste Eigenschaft ----------------------------------------- - -Schrittstand anzeigen - -Zeigt den aktuellen Schritt und die Gesamtzahl - -- Zähler nennt Schritt und Gesamtzahl -- Balken wächst mit dem Fortschritt -- Text kommt aus einem Textbaustein - -- Konfigurator öffnen -- Zähler zeigt 1 von 3 ----------------------------------------- - -Optionen auflisten - -Zeigt alle Optionen der Eigenschaft mit Namen und Bild - -- Jede Option nennt ihren Namen -- Bild erscheint nur bis zwei Schritte -- Ohne Bild erscheint der Farbwert -- Ohne Farbwert bleibt die Zeile ohne Zeichen - -- Konfigurator öffnen -- Jede Option zeigt ihren Namen diff --git a/daten/MtoVariantConfigurator/schrittzeile.md b/daten/MtoVariantConfigurator/schrittzeile.md new file mode 100644 index 0000000..fce3cb0 --- /dev/null +++ b/daten/MtoVariantConfigurator/schrittzeile.md @@ -0,0 +1,30 @@ + +Schrittzeile +---------------------------------------- + +kern +---------------------------------------- + +Zeigt je Gruppe die aktuelle Wahl auf der Seite +---------------------------------------- + +- Eine Zeile je Eigenschaftsgruppe +- Die Zeile nennt Gruppe und Schrittnummer +- Vor dem Start steht eine Aufforderung darin +- Danach steht die Vorauswahl darin +- Ein Hinweistext gibt es bis Schritt fünf +- Ein leerer Hinweistext bleibt verborgen +- Das Auswahlfeld bleibt verborgen im Seitenaufbau +- Das Auswahlfeld trägt den echten Variantenwechsel +---------------------------------------- + +Wahl ablesen + +Zeigt die aktuell gewählte Ausprägung je Gruppe + +- Der Seitenaufbau zeigt die Wahl der Variante +- Fehlt sie, zeigt die Zeile die erste Option + +- Produktseite mit Konfigurator öffnen +- Schrittzeilen lesen +- Gewählte Ausprägung sichtbar diff --git a/daten/MtoVariantConfigurator/variante.md b/daten/MtoVariantConfigurator/variante.md new file mode 100644 index 0000000..dff2279 --- /dev/null +++ b/daten/MtoVariantConfigurator/variante.md @@ -0,0 +1,48 @@ + +Variante +---------------------------------------- + +kern +---------------------------------------- + +Verbindet eine Auswahl mit einem echten Artikel +---------------------------------------- + +- Nur aktive Varianten zählen +- Sichtbarkeit im Verkaufskanal wird nicht geprüft +- Jede Variante nennt ihre Ausprägungen +- Die Vorauswahl kommt aus den Auswahlfeldern +- Vorgaben greifen nur bei leerem Feld +- Die Vorgabe folgt der Hauptvariante +- Sonst gelten die Ausprägungen des Artikels +- Sonst die erste aktive nach Artikelnummer +- Eine Wahl ohne Variante fällt weg +- Die Gruppe bleibt dann ohne Wahl +- Die Auflösung nutzt die Standardsuche +- Ohne Treffer bleibt das Ausgangsprodukt stehen +---------------------------------------- + +Variante auflösen + +Findet den Artikel zur gewählten Zusammenstellung + +- Der Abruf nennt die gewechselte Gruppe +- Eine unlesbare Anfrage gilt als leer + +- Konfigurator öffnen +- Option wählen +- Preis der Variante sichtbar +---------------------------------------- + +Variante übernehmen + +Wechselt die Produktseite auf den Artikel + +- Der Wechsel läuft über den Standardweg +- Ein Signal am letzten geänderten Feld genügt +- Ohne Änderung bleibt die Seite stehen +- Die Übernahme lädt die Produktseite neu + +- Konfigurator öffnen +- Auswahl abschließen +- Produktseite zeigt die Variante diff --git a/daten/MtoVariantConfigurator/varianten-waehlen.md b/daten/MtoVariantConfigurator/varianten-waehlen.md deleted file mode 100644 index c732ab7..0000000 --- a/daten/MtoVariantConfigurator/varianten-waehlen.md +++ /dev/null @@ -1,109 +0,0 @@ - -Varianten wählen ----------------------------------------- - -kern ----------------------------------------- - -Der Kunde findet Schritt für Schritt eine bestellbare Kombination ----------------------------------------- - -- Erster Schritt zeigt alle Optionen seiner Eigenschaft -- Folgeschritte zeigen nur kombinierbare Optionen -- Der Ablauf trägt beliebig viele Eigenschaften -- Reihenfolge der Schritte kommt aus dem Backend -- Ohne Auswahl greifen die Standardvarianten des Elternartikels -- Schritte ohne gültige Option werden übersprungen -- Eine Auswahl wechselt den Schritt nicht -- Ungültige Folgeauswahl fällt beim Wechsel weg -- Auf kleinen Bildschirmen bleibt der Ablauf derselbe -- Escape schließt den Konfigurator -- Tabulator bleibt im Dialog ----------------------------------------- - -Schritt öffnen - -Öffnet den Konfigurator beim angeklickten Schritt - -- LMB auf einen Schritt öffnet das Modal -- Offener Konfigurator wechselt nur den Schritt -- Modal hängt am Seitenkörper - -- Produktseite öffnen -- LMB auf zweiten Schritt -- Modal öffnet bei Schritt 2 ----------------------------------------- - -Option wählen - -Übernimmt eine Option in die laufende Auswahl - -- Gewählte Option ist hervorgehoben -- Nicht kombinierbare Optionen sind gesperrt -- Auswahl verwirft ungültige Folgeschritte -- Schritt bleibt nach der Wahl derselbe - -- Konfigurator öffnen -- LMB auf eine Option -- Option ist hervorgehoben ----------------------------------------- - -Nächsten Schritt anzeigen - -Führt zum nächsten Schritt mit gültigen Optionen - -- Weiter-Knopf heißt am letzten Schritt Fertig -- Leere Schritte werden übersprungen - -- Konfigurator öffnen -- LMB auf Weiter-Knopf -- Nächster Schritt erscheint ----------------------------------------- - -Vorherigen Schritt anzeigen - -Führt zurück zum letzten Schritt mit Optionen - -- Zurück-Knopf ist am ersten Schritt gesperrt -- Leere Schritte werden übersprungen - -- Zum zweiten Schritt gehen -- LMB auf Zurück-Knopf -- Erster Schritt erscheint ----------------------------------------- - -Auswahl übernehmen - -Wechselt das Produkt auf die gewählte Variante - -- Fertig überträgt die Auswahl in die Auswahlfelder -- Unbesuchte Schritte bekommen die erste gültige Option -- Shopware führt den Variantenwechsel aus - -- Alle Schritte durchgehen -- LMB auf Fertig-Knopf -- Produktseite zeigt die gewählte Variante ----------------------------------------- - -Konfigurator schließen - -Beendet die Auswahl ohne Wechsel der Variante - -- x-Icon schließt das Modal -- Escape schließt das Modal -- Fokus kehrt zum Auslöser zurück - -- Konfigurator öffnen -- Escape drücken -- Modal ist geschlossen ----------------------------------------- - -Konfigurationsdaten bereitstellen - -Legt der Produktseite alles bei, was der Konfigurator braucht - -- Kombinationen stammen vom Hauptartikel -- Ohne aktives Layout bleibt die Beilage aus - -- Produktseite mit aktivem Layout öffnen -- Seite trägt Kombinationen und Vorbelegung diff --git a/daten/MtoVariantConfigurator/vision.md b/daten/MtoVariantConfigurator/vision.md new file mode 100644 index 0000000..c44c088 --- /dev/null +++ b/daten/MtoVariantConfigurator/vision.md @@ -0,0 +1,48 @@ + +Vision +---------------------------------------- + +vision +---------------------------------------- + +Eine Variante zu finden soll leicht sein, auch bei vielen Kombinationen. +---------------------------------------- + +Schritt für Schritt führen + +Der Kunde entscheidet eine Sache nach der anderen +- Jede Eigenschaft bekommt einen eigenen Schritt +- Der Fortschritt ist jederzeit ablesbar +- Der Weg zurück bleibt offen +---------------------------------------- + +Sackgassen verhindern + +Nur Wege anbieten, die zu einem Artikel führen +- Unerreichbare Ausprägungen bleiben gesperrt +- Eine spätere Wahl passt sich der früheren an +- Am Ende steht ein Artikel aus aktiven Varianten +---------------------------------------- + +Wirkung sofort zeigen + +Bild und Preis folgen jeder Entscheidung +- Die Bilder zeigen die gewählte Zusammenstellung +- Der Preis gilt für den angemeldeten Kunden +- Während der Auswahl wird nicht neu geladen +---------------------------------------- + +Ohne Standard brechen + +Der Shop bleibt in seinen gewohnten Bahnen +- Der Variantenwechsel läuft über den Standardweg +- Das Layout gilt nur für freigeschaltete Produkte +- Einstellungen bleiben mit dem Produkt importierbar +---------------------------------------- + +Beim Zweifel helfen + +Wer unsicher ist, findet Hilfe ohne Umweg +- Eine Übersicht aller Kombinationen ist erreichbar +- Die Beratung ist aus dem Konfigurator erreichbar +- Vertrauenshinweise stehen beim Preis diff --git a/daten/MtoVariantConfigurator/vorschau-zeigen.md b/daten/MtoVariantConfigurator/vorschau-zeigen.md deleted file mode 100644 index d4704fd..0000000 --- a/daten/MtoVariantConfigurator/vorschau-zeigen.md +++ /dev/null @@ -1,53 +0,0 @@ - -Vorschau zeigen ----------------------------------------- - -kern ----------------------------------------- - -Der Kunde sieht Bild und Preis der gewählten Kombination ----------------------------------------- - -- Preis stimmt mit dem Preis der Produktseite überein -- Antwort wird nicht zwischengespeichert -- Späte Antworten überholter Anfragen werden verworfen -- Ohne eigene Bilder greifen die Bilder des Elternartikels ----------------------------------------- - -Vorschau laden - -Holt Bilder und Preis zur laufenden Auswahl - -- Jede Auswahl löst eine neue Anfrage aus -- Titelbild der Variante steht an erster Stelle -- Ohne Treffer bleibt die Produkt-ID als Rückfall - -- Konfigurator öffnen -- Andere Option wählen -- Bild und Preis ändern sich ----------------------------------------- - -Galerie blättern - -Zeigt weitere Bilder der gewählten Variante - -- Pfeil-Icons blättern vor -- Pfeil-Icons blättern zurück -- Nach dem letzten Bild folgt das erste -- Bei einem Bild bleibt die Navigation aus - -- Konfigurator öffnen -- LMB auf Vor-Icon -- Nächstes Bild erscheint ----------------------------------------- - -Bild wählen - -Wechselt das große Bild über die Vorschaubilder - -- Aktives Vorschaubild ist hervorgehoben -- Großes Bild folgt der Wahl - -- Konfigurator öffnen -- LMB auf drittes Vorschaubild -- Großes Bild zeigt dieses Motiv diff --git a/daten/MtoVariantConfigurator/vorschau.md b/daten/MtoVariantConfigurator/vorschau.md new file mode 100644 index 0000000..0437297 --- /dev/null +++ b/daten/MtoVariantConfigurator/vorschau.md @@ -0,0 +1,52 @@ + +Vorschau +---------------------------------------- + +kern +---------------------------------------- + +Zeigt Bilder und Preis der gewählten Zusammenstellung +---------------------------------------- + +- Bilder und Preis kommen vom Server +- Das Deckelbild steht immer vorn +- Weitere Bilder folgen ihrer Position +- Ohne eigene Bilder greifen die des Hauptprodukts +- Der Preis kommt aus dem Verkaufskanal +- Der Preis gilt in der gewählten Währung +- Das Format folgt der aktiven Sprache +- Späte Antworten überholter Abrufe fallen weg +- Die Vorschau wird nie zwischengespeichert +---------------------------------------- + +Vorschau abrufen + +Holt Bilder und Preis zur aktuellen Wahl + +- Der Abruf läuft bei jeder Wahl +- Jeder Abruf springt auf das erste Bild +- Ohne passende Variante gilt das Elternprodukt +- Eine unlesbare Antwort ändert nichts + +- Konfigurator öffnen +- Option wählen +- Bilder und Preis aktualisiert +---------------------------------------- + +Bild wechseln + +- Ein einzelnes Bild lässt sich nicht wechseln +- Nach dem letzten Bild folgt das erste + +- Konfigurator öffnen +- LMB auf nächstes Bild +- Nächstes Bild sichtbar +---------------------------------------- + +Bild aus Leiste wählen + +- Das gewählte Bild ist markiert + +- Konfigurator öffnen +- LMB auf ein Vorschaubild +- Bild in voller Größe sichtbar diff --git a/daten/Planer/.planung/karten-besprechen.md b/daten/Planer/.planung/anweisung.md similarity index 51% rename from daten/Planer/.planung/karten-besprechen.md rename to daten/Planer/.planung/anweisung.md index 984d38e..255c5b9 100644 --- a/daten/Planer/.planung/karten-besprechen.md +++ b/daten/Planer/.planung/anweisung.md @@ -1,61 +1,52 @@ -Karten besprechen +Anweisung ---------------------------------------- optional ---------------------------------------- -Entwickelt Karten im Gespräch mit der KI +Lässt die KI Features aus einer Beschreibung entwerfen ---------------------------------------- -- Die KI schreibt nie selbst in eine Karte +- Die KI schreibt nie selbst in ein Feature - Sie beschreibt den Sollzustand - Was sich ändert, rechnet der Code aus -- Vorschläge sehen aus wie bei der Prüfung - Neue Funktionen gelten als offen -- Das Gespräch überlebt den Neustart - Die letzten 30 Wortmeldungen bleiben -- Gespräch und Prüfung teilen eine Spalte +- Nur Anweisungen oder Prüfung ist offen ---------------------------------------- -Gespräch öffnen +Anweisungen öffnen -- Stift-Icon in der Kopfzeile -- Icon leuchtet bei offenem Gespräch +- Öffnet sich mit der Planung -- LMB auf Stift-Icon -- Gespräch geöffnet +- LMB auf Anweisungen in der Kopfzeile +- Anweisungen geöffnet -Nachricht senden +Anweisung senden Sagt der KI, was das Projekt können soll -- Enter sendet +- Leere Anweisung wird abgelehnt - Eigene Zeile erscheint sofort - Text bleibt bei einem Fehler stehen +- Tippen bleibt während der Antwort möglich - Text eingeben - Enter drücken - Antwort und Vorschläge erscheinen -Vorgeschlagene Karte anlegen +Anweisungen verwerfen -Macht aus einem Umriss eine echte Karte +Streicht alles Gesagte, die Features bleiben -- Gestrichelter Rand vor dem Annehmen +- Rückfrage vor dem Löschen -- LMB auf Haken am Umriss -- Karte angelegt +- LMB auf Verwerfen bei den Anweisungen +- Bestätigen +- Anweisungen geleert -Gespräch verwerfen - -- Löscht nur das Gespräch -- Karten bleiben unberührt +Anweisungen schließen -- LMB auf Papierkorb-Icon -- Gespräch geleert - -Gespräch schließen - -- LMB auf x-Icon +- LMB auf Schließen bei den Anweisungen - Spalte wieder frei diff --git a/daten/Planer/.planung/design.md b/daten/Planer/.planung/design.md deleted file mode 100644 index 54257c1..0000000 --- a/daten/Planer/.planung/design.md +++ /dev/null @@ -1,44 +0,0 @@ - -Design ----------------------------------------- - -optional ----------------------------------------- - -Hält die Oberfläche lesbar und ruhig ----------------------------------------- - -- Karten stapeln sich lückenlos in Spalten -- Lesefeld ist in der Breite gedeckelt -- Leisten scrollen nicht mit -- Schmale Fenster stapeln die Bereiche -- Klickflächen sind mindestens 28 Pixel -- Textkontrast erfüllt die Lesbarkeitsschwelle -- Kontextmenü bleibt im Fenster -- Modal setzt den Fokus ins Eingabefeld -- Escape schließt das Modal ----------------------------------------- - -Eingabe mit Enter bestätigen - -Spart den Weg zum Knopf - -- Gilt in einzeiligen Feldern -- Escape verwirft stattdessen - -- Modal öffnen -- Text eingeben -- Enter drücken -- Eingabe übernommen - -Kontextmenü schließen - -Räumt ein offenes Menü aus dem Weg - -- Klick daneben schließt es -- Escape schließt es -- Ein neues Menü verdrängt das alte - -- RMB auf eine Karte -- LMB daneben -- Menü geschlossen diff --git a/daten/Planer/.planung/feature.md b/daten/Planer/.planung/feature.md new file mode 100644 index 0000000..19ec543 --- /dev/null +++ b/daten/Planer/.planung/feature.md @@ -0,0 +1,90 @@ + +Feature +---------------------------------------- + +kern +---------------------------------------- + +Hält fest, was ein Projekt können soll +---------------------------------------- + +- Eine Markdown-Datei je Feature +- Die Datei ist die Wahrheit +- Titel bestimmt den Dateinamen +- Namensgleichheit bekommt eine Nummer +- Fremde Marker bleiben erhalten +- Sortiert nach Vision, kern, optional +- Innerhalb der Gruppe alphabetisch +---------------------------------------- + +Feature anlegen + +- Titel ist Pflicht + +- RMB auf den Hauptbereich +- Klick auf "Feature erstellen" +- Titel eingeben +- Bestätigen +- Feature angelegt und offen + +Feature öffnen + +Zeigt alle Felder und gibt sie zum Anpassen frei + +- Kompakt bleiben Regeln und Details verborgen +- Höchstens ein Feature offen +- Ein Feature mit Befunden öffnet sich sofort + +- LMB auf ein kompaktes Feature +- LMB auf ein zweites +- Erstes wieder kompakt + +Feature schließen + +- Feature öffnen +- MMB auf das Feature +- Feature wieder kompakt + +Feature anpassen + +Ändert Titel, Ziel oder Regeln + +- Nur im offenen Feature +- Neuer Titel aktualisiert den Dateinamen +- Leerer Titel wird verworfen +- Verlassen speichert +- Escape verwirft + +- Feature öffnen +- LMB auf ein Feld des Features +- Text ändern +- Feature angepasst + +Feature einstufen + +Trennt tragende von verzichtbaren Features + +- Entweder kern oder optional + +- Feature öffnen +- LMB auf die Einstufung +- Einstufung gewechselt + +Feature durchsuchen + +Findet das Feature, ohne alle zu lesen + +- Sucht in allen Feldern +- Zählt Ausgeblendete mit + +- Suchwort eingeben +- Nur passende Features bleiben + +Feature entfernen + +- Rückfrage vor dem Entfernen + +- RMB auf das Feature +- Klick auf "Feature entfernen" +- Bestätigen +- Feature entfernt diff --git a/daten/Planer/.planung/features.md b/daten/Planer/.planung/features.md deleted file mode 100644 index 04d00f8..0000000 --- a/daten/Planer/.planung/features.md +++ /dev/null @@ -1,109 +0,0 @@ - -Features ----------------------------------------- - -kern ----------------------------------------- - -Hält fest, was ein Projekt können soll ----------------------------------------- - -- Eine Markdown-Datei je Feature -- Die Datei ist die Wahrheit -- Titel bestimmt den Dateinamen -- Namensgleichheit bekommt eine Nummer -- Fremde Marker bleiben erhalten -- Alphabetisch sortiert -- Anpassen nur im Vollmodus -- Verlassen speichert -- Escape verwirft ----------------------------------------- - -Anzeigemodus umschalten - -Kompaktmodus zum Lesen, Vollmodus zum Anpassen - -- Standard ist Kompaktmodus -- Vollmodus zeigt alle Felder -- Augen-Icon rechts oben - -- MMB auf Featurecard -- Modus umgeschaltet - -Feature anlegen - -- +-Icon -- Feature öffnet im Vollmodus - -- RMB auf Hauptbereich -- Klick auf "Feature erstellen" -- Namen im Modal eingeben -- Bestätigen mit LMB -- Feature angelegt - -Feature einstufen - -Trennt tragende von verzichtbaren Features - -- Kern blau umrandet -- Optional grün umrandet -- Badge zeigt die Einstufung - -- Vollmodus öffnen -- LMB auf Badge -- Einstufung gewechselt - -Feature durchsuchen - -Findet die Karte, ohne alle zu lesen - -- Sucht in allen Feldern -- Zählt Ausgeblendete mit - -- Suchwort eingeben -- Nur passende Karten bleiben - -Feature entfernen - -- x-Icon - -- RMB auf Featurecard -- Klick auf "Feature entfernen" -- Bestätigen im Modal -- Feature entfernt - -Feature verschieben - -Hängt ein Feature in ein anderes Projekt um - -- Datei wandert -- Datei wird nicht kopiert -- Nur bei mehreren Projekten - -- RMB auf Featurecard -- Klick auf "Feature verschieben" -- Zielprojekt wählen -- Feature verschoben - -Regeln anpassen - -- Vollmodus öffnen -- LMB auf Regeln der Karte -- Text ändern -- Regeln angepasst - -Titel anpassen - -- Aktualisiert den Dateinamen - -- Vollmodus öffnen -- LMB auf Titel der Karte -- Text ändern -- Titel angepasst - -Ziel anpassen - -- Vollmodus öffnen -- LMB auf Ziel der Karte -- Text ändern -- Ziel angepasst diff --git a/daten/Planer/.planung/funktion.md b/daten/Planer/.planung/funktion.md new file mode 100644 index 0000000..7c6e17f --- /dev/null +++ b/daten/Planer/.planung/funktion.md @@ -0,0 +1,66 @@ + +Funktion +---------------------------------------- + +kern +---------------------------------------- + +Zerlegt ein Feature in testbare Stücke mit Stand +---------------------------------------- + +- Gehört zu genau einem Feature +- Eine Regel je Zeile +- Ein Testschritt je Zeile +- Ziel bleibt freiwillig +- Regeln bleiben freiwillig +- Testschritte sind Pflicht +---------------------------------------- + +Funktion anlegen + +- Titel ist Pflicht +- Gilt als gebaut + +- Feature öffnen +- RMB auf das Feature +- Klick auf "Funktion erstellen" +- Titel eingeben +- Bestätigen +- Funktion angelegt + +Funktion anpassen + +Ändert Titel, Ziel, Regeln oder Testschritte + +- Nur im offenen Feature +- Leerer Titel wird verworfen +- Verlassen speichert +- Escape verwirft + +- Feature öffnen +- LMB auf ein Feld der Funktion +- Text ändern +- Funktion angepasst + +Funktion einstufen + +Trennt Bewiesenes von Unbewiesenem + +- Entweder offen oder gebaut +- Offen heißt unbewiesen +- Zurücksetzen bestellt eine Prüfung durch Claude +- Der Agent hakt eine geprüfte Funktion selbst ab + +- Feature öffnen +- LMB auf den Stand +- Stand gewechselt + +Funktion entfernen + +- Rückfrage vor dem Entfernen + +- Feature öffnen +- RMB auf die Funktion +- Klick auf "Funktion entfernen" +- Bestätigen +- Funktion entfernt diff --git a/daten/Planer/.planung/funktionen.md b/daten/Planer/.planung/funktionen.md deleted file mode 100644 index c65e957..0000000 --- a/daten/Planer/.planung/funktionen.md +++ /dev/null @@ -1,98 +0,0 @@ - -Funktionen ----------------------------------------- - -kern ----------------------------------------- - -Zerlegt ein Feature in prüfbare Stücke ----------------------------------------- - -- Gehört zu genau einem Feature -- Offen heißt bestellt, nicht gebaut -- Neue Funktionen von Hand gelten als gebaut -- Reihenfolge frei wählbar -- Ziel bleibt freiwillig -- Regeln bleiben freiwillig -- Testen bleibt freiwillig -- Anpassen nur im Vollmodus -- Verlassen speichert -- Escape verwirft ----------------------------------------- - -Funktion anlegen - -- +-Icon - -- Vollmodus öffnen -- RMB auf Featurecard -- Klick auf "Funktion erstellen" -- Namen im Modal eingeben -- Bestätigen mit LMB -- Funktion angelegt - -Funktion entfernen - -- x-Icon - -- Vollmodus öffnen -- RMB auf Funktion -- Klick auf "Funktion entfernen" -- Bestätigen im Modal -- Funktion entfernt - -Stand umschalten - -Trennt Bestelltes von Gebautem - -- Marke rechts vom Titel -- Offen ist gelb -- Gebaut ist ein Haken -- Kompakt erscheint nur die offene Marke - -- Vollmodus öffnen -- LMB auf die Marke -- Stand gewechselt - -Funktion verschieben - -Bringt die Schritte in ihre natürliche Folge - -- Reihenfolge steht in der Datei - -- Vollmodus öffnen -- RMB auf Funktion -- Klick auf "Nach oben" -- Funktion verschoben - -Titel anpassen - -- Vollmodus öffnen -- LMB auf Funktionstitel -- Text ändern -- Titel angepasst - -Ziel anpassen - -- Vollmodus öffnen -- LMB auf Ziel der Funktion -- Text ändern -- Ziel angepasst - -Regeln anpassen - -- Eine Regel je Zeile - -- Vollmodus öffnen -- LMB auf Regeln der Funktion -- Text ändern -- Regeln angepasst - -Testschritte anpassen - -- Ein Schritt je Zeile - -- Vollmodus öffnen -- LMB auf Testen der Funktion -- Text ändern -- Testschritte angepasst diff --git a/daten/Planer/.planung/k1-1024.png b/daten/Planer/.planung/k1-1024.png index 2a67485bcb179e45cac7b386d03d9851d77d6dc6..b06955a85ef7173788f21c745a0200d67b097213 100644 GIT binary patch literal 33144 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