- App-Review rv_01..rv_06 -> 5 Aktivitaeten (Service-Reviews durchfuehren, Bewertung, Aenderungen definieren/starten/implementieren). Rolle DPM ergaenzt; Routing-Pfade RUN/DPM/MB an rv_04; Tour-Narrative angepasst. - RACI + Quiz abgeleitet (Frank nennt nur Aktivitaeten) und als Arbeitsstand markiert. App jetzt 39 Stationen. - NICHT geaendert: Blueprint-YAML, kanonisches Konzept, materialliste, board-layout (zeigen weiter 6 Review-Pucks) — vor Uebernahme mit Michael abstimmen. - Notiz: 00_Konzept/review-phase_arbeitsstand-frank.md (Vorschlag + offene Punkte: MB undefiniert, Retirement fehlt, Vokabular-/RACI-Abgleich). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1228 lines
82 KiB
HTML
1228 lines
82 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||
<title>SLC-Workshop — Companion-App</title>
|
||
<meta name="description" content="Begleit-App zum SLC-Workshop-Tabletop: führt durch die Stationen, vermittelndes Quiz, Auflösung und Debrief. Offline lauffähig." />
|
||
<meta name="theme-color" content="#1d2430" />
|
||
<link rel="manifest" href="manifest.webmanifest" />
|
||
<link rel="apple-touch-icon" href="icon.svg" />
|
||
<link rel="icon" href="icon.svg" type="image/svg+xml" />
|
||
<style>
|
||
:root {
|
||
--bg: #f4f5f7;
|
||
--panel: #ffffff;
|
||
--ink: #1d2430;
|
||
--muted: #6b7686;
|
||
--line: #e2e6ec;
|
||
--accent: #e2001a; /* Freiburg-Rot */
|
||
--ok: #1f9d57;
|
||
--bad: #d23b3b;
|
||
--design: #2f80c9;
|
||
--transition: #e8862b;
|
||
--operation: #2f9e57;
|
||
--support: #18a9a0;
|
||
--review: #8358c6;
|
||
--radius: 14px;
|
||
--shadow: 0 1px 3px rgba(20,30,50,.08), 0 6px 24px rgba(20,30,50,.06);
|
||
}
|
||
* { box-sizing: border-box; }
|
||
html, body { margin: 0; height: 100%; }
|
||
body {
|
||
font: 16px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
||
color: var(--ink); background: var(--bg);
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
header {
|
||
display: flex; align-items: center; gap: 16px;
|
||
padding: 12px 20px; background: var(--panel);
|
||
border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 5;
|
||
}
|
||
header .brand { font-weight: 700; letter-spacing: .2px; }
|
||
header .brand b { color: var(--accent); }
|
||
header .tag { font-size: 12px; color: var(--muted); border:1px solid var(--line); padding:2px 8px; border-radius:999px; }
|
||
header .spacer { flex: 1; }
|
||
.scenario { display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
|
||
.scenario select, button {
|
||
font: inherit; border-radius: 10px; border: 1px solid var(--line);
|
||
background: #fff; color: var(--ink); padding: 8px 12px; cursor: pointer;
|
||
}
|
||
.scenario select { max-width: 260px; }
|
||
button.primary { background: var(--accent); color: #fff; border-color: var(--accent); font-weight: 600; }
|
||
button.ghost { background: #fff; }
|
||
button:disabled { opacity: .45; cursor: default; }
|
||
.progress { height: 6px; background: var(--line); }
|
||
.progress > div { height: 100%; background: var(--accent); transition: width .3s; }
|
||
|
||
.layout { display: grid; grid-template-columns: 300px 1fr; gap: 0; min-height: calc(100% - 55px); }
|
||
@media (max-width: 820px) { .layout { grid-template-columns: 1fr; } aside { display:none; } }
|
||
|
||
aside { border-right: 1px solid var(--line); background: var(--panel); padding: 14px; overflow:auto; }
|
||
aside h3 { font-size: 11px; text-transform: uppercase; letter-spacing: .8px; color: var(--muted); margin: 16px 0 6px; }
|
||
.stationItem {
|
||
display:flex; align-items:center; gap:8px; padding:8px 10px; border-radius:10px;
|
||
cursor:pointer; font-size: 14px;
|
||
}
|
||
.stationItem:hover { background: #f7f9fb; }
|
||
.stationItem.active { background: #eef4fb; font-weight:600; }
|
||
.stationItem .dot { width:10px; height:10px; border-radius:50%; flex:none; }
|
||
.stationItem .id { color: var(--muted); font-variant-numeric: tabular-nums; font-size:12px; }
|
||
.stationItem .flag { margin-left:auto; color: var(--accent); }
|
||
.stationItem.done .id::after { content:" ✓"; color: var(--ok); }
|
||
|
||
main { padding: 28px clamp(20px, 5vw, 64px); overflow:auto; }
|
||
.card { background: var(--panel); border:1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); padding: 26px; max-width: 860px; margin: 0 auto; }
|
||
.phaseChip { display:inline-flex; align-items:center; gap:8px; font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.6px; color:#fff; padding:5px 12px; border-radius:999px; }
|
||
.gateChip { background: var(--ink); }
|
||
.stationName { font-size: 28px; font-weight: 700; margin: 14px 0 4px; line-height:1.2; }
|
||
.stationId { color: var(--muted); font-size: 14px; }
|
||
.token { font-size:13px; color:var(--muted); margin-top:10px; }
|
||
.token b { color: var(--ink); }
|
||
.ctChip { display:inline-block; margin-left:6px; font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.4px; color:var(--accent); border:1px solid var(--accent); border-radius:999px; padding:2px 9px; vertical-align:middle; }
|
||
.ctText { margin-top:8px; font-size:14px; color:var(--ink); background:#fff7f7; border-left:3px solid var(--accent); border-radius:8px; padding:10px 14px; max-width:760px; }
|
||
|
||
.step { margin-top: 22px; }
|
||
.stepHead { display:flex; align-items:center; gap:10px; font-size:12px; text-transform:uppercase; letter-spacing:.8px; color:var(--muted); margin-bottom:10px; }
|
||
.stepHead .n { width:22px; height:22px; border-radius:50%; background:var(--ink); color:#fff; display:grid; place-items:center; font-size:12px; }
|
||
|
||
.discuss { background:#fbfdff; border:1px dashed var(--line); border-radius:12px; padding:18px 20px; }
|
||
.discuss ul { margin:8px 0 0; padding-left:20px; }
|
||
.discuss li { margin:4px 0; }
|
||
|
||
.q { border:1px solid var(--line); border-radius:12px; padding:18px 20px; margin-bottom:14px; }
|
||
.q .frage { font-weight:600; margin-bottom:12px; }
|
||
.opts { display:grid; gap:8px; }
|
||
.opt { text-align:left; padding:12px 14px; border-radius:10px; border:1px solid var(--line); background:#fff; cursor:pointer; }
|
||
.opt:hover { border-color:#c9d2dd; }
|
||
.opt.sel { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(226,0,26,.12); }
|
||
.opt.correct { border-color: var(--ok); background:#f1faf4; }
|
||
.opt.wrong { border-color: var(--bad); background:#fdf3f3; }
|
||
.opt .mark { float:right; font-weight:700; }
|
||
.qExpl { margin-top:10px; font-size:14px; color:var(--muted); border-left:3px solid var(--line); padding-left:12px; }
|
||
|
||
.reveal h4 { margin: 18px 0 6px; font-size: 13px; text-transform:uppercase; letter-spacing:.6px; color:var(--muted); }
|
||
.reveal p { margin: 0 0 8px; }
|
||
.reveal ul { margin: 4px 0; padding-left: 20px; }
|
||
table.raci { width:100%; border-collapse: collapse; font-size:14px; }
|
||
table.raci th, table.raci td { text-align:left; padding:8px 10px; border-bottom:1px solid var(--line); }
|
||
table.raci th { color:var(--muted); font-weight:600; font-size:12px; text-transform:uppercase; letter-spacing:.5px; }
|
||
.raciBadge { display:inline-block; min-width:22px; text-align:center; font-weight:700; border-radius:6px; padding:2px 6px; font-size:12px; background:#eef0f3; color:#5a6675; }
|
||
.raci-A { background:#fbe3e3; color:#b5202a; }
|
||
.raci-R { background:#e3eefb; color:#1f5fae; }
|
||
.raci-C { background:#fff1dd; color:#b5701a; }
|
||
.raci-I { background:#eef0f3; color:#5a6675; }
|
||
.pfade { display:grid; gap:8px; }
|
||
.pfad { border:1px solid var(--line); border-left:4px solid var(--transition); border-radius:8px; padding:10px 12px; }
|
||
.pfad b { display:block; }
|
||
|
||
.actions { display:flex; gap:10px; align-items:center; margin-top:24px; flex-wrap:wrap; }
|
||
.actions .spacer { flex:1; }
|
||
.unclear { display:flex; align-items:center; gap:8px; color:var(--muted); font-size:14px; }
|
||
|
||
dialog { border:none; border-radius:16px; padding:0; box-shadow: var(--shadow); max-width: 640px; width: 92%; }
|
||
dialog::backdrop { background: rgba(15,22,35,.45); }
|
||
.modal { padding: 24px; }
|
||
.modal h2 { margin:0 0 6px; }
|
||
pre.export { background:#0f1623; color:#d6e2f0; padding:14px; border-radius:10px; overflow:auto; max-height:320px; font-size:13px; }
|
||
.stat { display:flex; gap:20px; margin:14px 0; }
|
||
.stat div b { display:block; font-size:24px; }
|
||
.stat div span { color:var(--muted); font-size:12px; }
|
||
.note { font-size:12px; color:var(--muted); margin-top:18px; text-align:center; }
|
||
|
||
/* Setup-Screens (Action Card / Startpunkt) */
|
||
body:not(.runMode) aside { display:none; }
|
||
body:not(.runMode) .layout { grid-template-columns: 1fr; }
|
||
body:not(.runMode) .progress { display:none; }
|
||
.cardBadge { display:none; align-items:center; gap:8px; font-size:13px; }
|
||
.cardBadge .cb-svc { font-weight:600; }
|
||
.setupHead { font-size:12px; text-transform:uppercase; letter-spacing:.8px; color:var(--muted); }
|
||
.setupTitle { font-size:26px; margin:6px 0 4px; line-height:1.2; }
|
||
.muted { color:var(--muted); }
|
||
.cardForm { display:flex; gap:16px; flex-wrap:wrap; margin:18px 0; }
|
||
.cardForm label { display:flex; flex-direction:column; gap:6px; font-size:12px; text-transform:uppercase; letter-spacing:.5px; color:var(--muted); }
|
||
.cardForm select { font:inherit; padding:10px 12px; border-radius:10px; border:1px solid var(--line); min-width:280px; background:#fff; color:var(--ink); }
|
||
.pickerList { margin:14px 0 4px; }
|
||
.pickerPhase { font-size:11px; text-transform:uppercase; letter-spacing:.8px; color:var(--muted); margin:16px 0 6px; }
|
||
.pickerItem { display:flex; align-items:center; gap:10px; padding:9px 12px; border:1px solid var(--line); border-radius:10px; margin-bottom:6px; cursor:pointer; }
|
||
.pickerItem:hover { border-color:#c9d2dd; background:#f7f9fb; }
|
||
.pickerItem.sel { border-color:var(--accent); box-shadow:0 0 0 2px rgba(226,0,26,.12); }
|
||
.pickerItem .dot { width:10px; height:10px; border-radius:50%; flex:none; }
|
||
.pickerItem .id { color:var(--muted); font-size:12px; font-variant-numeric:tabular-nums; }
|
||
.pickerItem .gate { margin-left:auto; font-size:11px; font-weight:700; color:#fff; background:var(--ink); padding:1px 8px; border-radius:999px; }
|
||
.pickerItem.correct { border-color:var(--ok); background:#f1faf4; }
|
||
.pickerItem.wrongPick { border-color:var(--bad); background:#fdf3f3; }
|
||
.recBox { border:1px solid var(--line); border-left:4px solid var(--ok); border-radius:10px; padding:14px 16px; margin:14px 0; }
|
||
.recBox h4 { margin:0 0 6px; font-size:13px; text-transform:uppercase; letter-spacing:.5px; color:var(--muted); }
|
||
/* Geführte Tour */
|
||
.tourBanner { background:#fff7f7; border:1px solid var(--line); border-left:4px solid var(--accent); border-radius:10px; padding:10px 14px; margin-bottom:16px; font-size:13px; line-height:1.45; }
|
||
.tourBanner b { color:var(--ink); }
|
||
.tourProg { font-size:12px; color:var(--muted); margin-bottom:8px; font-variant-numeric:tabular-nums; }
|
||
.tourNarr { background:#eef4fb; border-radius:12px; padding:16px 18px; margin:14px 0; font-size:16px; line-height:1.55; }
|
||
.tourNarr h4 { margin:0 0 8px; font-size:12px; text-transform:uppercase; letter-spacing:.6px; color:var(--design); }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<header>
|
||
<div class="brand">SLC <b>Companion</b></div>
|
||
<span class="tag">v0.5</span>
|
||
<div id="cardBadge" class="cardBadge"></div>
|
||
<div class="spacer"></div>
|
||
<button class="ghost" id="resetBtn" title="Neue Action Card / Durchlauf zurücksetzen">Neu starten</button>
|
||
<button class="primary" id="debriefBtn">Debrief</button>
|
||
</header>
|
||
<div class="progress"><div id="progressBar" style="width:0%"></div></div>
|
||
|
||
<div class="layout">
|
||
<aside id="stationList"></aside>
|
||
<main><div class="card" id="panel"></div></main>
|
||
</div>
|
||
|
||
<dialog id="debriefDlg">
|
||
<div class="modal">
|
||
<h2>Debrief-Export</h2>
|
||
<p style="color:var(--muted);margin-top:0">Lokale Auswertung dieses Durchlaufs — nichts wird hochgeladen.</p>
|
||
<div class="stat" id="debriefStat"></div>
|
||
<pre class="export" id="debriefText"></pre>
|
||
<div class="actions">
|
||
<button class="ghost" id="copyBtn">In Zwischenablage</button>
|
||
<button class="ghost" id="dlMd">↓ Markdown</button>
|
||
<button class="ghost" id="dlJson">↓ JSON</button>
|
||
<div class="spacer"></div>
|
||
<button class="primary" id="closeDebrief">Schließen</button>
|
||
</div>
|
||
</div>
|
||
</dialog>
|
||
|
||
<script>
|
||
/* Empfohlener Einstiegspunkt je Change-Typ (didaktische Auflösung in Schritt 2).
|
||
Reihenfolge entspricht CHANGE_TYPES. */
|
||
const START_EMPFEHLUNG = [
|
||
{ id:"ds_01", grund:"Ein Major Change auf Top-Level ist strategisch getrieben und betrifft den Service grundlegend – er durchläuft den vollen Lebenszyklus ab dem Design (Service-Definition)." },
|
||
{ id:"ds_01", grund:"Auch ein Major Change auf Low-Level bringt neue Komponenten/Funktionen und braucht ein echtes Design – Einstieg im Design. Unterschied zum Top-Level ist v.a. Tragweite und Freigabe-Ebene, nicht der Einstiegspunkt." },
|
||
{ id:"tr_01", grund:"Ein Normal Change ist geplant und dokumentiert, aber nicht strategisch. Er steigt an Gate 1 ein, wo Build-oder-Konfiguration entschieden wird – meist der Konfigurationspfad (tr_05)." },
|
||
{ id:"op_03", grund:"Ein Standard Change ist vorab genehmigt und im Katalog hinterlegt. Er braucht keine Gates und kein Design, sondern wird im laufenden Betrieb umgesetzt (op_03: Umsetzung freigegebener Standard-Changes)." },
|
||
{ id:"tr_10", grund:"Ein Emergency Change muss die Störung sofort beheben. Der Fix wird beschleunigt ausgerollt (tr_10); die formale Freigabe (Gate 3) erfolgt nachgelagert. Ausgelöst wird er typischerweise durch einen Incident aus Operation/Support." }
|
||
];
|
||
|
||
/* Geführtes Beispiel ("for dummies"-Tour): EIN konkreter Fall durch den ganzen
|
||
Lifecycle. Online-Bürgerportal · Major Change Top-Level (neues Landesgesetz zur
|
||
digitalen Bürgerbeteiligung → Erweiterung um Beteiligungs-Module). */
|
||
const TOUR = {
|
||
service: 2, change: 0,
|
||
text: {
|
||
ds_01: "Das neue Landesgesetz verlangt Online-Beteiligung. Zuerst klären Fachamt und (designierter) Service Owner, was das Beteiligungs-Modul leisten muss: Wer nutzt es (Bürger:innen, Planungsamt)? Welchen Nutzen bringt es? Welche Fristen und Verfügbarkeiten sind gesetzlich nötig? Ergebnis ist ein erster Entwurf der Service-Definition.",
|
||
ds_02: "Jetzt entsteht das Lösungsdesign: welche Module (Online-Konsultation, Kommentar-Workflows, Veröffentlichung von Plänen), welche Schnittstellen zum bestehenden Portal und zum DMS, welche Datenschutz- und Barrierefreiheits-Vorgaben. Das ist das Service Design Document.",
|
||
ds_03: "Hier wird geplant, WIE das Modul organisatorisch eingeführt wird – noch nicht technisch: Wer schult die Sachbearbeiter:innen im Planungsamt? Welche Prozesse und Rollen ändern sich? Wann kann der Betrieb übernehmen? Ergebnis: Implementation Blueprint.",
|
||
ds_04: "Letzte Vorbereitung vor der Transition: Betrieb und Support werden abgestimmt, Tools und Strukturen vorbereitet, ein Early-Life-Support-Konzept skizziert, und der Service wird vollständig im Portfolio erfasst.",
|
||
tr_01: "Erstes Tor – die SOR entscheidet: bauen oder nur konfigurieren? Da völlig neue Beteiligungs-Module gebraucht werden, fällt die Entscheidung auf ENTWICKLUNG → weiter zu tr_02. (Bei einer reinen Einstellung wäre es Konfiguration, und tr_02–tr_04 würden übersprungen.)",
|
||
tr_02: "Die Projektleitung steuert die Umsetzung: Abstimmung mit dem Dienstleister, der die Module baut, dazu Termine, Budget und Arbeitspakete.",
|
||
tr_03: "Projektteam bzw. Dienstleister entwickeln die Beteiligungs-Module: Formulare, Kommentar-Workflows, Veröffentlichungsfunktion und die Schnittstellen.",
|
||
tr_04: "Die fertigen Komponenten werden geprüft und angenommen (Vollständigkeit, Qualität, Dokumentation) und ans Testmanagement übergeben.",
|
||
tr_05: "Parameter, Rollen, Zugänge und die Anbindung an Portal und Service-Katalog werden eingerichtet. (Genau hier wäre der Einstieg gewesen, hätte Gate 1 'Konfiguration' entschieden.)",
|
||
tr_06: "Die Betriebs- und Supportunterlagen entstehen: Betriebshandbuch, Supportanleitungen, Monitoring-Vorgaben und Eskalationswege für das neue Modul.",
|
||
tr_07: "Das Testmanagement prüft Funktion, Integration und Abnahme – etwa ob eine Online-Konsultation fristgerecht startet und endet und Eingaben korrekt gespeichert werden.",
|
||
tr_08: "Der Build ist fertig. Alle Unterlagen und Testprotokolle werden für die Prüfung an Gate 2 zusammengestellt.",
|
||
tr_09: "Zweites Tor – der Service Owner entscheidet allein: Ist alles übergabefähig? Doku vollständig, Abnahme liegt vor, Betrieb und Support vorbereitet → FREIGABE → weiter zu tr_10.",
|
||
tr_10: "Das Betriebsteam rollt die Module in die produktive Umgebung aus: Systeme konfigurieren, Daten migrieren, Monitoring aktivieren, Zugänge schalten.",
|
||
tr_11: "Letzter Check vor dem Go-Live: Betriebsdoku, Überwachung und Eskalationswege werden geprüft, die Go-Live-Kommunikation an die Ämter vorbereitet und der Gate-3-Antrag erstellt.",
|
||
tr_12: "Drittes Tor – die SOR entscheidet im Konsent: Go-Live? Portfolio passt, Betrieb und Support sind bereit, SLAs vereinbart → GO-LIVE. Der Service wird formal ins Portfolio aufgenommen und geht in die Operation.",
|
||
op_01: "Direkt nach dem Start läuft das Modul unter erhöhter Aufmerksamkeit (Early Life Support): enge Beobachtung, schnelle Hilfe, erste Bürger-Rückmeldungen werden aufgearbeitet. Der Service Owner entscheidet, wann der Normalbetrieb beginnt.",
|
||
op_02: "Betriebshandbuch und Betriebsprozesse sind bereitgestellt – klare Regeln und Zuständigkeiten für den täglichen Betrieb des Beteiligungs-Moduls.",
|
||
op_03: "Tagesgeschäft: Benutzer und Berechtigungen, Backups, Routinepflege und die Umsetzung freigegebener Standard-Changes (z. B. ein neues Beteiligungsverfahren anlegen).",
|
||
op_04: "Es wird sichergestellt, dass genug Personal, Technik und Budget vorhanden sind – inklusive Steuerung des Dienstleisters.",
|
||
op_05: "Verfügbarkeit und Performance werden überwacht – besonders wichtig, wenn zum Ende einer Beteiligungsfrist viele Bürger:innen gleichzeitig zugreifen.",
|
||
op_06: "Regelmäßiger Qualitätsbericht: Wurden SLAs/SLOs eingehalten? Wie war die Verfügbarkeit während der Konsultationen? Das ist die Grundlage fürs Review.",
|
||
op_07: "Über das reine Monitoring hinaus: Trends erkennen – etwa wiederkehrende Lastspitzen oder ein Formular, das auffällig oft abgebrochen wird.",
|
||
sp_01: "Der Support bekommt seinen Rahmen: Incident- und Request-Prozesse, Reaktionszeiten und Ticketkategorien für das Beteiligungs-Modul.",
|
||
sp_02: "Lösungen, Workarounds und FAQ werden gepflegt – damit der 1st Level häufige Bürgerfragen schnell beantworten kann.",
|
||
sp_03: "Eingehende Tickets von Bürger:innen und Ämtern werden gesichtet, priorisiert und an die richtige Stelle geroutet.",
|
||
sp_04: "Standardanfragen werden erledigt – z. B. ein Zugang für eine neue Sachbearbeiterin im Planungsamt.",
|
||
sp_05: "Typische Störungen löst der 1st Level direkt – etwa wenn ein Nutzer den Kommentar-Button nicht findet (Anleitung aus der Wissensdatenbank).",
|
||
sp_06: "Knifflige Fälle gehen an den 2nd Level – z. B. Kommentare werden unter hoher Last nicht gespeichert. Bleibt es ungelöst, entsteht daraus ein Problem Record.",
|
||
sp_07: "Der Fall wird sauber abgeschlossen: Lösung validiert, Nutzer informiert, Dokumentation und FAQ aktualisiert.",
|
||
sp_08: "Endgültiges Schließen inklusive Klassifizierung für die Statistik und Erkennen wiederkehrender Fälle.",
|
||
sp_09: "Ein Incident bleibt ungelöst – eine strukturelle Ursache wird vermutet. Der Problem Manager legt einen Problem Record an.",
|
||
sp_10: "Mehrere ähnliche Speicher-Fehler häufen sich → sie werden geclustert und gebündelt als Problem Record erfasst.",
|
||
sp_11: "Ursachensuche: Das Speicherproblem entsteht durch einen Timeout unter Last. Es gibt einen Workaround (Eintrag in die Wissensdatenbank) und die Entscheidung, dass ein Change nötig ist.",
|
||
rv_01: "Im Service-Review werden die Betriebsdaten des Beteiligungs-Moduls ausgewertet: KPIs, die gehäuften Speicher-Incidents, Kundenfeedback und die Infrastruktur — alles fließt ins Service-Review-Dokument.",
|
||
rv_02: "Die Ergebnisse werden bewertet: Der wiederkehrende Speicher-Fehler rechtfertigt einen RFC. Der Bericht geht an die SOR, die ganzheitlich bewertet.",
|
||
rv_03: "Auf Basis der Bewertung werden Änderungsvorschläge formuliert (z. B. Last-/Timeout-Optimierung), konsolidiert und die ausgewählte Änderung beschrieben.",
|
||
rv_04: "Die Änderung wird gestartet. Es ist eine überschaubare Anpassung → Normal-Change-Logik: Umsetzung planen. (Wäre sie grundlegend, würde hier das Routing RUN/DPM/MB geklärt und ein Change-Steckbrief erstellt.)",
|
||
rv_05: "Die Änderung wird umgesetzt: Im Weg RUN führt der Service Owner sie durch, dokumentiert und schließt sie ab. Der Service läuft verbessert weiter — der Kreis schließt sich."
|
||
}
|
||
};
|
||
|
||
/* =========================================================================
|
||
STATIONEN — vollständiger Lifecycle, abgeleitet aus den Blueprint-YAMLs
|
||
(service-lifecycle_design/transition/operation/support/review.yaml v3.2 +
|
||
spm_rollen.yaml). Reihenfolge: Design → Transition (inkl. Gate 1–3) →
|
||
Operation ⇄ Support → Review. Quiz-Fragen sind vermittelnd formuliert.
|
||
Im Echtbetrieb generiert ein Build-Skript questions.json aus den YAMLs.
|
||
========================================================================= */
|
||
const ROLLEN = {
|
||
spm:"Service-Portfolio-Manager", sor:"Service Operations Runde (SOR)",
|
||
service_owner:"Service Owner", al_basis_cloud:"AL Basis & Cloud",
|
||
al_applikationen:"AL Applikationen", support_manager:"Support Manager",
|
||
problem_manager:"Problem Manager", projektleitung:"Projektleitung",
|
||
betriebsteam:"Betriebsteam", service_support_team:"Service-Support Team",
|
||
projektteam:"Projektteam", queue_koordinator:"Queue Koordinator",
|
||
first_level_agent:"1st Level Agent", second_level_agent:"2nd Level Agent",
|
||
testmanagement:"Testmanagement", architektur:"Architektur",
|
||
lieferant:"Lieferant", operations_manager:"Betrieb (AL B&C / AL App)", dpm:"Demand Portfolio Manager"
|
||
};
|
||
const PHASEN = {
|
||
design:{label:"Design", color:"var(--design)"},
|
||
transition:{label:"Transition", color:"var(--transition)"},
|
||
operation:{label:"Operation", color:"var(--operation)"},
|
||
support:{label:"Support", color:"var(--support)"},
|
||
review:{label:"Review", color:"var(--review)"}
|
||
};
|
||
/* Action Cards: 6 Services × 5 Change-Typen (aus „Use Cases mit möglichen Changes"). */
|
||
const CHANGE_TYPES = [
|
||
"Major Change – Top-Level",
|
||
"Major Change – Low Level",
|
||
"Normal Change",
|
||
"Standard Change",
|
||
"Emergency Change"
|
||
];
|
||
const USE_CASES = [
|
||
{ service:"Zentrale VDI (Virtual-Desktop-Infrastructure)",
|
||
desc:"Bereitstellung von virtuellen Windows-Desktops über das interne Rechenzentrum.",
|
||
changes:[
|
||
{titel:"Open Source von oben!", text:"Der OB gibt die Richtung vor: Die proprietäre VDI-Lösung soll auf eine Open-Source-Alternative (OpenStack + Thin-Client) umgestellt werden."},
|
||
{titel:"Bauamt will mehr!", text:"Das Bauamt fordert ein neues GIS-Fachverfahren, das künftig direkt auf dem virtuellen Desktop laufen soll."},
|
||
{titel:"Tapetenwechsel", text:"Die Stadt bekommt ein neues Logo — der Desktop-Hintergrund aller virtuellen Arbeitsplätze muss angepasst werden."},
|
||
{titel:"Quartalspflege", text:"Das turnusmäßige Firmware-Update der VDI-Host-Hypervisoren steht an — im Standard-Change-Katalog längst hinterlegt."},
|
||
{titel:"Blackout!", text:"Ein Stromausfall reißt ein ganzes VDI-Host-Cluster aus dem Betrieb — die Sitzungen müssen sofort auf ein Backup-Cluster migriert werden."}
|
||
]},
|
||
{ service:"Managed VPN-Access Service",
|
||
desc:"Zentral verwalteter VPN-Dienst, der Mitarbeitenden der Fachämter sicheren Remote-Zugriff auf interne Systeme (Intranet, Fachanwendungen, Datenbanken) ermöglicht.",
|
||
changes:[
|
||
{titel:"Brüssel ruft!", text:"Eine neue EU-weite IT-Sicherheitsverordnung zwingt dazu, die gesamte VPN-Architektur neu aufzustellen."},
|
||
{titel:"Schlüsselpflicht", text:"Das Hauptpersonalamt verlangt eine neue Authentifizierung: FIDO2-Security-Keys werden für alle verpflichtend."},
|
||
{titel:"Heimvorteil", text:"Ein neues Intranet-Portal soll in die Split-Tunnel-Liste, damit Mitarbeitende auch aus dem Homeoffice darauf zugreifen."},
|
||
{titel:"Monatsroutine", text:"Das monatliche Firmware-Update der VPN-Appliance steht an — als Standard-Change bereits freigegeben."},
|
||
{titel:"Gephisht!", text:"Ein erfolgreicher Phishing-Angriff hat eine VPN-Zertifikatskette kompromittiert — sofort sperren und neu ausstellen."}
|
||
]},
|
||
{ service:"Online-Bürgerportal für Meldungen & Anträge",
|
||
desc:"Zentrales Web-Portal, über das Bürger*innen Meldungen (z. B. Straßenreparatur, Lärm) und Anträge (z. B. Baugenehmigung, Personalausweis) digital einreichen und den Status verfolgen.",
|
||
changes:[
|
||
{titel:"Mitreden, Pflicht!", text:"Ein neues Landesgesetz schreibt digitale Bürgerbeteiligung vor — das Portal muss um komplette Beteiligungs-Module erweitert werden."},
|
||
{titel:"Ratsbeschluss!", text:"Der Gemeinderat will einen neuen Meldetyp „Klimaschutz“ — das Umweltamt braucht dafür eigene Formulare und Workflows."},
|
||
{titel:"Rotstift gefragt", text:"Der Bürgerservice meldet einen Rechtschreibfehler in einem statischen Hinweistext, der korrigiert werden muss."},
|
||
{titel:"Patchday", text:"Das monatliche Sicherheits-Patch des Webservers (Apache/Nginx) steht an — im Change-Katalog definiert."},
|
||
{titel:"Lücke im Formular!", text:"In einem Eingabe-Formular wird eine kritische XSS-Schwachstelle entdeckt — ein Hotfix muss sofort raus."}
|
||
]},
|
||
{ service:"Zentrales Dokumenten-Management-System (DMS)",
|
||
desc:"Elektronisches Archiv, das alle ein- und ausgehenden Dokumente (PDF, Scans, E-Mails) zentral speichert, versioniert und revisionssicher archiviert.",
|
||
changes:[
|
||
{titel:"Datendiät", text:"Eine DSGVO-Ergänzung zur Datenminimierung erzwingt die komplette Neugestaltung von Metadaten-Modell und Archivierungs-Policies."},
|
||
{titel:"Akten-Zuwachs", text:"Ein neues Fachverfahren zieht ein und braucht eigene Dokumentenklassen und Workflows im DMS."},
|
||
{titel:"Dropdown-Wunsch", text:"Das Finanzamt bittet um ein neues Metadaten-Feld „Kostenstelle“ als Auswahlliste."},
|
||
{titel:"Versionspflege", text:"Das quartalsweise Update der DMS-Software (Sicherheits- und Funktions-Patches) steht an."},
|
||
{titel:"Ransomware!", text:"Alarm: Dokumente werden verdächtig verschlüsselt — Storage sofort isolieren und aus den letzten Snapshots wiederherstellen."}
|
||
]},
|
||
{ service:"Kommunales GIS-Portal (Geoinformations-System)",
|
||
desc:"Web-basiertes Karten- und Analyse-Portal, das Fachämtern (Bau, Umwelt, Verkehr) räumliche Daten (Flurstücke, Infrastruktur, Umweltzonen) und bearbeitbare Layer bereitstellt.",
|
||
changes:[
|
||
{titel:"Norm-Zwang", text:"Eine bundesweite Vorgabe zu EU-Standards erzwingt die komplette Migration des GIS-Stacks auf konforme Services und Datenmodelle."},
|
||
{titel:"Klimarisiko im Blick", text:"Das Umweltamt will ein neues Analyse-Modul „Klimarisiko“ — mit neuen Daten-Layern und Rechen-Ressourcen."},
|
||
{titel:"Falsch beschriftet", text:"Das Bauamt meldet eine falsche Beschriftung eines Karten-Layers, die korrigiert werden muss."},
|
||
{titel:"GeoServer-Update", text:"Das monatliche Update der GIS-Software (GeoServer 2.23 → 2.24) steht an — im Standard-Change-Katalog."},
|
||
{titel:"Schnittstelle offen!", text:"An einer Schnittstelle wird eine kritische Schwachstelle entdeckt, die unautorisierten Datenzugriff erlaubt — Dienst sofort abschalten und patchen."}
|
||
]},
|
||
{ service:"Beschaffungs- und Vertrags-System für Fachämter",
|
||
desc:"Web-Applikation, über die Fachämter interne Beschaffungen (Material, Dienstleistungen) anlegen, prüfen und Verträge digital verwalten.",
|
||
changes:[
|
||
{titel:"Vergabe neu!", text:"Eine neue EU-Vergaberichtlinie zwingt zur Einführung von E-Invoicing und erweiterten Transparenz-Reports."},
|
||
{titel:"Portal für Partner", text:"Ein neues Lieferanten-Portal (z. B. für Badenova) soll andocken — mit neuen API-Schnittstellen und Authentifizierungs-Flows."},
|
||
{titel:"Vierstellig, bitte", text:"Das Finanzamt wünscht eine kleine Anpassung: aus dem Label „Kostenstelle“ wird „Kostenstelle (4-stellig)“."},
|
||
{titel:"Patch-Quartal", text:"Das quartalsweise Sicherheits-Patch des Anwendungsservers steht an — bereits im Change-Katalog."},
|
||
{titel:"Upload-Falle!", text:"Im Vertrags-Upload wird eine kritische Lücke entdeckt, über die sich Schadcode hochladen lässt — Endpoint sofort sperren, Hotfix einspielen."}
|
||
]}
|
||
];
|
||
|
||
const STATIONEN = [
|
||
{ id:"ds_01", phase:"design", typ:"aktivitaet",
|
||
name:"Definieren der erforderlichen Service-Eigenschaften",
|
||
beschreibung:"Grundlegende Definition des neuen oder geänderten Services aus fachlicher Perspektive. Startpunkt für die Service-Definition als zentrales Artefakt.",
|
||
umfasst:["Zweck, Nutzen, Zielgruppen","Utility & Warranty","SLA-/SLO-Anforderungen","Abhängigkeiten zu unterstützenden Services","Fachliche & technische Anforderungen"],
|
||
artefakt:"Service-Definition (Entwurf)",
|
||
raci:[["service_owner","A"],["projektleitung","R"],["betriebsteam","C"],["architektur","C"],["spm","C"]],
|
||
quiz:[
|
||
{frage:"Wer trägt die Ergebnisverantwortung (A) für diese Aktivität?",
|
||
optionen:["Service Owner","Projektleitung","SPM","Architektur"], richtig:0,
|
||
expl:"Der (designierte) Service Owner ist Accountable; die Projektleitung führt operativ aus (R)."},
|
||
{frage:"Welches zentrale Artefakt entsteht hier?",
|
||
optionen:["Betriebshandbuch","Service-Definition","Review-Bericht","Incident Record"], richtig:1,
|
||
expl:"Die Service-Definition ist das zentrale Artefakt der Design-Phase."}
|
||
]},
|
||
{ id:"ds_02", phase:"design", typ:"aktivitaet",
|
||
name:"Designen der erforderlichen Service- und Service-Management-Komponenten",
|
||
beschreibung:"Einarbeiten der Service-Eigenschaften in ein vollständiges Designmodell.",
|
||
umfasst:["Servicearchitektur (Komponenten, Schnittstellen)","Design der Betriebs- & Supportprozesse","Sicherheit/Compliance/Datenschutz","Monitoring & Reporting","Rollenmodell"],
|
||
artefakt:"Service Design Document",
|
||
raci:[["service_owner","A"],["architektur","R"],["projektteam","R"],["spm","I"]],
|
||
quiz:[
|
||
{frage:"Wer führt das Architektur-Design operativ aus (R)?",
|
||
optionen:["SPM","Service Owner","Architektur","Support Manager"], richtig:2,
|
||
expl:"Architektur und Projektteam sind Responsible; der Service Owner bleibt Accountable."}
|
||
]},
|
||
{ id:"ds_03", phase:"design", typ:"aktivitaet",
|
||
name:"Beschreiben des Vorgehens zur Implementierung",
|
||
beschreibung:"Planen, WIE der Service organisatorisch eingeführt wird (nicht technisch deployt wird).",
|
||
umfasst:["Organisatorische Integration","Rollenübergaben","Anpassung Richtlinien/Prozesse/Tools","Trainings & Kommunikation","Time-to-Operate"],
|
||
artefakt:"Implementation Blueprint",
|
||
raci:[["service_owner","A"],["projektleitung","R"],["betriebsteam","C"],["service_support_team","C"],["spm","I"]],
|
||
quiz:[
|
||
{frage:"Was wird hier geplant?",
|
||
optionen:["Das technische Deployment","Wie der Service organisatorisch eingeführt wird","Die Incident-Bearbeitung","Die Portfolio-Strategie"], richtig:1,
|
||
expl:"ds_03 plant die organisatorische Einführung — bewusst getrennt vom technischen Build."}
|
||
]},
|
||
{ id:"ds_04", phase:"design", typ:"aktivitaet",
|
||
name:"Vorbereiten der Service-Implementierung",
|
||
beschreibung:"Finalisieren aller organisatorischen Voraussetzungen für die spätere Übergabe in den Betrieb.",
|
||
umfasst:["Abstimmung mit Betrieb & Support","Prozesse/Tools/Strukturen vorbereiten","ELS-Konzept (Early Life Support)","Service vollständig im Portfolio erfasst"],
|
||
artefakt:"Übergabe-Readiness (organisatorisch)",
|
||
raci:[["service_owner","A"],["projektleitung","R"],["betriebsteam","C"],["service_support_team","C"],["spm","I"]],
|
||
quiz:[
|
||
{frage:"Wofür steht das ELS-Konzept?",
|
||
optionen:["Early Life Support","End of Life Service","Enterprise License System","Externer Lieferanten-Support"], richtig:0,
|
||
expl:"Early Life Support = erhöhte Betreuung direkt nach Go-Live (siehe op_01)."}
|
||
]},
|
||
{ id:"tr_01", phase:"transition", typ:"gate", gateNr:1,
|
||
name:"Gate 1: Entwicklung oder Konfiguration?",
|
||
beschreibung:"Entry-Gate der Transition: Entscheidung, ob die Service-Komponenten entwickelt oder nur konfiguriert werden. Erfordert SOR-Approval (Budget- und Ressourcenimplikationen).",
|
||
umfasst:["Aufwandsschätzung (Build vs. Configure)","Technische Risiken","Budget-Abgleich","ggf. Lieferanten-Einbindung","SOR-Vorlage für Freigabe"],
|
||
artefakt:"Gate-Entscheidung + SOR-Vorlage",
|
||
pfade:[
|
||
["Entwicklung","Neuentwicklung/wesentliche Anpassung → weiter zu tr_02"],
|
||
["Konfiguration","Bestehende Komponenten konfigurieren → springt zu tr_05"]
|
||
],
|
||
pruef:[
|
||
["Design-Vollständigkeit","Ist das Service Design Document vollständig?"],
|
||
["Budget-Verfügbarkeit","Ist Budget für die Strategie verfügbar?"],
|
||
["Projektressourcen","Können Ressourcen mobilisiert werden?"],
|
||
["Betriebs-/Support-Bereitschaft","Grundsätzliches Commitment vorhanden?"]
|
||
],
|
||
raci:[["sor","A"],["service_owner","R"],["projektleitung","R"],["architektur","R"],["spm","C"],["lieferant","I"]],
|
||
quiz:[
|
||
{frage:"Wer entscheidet an Gate 1 (Accountable)?",
|
||
optionen:["Service Owner","SOR","SPM","Projektleitung"], richtig:1,
|
||
expl:"Gate 1 ist eine SOR-Gremienentscheidung (Budget-/Ressourcenimplikationen)."},
|
||
{frage:"Welche zwei Pfade öffnet Gate 1?",
|
||
optionen:["Go oder Stop","Intern oder Extern","Entwicklung oder Konfiguration","Test oder Release"], richtig:2,
|
||
expl:"Entwicklung (tr_02) vs. Konfiguration (tr_05) — Konfiguration überspringt tr_02–tr_04."}
|
||
]},
|
||
{ id:"tr_02", phase:"transition", typ:"aktivitaet",
|
||
name:"Koordinieren der Entwicklungs- und Beschaffungsaktivitäten",
|
||
beschreibung:"Steuern der Entwicklungsaktivitäten im Projekt.",
|
||
umfasst:["Abstimmung mit Lieferanten","Ressourcenplanung","Termin- und Budgetnachführung","Sicherstellung von Change-Kontrollen","Definition von Build- und Konfigurationspaketen"],
|
||
artefakt:"Projektsteuerung / Build- & Konfigurationspakete",
|
||
raci:[["projektleitung","A"],["architektur","C"],["service_owner","I"],["lieferant","C/I"]],
|
||
quiz:[
|
||
{frage:"Wer trägt die Ergebnisverantwortung (A) für die Koordination der Entwicklung?",
|
||
optionen:["Projektleitung","Architektur","Service Owner","Lieferant"], richtig:0,
|
||
expl:"Die Projektleitung ist Accountable; Architektur berät (C), der Service Owner ist informiert (I)."}
|
||
]},
|
||
{ id:"tr_03", phase:"transition", typ:"aktivitaet",
|
||
name:"Entwickeln von Anwendungen und Systemen",
|
||
beschreibung:"Realisierung der technischen Service-Komponenten.",
|
||
umfasst:["Softwareentwicklung","Customizing","Schnittstellenentwicklung","Infrastrukturaufbau","Versionierung & Dokumentation","Testdaten & Migrationspfade vorbereiten"],
|
||
artefakt:"Entwickelte Service-Komponenten",
|
||
raci:[["projektleitung","A"],["projektteam","R"],["lieferant","R"],["service_owner","C"],["architektur","C"]],
|
||
quiz:[
|
||
{frage:"Wer führt die Entwicklung operativ aus (R)?",
|
||
optionen:["SPM","Projektteam bzw. Lieferant","Service Owner","Testmanagement"], richtig:1,
|
||
expl:"Projektteam (intern) und Lieferant (extern) sind Responsible; die Projektleitung bleibt Accountable."}
|
||
]},
|
||
{ id:"tr_04", phase:"transition", typ:"aktivitaet",
|
||
name:"Entgegennehmen der Service-Komponenten",
|
||
beschreibung:"Qualitätssicherung beim Übergang von der Entwicklung zur Testphase.",
|
||
umfasst:["Eingangskontrolle","Prüfung von Vollständigkeit / Qualität","Sicherstellung der Dokumentationen","Übergabe an Testmanagement"],
|
||
artefakt:"Abgenommene Service-Komponenten",
|
||
raci:[["service_owner","A"],["projektleitung","R"],["testmanagement","R"],["lieferant","C"]],
|
||
quiz:[
|
||
{frage:"An wen werden die entgegengenommenen Komponenten übergeben?",
|
||
optionen:["An den Betrieb","An das Testmanagement","An die SOR","An das SPM"], richtig:1,
|
||
expl:"tr_04 ist die Qualitätssicherung beim Übergang in die Testphase — Übergabe an das Testmanagement."}
|
||
]},
|
||
{ id:"tr_05", phase:"transition", typ:"aktivitaet",
|
||
name:"Konfiguration der Service-Komponenten",
|
||
beschreibung:"Einrichtung von Konfigurationsparametern, Settings, Rollen und Zugängen. Einstiegspunkt bei Gate-1-Entscheidung Konfiguration (überspringt tr_02–tr_04).",
|
||
umfasst:["Setup von Parametern, Policies, Templates","Toolkonfiguration (ITSM-Systeme, Monitoring)","Anpassung bestehender Komponenten","Verknüpfung mit Service-Katalog / Portfolio"],
|
||
artefakt:"Konfigurierte Service-Komponenten",
|
||
raci:[["service_owner","A"],["projektteam","R"],["betriebsteam","C"],["service_support_team","C"]],
|
||
quiz:[
|
||
{frage:"Bei welcher Gate-1-Entscheidung ist tr_05 der Einstiegspunkt?",
|
||
optionen:["Entwicklung","Konfiguration","Ablehnung","Go-Live"], richtig:1,
|
||
expl:"Bei der Entscheidung Konfiguration werden tr_02–tr_04 übersprungen und direkt bei tr_05 eingestiegen."}
|
||
]},
|
||
{ id:"tr_06", phase:"transition", typ:"aktivitaet",
|
||
name:"Erstellen oder Aktualisieren der Betriebs-Dokumentation",
|
||
beschreibung:"Alle Betriebsunterlagen werden erstellt oder aktualisiert.",
|
||
umfasst:["Service Operation Manual","Supportanleitungen","Monitoring-Spezifikationen","Eskalationswege","Standard Changes","Konfigurations-/Betriebsrichtlinien"],
|
||
artefakt:"Betriebsdokumentation (Service Operation Manual)",
|
||
raci:[["service_owner","A"],["projektteam","R"],["betriebsteam","C"],["service_support_team","C"]],
|
||
quiz:[
|
||
{frage:"Welches Artefakt entsteht hier vor allem?",
|
||
optionen:["Service-Definition","Betriebsdokumentation (Service Operation Manual)","Gate-Vorlage","Review-Bericht"], richtig:1,
|
||
expl:"tr_06 erstellt/aktualisiert alle Betriebsunterlagen (u.a. Service Operation Manual, Supportanleitungen)."}
|
||
]},
|
||
{ id:"tr_07", phase:"transition", typ:"aktivitaet",
|
||
name:"Testen der Service-Komponenten",
|
||
beschreibung:"Verifizierung, dass alle Servicekomponenten funktionsfähig und betriebsbereit sind.",
|
||
umfasst:["Funktionstests","Integrationstests","Abnahmetests","Nachweis der Betriebsreife","Testprotokolle & Freigaben"],
|
||
artefakt:"Testprotokolle & Freigaben",
|
||
raci:[["projektleitung","A"],["testmanagement","R"],["service_owner","C"],["lieferant","C/I"]],
|
||
quiz:[
|
||
{frage:"Wer ist Responsible (R) für das Testen der Komponenten?",
|
||
optionen:["Projektleitung","Testmanagement","Service Owner","Betriebsteam"], richtig:1,
|
||
expl:"Das Testmanagement ist Responsible; die Projektleitung ist Accountable."}
|
||
]},
|
||
{ id:"tr_08", phase:"transition", typ:"aktivitaet",
|
||
name:"Formale Übergabe (Build abgeschlossen)",
|
||
beschreibung:"Der Build ist abgeschlossen. Alle Artefakte werden für die Entry-Prüfung (Gate 2) bereitgestellt.",
|
||
umfasst:["Bereitstellung aller Betriebsunterlagen","Bereitstellung der Testprotokolle","Dokumentierter Übergabe-Termin","Vorbereitung Gate-2-Antrag"],
|
||
artefakt:"Übergabepaket (Gate-2-Antrag)",
|
||
raci:[["projektleitung","A"],["service_owner","R"],["betriebsteam","C"],["service_support_team","C"],["spm","I"]],
|
||
quiz:[
|
||
{frage:"Worauf bereitet die formale Übergabe (Build abgeschlossen) vor?",
|
||
optionen:["Gate 1","Gate 2","Gate 3","ELS-Exit"], richtig:1,
|
||
expl:"tr_08 stellt alle Artefakte für die Entry-Prüfung an Gate 2 (tr_09) bereit."}
|
||
]},
|
||
{ id:"tr_09", phase:"transition", typ:"gate", gateNr:2,
|
||
name:"Gate 2: Entry-Prüfung nach Build",
|
||
beschreibung:"Validierung der Übergabefähigkeit nach Abschluss des Builds. Dies ist eine SO-Einzelentscheidung (keine Gremienentscheidung).",
|
||
umfasst:["Prüfung der Übergabe-Vollständigkeit","Prüfung des Abnahme-Status","Ressourcen-Outlook (Betrieb/Support vorbereitet)","Pilot-Entscheidung (falls erforderlich)","Dokumentation im Transition-Steckbrief"],
|
||
artefakt:"Gate-2-Entscheidung (Transition-Steckbrief)",
|
||
pfade:[
|
||
["Freigabe","Weiter zu den Deploy-Aktivitäten → tr_10"],
|
||
["Freigabe mit Auflagen","Weiter, definierte Punkte müssen nachgearbeitet werden"],
|
||
["Zurück an Build","Nachbesserung erforderlich → tr_02 (ggf. tr_05–tr_07)"],
|
||
["Ablehnung","Endgültige Ablehnung — erfordert SOR-Eskalation"]
|
||
],
|
||
pruef:[
|
||
["Übergabe-Vollständigkeit","Sind alle Artefakte vorhanden?"],
|
||
["Abnahme-Status","Liegt die Auftraggeber-Abnahme vor?"],
|
||
["Ressourcen-Outlook","Sind Betrieb und Support prinzipiell vorbereitet?"],
|
||
["Pilot-Entscheidung","Ist ein Pilotbetrieb erforderlich?"]
|
||
],
|
||
raci:[["service_owner","A"],["projektleitung","R"],["betriebsteam","C"],["service_support_team","C"],["spm","I"]],
|
||
quiz:[
|
||
{frage:"Wer entscheidet an Gate 2 (Accountable)?",
|
||
optionen:["SOR-Gremium","Service Owner allein","SPM","Projektleitung"], richtig:1,
|
||
expl:"Gate 2 ist eine SO-Einzelentscheidung; bei Ablehnung erfolgt SOR-Eskalation."},
|
||
{frage:"Was prüft Gate 2 vor allem?",
|
||
optionen:["Die Budgetfreigabe für das Design","Die Übergabefähigkeit nach dem Build","Die Portfolio-Strategie","Die Incident-Quote"], richtig:1,
|
||
expl:"Gate 2 validiert die Übergabefähigkeit nach Abschluss des Builds (Vollständigkeit, Abnahme, Ressourcen)."}
|
||
]},
|
||
{ id:"tr_10", phase:"transition", typ:"aktivitaet",
|
||
name:"Ausrollen der Service-Komponenten",
|
||
beschreibung:"Technische Bereitstellung/Deployment des Services in die produktive Umgebung.",
|
||
umfasst:["Deployment von Anwendungen, Systemen, Komponenten","Konfiguration produktiver Systeme","Migration von Daten","Aktivierung von Monitoring","Zugänge, Rollen, Berechtigungen","Schnittstellen-Integration","Technische Abnahmetests"],
|
||
artefakt:"Ausgerollter Service (produktiv)",
|
||
raci:[["service_owner","A"],["betriebsteam","R"],["spm","C"],["lieferant","C/I"]],
|
||
quiz:[
|
||
{frage:"Wer rollt die Service-Komponenten aus (R)?",
|
||
optionen:["Betriebsteam","Projektteam","Testmanagement","SPM"], richtig:0,
|
||
expl:"Das Betriebsteam ist Responsible für das Deployment; der Service Owner ist Accountable."}
|
||
]},
|
||
{ id:"tr_11", phase:"transition", typ:"aktivitaet",
|
||
name:"Vorbereiten der Service-Aktivierung",
|
||
beschreibung:"Prüfung der Betriebsbereitschaft und Vorbereitung des Go-Live-Antrags für Gate 3.",
|
||
umfasst:["Review der Betriebsdokumentation","Prüfung der Überwachungsregeln","Prüfung der Rollen- und Eskalationswege","Zugriffe & Toolanbindung sicherstellen","Vorbereitung der Go-Live-Kommunikation","Validierung mit Supportteams","Vorbereitung Gate-3-Antrag (SOR-Vorlage)"],
|
||
artefakt:"Go-Live-Readiness (Gate-3-Antrag)",
|
||
raci:[["service_owner","A"],["betriebsteam","R"],["spm","C"]],
|
||
quiz:[
|
||
{frage:"Worauf bereitet tr_11 vor?",
|
||
optionen:["Den Build-Start","Den Go-Live-Antrag für Gate 3","Das ELS-Ende","Die Außerbetriebnahme"], richtig:1,
|
||
expl:"tr_11 prüft die Betriebsbereitschaft und bereitet den Gate-3-Antrag (SOR-Vorlage) vor."}
|
||
]},
|
||
{ id:"tr_12", phase:"transition", typ:"gate", gateNr:3,
|
||
name:"Gate 3: Go-Live-Freigabe",
|
||
beschreibung:"Portfolio-Freigabe und formale Aktivierung des Services. Exit-Gate der Transition — SOR-Entscheidung nach dem Konsent-Prinzip.",
|
||
umfasst:["Prüfung der Portfolio-Konsistenz","Prüfung der Betriebsreife (SO-Bestätigung)","Prüfung der Support-Bereitschaft","Prüfung der SLA/SLO-Vereinbarung","Prüfung der Auflagen-Erfüllung aus Gate 2","Bewertung der Geschäftskritikalität","Formale Aufnahme ins Service-Portfolio"],
|
||
artefakt:"Gate-3-Entscheidung + Portfolio-Aufnahme",
|
||
pfade:[
|
||
["Go-Live","Service wird aktiviert → Operation (op_01)"],
|
||
["Go-Live mit Auflagen","Aktivierung, definierte Punkte nacharbeiten → Operation"],
|
||
["Zurück an Transition","Nachbesserung erforderlich → tr_10 (ggf. tr_09)"],
|
||
["Ablehnung","Endgültige Ablehnung des Service-Vorhabens"]
|
||
],
|
||
raci:[["sor","A"],["service_owner","R"],["spm","C"],["projektleitung","C"],["operations_manager","C"],["support_manager","C"]],
|
||
quiz:[
|
||
{frage:"Wer entscheidet an Gate 3 (Accountable)?",
|
||
optionen:["Service Owner","SOR (Konsent)","Support Manager","Betrieb"], richtig:1,
|
||
expl:"Gate 3 ist eine SOR-Entscheidung nach dem Konsent-Prinzip — das Exit-Gate der Transition."},
|
||
{frage:"Was bewirkt die Go-Live-Freigabe zusätzlich?",
|
||
optionen:["Die Aufnahme ins Service-Portfolio","Den Start des Designs","Die Schließung aller Incidents","Den ELS-Exit"], richtig:0,
|
||
expl:"Mit der Freigabe wird der Service formal ins Portfolio aufgenommen und der Katalog-Eintrag aktiviert."}
|
||
]},
|
||
{ id:"op_01", phase:"operation", typ:"aktivitaet",
|
||
name:"Early Life Support (ELS)",
|
||
beschreibung:"Phase erhöhter Aufmerksamkeit direkt nach Go-Live: produktiv, aber intensiver beobachtet und betreut als im Normalbetrieb.",
|
||
umfasst:["Erhöhte Monitoring-Bereitschaft","Direkte Eskalation zum Projektteam","Schnelles Troubleshooting","Erste Incidents aufarbeiten","ELS-Exit-Entscheidung (SO)"],
|
||
artefakt:"Stabilisierter Service (ELS-Exit)",
|
||
raci:[["service_owner","A"],["support_manager","R"],["operations_manager","R"],["projektteam","C"],["spm","I"]],
|
||
quiz:[
|
||
{frage:"Wer entscheidet über den ELS-Exit?",
|
||
optionen:["SOR","Service Owner","Support Manager","Betrieb"], richtig:1,
|
||
expl:"Der Service Owner entscheidet eigenständig (Informationspflicht an SPM)."}
|
||
]},
|
||
{ id:"op_02", phase:"operation", typ:"aktivitaet",
|
||
name:"Bereitstellen von Leitlinien für den Service-Betrieb",
|
||
beschreibung:"Strukturelle Grundlage für den täglichen Servicebetrieb.",
|
||
umfasst:["Betriebshandbuch bereitstellen/pflegen","Betriebsprozesse & Arbeitsanweisungen","Rollen, Eskalation, Kommunikation klar","Standard Changes & Known Errors"],
|
||
artefakt:"Betriebshandbuch",
|
||
raci:[["service_owner","A"],["operations_manager","R"],["spm","C/I"]],
|
||
quiz:[
|
||
{frage:"Welches Artefakt ist hier zentral?",
|
||
optionen:["Service-Definition","Betriebshandbuch","Testbericht","Gate-Vorlage"], richtig:1,
|
||
expl:"Das Betriebshandbuch ist die strukturelle Grundlage des laufenden Betriebs."}
|
||
]},
|
||
{ id:"op_03", phase:"operation", typ:"aktivitaet",
|
||
name:"Durchführen laufender Betriebsaufgaben",
|
||
beschreibung:"Täglich wiederkehrende Betriebsaktivitäten zur Erbringung des Services.",
|
||
umfasst:["Benutzerverwaltung & Berechtigungen","Backup/Restore","Technische Routineaufgaben","Konfigurationspflege","Pflege von Logs, Diensten, Überwachungsobjekten","Security- & Compliance-Anforderungen","Umsetzung freigegebener Standard-Changes"],
|
||
artefakt:"Erbrachte Betriebsleistung",
|
||
raci:[["operations_manager","A"],["betriebsteam","R"],["service_owner","C"],["lieferant","C/I"],["spm","I"]],
|
||
quiz:[
|
||
{frage:"Wer ist Responsible (R) für die laufenden Betriebsaufgaben?",
|
||
optionen:["Betriebsteam","Service Owner","SPM","Support Manager"], richtig:0,
|
||
expl:"Das Betriebsteam führt aus (R); der Betrieb (AL B&C / AL App) ist Accountable."}
|
||
]},
|
||
{ id:"op_04", phase:"operation", typ:"aktivitaet",
|
||
name:"Ressourcen, Dienstleister und Budget managen",
|
||
beschreibung:"Sicherstellen, dass der Servicebetrieb über die nötigen Mittel verfügt — stabil und wirtschaftlich.",
|
||
umfasst:["Personelle und technische Ressourcen sicherstellen","Koordination mit externen Dienstleistern","Überwachung des Betriebsbudgets","Abstimmung mit Supplier-/Finanz-/Vertragsmanagement","Sicherstellen von Wartung & Lizenzen"],
|
||
artefakt:"Ressourcen- & Budget-Status",
|
||
raci:[["operations_manager","A"],["betriebsteam","R"],["service_owner","C"],["spm","I"]],
|
||
quiz:[
|
||
{frage:"Was ist das Ziel dieser Aktivität?",
|
||
optionen:["Incidents lösen","Ressourcen, Dienstleister und Budget steuern","Den Service designen","Das Review durchführen"], richtig:1,
|
||
expl:"op_04 sichert die nötigen personellen, technischen und finanziellen Mittel für einen stabilen, wirtschaftlichen Betrieb."}
|
||
]},
|
||
{ id:"op_05", phase:"operation", typ:"aktivitaet",
|
||
name:"Überwachen der Services",
|
||
beschreibung:"Strukturierte Überwachung des Services anhand definierter KPIs und Metriken.",
|
||
umfasst:["Verfügbarkeit, Performance, Auslastung überwachen","Schnittstellen und Konfigurationsobjekte überwachen","Trends / drohende Störungen erkennen","Verknüpfung mit Events, Alerts, Dashboards","Monitoring-Regeln im Betrieb erstellen"],
|
||
artefakt:"Monitoring-Daten / Alerts",
|
||
raci:[["operations_manager","A"],["betriebsteam","R"],["service_owner","C"],["service_support_team","I"],["spm","I"]],
|
||
quiz:[
|
||
{frage:"Welche Aktivität beschreibt op_05?",
|
||
optionen:["Strukturierte Überwachung anhand von KPIs/Metriken","Erstellung der Service-Definition","Lösen von Incidents","Gate-Entscheidung"], richtig:0,
|
||
expl:"op_05 überwacht Verfügbarkeit, Performance und Auslastung und verknüpft mit Events/Alerts/Dashboards."}
|
||
]},
|
||
{ id:"op_06", phase:"operation", typ:"aktivitaet",
|
||
name:"Erstellen des Service-Qualitätsbericht",
|
||
beschreibung:"Regelmäßige formale Berichte über die erreichte Servicequalität.",
|
||
umfasst:["SLA-/SLO-Auswertung","Auswertung technischer KPIs","Abgleich gegen Qualitätsziele","Identifikation von Verbesserungspotenzialen","Zuarbeit für Service Review & SPM"],
|
||
artefakt:"Service-Qualitätsbericht",
|
||
raci:[["service_owner","A"],["betriebsteam","R"],["spm","C"]],
|
||
quiz:[
|
||
{frage:"Welches Artefakt entsteht hier?",
|
||
optionen:["Betriebshandbuch","Service-Qualitätsbericht","Problem Record","Testbericht"], richtig:1,
|
||
expl:"op_06 erstellt den Service-Qualitätsbericht (SLA-/SLO-Auswertung, KPIs) als Zuarbeit für das Review."}
|
||
]},
|
||
{ id:"op_07", phase:"operation", typ:"aktivitaet",
|
||
name:"Proaktive Problem Identifikation",
|
||
beschreibung:"Geht über Monitoring hinaus: aktive Suche nach strukturellen Problemen.",
|
||
umfasst:["Trendanalysen aus Monitoringdaten","Analyse von Engpässen, Ressourcenproblemen","Technische Analyse von Systemmustern","Erkennen potenzieller SLA-Verletzungen"],
|
||
artefakt:"Identifizierte strukturelle Probleme",
|
||
raci:[["service_owner","A"],["betriebsteam","R"],["spm","I"]],
|
||
quiz:[
|
||
{frage:"Wodurch unterscheidet sich op_07 vom reinen Monitoring?",
|
||
optionen:["Es ist rein reaktiv","Es ist die aktive Suche nach strukturellen Problemen","Es schließt Tickets","Es entscheidet über Go-Live"], richtig:1,
|
||
expl:"Proaktive Problem-Identifikation nutzt Trend-/Musteranalyse zur Früherkennung struktureller Probleme."}
|
||
]},
|
||
{ id:"sp_01", phase:"support", typ:"aktivitaet",
|
||
name:"Bereitstellen von Leitlinien für den Service-Support",
|
||
beschreibung:"Strukturelle Rahmenbedingungen, damit der Service-Support effizient arbeiten kann.",
|
||
umfasst:["Unterstützungsprozesse (Incident-/Request-Modell)","Vorgaben zu Eskalationen, Reaktionszeiten, Rollen","Tool-Konfigurationen (Ticketklassen, Templates)","Zugriffsmöglichkeiten & Security-Policies","Konsistentes Wissensmanagement"],
|
||
artefakt:"Support-Leitlinien",
|
||
raci:[["service_owner","A"],["support_manager","R"],["spm","C/I"]],
|
||
quiz:[
|
||
{frage:"Wer ist Responsible (R) für die Support-Leitlinien?",
|
||
optionen:["Support Manager","Service Owner","SPM","1st Level Agent"], richtig:0,
|
||
expl:"Der Support Manager führt aus und pflegt die Leitlinien; der Service Owner verantwortet die fachlichen Vorgaben (A)."}
|
||
]},
|
||
{ id:"sp_02", phase:"support", typ:"aktivitaet",
|
||
name:"Wissensdatenbank",
|
||
beschreibung:"Strukturierter Wissensspeicher für Support-Lösungen, Betriebsinfos, Workarounds und Standardanfragen.",
|
||
umfasst:["Lösungen zu Incidents speichern","Workarounds dokumentieren","FAQ, Standard-Requests, Anleitungen","Pflege & Aktualisierung","Zentrales Arbeitsmittel für 1st & 2nd Level"],
|
||
artefakt:"Gepflegte Wissensdatenbank",
|
||
raci:[["service_owner","A"],["service_support_team","R"],["problem_manager","C"]],
|
||
quiz:[
|
||
{frage:"Wer liefert Workarounds und Known Errors für die Wissensdatenbank (C)?",
|
||
optionen:["Problem Manager","Queue Koordinator","SPM","Testmanagement"], richtig:0,
|
||
expl:"Der Problem Manager liefert Workarounds/Known Errors; das Service-Support-Team pflegt die Inhalte (R)."}
|
||
]},
|
||
{ id:"sp_03", phase:"support", typ:"aktivitaet",
|
||
name:"Überwachen / Verteilung von Incidents und Service Requests",
|
||
beschreibung:"Koordination eingehender Störungen/Anfragen: Priorisierung, Routing, korrekte Aufnahme und Verteilung (Ticket-Queue-Koordination).",
|
||
umfasst:["Sichtung neuer Tickets","Automatisches oder manuelles Routing","Prioritäts- und Impact-Bewertung","SLA-Konformität sicherstellen","Eskalation bei Bedarf"],
|
||
artefakt:"Priorisierte/geroutete Tickets",
|
||
raci:[["support_manager","A"],["queue_koordinator","R"]],
|
||
quiz:[
|
||
{frage:"Wer übernimmt Sichtung und Routing der Tickets (R)?",
|
||
optionen:["Queue Koordinator","Support Manager","2nd Level Agent","Service Owner"], richtig:0,
|
||
expl:"Der Queue Koordinator erledigt die initiale Sichtung und das Routing; der Support Manager ist Accountable."}
|
||
]},
|
||
{ id:"sp_04", phase:"support", typ:"aktivitaet",
|
||
name:"Bearbeiten von Requests",
|
||
beschreibung:"Behandlung aller Standard-Serviceanfragen von Nutzern (z.B. Passwort, Berechtigungen, Informationen).",
|
||
umfasst:["Klassifizierung gemäß Request-Katalog","Prüfung von Berechtigungen","Erfüllung standardisierter Anfragen","Dokumentation der Erledigung"],
|
||
artefakt:"Erledigter Service Request",
|
||
raci:[["support_manager","A"],["first_level_agent","R"]],
|
||
quiz:[
|
||
{frage:"Wer bearbeitet einfache Standard-Requests (R)?",
|
||
optionen:["1st Level Agent","2nd Level Agent","Problem Manager","Betriebsteam"], richtig:0,
|
||
expl:"Der 1st Level Agent bearbeitet Standard-Requests gemäß Katalog; der Support Manager ist Accountable."}
|
||
]},
|
||
{ id:"sp_05", phase:"support", typ:"aktivitaet",
|
||
name:"Lösen von Incidents im 1st Level Support",
|
||
beschreibung:"Schnelle Lösung typischer Störungen mit bekanntem Wissen.",
|
||
umfasst:["Erstdiagnose","Nutzung der Wissensdatenbank","Anwenderunterstützung","Workarounds anwenden","Lösung dokumentieren","Entscheidung über Weiterleitung an 2nd Level"],
|
||
artefakt:"Gelöster Incident (1st Level)",
|
||
raci:[["support_manager","A"],["first_level_agent","R"]],
|
||
quiz:[
|
||
{frage:"Wer löst typische Incidents im 1st Level (R)?",
|
||
optionen:["1st Level Agent","2nd Level Agent","Problem Manager","Lieferant"], richtig:0,
|
||
expl:"Der 1st Level Agent löst mit bekanntem Wissen; reicht es nicht, erfolgt Weiterleitung an den 2nd Level."}
|
||
]},
|
||
{ id:"sp_06", phase:"support", typ:"aktivitaet",
|
||
name:"Lösen von Incidents im 2nd Level Support",
|
||
beschreibung:"Bearbeitung von Incidents, die im 1st Level nicht lösbar sind — tiefergehende Diagnostik und technische Lösung.",
|
||
umfasst:["Komplexe technische Diagnosen","Zusammenarbeit mit Betrieb, Fachverfahren, Lieferanten","Ggf. Einbezug von Spezialisten/Herstellern","Rückmeldung an 1st Level / Anwender","Lösung dokumentieren","Ungelöst → Problem Record"],
|
||
artefakt:"Gelöster Incident (2nd Level)",
|
||
raci:[["support_manager","A"],["second_level_agent","R"],["lieferant","C"],["service_owner","I"]],
|
||
quiz:[
|
||
{frage:"Wer übernimmt Incidents, die der 1st Level nicht lösen kann (R)?",
|
||
optionen:["2nd Level Agent","Queue Koordinator","SPM","Service Owner"], richtig:0,
|
||
expl:"Der 2nd Level Agent macht die tiefergehende Diagnose; bleibt es ungelöst, entsteht ein Problem Record (sp_09)."}
|
||
]},
|
||
{ id:"sp_07", phase:"support", typ:"aktivitaet",
|
||
name:"Incident Record (Gelöst) / Request Record (Gelöst)",
|
||
beschreibung:"Abschluss der Ticketbearbeitung inkl. Dokumentation und Qualitätssicherung.",
|
||
umfasst:["Validierung, ob wirklich gelöst","Kommunikation an den Endnutzer","Dokumentationen / FAQs aktualisieren","Klassifikation für Trendanalysen","Übergabe an Schließen von Incidents"],
|
||
artefakt:"Incident/Request Record (gelöst)",
|
||
raci:[["support_manager","A"],["first_level_agent","R"],["second_level_agent","R"]],
|
||
quiz:[
|
||
{frage:"Was passiert in sp_07?",
|
||
optionen:["Eröffnen eines Problem Records","Abschluss der Bearbeitung inkl. Validierung und Doku","Routing der Tickets","Root-Cause-Analyse"], richtig:1,
|
||
expl:"sp_07 validiert die Lösung, kommuniziert an den Nutzer und bereitet den finalen Abschluss (sp_08) vor."}
|
||
]},
|
||
{ id:"sp_08", phase:"support", typ:"aktivitaet",
|
||
name:"Schließen von Incidents & Service Requests",
|
||
beschreibung:"Finaler Ticketabschluss inkl. Dokumentation, Reporting und Einordnung für spätere Verbesserungen.",
|
||
umfasst:["Ticket final schließen","Prüfung vollständiger Dokumentation","Ticketklassifizierung / KPI-Zuordnung","Rückmeldung an Monitoring/Reporting","Wiederkehrende Incidents identifizieren"],
|
||
artefakt:"Geschlossenes Ticket + KPI-Zuordnung",
|
||
raci:[["support_manager","A"],["first_level_agent","R"],["second_level_agent","R"]],
|
||
quiz:[
|
||
{frage:"Wer ist Accountable für das Schließen von Incidents und Requests?",
|
||
optionen:["Support Manager","1st Level Agent","Problem Manager","SOR"], richtig:0,
|
||
expl:"Der Support Manager ist Accountable; 1st und 2nd Level sind Responsible für den finalen Abschluss."}
|
||
]},
|
||
{ id:"sp_09", phase:"support", typ:"aktivitaet",
|
||
name:"Anlegen Problem Record für nicht lösbare Incidents",
|
||
beschreibung:"Ist ein Incident auch im 2nd Level nicht lösbar, wird eine strukturelle Ursache vermutet.",
|
||
umfasst:["Nicht-lösbar-Entscheidung","Dokumentation der Symptome","Eröffnen eines Problem Records","Übergabe an Root-Cause-Analyse"],
|
||
artefakt:"Problem Record",
|
||
raci:[["problem_manager","A"],["second_level_agent","R"],["service_owner","I"]],
|
||
quiz:[
|
||
{frage:"Welches Artefakt entsteht, wenn ein Incident nicht lösbar ist?",
|
||
optionen:["Workaround","Problem Record","Service-Definition","Testprotokoll"], richtig:1,
|
||
expl:"sp_09 eröffnet einen Problem Record; der Problem Manager ist Accountable, der 2nd Level Agent Responsible."}
|
||
]},
|
||
{ id:"sp_10", phase:"support", typ:"aktivitaet",
|
||
name:"Wiederkehrende Incidents analysieren & Problem Record anlegen",
|
||
beschreibung:"Reaktiver Weg zur strukturierten Problemerkennung, wenn dieselbe Störung mehrfach auftritt.",
|
||
umfasst:["Clustering wiederkehrender Incidents","Analyse gemeinsamer Ursachen","Entscheidung: Problem Record notwendig","Übergabe an Problem Management"],
|
||
artefakt:"Problem Record (aus wiederkehrenden Incidents)",
|
||
raci:[["problem_manager","A"],["support_manager","R"],["second_level_agent","C"],["service_owner","I"]],
|
||
quiz:[
|
||
{frage:"Wann wird in sp_10 ein Problem Record angelegt?",
|
||
optionen:["Bei jedem Incident","Wenn dieselbe Störung mehrfach auftritt","Nur an Gates","Bei Go-Live"], richtig:1,
|
||
expl:"sp_10 clustert wiederkehrende Incidents und legt bei gemeinsamer Ursache einen Problem Record an."}
|
||
]},
|
||
{ id:"sp_11", phase:"support", typ:"aktivitaet",
|
||
name:"Operative Root-Cause-Analyse durchführen & Workaround bereitstellen",
|
||
beschreibung:"Start der Problembehandlung zur Ermittlung der Ursache und Schaffung eines Workarounds.",
|
||
umfasst:["Root-Cause-Analyse","Erstellen eines Workarounds","Eintrag in die Wissensdatenbank","Entscheidung über Change-Bedarf"],
|
||
artefakt:"Workaround + aktualisierter Problem Record",
|
||
raci:[["service_owner","A"],["problem_manager","R"],["second_level_agent","C"],["lieferant","C/I"]],
|
||
quiz:[
|
||
{frage:"Was wird in der operativen Root-Cause-Analyse zusätzlich bereitgestellt?",
|
||
optionen:["Ein Workaround","Ein Betriebshandbuch","Eine Gate-Vorlage","Ein Review-Bericht"], richtig:0,
|
||
expl:"sp_11 ermittelt die Ursache, erstellt einen Workaround und entscheidet über Change-Bedarf (aktualisiert den Problem Record)."}
|
||
]},
|
||
/* Review-Phase = ARBEITSSTAND (Vorschlag Frank, Change-Enablement) — noch NICHT
|
||
im Blueprint-YAML; vor Konzept-Uebernahme mit Michael abstimmen.
|
||
RACI + Quiz hier abgeleitet (Franks Entwurf nennt nur die Aktivitaeten). */
|
||
{ id:"rv_01", phase:"review", typ:"aktivitaet",
|
||
name:"Durchführen von Service-Reviews",
|
||
beschreibung:"Den Service systematisch auswerten und die Ergebnisse im Service-Review-Dokument festhalten.",
|
||
umfasst:["KPIs & Monitoring auswerten","Problems & Incidents auswerten","Kundenfeedback sammeln/einholen","zugrunde liegende Infrastruktur bewerten","Service-Review-Dokument ausfüllen"],
|
||
artefakt:"Service-Review-Dokument",
|
||
raci:[["service_owner","A"],["betriebsteam","R"],["service_support_team","C"],["problem_manager","C"]],
|
||
quiz:[
|
||
{frage:"Welches Dokument entsteht beim Service-Review?",
|
||
optionen:["RFC","Service-Review-Dokument","Change-Steckbrief","Incident Record"], richtig:1,
|
||
expl:"KPIs, Incidents, Feedback und Infrastrukturbewertung werden im Service-Review-Dokument zusammengeführt."}
|
||
]},
|
||
{ id:"rv_02", phase:"review", typ:"aktivitaet",
|
||
name:"Bewertung der Review-Ergebnisse",
|
||
beschreibung:"Die Review-Ergebnisse bewerten und bei Änderungsbedarf einen RFC erstellen; relevante Berichte gehen an die SOR.",
|
||
umfasst:["RFC für Normal- bzw. Major-Change erstellen","Berichte bei Bedarf an die SOR weiterleiten","Ergebnisse in der SOR ganzheitlich bewerten"],
|
||
artefakt:"RFC (Request for Change)",
|
||
raci:[["sor","A"],["service_owner","R"],["spm","C"]],
|
||
quiz:[
|
||
{frage:"Was wird erstellt, wenn die Bewertung Änderungsbedarf zeigt?",
|
||
optionen:["Ein RFC (Request for Change)","Ein Incident Record","Ein Test-Report","Eine Service-Definition"], richtig:0,
|
||
expl:"Bei Normal- oder Major-Change entsteht ein RFC; Berichte gehen an die SOR."},
|
||
{frage:"Wer bewertet die Review-Ergebnisse ganzheitlich?",
|
||
optionen:["Der 1st Level","Die SOR","Das Testmanagement","Der Lieferant"], richtig:1,
|
||
expl:"Die SOR bewertet die Ergebnisse als Gremium ganzheitlich."}
|
||
]},
|
||
{ id:"rv_03", phase:"review", typ:"aktivitaet",
|
||
name:"Definieren von Service-Änderungen",
|
||
beschreibung:"Auf Basis der Bewertung konkrete Änderungsvorschläge formulieren, konsolidieren und die ausgewählte Änderung beschreiben.",
|
||
umfasst:["passende Änderungsvorschläge formulieren","Vorschläge bewerten & konsolidieren","ausgewählte Änderung beschreiben"],
|
||
artefakt:"Beschriebene Service-Änderung",
|
||
raci:[["service_owner","A"],["sor","C"],["architektur","C"]],
|
||
quiz:[
|
||
{frage:"Was ist das Ziel dieser Aktivität?",
|
||
optionen:["Incidents schließen","Änderungsvorschläge formulieren, konsolidieren und beschreiben","Den Service abschalten","Das Budget planen"], richtig:1,
|
||
expl:"Aus der Bewertung werden konkrete, beschriebene Service-Änderungen abgeleitet."}
|
||
]},
|
||
{ id:"rv_04", phase:"review", typ:"aktivitaet",
|
||
name:"Starten von Service-Änderungen",
|
||
beschreibung:"Die Änderung anstoßen: bei Normal Change die Umsetzung planen; bei Major Change das Routing klären und den Change-Steckbrief ausfüllen.",
|
||
umfasst:["Normal Change: Umsetzung planen","Major Change: Routing klären (RUN / DPM / MB)","Major Change: Change-Steckbrief ausfüllen & weiterleiten"],
|
||
artefakt:"Change-Steckbrief (bei Major Change)",
|
||
raci:[["service_owner","A"],["sor","C"],["spm","C"],["dpm","I"]],
|
||
pfade:[["RUN","Durchführung im laufenden Betrieb (Service Owner)"],["DPM","über den Demand- & Projektprozess"],["MB","direkt in den Projektprozess oder RUN"]],
|
||
quiz:[
|
||
{frage:"Was muss beim Major Change vor der Umsetzung geklärt werden?",
|
||
optionen:["Das Routing: RUN, DPM oder MB","Die Ticket-Queue","Der Eskalationsweg","Die Lizenzkosten"], richtig:0,
|
||
expl:"Beim Major Change wird das Routing (RUN/DPM/MB) geklärt und ein Change-Steckbrief erstellt; beim Normal Change wird direkt die Umsetzung geplant."}
|
||
]},
|
||
{ id:"rv_05", phase:"review", typ:"aktivitaet",
|
||
name:"Implementieren von Service-Änderungen",
|
||
beschreibung:"Die Änderung gemäß gewähltem Weg umsetzen, dokumentieren und abschließen.",
|
||
umfasst:["Normal & Major (Weg RUN): SO führt durch, dokumentiert, schließt ab","Major (Weg DPM): Demand- & Projektprozess","Major (Weg MB): Projektprozess oder RUN"],
|
||
artefakt:"Umgesetzte & dokumentierte Service-Änderung",
|
||
raci:[["service_owner","A"],["projektteam","R"],["dpm","C"]],
|
||
quiz:[
|
||
{frage:"Wer führt eine Änderung auf dem Weg „RUN“ durch?",
|
||
optionen:["Der Service Owner","Der Demand Portfolio Manager","Ein externes Projektteam","Die SOR"], richtig:0,
|
||
expl:"Im Weg RUN führt der Service Owner die Änderung durch, dokumentiert und schließt sie ab."}
|
||
]}
|
||
];
|
||
|
||
/* ====================== STATE ====================== */
|
||
const LS_KEY = "slc-companion-proto";
|
||
function defaultState(){
|
||
return { view:"card", service:0, change:0, startIndex:null, startRevealed:false,
|
||
tourIndex:0, index:0, stage:"discuss", quizIndex:0,
|
||
picks:{}, done:{}, unclear:{} };
|
||
}
|
||
let S = load();
|
||
function load(){ try{ return Object.assign(defaultState(), JSON.parse(localStorage.getItem(LS_KEY)||"{}")); }catch(e){ return defaultState(); } }
|
||
function save(){ localStorage.setItem(LS_KEY, JSON.stringify(S)); }
|
||
|
||
/* ====================== HELPERS ====================== */
|
||
const $ = s => document.querySelector(s);
|
||
const cur = () => STATIONEN[S.index];
|
||
function pkey(sid, qi){ return sid+"#"+qi; }
|
||
function roleLabel(id){ return ROLLEN[id] || id; }
|
||
function acard(si, ci){ return USE_CASES[si].changes[ci]; } // {titel, text}
|
||
function cardHtml(si, ci){ const c = acard(si, ci);
|
||
return `<div style="font-weight:800;font-size:18px;color:var(--ink);margin-bottom:6px">${c.titel}</div>`
|
||
+ `<div>${c.text}</div>`
|
||
+ `<div style="color:var(--muted);font-style:italic;margin-top:8px">Was passiert an welchen Stellen?</div>`; }
|
||
|
||
/* ====================== RENDER: SIDEBAR ====================== */
|
||
function renderList(){
|
||
const groups = {};
|
||
STATIONEN.forEach((st,i)=>{ (groups[st.phase]=groups[st.phase]||[]).push({st,i}); });
|
||
let html = "";
|
||
for(const ph in PHASEN){
|
||
if(!groups[ph]) continue;
|
||
html += `<h3>${PHASEN[ph].label}</h3>`;
|
||
groups[ph].forEach(({st,i})=>{
|
||
const cls = [ "stationItem", i===S.index?"active":"", S.done[st.id]?"done":"" ].join(" ");
|
||
html += `<div class="${cls}" data-i="${i}">
|
||
<span class="dot" style="background:${PHASEN[ph].color}"></span>
|
||
<span class="id">${st.id}</span>
|
||
<span class="nm">${st.typ==="gate"?"⛩ ":""}${st.name.length>34?st.name.slice(0,32)+"…":st.name}</span>
|
||
${S.unclear[st.id]?'<span class="flag">●</span>':''}
|
||
</div>`;
|
||
});
|
||
}
|
||
$("#stationList").innerHTML = html;
|
||
$("#stationList").querySelectorAll(".stationItem").forEach(el=>{
|
||
el.onclick = ()=>{ S.index = +el.dataset.i; S.stage="discuss"; S.quizIndex=0; save(); draw(); };
|
||
});
|
||
const pct = Math.round(Object.keys(S.done).length / STATIONEN.length * 100);
|
||
$("#progressBar").style.width = pct+"%";
|
||
}
|
||
|
||
/* ====================== VIEW DISPATCH ====================== */
|
||
function draw(){
|
||
document.body.classList.toggle("runMode", S.view==="run");
|
||
renderCardBadge();
|
||
if(S.view==="card") return renderCardScreen();
|
||
if(S.view==="tour") return renderTour();
|
||
if(S.view==="start") return renderStartScreen();
|
||
renderRun();
|
||
}
|
||
|
||
function renderCardBadge(){
|
||
const el = $("#cardBadge");
|
||
if(S.view==="card" || S.view==="tour"){ el.style.display="none"; el.innerHTML=""; return; }
|
||
el.style.display="flex";
|
||
el.innerHTML = `<span class="cb-svc">${USE_CASES[S.service].service}</span><span class="ctChip">${CHANGE_TYPES[S.change]}</span>`;
|
||
}
|
||
|
||
/* ---------- Screen 1: Action Card ziehen ---------- */
|
||
function renderCardScreen(){
|
||
$("#panel").innerHTML = `
|
||
<div class="setupHead">Schritt 1 · Action Card</div>
|
||
<h2 class="setupTitle">Welches Szenario zieht ihr?</h2>
|
||
<p class="muted">Wählt Service und Change-Typ der gezogenen Action Card – oder zieht zufällig. Diese Karte liegt an der aktuellen Station und wandert mit durch alle Stationen.</p>
|
||
<div class="cardForm">
|
||
<label>Service<select id="serviceSel"></select></label>
|
||
<label>Change-Typ<select id="changeSel"></select></label>
|
||
</div>
|
||
<div class="ctText" id="cardTrigger">${cardHtml(S.service,S.change)}</div>
|
||
<div class="actions">
|
||
<button class="ghost" id="randomCard">🎲 Zufällig ziehen</button>
|
||
<button class="ghost" id="tourBtn">📘 Geführtes Beispiel</button>
|
||
<div class="spacer"></div>
|
||
<button class="primary" id="toStart">Weiter → Startpunkt wählen</button>
|
||
</div>
|
||
<p class="note" style="text-align:left">Neu hier? Das „Geführte Beispiel" spielt einen kompletten Fall (Bürgerportal) Station für Station durch – zum Verstehen, ohne Quiz.</p>`;
|
||
const svc=$("#serviceSel"), ch=$("#changeSel");
|
||
svc.innerHTML = USE_CASES.map((u,i)=>`<option value="${i}">${u.service}</option>`).join("");
|
||
ch.innerHTML = CHANGE_TYPES.map((c,i)=>`<option value="${i}">${c}</option>`).join("");
|
||
svc.value=S.service; ch.value=S.change;
|
||
const refresh=()=>{ $("#cardTrigger").innerHTML=cardHtml(S.service,S.change); };
|
||
svc.onchange=()=>{ S.service=+svc.value; save(); refresh(); };
|
||
ch.onchange=()=>{ S.change=+ch.value; save(); refresh(); };
|
||
$("#randomCard").onclick=()=>{ S.service=Math.floor(Math.random()*USE_CASES.length); S.change=Math.floor(Math.random()*CHANGE_TYPES.length); save(); draw(); };
|
||
$("#tourBtn").onclick=()=>{ S.view="tour"; S.tourIndex=0; save(); draw(); };
|
||
$("#toStart").onclick=()=>{ S.view="start"; S.startRevealed=false; save(); draw(); };
|
||
}
|
||
|
||
/* ---------- Geführte Tour (ein Beispiel durch alle Stationen) ---------- */
|
||
function renderTour(){
|
||
const st = STATIONEN[S.tourIndex];
|
||
const ph = PHASEN[st.phase];
|
||
const chip = st.typ==="gate"
|
||
? `<span class="phaseChip gateChip">⛩ Gate ${st.gateNr}</span>`
|
||
: `<span class="phaseChip" style="background:${ph.color}">${ph.label}</span>`;
|
||
const raci = st.raci.map(([r,c])=>`<tr><td>${roleLabel(r)}</td><td><span class="raciBadge raci-${c}">${c}</span></td></tr>`).join("");
|
||
let extra="";
|
||
if(st.pfade){
|
||
extra += `<h4>Entscheidungspfade</h4><div class="pfade">` +
|
||
st.pfade.map(([n,d])=>`<div class="pfad"><b>${n}</b><span style="color:var(--muted)">${d}</span></div>`).join("") + `</div>`;
|
||
}
|
||
const narr = TOUR.text[st.id] || "—";
|
||
const last = S.tourIndex === STATIONEN.length-1;
|
||
$("#panel").innerHTML = `
|
||
<div class="tourBanner">📘 Geführtes Beispiel · <b>${USE_CASES[TOUR.service].service}</b> — ${CHANGE_TYPES[TOUR.change]}<br>
|
||
<span style="color:var(--muted)"><b>${acard(TOUR.service,TOUR.change).titel}</b> — ${acard(TOUR.service,TOUR.change).text}</span></div>
|
||
<div class="tourProg">Station ${S.tourIndex+1} von ${STATIONEN.length}</div>
|
||
${chip}
|
||
<div class="stationName">${st.name}</div>
|
||
<div class="stationId">${st.id}</div>
|
||
<div class="tourNarr"><h4>In diesem Beispiel</h4>${narr}</div>
|
||
<div class="reveal">
|
||
<h4>Fachlich (aus dem Blueprint)</h4>
|
||
<p>${st.beschreibung}</p>
|
||
<h4>Umfasst</h4><ul>${st.umfasst.map(u=>`<li>${u}</li>`).join("")}</ul>
|
||
<h4>Rollen / RACI</h4>
|
||
<table class="raci"><thead><tr><th>Rolle</th><th>RACI</th></tr></thead><tbody>${raci}</tbody></table>
|
||
<h4>Artefakt</h4><p>${st.artefakt}</p>
|
||
${extra}
|
||
</div>
|
||
<div class="actions">
|
||
<button class="ghost" id="tourExit">Tour beenden</button>
|
||
<button class="ghost" id="tourBack" ${S.tourIndex===0?'disabled':''}>← Zurück</button>
|
||
<div class="spacer"></div>
|
||
<button class="primary" id="tourNext">${last?'Fertig — zur Startseite':'Weiter →'}</button>
|
||
</div>`;
|
||
$("#tourExit").onclick=()=>{ S.view="card"; save(); draw(); };
|
||
$("#tourBack").onclick=()=>{ if(S.tourIndex>0){ S.tourIndex--; save(); renderTour(); } };
|
||
$("#tourNext").onclick=()=>{ if(last){ S.view="card"; save(); draw(); } else { S.tourIndex++; save(); renderTour(); } };
|
||
}
|
||
|
||
/* ---------- Screen 2: Startpunkt bestimmen (Tipp → Auflösen) ---------- */
|
||
function renderStartScreen(){
|
||
const rec = START_EMPFEHLUNG[S.change];
|
||
const recIndex = STATIONEN.findIndex(s=>s.id===rec.id);
|
||
const revealed = S.startRevealed;
|
||
const groups={};
|
||
STATIONEN.forEach((st,i)=>{ (groups[st.phase]=groups[st.phase]||[]).push({st,i}); });
|
||
let list="";
|
||
for(const ph in PHASEN){
|
||
if(!groups[ph]) continue;
|
||
list += `<div class="pickerPhase">${PHASEN[ph].label}</div>`;
|
||
groups[ph].forEach(({st,i})=>{
|
||
let cls="pickerItem";
|
||
if(revealed){
|
||
if(i===recIndex) cls+=" correct";
|
||
else if(i===S.startIndex) cls+=" wrongPick";
|
||
} else if(i===S.startIndex) cls+=" sel";
|
||
list += `<div class="${cls}" data-i="${i}">
|
||
<span class="dot" style="background:${PHASEN[ph].color}"></span>
|
||
<span class="id">${st.id}</span>
|
||
<span class="nm">${st.name}</span>
|
||
${st.typ==="gate"?`<span class="gate">Gate ${st.gateNr}</span>`:''}
|
||
</div>`;
|
||
});
|
||
}
|
||
let head, actions;
|
||
if(!revealed){
|
||
head = `<p class="muted">Welches Tile ist der sinnvolle Einstieg für diese Action Card? Diskutiert in der Gruppe, wählt ein Tile und löst dann auf.</p>`;
|
||
actions = `<button class="ghost" id="backToCard">← Action Card</button>
|
||
<div class="spacer"></div>
|
||
<button class="primary" id="revealStart" ${S.startIndex==null?'disabled':''}>Auflösen</button>`;
|
||
} else {
|
||
const tip = S.startIndex==null ? `` :
|
||
(S.startIndex===recIndex
|
||
? `<p style="color:var(--ok);font-weight:600;margin:0 0 8px">Euer Tipp ${STATIONEN[S.startIndex].id} passt zum empfohlenen Einstieg. ✓</p>`
|
||
: `<p style="color:var(--bad);font-weight:600;margin:0 0 8px">Euer Tipp war ${STATIONEN[S.startIndex].id} — nicht der empfohlene Einstieg.</p>`);
|
||
head = `${tip}<div class="recBox"><h4>Empfohlener Einstieg · ${CHANGE_TYPES[S.change]}</h4>
|
||
<p style="margin:0 0 6px"><b>${rec.id} — ${STATIONEN[recIndex].name}</b></p>
|
||
<p style="margin:0;color:var(--muted)">${rec.grund}</p></div>`;
|
||
const ownDiff = (S.startIndex!=null && S.startIndex!==recIndex);
|
||
actions = `<button class="ghost" id="backToCard">← Action Card</button>
|
||
<div class="spacer"></div>
|
||
${ownDiff?`<button class="ghost" id="startOwn">Auf eigener Wahl starten</button>`:``}
|
||
<button class="primary" id="startRec">Auf ${rec.id} starten →</button>`;
|
||
}
|
||
$("#panel").innerHTML = `
|
||
<div class="setupHead">Schritt 2 · Startpunkt</div>
|
||
<h2 class="setupTitle">Wo startet ihr sinnvollerweise?</h2>
|
||
${head}
|
||
<div class="pickerList">${list}</div>
|
||
<div class="actions">${actions}</div>`;
|
||
if(!revealed){
|
||
$("#panel").querySelectorAll(".pickerItem").forEach(el=>{
|
||
el.onclick=()=>{ S.startIndex=+el.dataset.i; save(); renderStartScreen(); };
|
||
});
|
||
}
|
||
$("#backToCard").onclick=()=>{ S.view="card"; S.startRevealed=false; save(); draw(); };
|
||
if($("#revealStart")) $("#revealStart").onclick=()=>{ if(S.startIndex==null) return; S.startRevealed=true; save(); renderStartScreen(); };
|
||
if($("#startRec")) $("#startRec").onclick=()=>{ S.index=recIndex; S.view="run"; S.stage="discuss"; S.quizIndex=0; save(); draw(); };
|
||
if($("#startOwn")) $("#startOwn").onclick=()=>{ S.index=S.startIndex; S.view="run"; S.stage="discuss"; S.quizIndex=0; save(); draw(); };
|
||
}
|
||
|
||
/* ====================== RENDER: RUN (Station) ====================== */
|
||
function renderRun(){
|
||
renderList();
|
||
const st = cur();
|
||
const ph = PHASEN[st.phase];
|
||
const chip = st.typ==="gate"
|
||
? `<span class="phaseChip gateChip">⛩ Gate ${st.gateNr}</span>`
|
||
: `<span class="phaseChip" style="background:${ph.color}">${ph.label}</span>`;
|
||
|
||
let body = `
|
||
${chip}
|
||
<div class="stationName">${st.name}</div>
|
||
<div class="stationId">${st.id}</div>
|
||
<div class="token">Action Card: <b>${USE_CASES[S.service].service}</b>
|
||
<span class="ctChip">${CHANGE_TYPES[S.change]}</span>
|
||
<div class="ctText"><b>${acard(S.service,S.change).titel}</b> — ${acard(S.service,S.change).text}</div>
|
||
</div>
|
||
`;
|
||
|
||
if(S.stage==="discuss") body += renderDiscuss(st);
|
||
else if(S.stage==="quiz") body += renderQuiz(st);
|
||
else body += renderReveal(st);
|
||
|
||
$("#panel").innerHTML = body;
|
||
wire(st);
|
||
}
|
||
|
||
function renderDiscuss(st){
|
||
return `
|
||
<div class="step">
|
||
<div class="stepHead"><span class="n">1</span> Diskussion · App noch zu</div>
|
||
<div class="discuss">
|
||
<strong>Besprecht in der Gruppe — anhand der Kurzbezeichnung:</strong>
|
||
<ul>
|
||
<li>Was passiert hier konkret für euer Szenario?</li>
|
||
<li>Wer macht es? Steckt die Rollen-Figuren ins <b>Aktiv-Feld (R/A/C/I)</b>.</li>
|
||
<li>Welches Artefakt entsteht?</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="actions">
|
||
<div class="spacer"></div>
|
||
<button class="primary" id="toQuiz">Quiz starten →</button>
|
||
</div>`;
|
||
}
|
||
|
||
function renderQuiz(st){
|
||
const qi = S.quizIndex, q = st.quiz[qi];
|
||
const picked = S.picks[pkey(st.id,qi)];
|
||
const answered = picked !== undefined;
|
||
const opts = q.optionen.map((o,i)=>{
|
||
let cls = "opt";
|
||
if(answered){
|
||
if(i===q.richtig) cls+=" correct";
|
||
else if(i===picked) cls+=" wrong";
|
||
} else if(i===picked) cls+=" sel";
|
||
const mark = answered ? (i===q.richtig?'<span class="mark" style="color:var(--ok)">✓</span>': (i===picked?'<span class="mark" style="color:var(--bad)">✗</span>':'')) : '';
|
||
return `<button class="${cls}" data-opt="${i}" ${answered?'disabled':''}>${o}${mark}</button>`;
|
||
}).join("");
|
||
return `
|
||
<div class="step">
|
||
<div class="stepHead"><span class="n">2</span> Quiz · Frage ${qi+1} / ${st.quiz.length}</div>
|
||
<div class="q">
|
||
<div class="frage">${q.frage}</div>
|
||
<div class="opts">${opts}</div>
|
||
${answered ? `<div class="qExpl">${q.expl}</div>` : ``}
|
||
</div>
|
||
</div>
|
||
<div class="actions">
|
||
<button class="ghost" id="backDiscuss">← Diskussion</button>
|
||
<div class="spacer"></div>
|
||
${answered
|
||
? (qi < st.quiz.length-1
|
||
? `<button class="primary" id="nextQ">Nächste Frage →</button>`
|
||
: `<button class="primary" id="toReveal">Auflösung anzeigen →</button>`)
|
||
: `<button class="primary" disabled>Antwort wählen…</button>`}
|
||
</div>`;
|
||
}
|
||
|
||
function renderReveal(st){
|
||
const raci = st.raci.map(([r,c])=>`<tr><td>${roleLabel(r)}</td><td><span class="raciBadge raci-${c}">${c}</span></td></tr>`).join("");
|
||
let extra = "";
|
||
if(st.pfade){
|
||
extra += `<h4>Entscheidungspfade</h4><div class="pfade">` +
|
||
st.pfade.map(([n,d])=>`<div class="pfad"><b>${n}</b><span style="color:var(--muted)">${d}</span></div>`).join("") + `</div>`;
|
||
}
|
||
if(st.pruef){
|
||
extra += `<h4>Prüf-Dimensionen</h4><ul>` + st.pruef.map(([n,d])=>`<li><b>${n}</b> — ${d}</li>`).join("") + `</ul>`;
|
||
}
|
||
return `
|
||
<div class="step reveal">
|
||
<div class="stepHead"><span class="n">3</span> Auflösung & Reflexion</div>
|
||
<p>${st.beschreibung}</p>
|
||
<h4>Umfasst</h4>
|
||
<ul>${st.umfasst.map(u=>`<li>${u}</li>`).join("")}</ul>
|
||
<h4>Rollen / RACI</h4>
|
||
<table class="raci"><thead><tr><th>Rolle</th><th>RACI</th></tr></thead><tbody>${raci}</tbody></table>
|
||
<h4>Artefakt</h4><p>${st.artefakt}</p>
|
||
${extra}
|
||
</div>
|
||
<div class="actions">
|
||
<label class="unclear"><input type="checkbox" id="unclear" ${S.unclear[st.id]?'checked':''}/> War unklar</label>
|
||
<div class="spacer"></div>
|
||
${S.index < STATIONEN.length-1
|
||
? `<button class="primary" id="nextStation">Nächste Station →</button>`
|
||
: `<button class="primary" id="finish">Durchlauf abschließen</button>`}
|
||
</div>`;
|
||
}
|
||
|
||
/* ====================== WIRING ====================== */
|
||
function wire(st){
|
||
const b = id => $("#"+id);
|
||
if(b("toQuiz")) b("toQuiz").onclick = ()=>{ S.stage="quiz"; S.quizIndex=0; save(); draw(); };
|
||
if(b("backDiscuss")) b("backDiscuss").onclick = ()=>{ S.stage="discuss"; save(); draw(); };
|
||
$("#panel").querySelectorAll(".opt[data-opt]").forEach(el=>{
|
||
el.onclick = ()=>{ S.picks[pkey(st.id,S.quizIndex)] = +el.dataset.opt; save(); draw(); };
|
||
});
|
||
if(b("nextQ")) b("nextQ").onclick = ()=>{ S.quizIndex++; save(); draw(); };
|
||
if(b("toReveal")) b("toReveal").onclick = ()=>{ S.stage="reveal"; save(); draw(); };
|
||
if(b("unclear")) b("unclear").onchange = e=>{ if(e.target.checked) S.unclear[st.id]=true; else delete S.unclear[st.id]; save(); renderList(); };
|
||
if(b("nextStation")) b("nextStation").onclick = ()=>{ S.done[st.id]=true; S.index++; S.stage="discuss"; S.quizIndex=0; save(); draw(); };
|
||
if(b("finish")) b("finish").onclick = ()=>{ S.done[st.id]=true; save(); openDebrief(); };
|
||
}
|
||
|
||
/* ====================== DEBRIEF ====================== */
|
||
function quizScore(){
|
||
let correct=0, total=0;
|
||
STATIONEN.forEach(st=> st.quiz.forEach((q,qi)=>{
|
||
const p = S.picks[pkey(st.id,qi)];
|
||
if(p!==undefined){ total++; if(p===q.richtig) correct++; }
|
||
}));
|
||
return {correct,total};
|
||
}
|
||
let DEBRIEF = { md:"", json:null };
|
||
function download(name, text, mime){
|
||
const blob = new Blob([text], {type:mime});
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement("a");
|
||
a.href = url; a.download = name; document.body.appendChild(a); a.click();
|
||
a.remove(); setTimeout(()=>URL.revokeObjectURL(url), 1000);
|
||
}
|
||
function openDebrief(){
|
||
const {correct,total} = quizScore();
|
||
const doneN = Object.keys(S.done).length;
|
||
const unclearList = STATIONEN.filter(st=>S.unclear[st.id]);
|
||
$("#debriefStat").innerHTML = `
|
||
<div><b>${doneN}/${STATIONEN.length}</b><span>Stationen</span></div>
|
||
<div><b>${total?Math.round(correct/total*100):0}%</b><span>Quiz richtig (${correct}/${total})</span></div>
|
||
<div><b>${unclearList.length}</b><span>als unklar markiert</span></div>`;
|
||
let md = `# SLC-Workshop — Debrief\n\n`;
|
||
md += `**Service:** ${USE_CASES[S.service].service}\n`;
|
||
md += `**Change-Typ:** ${CHANGE_TYPES[S.change]}\n`;
|
||
md += `**Action Card:** „${acard(S.service,S.change).titel}“ — ${acard(S.service,S.change).text}\n`;
|
||
md += `**Stationen bearbeitet:** ${doneN}/${STATIONEN.length}\n`;
|
||
md += `**Quiz:** ${correct}/${total} richtig\n\n`;
|
||
md += `## Als unklar markiert\n`;
|
||
md += unclearList.length ? unclearList.map(st=>`- ${st.id} — ${st.name}`).join("\n") : "_keine_";
|
||
md += `\n\n## Quiz-Detail\n`;
|
||
STATIONEN.forEach(st=> st.quiz.forEach((q,qi)=>{
|
||
const p = S.picks[pkey(st.id,qi)];
|
||
if(p===undefined) return;
|
||
md += `- [${p===q.richtig?"✓":"✗"}] ${st.id}: ${q.frage} → „${q.optionen[p]}"\n`;
|
||
}));
|
||
const stamp = new Date().toISOString().slice(0,16).replace("T"," ");
|
||
const json = {
|
||
erzeugt: stamp,
|
||
service: USE_CASES[S.service].service,
|
||
changeTyp: CHANGE_TYPES[S.change],
|
||
actionCard: acard(S.service,S.change).titel,
|
||
ausloeser: acard(S.service,S.change).text,
|
||
stationenBearbeitet: doneN,
|
||
stationenGesamt: STATIONEN.length,
|
||
quiz: { richtig: correct, gesamt: total },
|
||
unklar: unclearList.map(st=>({id:st.id, name:st.name})),
|
||
quizDetail: []
|
||
};
|
||
STATIONEN.forEach(st=> st.quiz.forEach((q,qi)=>{
|
||
const p = S.picks[pkey(st.id,qi)];
|
||
if(p===undefined) return;
|
||
json.quizDetail.push({station:st.id, frage:q.frage, gewaehlt:q.optionen[p], richtig:p===q.richtig});
|
||
}));
|
||
DEBRIEF = { md, json };
|
||
$("#debriefText").textContent = md;
|
||
$("#debriefDlg").showModal();
|
||
}
|
||
|
||
/* ====================== INIT ====================== */
|
||
(function init(){
|
||
$("#debriefBtn").onclick = openDebrief;
|
||
$("#closeDebrief").onclick = ()=> $("#debriefDlg").close();
|
||
$("#copyBtn").onclick = ()=> navigator.clipboard?.writeText($("#debriefText").textContent);
|
||
$("#dlMd").onclick = ()=> download("slc-debrief.md", DEBRIEF.md, "text/markdown");
|
||
$("#dlJson").onclick = ()=> download("slc-debrief.json", JSON.stringify(DEBRIEF.json, null, 2), "application/json");
|
||
$("#resetBtn").onclick = ()=>{ if(confirm("Neue Action Card ziehen und Durchlauf zurücksetzen?")){ S=defaultState(); save(); draw(); } };
|
||
draw();
|
||
})();
|
||
|
||
// PWA: Service Worker fuer Offline-/Kiosk-Betrieb (nur ueber http/https aktiv)
|
||
if ("serviceWorker" in navigator) {
|
||
window.addEventListener("load", ()=> navigator.serviceWorker.register("sw.js").catch(()=>{}));
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|