1637 lines
111 KiB
HTML
1637 lines
111 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 und Auflösung. 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: 1fr; gap: 0; min-height: calc(100% - 55px); }
|
||
|
||
/* Stationsliste als aufklappbares Overlay (Header-Button ☰ Stationen) */
|
||
aside {
|
||
position: fixed; top:0; left:0; bottom:0; width: 320px; max-width: 86vw;
|
||
background: var(--panel); border-right:1px solid var(--line); padding: 14px;
|
||
overflow:auto; z-index: 30;
|
||
transform: translateX(-100%); transition: transform .22s ease;
|
||
box-shadow: 0 0 40px rgba(20,30,50,.18);
|
||
}
|
||
body.navOpen aside { transform: translateX(0); }
|
||
.navBackdrop { position:fixed; inset:0; background:rgba(15,22,35,.42); z-index:29; opacity:0; pointer-events:none; transition:opacity .2s; }
|
||
body.navOpen .navBackdrop { opacity:1; pointer-events:auto; }
|
||
body.akteOpen .navBackdrop { opacity:1; pointer-events:auto; }
|
||
/* Service-Akte als Overlay von rechts (Header-Button 📁 Akte) */
|
||
#akteList {
|
||
position: fixed; top:0; right:0; bottom:0; width: 340px; max-width: 88vw;
|
||
background: var(--panel); border-left:1px solid var(--line); padding: 14px;
|
||
overflow:auto; z-index: 30;
|
||
transform: translateX(100%); transition: transform .22s ease;
|
||
box-shadow: 0 0 40px rgba(20,30,50,.18);
|
||
}
|
||
body.akteOpen #akteList { transform: translateX(0); }
|
||
body:not(.runMode) #akteList { display:none; }
|
||
body:not(.runMode) #akteBtn { display:none; }
|
||
#akteList h3 { font-size:11px; text-transform:uppercase; letter-spacing:.8px; color:var(--muted); margin:14px 0 4px; }
|
||
.akteCount { font-size:13px; color:var(--muted); margin:2px 0 6px; font-variant-numeric:tabular-nums; }
|
||
.akteItem { display:flex; align-items:center; gap:10px; padding:7px 4px; border-radius:8px; font-size:13px; opacity:.5; }
|
||
.akteItem.have { opacity:1; }
|
||
.akteItem .aId { color:#fff; font-size:11px; font-weight:700; border-radius:6px; padding:2px 7px; min-width:30px; text-align:center; flex:none; }
|
||
.akteItem .aNm { flex:1; }
|
||
.akteItem .aNm i { color:var(--muted); font-style:italic; }
|
||
.akteItem .aChk { color:var(--ok); font-weight:700; }
|
||
/* Gate: Artefakt-Anforderung (harte Kopplung) */
|
||
.gateReq { border-radius:8px; padding:9px 12px; margin:8px 0 12px; font-size:14px; font-weight:600; line-height:1.4; }
|
||
.gateReq.ok { background:#f1faf4; color:#177a44; border:1px solid #cde6d6; }
|
||
.gateReq.bad { background:#fdf3f3; color:#b5202a; border:1px solid #f0c9c9; }
|
||
.choice[disabled] { opacity:.45; cursor:default; }
|
||
/* Rollen-Glossar als Overlay von links (Header-Button 👥 Rollen) */
|
||
#rollenList {
|
||
position: fixed; top:0; left:0; bottom:0; width: 330px; max-width: 88vw;
|
||
background: var(--panel); border-right:1px solid var(--line); padding: 14px;
|
||
overflow:auto; z-index: 30;
|
||
transform: translateX(-100%); transition: transform .22s ease;
|
||
box-shadow: 0 0 40px rgba(20,30,50,.18);
|
||
}
|
||
body.rollenOpen #rollenList { transform: translateX(0); }
|
||
body.rollenOpen .navBackdrop { opacity:1; pointer-events:auto; }
|
||
body:not(.runMode) #rollenList { display:none; }
|
||
body:not(.runMode) #rollenBtn { display:none; }
|
||
#rollenList h3 { font-size:11px; text-transform:uppercase; letter-spacing:.8px; color:var(--muted); margin:14px 0 4px; }
|
||
.rolleItem { display:flex; align-items:center; gap:10px; padding:6px 4px; font-size:13px; }
|
||
.rolleItem .rDot { width:12px; height:12px; border-radius:50%; flex:none; border:1px solid rgba(0,0,0,.18); }
|
||
.navTop { display:flex; align-items:center; justify-content:space-between; margin-bottom:8px; }
|
||
.navTop b { font-size:13px; text-transform:uppercase; letter-spacing:.6px; color:var(--muted); }
|
||
.navTop button { border:none; background:none; font-size:20px; line-height:1; color:var(--muted); cursor:pointer; padding:4px 8px; }
|
||
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.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; }
|
||
|
||
/* ---- Minimal Run-Screens ---- */
|
||
.sHead{display:flex;align-items:center;gap:10px}
|
||
.sHead .sId{color:var(--muted);font-size:13px;font-variant-numeric:tabular-nums}
|
||
.sTitle{font-size:22px;font-weight:700;line-height:1.25;margin:10px 0 4px}
|
||
.caseLine{color:var(--muted);font-size:13px;margin:0 0 22px}
|
||
.lead{font-size:16px;margin:0 0 16px}
|
||
.todo{margin:0 0 8px;padding-left:22px}
|
||
.todo li{margin:8px 0}
|
||
.crit{margin:8px 0 0;padding-left:20px;color:var(--muted)}
|
||
.crit li{margin:4px 0}
|
||
details.det{margin:8px 0 4px;border-top:1px solid var(--line);padding-top:12px}
|
||
details.det>summary{cursor:pointer;color:var(--muted);font-size:14px;font-weight:600;list-style:none}
|
||
details.det>summary::-webkit-details-marker{display:none}
|
||
details.det>summary::before{content:"▸ ";color:var(--muted)}
|
||
details.det[open]>summary::before{content:"▾ "}
|
||
details.det>div,details.det>p,details.det>ul{margin-top:10px}
|
||
/* Schrittweise Aktivitaet: Aufloesung */
|
||
.aufBox{background:#f1faf4;border:1px solid #cde6d6;border-left:3px solid var(--ok);border-radius:10px;padding:14px 16px;margin:14px 0 4px}
|
||
.aufBox .aufH{margin:0 0 6px;font-size:12px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted)}
|
||
.aufBox ul{margin:6px 0 0;padding-left:20px}
|
||
.aufBox ul li{margin:3px 0}
|
||
.roleChips{display:flex;flex-wrap:wrap;gap:6px}
|
||
.roleChip{background:#eef0f3;border-radius:999px;padding:3px 11px;font-size:13px}
|
||
/* RACI-Legende */
|
||
.raciLegend{border:1px solid var(--line);border-radius:10px;padding:12px 14px;margin:10px 0 4px;background:#f7f9fb}
|
||
.raciLegend .rlHead{font-size:11px;text-transform:uppercase;letter-spacing:.6px;color:var(--muted);font-weight:700;margin-bottom:8px}
|
||
.raciLegend .rlRow{display:flex;align-items:flex-start;gap:10px;margin:5px 0;font-size:14px;line-height:1.45}
|
||
.raciLegend .rlRow .raciBadge{flex:none;margin-top:1px}
|
||
/* Aufgaben-Kasten (Anweisung hervorgehoben) */
|
||
.frageBox{background:#f7f9fc;border:1px solid var(--line);border-left:4px solid var(--accent);border-radius:12px;padding:14px 18px;margin:6px 0;font-size:16px;line-height:1.55}
|
||
.frageBox .frageLabel{font-size:11px;text-transform:uppercase;letter-spacing:.7px;color:var(--muted);font-weight:700;margin-bottom:5px}
|
||
/* Phasen-Abschluss-Feedback (an Gates) */
|
||
.phaseDone{margin:16px 0 4px;padding:16px 18px;border-radius:12px;background:#fffdf5;border:1px solid var(--line);border-left:4px solid var(--accent)}
|
||
.phaseDone .pdTitle{font-weight:800;font-size:18px;margin-bottom:6px}
|
||
.phaseDone p{color:var(--ink)}
|
||
/* Aktivitaets-Abschluss-Feedback */
|
||
.actDone{margin:16px 0 4px;padding:14px 16px;border-radius:12px;background:#fff;border:1px solid var(--line);border-left:4px solid var(--ok)}
|
||
.actDone .adTitle{font-weight:800;font-size:16px;color:#177a44;margin-bottom:2px}
|
||
.actDone .adPhase{margin:10px 0 0;padding-top:10px;border-top:1px dashed var(--line);font-size:15px}
|
||
.actDone.big{margin:8px 0 4px;padding:22px 24px}
|
||
.actDone.big .adTitle{font-size:22px;margin-bottom:6px}
|
||
.actDone.big p{font-size:16px}
|
||
|
||
.actions { display:flex; gap:10px; align-items:center; margin-top:24px; flex-wrap:wrap; }
|
||
.actions .spacer { flex:1; }
|
||
|
||
/* 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; }
|
||
body:not(.runMode) #stationsBtn { 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); }
|
||
|
||
/* ---- Neuer Einstiegs-Flow (Deck / Classify / Entry) ---- */
|
||
.deck{display:flex;flex-direction:column;gap:16px}
|
||
.deckGroup .deckSvc{font-size:13px;font-weight:700;color:var(--muted);margin-bottom:6px}
|
||
.deckRow{display:grid;grid-template-columns:repeat(5,1fr);gap:10px}
|
||
.deckCard{padding:0;border:1px solid var(--line);background:#fff;border-radius:10px;cursor:pointer;overflow:hidden;transition:transform .08s,box-shadow .08s}
|
||
.deckCard:hover{transform:translateY(-2px);box-shadow:0 4px 14px rgba(0,0,0,.16)}
|
||
.deckCard img{display:block;width:100%;height:auto}
|
||
.cardThumb{display:block;width:150px;border-radius:8px;margin:0 auto 14px;box-shadow:0 2px 10px rgba(0,0,0,.12)}
|
||
.choiceGrid{display:flex;flex-direction:column;gap:8px;margin:10px 0}
|
||
.choiceGrid.grid2{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}
|
||
@media(max-width:440px){.choiceGrid.grid2{grid-template-columns:1fr}}
|
||
/* Klassifizieren: links große Karte, rechts Frage + Antworten */
|
||
.classifyTop{display:grid;grid-template-columns:minmax(220px,320px) 1fr;gap:26px;align-items:start;margin:18px 0 6px}
|
||
.classifyCard{display:block;width:100%;border-radius:12px;box-shadow:0 3px 16px rgba(0,0,0,.16)}
|
||
.classifyMain{min-width:0}
|
||
.classifyMain .phaseRow{grid-template-columns:repeat(2,1fr);margin-top:12px}
|
||
@media(max-width:680px){.classifyTop{grid-template-columns:1fr}.classifyCard{max-width:300px;margin:0 auto}.classifyMain{margin-top:6px}}
|
||
.choice{text-align:left;padding:12px 14px;border:1px solid var(--line);border-radius:10px;background:#fff;cursor:pointer;font-size:15px;font-weight:600}
|
||
.choice:hover{border-color:var(--ink)}
|
||
.choice.bad{border-color:var(--bad);background:#fdf3f3}
|
||
.legend{border:1px solid var(--line);border-radius:10px;padding:10px 14px;margin-top:12px;background:#f7f9fb}
|
||
.legend h4{margin:0 0 8px;font-size:12px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted)}
|
||
.legend dt{font-weight:700;font-size:13px}
|
||
.legend dd{margin:2px 0 8px;color:var(--muted);font-size:13px}
|
||
.lgItem{padding:8px 0;border-top:1px solid var(--line)}
|
||
.lgItem:first-of-type{border-top:0;padding-top:2px}
|
||
.lgName{font-weight:700;font-size:13px;color:var(--ink)}
|
||
.lgIdee{margin:2px 0 4px;font-size:13px;color:var(--ink)}
|
||
.lgBed{margin:4px 0;color:var(--muted);font-size:13px}
|
||
.lgBed div{margin:2px 0}
|
||
.lgBsp{font-size:12px;color:var(--muted)}
|
||
.hint{font-weight:600;margin:8px 0}
|
||
.hint.bad{color:var(--bad)} .hint.ok{color:var(--ok)}
|
||
.phaseRow{display:grid;grid-template-columns:repeat(5,1fr);gap:8px;margin:14px 0}
|
||
.phaseZone{padding:22px 8px;border-radius:12px;color:#fff;font-weight:800;font-size:14px;text-align:center;cursor:pointer;border:0}
|
||
.phaseZone:hover{filter:brightness(1.06)}
|
||
.phaseZone.bad{outline:3px solid var(--bad);outline-offset:2px}
|
||
@media(max-width:760px){.deckRow{grid-template-columns:repeat(3,1fr)}.phaseRow{grid-template-columns:repeat(3,1fr)}}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<header>
|
||
<div class="brand">SLC <b>Companion</b></div>
|
||
<span class="tag">v0.6</span>
|
||
<div id="cardBadge" class="cardBadge"></div>
|
||
<div class="spacer"></div>
|
||
<button class="ghost" id="akteBtn" title="Service-Akte (gesammelte Artefakte)">📁 Akte</button>
|
||
<button class="ghost" id="rollenBtn" title="Rollen-Glossar (RACI)">👥 Rollen</button>
|
||
<button class="ghost" id="stationsBtn" title="Stationsübersicht">☰ Stationen</button>
|
||
<button class="ghost" id="resetBtn" title="Neue Action Card / Durchlauf zurücksetzen">Neu starten</button>
|
||
</header>
|
||
<div class="progress"><div id="progressBar" style="width:0%"></div></div>
|
||
|
||
<div class="navBackdrop" id="navBackdrop"></div>
|
||
<div class="layout">
|
||
<aside id="stationList"></aside>
|
||
<div id="akteList"></div>
|
||
<div id="rollenList"></div>
|
||
<main><div class="card" id="panel"></div></main>
|
||
</div>
|
||
|
||
<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 ist strategisch getrieben und betrifft den Service grundlegend – er durchläuft den vollen Lebenszyklus ab dem Design (Service-Definition)." },
|
||
{ 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)." },
|
||
{ 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." }
|
||
];
|
||
|
||
/* 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"
|
||
};
|
||
// Rollen-Glossar fuer das Overlay: gruppiert/eingefaerbt nach den 6 Figuren-Kategorien
|
||
// (Farbe = Filamentfarbe der Figuren). Deckt alle ROLLEN-Eintraege ab.
|
||
const ROLLEN_GRUPPEN = [
|
||
{ label:"Governance (Entscheider)", color:"#c9a227", roles:["spm","service_owner","sor"] },
|
||
{ label:"Umfeld / Auftraggeber", color:"#7d2e3f", roles:["dpm"] },
|
||
{ label:"Management (operative Führung)", color:"#2f80c9", roles:["projektleitung","operations_manager","al_basis_cloud","al_applikationen","support_manager","problem_manager"] },
|
||
{ label:"Operative / Fachexperten", color:"#6b7686", roles:["queue_koordinator","first_level_agent","second_level_agent","testmanagement","architektur"] },
|
||
{ label:"Externe", color:"#cfd6df", roles:["lieferant"] },
|
||
{ label:"Teams (Sonderfiguren)", color:"#2f9e57", roles:["betriebsteam","service_support_team","projektteam"] }
|
||
];
|
||
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",
|
||
"Normal Change",
|
||
"Standard Change",
|
||
"Emergency Change"
|
||
];
|
||
/* Legende-Inhalte, Index parallel zu CHANGE_TYPES (0 Major, 1 Normal, 2 Standard, 3 Emergency).
|
||
Quelle: DIGITOM-Definitionen. Emergency wurde nicht mitgeliefert -> bestehende Beschreibung. */
|
||
const CHANGE_LEGEND = [
|
||
{ idee:"Sonderform der Normal Change mit hohem Risiko, hohen Kosten oder breiter Auswirkung — höchste Eskalations- und Genehmigungsstufe.",
|
||
bed:["Hohes Risiko und/oder hohe Kosten und/oder weitreichende Auswirkung (viele Nutzer/Services betroffen)",
|
||
"Freigabe in der SOR; reicht deren Ressourcen-/Entscheidungshoheit nicht, wird daraus ein Demand (über DPM ans Mission Board)",
|
||
"Vollständige Bewertung, Business Case, ausführliche Planung & Tests, Kommunikationsplan",
|
||
"Durchläuft den vollen Lebenszyklus ab dem Design (alle Gates)"],
|
||
bsp:"Rechenzentrumsumzug, Austausch eines Kernsystems, organisationsweite Plattformmigration." },
|
||
{ idee:"Der Regelfall für alles, was nicht vorab genehmigt ist und kein Notfall ist. Durchläuft den Bewertungs- und Gate-Prozess.",
|
||
bed:["Änderungsantrag (RfC) wird erfasst",
|
||
"Risiko- und Impact-Bewertung wird durchgeführt",
|
||
"Freigabe an den Gates durch die SOR (Gate 2 durch den Service Owner) vor Umsetzung",
|
||
"Terminplanung, Test, ggf. Rollback-Plan",
|
||
"Geringes bis mittleres Risiko (die hochriskanten landen bei „Major“)"],
|
||
bsp:"Einführung einer neuen Software-Version, Konfigurationsänderung an einem produktiven System." },
|
||
{ idee:"Routine. Vorab genehmigt, weil sie oft vorkommt, das Risiko bekannt und niedrig ist und der Ablauf dokumentiert ist.",
|
||
bed:["Im Standard-Change-Katalog hinterlegtes Muster/Template für genau diese Änderung",
|
||
"Geringes, bekanntes Risiko, Auswirkung vorhersehbar",
|
||
"Wiederholbar, klar dokumentierter Ablauf",
|
||
"Keine Gate-/SOR-Einzelfreigabe nötig — generell autorisiert, läuft direkt im Betrieb"],
|
||
bsp:"Standard-Passwort-Reset, Austausch eines defekten Standard-Geräts, Einspielen eines geprüften Routine-Patches." },
|
||
{ idee:"Muss eine Störung sofort beheben — beschleunigt umgesetzt; die formale Freigabe erfolgt nachgelagert.",
|
||
bed:["Akuter Notfall / drohender oder laufender Ausfall kritischer Dienste",
|
||
"Beschleunigtes Verfahren mit Notfall-Autorisierung",
|
||
"Umsetzung sofort — Dokumentation und formale SOR-/Gate-Freigabe (Gate 3) nachgelagert"],
|
||
bsp:"Sofort-Sperrung einer kompromittierten VPN-Zertifikatskette, Notfall-Hotfix einer kritischen Sicherheitslücke." }
|
||
];
|
||
// Anzeige-Reihenfolge der Change-Arten (Indizes in CHANGE_TYPES): Standard, Emergency, Normal, Major
|
||
const CT_ORDER = [2, 3, 1, 0];
|
||
// Feste, EINMALIG gemischte Deck-Reihenfolge ([service, change]) — bei jedem Start gleich, nicht gruppiert.
|
||
const DECK_ORDER = [[2,1],[0,3],[4,0],[1,2],[5,3],[3,0],[0,1],[2,3],[4,2],[1,0],[5,1],[3,2],
|
||
[2,0],[0,2],[4,3],[1,3],[5,0],[3,1],[2,2],[0,0],[4,1],[1,1],[5,2],[3,3]];
|
||
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:"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:"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:"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:"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:"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:"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/R"],["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/R"],["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/R"],["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."}
|
||
]}
|
||
];
|
||
|
||
/* ====================== SERVICE-AKTE (Artefakte A1-A15, App-gefuehrt) ======================
|
||
Die Akte ist rein digital: erzeugte Artefakte werden per Choice bestimmt und
|
||
gesammelt; Gates sind hart gekoppelt (oeffnen nur mit den geforderten Artefakten). */
|
||
const ARTEFAKTE = {
|
||
A1:{name:"Projektauftrag", phase:"design",
|
||
was:"Der freigegebene Auftrag aus dem Demand-Lifecycle: Ziel, Rahmen, benannte Projektleitung sowie zugesagtes Budget und Ressourcen (nach DSR/MB-Freigabe).",
|
||
warum:"Er ist das Startsignal und Mandat für die Design-Phase — ohne ihn gibt es weder einen legitimierten Start noch zugewiesene Ressourcen."},
|
||
A2:{name:"Service-Definition", phase:"design", live:true,
|
||
was:"Zweck, Nutzen und Zielgruppen des Services, Utility & Warranty, die SLA-/SLO-Anforderungen sowie Abhängigkeiten zu anderen Services.",
|
||
warum:"Sie legt fachlich fest, WAS der Service leisten soll — der Bezugspunkt für Design, Betrieb und das spätere Review."},
|
||
A3:{name:"Service Design Document", phase:"design",
|
||
was:"Servicearchitektur (Komponenten, Schnittstellen), Design der Betriebs- und Supportprozesse, Security/Datenschutz/Compliance, Monitoring/Reporting und das Rollenmodell.",
|
||
warum:"Es übersetzt das „Was“ der Service-Definition in das WIE — der technische und organisatorische Bauplan und Voraussetzung für Gate 1."},
|
||
A4:{name:"Implementation Blueprint", phase:"design",
|
||
was:"Plan zur organisatorischen Einführung: Integration, Rollenübergaben, Anpassung von Prozessen/Tools, Trainings & Kommunikation, Bewertung der Time-to-Operate.",
|
||
warum:"Er stellt sicher, dass der Service nicht nur gebaut, sondern auch wirklich in die Organisation eingeführt und übernommen werden kann."},
|
||
A5:{name:"Gate-/SOR-Vorlage", phase:"transition",
|
||
was:"Die Entscheidungsvorlage für ein Gate: Aufwand/Risiken/Budget, Empfehlung und die zu prüfenden Dimensionen. An Gate 2 als „Transition-Steckbrief“.",
|
||
warum:"Sie macht Gate-Entscheidungen nachvollziehbar und legitimiert — ohne Vorlage keine SOR-/SO-Freigabe."},
|
||
A6:{name:"Betriebsdokumentation", phase:"transition",
|
||
was:"Service Operation Manual, Betriebshandbuch, Arbeitsanweisungen, Eskalationswege, Standard Changes, Known Errors und Konfigurations-/Betriebsrichtlinien.",
|
||
warum:"Sie macht den Service betreib- und supportbar — ohne sie kein stabiler Regelbetrieb und keine schnelle, einheitliche Störungsbehebung."},
|
||
A7:{name:"Test-Report", phase:"transition",
|
||
was:"Ergebnisse von Funktions-, Integrations- und Abnahmetests, der Nachweis der Betriebsreife sowie Testprotokolle und Freigaben.",
|
||
warum:"Er belegt, dass der Service funktioniert, BEVOR er live geht — Grundlage für die Freigabe an Gate 2."},
|
||
A8:{name:"Aktivierter Service", phase:"transition",
|
||
was:"Der freigegebene, produktive Service inklusive Aufnahme ins Portfolio und aktiviertem Katalog-Eintrag (ggf. mit Support-Dokumentation).",
|
||
warum:"Es markiert den offiziellen Go-Live — ab hier ist der Service in Betrieb und im Portfolio sichtbar und steuerbar."},
|
||
A9:{name:"Service-Qualitätsbericht", phase:"operation",
|
||
was:"SLA-/SLO-Auswertung, technische KPIs (Verfügbarkeit, Response Time), Abgleich gegen Qualitätsziele und Verbesserungspotenziale — inkl. Monitoring-/Betriebsdaten.",
|
||
warum:"Er zeigt objektiv, ob der Service seine Versprechen hält, und ist die Zuarbeit fürs Review."},
|
||
A10:{name:"Incident Record", phase:"support",
|
||
was:"Aufnahme, Bearbeitung, Lösung und Abschluss einer Störung oder eines Service Requests — inklusive Klassifizierung für Auswertungen. (Trägt auch den Request Record.)",
|
||
warum:"Es dokumentiert Störungen/Anfragen nachvollziehbar, sichert SLA-Konformität und liefert Daten für Trendanalysen."},
|
||
A11:{name:"Problem Record", phase:"support", live:true,
|
||
was:"Beschreibung, Symptome und Diagnosewege, bekannte Workarounds, die Ursache (Root Cause, wenn gefunden), Change-Bedarf sowie Status und Priorität.",
|
||
warum:"Es bündelt die strukturelle Ursachenarbeit hinter wiederkehrenden oder ungelösten Incidents — das einzige im Blueprint formal definierte Artefakt."},
|
||
A12:{name:"Workaround", phase:"support",
|
||
was:"Eine vorläufige Umgehungslösung, die den Betrieb stabil hält, bis die eigentliche Ursache behoben ist — mit Eintrag in die Wissensdatenbank.",
|
||
warum:"Es hält den Service nutzbar, obwohl die Ursache noch offen ist, und reduziert den Druck auf den Support."},
|
||
A13:{name:"Wissensdatenbank-Eintrag", phase:"support", live:true,
|
||
was:"Standardlösungen, Known Errors, Workarounds, FAQ und Anleitungen — das zentrale Arbeitsmittel für 1st und 2nd Level Support.",
|
||
warum:"Es beschleunigt den Support, sichert konsistente Antworten und entlastet die höheren Support-Level."},
|
||
A14:{name:"Service-Review-Bericht", phase:"review",
|
||
was:"Das „Service Performance & Improvement Review“: Bewertung über 4 Dimensionen (Leistung, Stabilität, Nutzerzufriedenheit, Zukunftsfähigkeit) per Ampel und eine Handlungsempfehlung (CONTINUE / IMPROVEMENT / REDESIGN / RETIRE).",
|
||
warum:"Es liefert die strukturierte Grundlage für die SOR-Entscheidung über die Zukunft des Service."},
|
||
A15:{name:"DPM-Rücklauf", phase:"review",
|
||
was:"Die Übergabe an den Demand-Lifecycle — Variante A: Neuer Demand (Redesign/Erweiterung) oder Variante B: Retirement-Plan / Decommissioning-Auftrag (Stilllegung).",
|
||
warum:"Es schließt den Lebenszyklus: größere Änderungen oder das Ende eines Service laufen kontrolliert über den Demand-Lifecycle, nicht „nebenbei“."}
|
||
};
|
||
// Welche Station erzeugt welches A-Artefakt (Choice-Schritt -> Aufnahme in die Akte).
|
||
const STATION_ARTEFAKT = {
|
||
ds_01:"A2", ds_02:"A3", ds_03:"A4",
|
||
tr_06:"A6", tr_07:"A7", tr_08:"A5",
|
||
op_06:"A9",
|
||
sp_02:"A13", sp_07:"A10", sp_09:"A11", sp_11:"A12",
|
||
rv_02:"A14", rv_05:"A15"
|
||
};
|
||
// Gate erzeugt Artefakt (beim Vorwaerts-Durchschreiten).
|
||
const GATE_PRODUCES = { tr_12:"A8" };
|
||
// Geforderte Artefakte je Gate (HARTE Kopplung).
|
||
const GATE_REQ = { tr_01:["A2","A3","A4"], tr_09:["A6","A7"], tr_12:["A6","A7","A2"] };
|
||
// Stationen ohne eigenes Akte-Artefakt: Ergebnis fliesst in dieses A-Artefakt ein
|
||
// (nur dokumentierte Faelle; alle uebrigen Nicht-Akte-Stationen ohne Zuordnung).
|
||
const FOLDS_INTO = {
|
||
op_02:"A6", op_05:"A9", op_07:"A11",
|
||
sp_03:"A10", sp_04:"A10", sp_05:"A10", sp_06:"A10", sp_08:"A10", sp_10:"A11"
|
||
};
|
||
|
||
function addArtefakt(a){ if(a){ S.akte = S.akte || {}; S.akte[a] = true; } }
|
||
// Beim Start nach Einstiegspunkt vorbefuellen: alles, was VOR der Einstiegs-Station
|
||
// (bzw. vor durchschrittenen Gates) entsteht, "liegt schon vor".
|
||
function seedAkte(entryIdx){
|
||
S.akte = { A1:true };
|
||
for(const sid in STATION_ARTEFAKT){
|
||
const j = STATIONEN.findIndex(s=>s.id===sid);
|
||
if(j>=0 && j < entryIdx) addArtefakt(STATION_ARTEFAKT[sid]);
|
||
}
|
||
for(const gid in GATE_PRODUCES){
|
||
const j = STATIONEN.findIndex(s=>s.id===gid);
|
||
if(j>=0 && j < entryIdx) addArtefakt(GATE_PRODUCES[gid]);
|
||
}
|
||
}
|
||
|
||
/* ====================== STATE ====================== */
|
||
const LS_KEY = "slc-companion-proto";
|
||
function defaultState(){
|
||
return { view:"deck", service:null, change:null,
|
||
classifyDone:false, classifyWrong:null,
|
||
entryDone:false, entryWrong:null,
|
||
index:0, stage:"discuss", quizIndex:0,
|
||
actStep:0, actReveal:false, actDone:false, arteWrong:null,
|
||
picks:{}, done:{}, akte:{},
|
||
loopback:null, revisit:{}, endReason:null, endGate:null };
|
||
}
|
||
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>`; }
|
||
// Finale Action-Card-Grafik (cards/s<service>-c<change>.png) — alle 30 vorhanden.
|
||
function cardImg(si, ci){ return `cards/s${si}-c${ci}.png`; }
|
||
function cardMedia(si, ci){ const f = cardImg(si, ci);
|
||
return f ? `<img class="acImg" src="${f}" alt="Action Card: ${acard(si,ci).titel}"
|
||
style="display:block;width:100%;max-width:300px;margin:6px auto;border-radius:8px;box-shadow:0 2px 10px rgba(0,0,0,.12)">`
|
||
: cardHtml(si, ci); }
|
||
|
||
/* ====================== RENDER: SIDEBAR ====================== */
|
||
function renderList(){
|
||
const groups = {};
|
||
STATIONEN.forEach((st,i)=>{ (groups[st.phase]=groups[st.phase]||[]).push({st,i}); });
|
||
let html = `<div class="navTop"><b>Stationen</b><button id="navClose" title="Schließen">✕</button></div>`;
|
||
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>
|
||
</div>`;
|
||
});
|
||
}
|
||
$("#stationList").innerHTML = html;
|
||
$("#stationList").querySelectorAll(".stationItem").forEach(el=>{
|
||
el.onclick = ()=>{ document.body.classList.remove("navOpen"); enterStation(+el.dataset.i); save(); draw(); };
|
||
});
|
||
const nc = $("#navClose"); if(nc) nc.onclick = ()=> document.body.classList.remove("navOpen");
|
||
const pct = Math.round(Object.keys(S.done).length / STATIONEN.length * 100);
|
||
$("#progressBar").style.width = pct+"%";
|
||
}
|
||
|
||
/* ====================== RENDER: SERVICE-AKTE (Overlay) ====================== */
|
||
function renderAkte(){
|
||
const order = ["design","transition","operation","support","review"];
|
||
const ids = Object.keys(ARTEFAKTE);
|
||
const have = S.akte || {};
|
||
const n = ids.filter(a=>have[a]).length;
|
||
let html = `<div class="navTop"><b>📁 Service-Akte</b><button id="akteClose" title="Schließen">✕</button></div>`;
|
||
html += `<div class="akteCount">${n}/15 Artefakten gesammelt</div>`;
|
||
for(const ph of order){
|
||
const group = ids.filter(a => ARTEFAKTE[a].phase === ph);
|
||
if(!group.length) continue;
|
||
html += `<h3>${PHASEN[ph].label}</h3>`;
|
||
group.forEach(a=>{
|
||
const ok = !!have[a];
|
||
html += `<div class="akteItem ${ok?'have':''}">
|
||
<span class="aId" style="background:${PHASEN[ph].color}">${a}</span>
|
||
<span class="aNm">${ARTEFAKTE[a].name}${ARTEFAKTE[a].live?' · <i>lebend</i>':''}</span>
|
||
<span class="aChk">${ok?'✓':'○'}</span>
|
||
</div>`;
|
||
});
|
||
}
|
||
$("#akteList").innerHTML = html;
|
||
const c = $("#akteClose"); if(c) c.onclick = ()=> document.body.classList.remove("akteOpen");
|
||
}
|
||
|
||
/* ====================== RENDER: ROLLEN-GLOSSAR (Overlay) ====================== */
|
||
function renderRollen(){
|
||
let html = `<div class="navTop"><b>👥 Rollen</b><button id="rollenClose" title="Schließen">✕</button></div>`;
|
||
html += `<div class="akteCount">RACI-Rollen im Lebenszyklus · Farbe = Figuren-Kategorie</div>`;
|
||
for(const g of ROLLEN_GRUPPEN){
|
||
html += `<h3>${g.label}</h3>`;
|
||
g.roles.forEach(r=>{
|
||
if(!ROLLEN[r]) return;
|
||
html += `<div class="rolleItem"><span class="rDot" style="background:${g.color}"></span><span>${ROLLEN[r]}</span></div>`;
|
||
});
|
||
}
|
||
html += `<p class="akteCount" style="margin-top:14px;line-height:1.45">Hinweis: Die <b>SOR</b> ist ein <b>Gremium</b> (SPM · Betrieb · Support-Manager · Service Owner …), das am Gate-Puck zusammenkommt — keine Einzelfigur.</p>`;
|
||
$("#rollenList").innerHTML = html;
|
||
const c = $("#rollenClose"); if(c) c.onclick = ()=> document.body.classList.remove("rollenOpen");
|
||
}
|
||
|
||
/* ====================== VIEW DISPATCH ====================== */
|
||
function draw(){
|
||
document.body.classList.toggle("runMode", S.view==="run");
|
||
if(S.view!=="run"){ document.body.classList.remove("navOpen","akteOpen","rollenOpen"); }
|
||
renderCardBadge();
|
||
if(S.view==="deck") return renderDeck();
|
||
if(S.view==="classify") return renderClassify();
|
||
if(S.view==="entry") return renderEntry();
|
||
if(S.view==="end") return renderEnd();
|
||
renderRun();
|
||
}
|
||
|
||
function renderCardBadge(){
|
||
const el = $("#cardBadge");
|
||
if(S.view==="deck" || S.service==null){ el.style.display="none"; el.innerHTML=""; return; }
|
||
el.style.display="flex";
|
||
const chip = S.classifyDone ? `<span class="ctChip">${CHANGE_TYPES[S.change]}</span>` : ``;
|
||
el.innerHTML = `<span class="cb-svc">${USE_CASES[S.service].service}</span>${chip}`;
|
||
}
|
||
|
||
/* ---------- Schritt 1: Action Card ziehen (Raster aller Karten) ---------- */
|
||
function renderDeck(){
|
||
const cards = DECK_ORDER.map(([si,ci])=>{
|
||
const c = USE_CASES[si].changes[ci];
|
||
return `<button class="deckCard" data-s="${si}" data-c="${ci}" title="${c.titel}">
|
||
<img src="cards/s${si}-c${ci}.png" alt="${c.titel}" loading="lazy"></button>`;
|
||
}).join("");
|
||
$("#panel").innerHTML = `
|
||
<div class="setupHead">Schritt 1 · Action Card ziehen</div>
|
||
<h2 class="setupTitle">Welche Karte habt ihr gezogen?</h2>
|
||
<p class="muted">Tippt auf die Action Card, die ihr gezogen habt.</p>
|
||
<div class="deck"><div class="deckRow">${cards}</div></div>`;
|
||
$("#panel").querySelectorAll(".deckCard").forEach(el=>{
|
||
el.onclick=()=>{ S.service=+el.dataset.s; S.change=+el.dataset.c;
|
||
S.classifyDone=false; S.classifyWrong=null; S.entryDone=false; S.entryWrong=null;
|
||
S.view="classify"; save(); draw(); };
|
||
});
|
||
}
|
||
|
||
/* ---------- Schritt 2+3: Change-Art bestimmen (retry bis richtig) -------- */
|
||
function renderClassify(){
|
||
const correct = S.change;
|
||
const card = acard(S.service,S.change);
|
||
const cardBig = `<img class="classifyCard" src="cards/s${S.service}-c${S.change}.png" alt="${card.titel}">`;
|
||
if(!S.classifyDone){
|
||
const choices = CT_ORDER.map(i=>
|
||
`<button class="choice ${S.classifyWrong===i?'bad':''}" data-i="${i}">${CHANGE_TYPES[i]}</button>`).join("");
|
||
const legend = `<div class="legend"><h4>Legende: Change-Arten im DIGITOM</h4>` +
|
||
CT_ORDER.map(i=>`<div class="lgItem"><div class="lgName">${CHANGE_TYPES[i]}</div><div class="lgIdee">${CHANGE_LEGEND[i].idee}</div></div>`).join("") + `</div>`;
|
||
const hint = S.classifyWrong!=null
|
||
? `<div class="hint bad">Nicht ganz — überlegt nochmal und probiert es erneut.</div>` : ``;
|
||
$("#panel").innerHTML = `
|
||
<div class="setupHead">Schritt 2 · Change-Art bestimmen</div>
|
||
<div class="classifyTop">
|
||
${cardBig}
|
||
<div class="classifyMain">
|
||
<h2 class="setupTitle" style="margin-top:0">Welche Art von Change könnte das sein?</h2>
|
||
<p class="muted">Überlegt gemeinsam und wählt die passende Change-Art. Die Legende hilft beim Einordnen.</p>
|
||
${legend}
|
||
${hint}
|
||
<div class="choiceGrid grid2">${choices}</div>
|
||
</div>
|
||
</div>
|
||
<div class="actions"><button class="ghost" id="backDeck">← Andere Karte</button></div>`;
|
||
$("#panel").querySelectorAll(".choice").forEach(el=>{
|
||
el.onclick=()=>{ const i=+el.dataset.i;
|
||
if(i===correct){ S.classifyWrong=null; S.classifyDone=true; } else { S.classifyWrong=i; }
|
||
save(); renderClassify(); };
|
||
});
|
||
$("#backDeck").onclick=()=>{ S.view="deck"; save(); draw(); };
|
||
} else {
|
||
$("#panel").innerHTML = `
|
||
<div class="setupHead">Schritt 3 · Erfolgreiche Kategorisierung</div>
|
||
<div class="classifyTop">
|
||
${cardBig}
|
||
<div class="classifyMain">
|
||
<div class="hint ok">✓ Richtig: ${CHANGE_TYPES[correct]}</div>
|
||
<div class="recBox"><h4>Warum?</h4>
|
||
<p style="margin:0 0 8px;color:var(--ink)">${CHANGE_LEGEND[correct].idee}</p>
|
||
<div class="lgBed">${CHANGE_LEGEND[correct].bed.map(b=>`<div>${b}</div>`).join("")}</div>
|
||
<p style="margin:8px 0 0;color:var(--muted)"><b>Beispiel:</b> ${CHANGE_LEGEND[correct].bsp}</p></div>
|
||
</div>
|
||
</div>
|
||
<div class="actions">
|
||
<button class="ghost" id="backDeck">← Andere Karte</button>
|
||
<div class="spacer"></div>
|
||
<button class="primary" id="toEntry">Weiter → Einstieg finden</button>
|
||
</div>`;
|
||
$("#backDeck").onclick=()=>{ S.view="deck"; save(); draw(); };
|
||
$("#toEntry").onclick=()=>{ S.view="entry"; S.entryDone=false; S.entryWrong=null; save(); draw(); };
|
||
}
|
||
}
|
||
|
||
/* ---------- Schritt 4+5: Einstieg finden (Phase anklicken) -------------- */
|
||
function renderEntry(){
|
||
const rec = START_EMPFEHLUNG[S.change];
|
||
const recIndex = STATIONEN.findIndex(s=>s.id===rec.id);
|
||
const correctPhase = STATIONEN[recIndex].phase;
|
||
const order = ["design","transition","operation","support","review"];
|
||
const cardBig = `<img class="classifyCard" src="cards/s${S.service}-c${S.change}.png" alt="${acard(S.service,S.change).titel}">`;
|
||
if(!S.entryDone){
|
||
const zones = order.map(ph=>
|
||
`<button class="phaseZone ${S.entryWrong===ph?'bad':''}" data-ph="${ph}"
|
||
style="background:${PHASEN[ph].color}">${PHASEN[ph].label}</button>`).join("");
|
||
const hint = S.entryWrong
|
||
? `<div class="hint bad">Diese Phase passt nicht zur Change-Art — denkt an die Definition und probiert es erneut.</div>` : ``;
|
||
$("#panel").innerHTML = `
|
||
<div class="setupHead">Schritt 4 · Einstieg finden</div>
|
||
<div class="classifyTop">
|
||
${cardBig}
|
||
<div class="classifyMain">
|
||
<div class="hint ok">Change-Art: ${CHANGE_TYPES[S.change]}</div>
|
||
<h2 class="setupTitle" style="margin-top:8px">In welcher Phase startet dieser Change?</h2>
|
||
<p class="muted">Klickt auf die Lebenszyklus-Phase, in der dieser Change einsteigt.</p>
|
||
${hint}
|
||
<div class="phaseRow">${zones}</div>
|
||
</div>
|
||
</div>
|
||
<div class="actions"><button class="ghost" id="backClassify">← zurück</button></div>`;
|
||
$("#panel").querySelectorAll(".phaseZone").forEach(el=>{
|
||
el.onclick=()=>{ const ph=el.dataset.ph;
|
||
if(ph===correctPhase){ S.entryWrong=null; S.entryDone=true; } else { S.entryWrong=ph; }
|
||
save(); renderEntry(); };
|
||
});
|
||
$("#backClassify").onclick=()=>{ S.view="classify"; save(); draw(); };
|
||
} else {
|
||
$("#panel").innerHTML = `
|
||
<div class="setupHead">Schritt 5 · Los geht's</div>
|
||
<div class="classifyTop">
|
||
${cardBig}
|
||
<div class="classifyMain">
|
||
<div class="hint ok">✓ Einstieg: ${PHASEN[correctPhase].label}</div>
|
||
<div class="recBox"><h4>Start-Station</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>
|
||
</div>
|
||
</div>
|
||
<div class="actions">
|
||
<button class="ghost" id="backClassify">← zurück</button>
|
||
<div class="spacer"></div>
|
||
<button class="primary" id="startRun">Los geht's →</button>
|
||
</div>`;
|
||
$("#backClassify").onclick=()=>{ S.view="classify"; save(); draw(); };
|
||
$("#startRun").onclick=()=>{ seedAkte(recIndex); enterStation(recIndex); S.view="run"; save(); draw(); };
|
||
}
|
||
}
|
||
|
||
/* ====================== RENDER: RUN (Station) ====================== */
|
||
const GATE_FLOW = {
|
||
tr_01: ["next","tr_05"], // Entwicklung / Konfiguration (Konfig ueberspringt Build)
|
||
tr_09: ["next","next","tr_02","end"], // Freigabe / m. Auflagen / Zurueck an Build / Ablehnung
|
||
tr_12: ["next","next","tr_10","end"] // Go-Live / m. Auflagen / Zurueck / Ablehnung
|
||
};
|
||
function enterStation(idx){
|
||
idx = Math.max(0, Math.min(idx, STATIONEN.length-1));
|
||
// Echte Rueckschleife: erreicht man das Gate wieder (oder ueberholt es), Schleife schliessen.
|
||
if(S.loopback && idx >= S.loopback.untilIdx){
|
||
if(idx === S.loopback.untilIdx) (S.revisit = S.revisit || {})[STATIONEN[idx].id] = true;
|
||
S.loopback = null;
|
||
}
|
||
S.index = idx;
|
||
S.stage = STATIONEN[idx].typ==="gate" ? "gate" : "act";
|
||
S.gatePick = null; S.quizIndex = 0;
|
||
S.actStep = 0; S.actReveal = false; S.actDone = false; S.arteWrong = null;
|
||
}
|
||
function gateGoto(st, i){
|
||
S.done[st.id] = true;
|
||
const t = (GATE_FLOW[st.id] || [])[i] || "next";
|
||
if(t==="end"){ S.view="end"; S.endReason="rejected"; S.endGate=st.id; save(); draw(); return; }
|
||
if(t==="next" && GATE_PRODUCES[st.id]) addArtefakt(GATE_PRODUCES[st.id]); // z. B. Gate 3 Go-Live -> A8
|
||
if(t==="next"){ enterStation(S.index+1); }
|
||
else {
|
||
const j = STATIONEN.findIndex(s=>s.id===t);
|
||
const target = j>=0 ? j : S.index+1;
|
||
// Sprung nach hinten = echte Rueckschleife: Banner setzen, Gate wird danach erneut vorgelegt.
|
||
if(target < S.index){ S.loopback = { gateId: st.id, gateNr: st.gateNr, untilIdx: S.index }; }
|
||
enterStation(target);
|
||
}
|
||
save(); draw();
|
||
}
|
||
/* Zielstation einer Gate-Entscheidung (für Phasenwechsel-Feedback). -1 = Ende/Ablehnung. */
|
||
function gateTargetIndex(st, i){
|
||
const t = (GATE_FLOW[st.id] || [])[i] || "next";
|
||
if(t==="end") return -1;
|
||
if(t==="next") return Math.min(S.index+1, STATIONEN.length-1);
|
||
const j = STATIONEN.findIndex(s=>s.id===t);
|
||
return j>=0 ? j : Math.min(S.index+1, STATIONEN.length-1);
|
||
}
|
||
|
||
function raciTable(st){
|
||
const rows = st.raci.map(([r,c])=>`<tr><td>${roleLabel(r)}</td><td><span class="raciBadge raci-${c}">${c}</span></td></tr>`).join("");
|
||
return `<table class="raci"><thead><tr><th>Rolle</th><th>RACI</th></tr></thead><tbody>${rows}</tbody></table>`;
|
||
}
|
||
/* RACI-Legende (deutsch) — wird bei der RACI-Frage immer mit angezeigt. */
|
||
function raciLegendHtml(){
|
||
const items = [
|
||
["R","Responsible","verantwortlich für die Durchführung — erledigt die Aufgabe operativ"],
|
||
["A","Accountable","rechenschaftspflichtig — trägt die Ergebnisverantwortung (genau eine Rolle)"],
|
||
["C","Consulted","konsultiert — wird vorab um Rat/Beitrag gefragt"],
|
||
["I","Informed","informiert — wird über das Ergebnis in Kenntnis gesetzt"]
|
||
];
|
||
return `<div class="raciLegend"><div class="rlHead">Wofür RACI steht</div>` +
|
||
items.map(([l,en,de])=>`<div class="rlRow"><span class="raciBadge raci-${l}">${l}</span><span><b>${en}</b> — ${de}</span></div>`).join("") +
|
||
`</div>`;
|
||
}
|
||
|
||
function renderRun(){
|
||
renderList();
|
||
renderAkte();
|
||
renderRollen();
|
||
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>`;
|
||
const loopBanner = (S.loopback && S.index < S.loopback.untilIdx)
|
||
? `<div class="tourBanner">↩ <b>Nacharbeit nach Gate ${S.loopback.gateNr}</b> — überarbeitet die folgenden Stationen; danach wird das Gate erneut vorgelegt und entscheidet neu.</div>`
|
||
: ``;
|
||
const cardBig = `<img class="classifyCard" src="cards/s${S.service}-c${S.change}.png" alt="${acard(S.service,S.change).titel}">`;
|
||
const stepBody = st.typ==="gate"
|
||
? (S.stage==="gateDone" ? renderGateDone(st) : renderGate(st))
|
||
: renderActivity(st);
|
||
let body = `
|
||
${loopBanner}
|
||
<div class="classifyTop">
|
||
${cardBig}
|
||
<div class="classifyMain">
|
||
<div class="sHead">${chip}<span class="sId">${st.id}</span></div>
|
||
<h2 class="sTitle" style="margin-top:8px">${st.name}</h2>
|
||
${stepBody}
|
||
</div>
|
||
</div>`;
|
||
$("#panel").innerHTML = body;
|
||
wire(st);
|
||
}
|
||
|
||
/* Aktivitaet — schrittweiser Mikro-Ablauf: 4 Fragen, je einzeln + Aufloesung.
|
||
1) Was steckt hinter der Ueberschrift? 2) Beteiligte Rollen 3) RACI 4) Artefakt */
|
||
function activitySteps(st){
|
||
return [
|
||
{ label:"Diskussion",
|
||
frage:`Diskutiert gemeinsam: Was fällt alles unter <b>„${st.name}"</b>? Was stellt ihr euch darunter vor? Nennt Beispiele.`,
|
||
auf:`<p style="margin:0 0 8px">${st.beschreibung}</p><h4 class="aufH">Das fällt darunter</h4><ul>${st.umfasst.map(u=>`<li>${u}</li>`).join("")}</ul>` },
|
||
{ label:"Operative Rollen (R)",
|
||
frage:`Welche Rollen setzen diese Aktivität <b>operativ</b> um — wer sorgt für die <b>Umsetzung</b> (Responsible)? Stellt deren Figuren auf die <b>Mulden des Station-Pucks</b>.`,
|
||
auf:`<h4 class="aufH">Operativ verantwortlich (R)</h4><div class="roleChips">${(st.raci.filter(([r,c])=>c.includes("R")).map(([r,c])=>`<span class="roleChip">${roleLabel(r)}${c==="A/R"?" (zugleich A)":""}</span>`).join("")) || '<span class="roleChip">— (keine eigene R-Rolle)</span>'}</div><p class="muted" style="margin:10px 0 0;font-size:13px">Das sind die „Macher" der Aktivität. <b>Wer</b> dafür geradesteht (A) sowie beratend (C) bzw. informiert (I) ist, klärt Schritt 3.</p>` },
|
||
{ label:"RACI",
|
||
frage:`Ergänzt nun die <b>vollständige RACI</b>: Wer ist <b>A</b>ccountable (trägt die Verantwortung), wer <b>C</b>onsulted, wer <b>I</b>nformed — zusätzlich zu den Responsible aus Schritt 2? Sortiert die Figuren ins <b>Aktiv-Feld (R·A·C·I)</b>.`,
|
||
legend: raciLegendHtml(),
|
||
auf:`<h4 class="aufH">RACI (vollständig)</h4>${raciTable(st)}` },
|
||
{ label:"Artefakt", artefakt:true,
|
||
frage:`Welches <b>Artefakt</b> entsteht hier und kommt in die <b>Service-Akte</b>?`,
|
||
auf:`<h4 class="aufH">Artefakt</h4><p style="margin:0"><b>${st.artefakt}</b></p>` }
|
||
];
|
||
}
|
||
// Antwort-Optionen fuer die Artefakt-Choice: richtiges A + 3 Distraktoren
|
||
// (bevorzugt aus derselben Phase), deterministisch nach A-Nummer sortiert.
|
||
function arteOptions(correct){
|
||
const ids = Object.keys(ARTEFAKTE);
|
||
const ph = ARTEFAKTE[correct].phase;
|
||
const same = ids.filter(a => a!==correct && ARTEFAKTE[a].phase===ph);
|
||
const other = ids.filter(a => a!==correct && ARTEFAKTE[a].phase!==ph);
|
||
const opts = [correct].concat(same.concat(other).slice(0,3));
|
||
return opts.sort((a,b)=> a.localeCompare(b, "en", {numeric:true}));
|
||
}
|
||
function renderActivity(st){
|
||
const phaseColor = PHASEN[st.phase].color;
|
||
const next = STATIONEN[S.index+1];
|
||
const lastOverall = S.index >= STATIONEN.length-1;
|
||
const phaseEnd = next && next.phase !== st.phase;
|
||
|
||
/* Eigener Abschluss-Screen nach der letzten Aufgabe */
|
||
if(S.actDone){
|
||
const phaseLine = phaseEnd
|
||
? `<p class="adPhase">🎉 Damit habt ihr die Phase <b style="color:${phaseColor}">${PHASEN[st.phase].label}</b> zu Ende gespielt — weiter mit der Phase <b style="color:${PHASEN[next.phase].color}">${PHASEN[next.phase].label}</b>.</p>`
|
||
: ``;
|
||
const btn = lastOverall ? `<button class="primary" id="finish">Durchlauf abschließen</button>`
|
||
: phaseEnd ? `<button class="primary" id="nextStation">→ Weiter zur Phase ${PHASEN[next.phase].label}</button>`
|
||
: `<button class="primary" id="nextStation">Nächste Station →</button>`;
|
||
return `<div class="actDone big">
|
||
<div class="adTitle">✓ Aktivität abgeschlossen</div>
|
||
<p style="margin:6px 0">Gut gemacht! Ihr habt <b>${st.id} — ${st.name}</b> durchgespielt.</p>
|
||
${phaseLine}
|
||
</div>
|
||
<div class="actions">
|
||
<button class="ghost" id="actBack">← zurück</button>
|
||
<div class="spacer"></div>
|
||
${btn}
|
||
</div>`;
|
||
}
|
||
|
||
/* Schrittweiser Frage-Flow */
|
||
const steps = activitySteps(st);
|
||
const i = Math.min(S.actStep||0, steps.length-1);
|
||
const step = steps[i];
|
||
const isLast = i === steps.length-1;
|
||
const arteId = STATION_ARTEFAKT[st.id]; // A-Nummer, falls diese Station eine erzeugt
|
||
const isArteChoice = step.artefakt && arteId; // Artefakt-Schritt mit echter Choice
|
||
const isNonAkte = step.artefakt && !arteId; // Station ohne eigenes Akte-Artefakt
|
||
const fold = FOLDS_INTO[st.id];
|
||
|
||
const frageHtml = isNonAkte
|
||
? `Was ist das <b>Arbeitsergebnis</b> dieser Station? <span style="color:var(--muted)">(Hier geht kein eigenes Artefakt in die Service-Akte.)</span>`
|
||
: step.frage;
|
||
|
||
let html = `<div class="tourProg">Schritt ${i+1}/${steps.length} · ${step.label}</div>
|
||
<div class="frageBox" style="border-left-color:${phaseColor}">
|
||
<div class="frageLabel">Aufgabe ${i+1}</div>
|
||
${frageHtml}
|
||
</div>`;
|
||
if(step.legend) html += step.legend;
|
||
|
||
if(isArteChoice && !S.actReveal){
|
||
// Auswahl: welches Artefakt entsteht? (richtiges A + Distraktoren)
|
||
const opts = arteOptions(arteId).map(a =>
|
||
`<button class="choice arteChoice ${S.arteWrong===a?'bad':''}" data-a="${a}">${a} — ${ARTEFAKTE[a].name}</button>`).join("");
|
||
html += `<div class="choiceGrid">${opts}</div>`;
|
||
if(S.arteWrong) html += `<div class="hint bad">Nicht ganz — überlegt nochmal, welches Ergebnis diese Station liefert.</div>`;
|
||
} else if(S.actReveal){
|
||
if(isArteChoice){
|
||
const A = ARTEFAKTE[arteId];
|
||
html += `<div class="aufBox">
|
||
<p style="margin:0 0 12px">✓ <b>${arteId} — ${A.name}</b> in die Service-Akte gelegt.</p>
|
||
<h4 class="aufH">Was umfasst es?</h4><p style="margin:0 0 10px">${A.was}</p>
|
||
<h4 class="aufH">Warum brauchen wir es?</h4><p style="margin:0">${A.warum}</p>
|
||
</div>`;
|
||
} else if(isNonAkte){
|
||
html += `<div class="aufBox">
|
||
<h4 class="aufH">Arbeitsergebnis</h4><p style="margin:0 0 8px"><b>${st.artefakt}</b></p>
|
||
<p style="margin:0;color:var(--muted)">ℹ️ Kein eigenes Akte-Artefakt${fold?` — fließt in <b>${fold} ${ARTEFAKTE[fold].name}</b> ein`:``}.</p>
|
||
</div>`;
|
||
} else {
|
||
html += `<div class="aufBox">${step.auf}</div>`;
|
||
}
|
||
}
|
||
|
||
let actions = `<div class="actions">`;
|
||
if(S.actReveal || i>0) actions += `<button class="ghost" id="actBack">← zurück</button>`;
|
||
actions += `<div class="spacer"></div>`;
|
||
if(isArteChoice && !S.actReveal){ /* Antwort per Klick auf eine Option — kein Auflösen-Button */ }
|
||
else if(!S.actReveal) actions += `<button class="primary" id="actReveal">Auflösen →</button>`;
|
||
else if(!isLast) actions += `<button class="primary" id="actNext">Weiter →</button>`;
|
||
else actions += `<button class="primary" id="actToDone">Weiter →</button>`;
|
||
actions += `</div>`;
|
||
return html + actions;
|
||
}
|
||
|
||
/* Gate — Entscheidung nach Kriterien */
|
||
function renderGate(st){
|
||
const keeper = (st.raci.find(([r,c])=>c==="A")||[])[0];
|
||
const pruef = (st.pruef||[]).map(([n,d])=>`<li><b>${n}</b> — ${d}</li>`).join("");
|
||
// Harte Artefakt-Kopplung: Gate "oeffnet" nur mit den geforderten Artefakten in der Akte.
|
||
const req = GATE_REQ[st.id] || [];
|
||
const missing = req.filter(a => !(S.akte && S.akte[a]));
|
||
const blocked = missing.length > 0;
|
||
const opts = (st.pfade||[]).map(([n,d],i)=>
|
||
`<button class="choice" data-i="${i}" ${blocked?"disabled":""}><b>${n}</b><br><span style="color:var(--muted);font-weight:400">${d}</span></button>`).join("");
|
||
const reqLine = req.length === 0 ? `` : blocked
|
||
? `<div class="gateReq bad">🔒 Gate öffnet nicht — es fehlt in der Akte: ${missing.map(a=>a+" "+ARTEFAKTE[a].name).join(" · ")}. Erzeugt diese Artefakte zuerst.</div>`
|
||
: `<div class="gateReq ok">✓ Alle geforderten Artefakte liegen in der Akte (${req.join(" · ")}).</div>`;
|
||
const revisitNote = (S.revisit && S.revisit[st.id])
|
||
? `<div class="hint ok">↩ Erneute Vorlage nach Nacharbeit — prüft erneut und entscheidet neu.</div>` : ``;
|
||
return `
|
||
${revisitNote}
|
||
<p class="lead"><b>Entscheidet:</b> ${roleLabel(keeper)}</p>
|
||
${reqLine}
|
||
<div class="choiceGrid">${opts}</div>
|
||
<details class="det">
|
||
<summary>Worum geht's & Prüf-Kriterien</summary>
|
||
<div>
|
||
<p>${st.beschreibung}</p>
|
||
<ul class="crit">${pruef}</ul>
|
||
<p class="muted">Geforderte Artefakte in der Akte (siehe oben)? Pflicht-Figuren am Gate-Puck?</p>
|
||
</div>
|
||
</details>`;
|
||
}
|
||
|
||
/* Gate — Konsequenz der Entscheidung */
|
||
function renderGateDone(st){
|
||
const i = S.gatePick || 0;
|
||
const pf = st.pfade[i] || st.pfade[0];
|
||
const keeper = (st.raci.find(([r,c])=>c==="A")||[])[0];
|
||
const sorNote = (keeper==="sor")
|
||
? `<p class="muted">Reicht die <b>Ressourcen-/Entscheidungshoheit der SOR</b> nicht (zusätzliche Mittel nötig), wird der Change zum <b>Demand</b> → über DPM ans <b>Mission Board</b>.</p>` : ``;
|
||
const tIdx = gateTargetIndex(st, i);
|
||
const target = tIdx>=0 ? STATIONEN[tIdx] : null;
|
||
const phaseEnd = target && target.phase !== st.phase;
|
||
let feedback = `<p class="muted">Die entscheidende Rolle (<b>${roleLabel(keeper)}</b>) bleibt als Marker am Gate-Puck stehen.</p>`;
|
||
let nextLabel = `Weiter →`;
|
||
if(phaseEnd){
|
||
const curColor = PHASEN[st.phase].color, nextColor = PHASEN[target.phase].color;
|
||
nextLabel = `→ Weiter zur Phase ${PHASEN[target.phase].label}`;
|
||
feedback += `<div class="phaseDone" style="border-left-color:${nextColor}">
|
||
<div class="pdTitle">🎉 Phase abgeschlossen</div>
|
||
<p style="margin:4px 0">Gratulation — ihr habt die Phase <b style="color:${curColor}">${PHASEN[st.phase].label}</b> zu Ende gespielt!</p>
|
||
<p style="margin:4px 0">Weiter geht's mit der Phase <b style="color:${nextColor}">${PHASEN[target.phase].label}</b>.</p>
|
||
</div>`;
|
||
}
|
||
return `
|
||
<div class="step reveal">
|
||
<div class="stepHead"><span class="n">⛩</span> Entscheidung getroffen</div>
|
||
<div class="recBox"><h4>${pf[0]}</h4><p style="margin:0;color:var(--muted)">${pf[1]}</p></div>
|
||
${sorNote}
|
||
${feedback}
|
||
</div>
|
||
<div class="actions">
|
||
<button class="ghost" id="gateBack">← andere Entscheidung</button>
|
||
<div class="spacer"></div>
|
||
<button class="primary" id="gateNext">${nextLabel}</button>
|
||
</div>`;
|
||
}
|
||
|
||
/* ====================== WIRING ====================== */
|
||
function wire(st){
|
||
const b = id => $("#"+id);
|
||
if(b("actReveal")) b("actReveal").onclick = ()=>{ S.actReveal=true; save(); draw(); };
|
||
if(b("actNext")) b("actNext").onclick = ()=>{ S.actStep=(S.actStep||0)+1; S.actReveal=false; save(); draw(); };
|
||
if(b("actToDone")) b("actToDone").onclick = ()=>{ S.actDone=true; save(); draw(); };
|
||
// Artefakt-Choice
|
||
$("#panel").querySelectorAll(".arteChoice[data-a]").forEach(el=>{
|
||
el.onclick = ()=>{ const a = el.dataset.a;
|
||
if(a === STATION_ARTEFAKT[st.id]){ S.arteWrong=null; addArtefakt(a); S.actReveal=true; }
|
||
else { S.arteWrong = a; }
|
||
save(); draw(); };
|
||
});
|
||
if(b("actBack")) b("actBack").onclick = ()=>{
|
||
if(S.actDone){ S.actDone=false; }
|
||
else if(S.actReveal){ S.actReveal=false; }
|
||
else if((S.actStep||0)>0){ S.actStep--; S.actReveal=true; }
|
||
save(); draw(); };
|
||
if(b("nextStation")) b("nextStation").onclick = ()=>{ S.done[st.id]=true; enterStation(S.index+1); save(); draw(); };
|
||
if(b("finish")) b("finish").onclick = ()=>{ S.done[st.id]=true; S.view="end"; S.endReason="done"; save(); draw(); };
|
||
// Gate
|
||
$("#panel").querySelectorAll(".choiceGrid .choice[data-i]").forEach(el=>{
|
||
el.onclick = ()=>{ S.gatePick=+el.dataset.i; S.stage="gateDone"; save(); draw(); };
|
||
});
|
||
if(b("gateBack")) b("gateBack").onclick = ()=>{ S.stage="gate"; save(); draw(); };
|
||
if(b("gateNext")) b("gateNext").onclick = ()=>{ gateGoto(st, S.gatePick||0); };
|
||
}
|
||
|
||
/* ====================== ABSCHLUSS-SCREEN ====================== */
|
||
function renderEnd(){
|
||
const rejected = S.endReason==="rejected";
|
||
const gate = rejected ? STATIONEN.find(s=>s.id===S.endGate) : null;
|
||
const head = rejected ? "Change abgelehnt" : "Durchlauf abgeschlossen";
|
||
const icon = rejected ? "✗" : "✓";
|
||
const box = rejected
|
||
? `<div class="recBox" style="border-left-color:var(--bad)">
|
||
<h4>Abgelehnt an ${gate ? "Gate "+gate.gateNr : "einem Gate"}</h4>
|
||
<p style="margin:0;color:var(--muted)">Das Vorhaben wird in dieser Form nicht weiterverfolgt. Eine endgültige Ablehnung erfordert die <b>SOR-Eskalation</b>.</p></div>`
|
||
: `<div class="recBox">
|
||
<h4>Service-Lifecycle durchlaufen</h4>
|
||
<p style="margin:0;color:var(--muted)">Ihr habt den Change von der Einordnung bis zur Umsetzung begleitet. Im Workshop schließt hier das gemeinsame <b>Debriefing am Tisch</b> an (Reflexion der Stationen, offene Fragen).</p></div>`;
|
||
$("#panel").innerHTML = `
|
||
<div class="setupHead">Abschluss</div>
|
||
<h2 class="setupTitle">${icon} ${head}</h2>
|
||
<div class="hint ${rejected?"bad":"ok"}">${USE_CASES[S.service].service} · ${CHANGE_TYPES[S.change]}</div>
|
||
${box}
|
||
<div class="actions">
|
||
<div class="spacer"></div>
|
||
<button class="primary" id="endRestart">Neue Action Card →</button>
|
||
</div>`;
|
||
$("#endRestart").onclick = ()=>{ S = defaultState(); save(); draw(); };
|
||
}
|
||
|
||
/* ====================== INIT ====================== */
|
||
(function init(){
|
||
$("#resetBtn").onclick = ()=>{ if(confirm("Neue Action Card ziehen und Durchlauf zurücksetzen?")){ S=defaultState(); save(); draw(); } };
|
||
const closeOverlays = ()=> document.body.classList.remove("navOpen","akteOpen","rollenOpen");
|
||
$("#stationsBtn").onclick = ()=>{ const o=document.body.classList.contains("navOpen"); closeOverlays(); if(!o) document.body.classList.add("navOpen"); };
|
||
$("#akteBtn").onclick = ()=>{ const o=document.body.classList.contains("akteOpen"); closeOverlays(); if(!o) document.body.classList.add("akteOpen"); };
|
||
$("#rollenBtn").onclick = ()=>{ const o=document.body.classList.contains("rollenOpen"); closeOverlays(); if(!o) document.body.classList.add("rollenOpen"); };
|
||
$("#navBackdrop").onclick = closeOverlays;
|
||
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>
|