<# .SYNOPSIS Pusht die Personal- und Bug-Analyse als Confluence-Seite .USAGE powershell -ExecutionPolicy Bypass -File ".\project-audit\scripts\confluence-push-personal.ps1" #> $ConfluenceUrl = "https://arija-confluence.jaas.service.deutschebahn.com" $SpaceKey = "BES" $ParentPageId = "581013135" $ApiBase = "$ConfluenceUrl/rest/api" [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Write-Host "============================================================" Write-Host " Personal- und Bug-Analyse -> Confluence" Write-Host "============================================================" $PAT = Read-Host "Confluence PAT" $Headers = @{ "Authorization" = "Bearer $PAT"; "Content-Type" = "application/json" } function Create-Or-Update-Page { param([string]$Title, [string]$HtmlBody, [string]$ParentId) # Umlaute automatisch konvertieren $HtmlBody = Fix-Umlauts $HtmlBody $SearchUri = "$ApiBase/content?spaceKey=$SpaceKey&title=$([Uri]::EscapeDataString($Title))&type=page" try { $SearchResp = Invoke-WebRequest -Uri $SearchUri -Headers $Headers -UseBasicParsing -ErrorAction Stop $SearchData = $SearchResp.Content | ConvertFrom-Json } catch { Write-Host " FEHLER bei Suche: $($_.Exception.Message)" -ForegroundColor Red return $null } if ($SearchData.results -and $SearchData.results.Count -gt 0) { $PageId = $SearchData.results[0].id try { $VerResp = Invoke-WebRequest -Uri "$ApiBase/content/$PageId`?expand=version,body.storage" -Headers $Headers -UseBasicParsing -ErrorAction Stop $VerData = $VerResp.Content | ConvertFrom-Json $Version = $VerData.version.number + 1 } catch { $Version = $SearchData.results[0].version.number + 1 } Write-Host " Aktualisiere (ID: $PageId, Version: $Version)..." -NoNewline $Body = @{ version = @{ number = $Version } title = $Title type = "page" body = @{ storage = @{ value = $HtmlBody; representation = "storage" } } } | ConvertTo-Json -Depth 10 try { $Resp = Invoke-WebRequest -Uri "$ApiBase/content/$PageId" -Method Put -Headers $Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -UseBasicParsing -ErrorAction Stop Write-Host " OK" -ForegroundColor Green return ($Resp.Content | ConvertFrom-Json).id } catch { Write-Host " FEHLER: $($_.Exception.Message)" -ForegroundColor Red return $null } } else { Write-Host " Erstelle neue Seite..." -NoNewline $Body = @{ type = "page" title = $Title space = @{ key = $SpaceKey } ancestors = @(@{ id = $ParentId }) body = @{ storage = @{ value = $HtmlBody; representation = "storage" } } } | ConvertTo-Json -Depth 10 try { $Resp = Invoke-WebRequest -Uri "$ApiBase/content" -Method Post -Headers $Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -UseBasicParsing -ErrorAction Stop Write-Host " OK" -ForegroundColor Green return ($Resp.Content | ConvertFrom-Json).id } catch { Write-Host " FEHLER: $($_.Exception.Message)" -ForegroundColor Red return $null } } } # ============================================================ # SEITE: Personal- und Bug-Analyse # ============================================================ Write-Host "" Write-Host ">> Seite 22: Personal- und Bug-Analyse" -ForegroundColor Yellow $PersonalHtml = @"

Personal- und Bug-Analyse pathOS

Stand: 2026-04-27 | Quellen: Jira (90d + 12M), Rollen-Mapping (BO-Input), Tenure-Daten

Diese Analyse korreliert Personaldaten (Rollen, Tenure, Aktivitaet) mit Bug-Raten und Qualitaetskennzahlen pro Team und Entwickler.

Team-Gesundheit im Ueberblick

TeamPersonenKern-DevsBug-Rate (90d)Bug-Rate (12M)TrendBewertung
Team 40410733%25%↑ SteigendKRITISCH
Team CIB13620%23%↓ SinkendGUT
Team Zero9615%15%→ StabilGUT
OPs Squad7+ rot.2 fest31%27%↓ SinkendBEOBACHTEN
DevOps739%7%→ StabilOK (SPOF)

Team 404 (Portal) — KRITISCH

Hoechste Bug-Rate (33%), steigend seit Go-Live. Portal ist kundenseitig — Bugs werden direkt von EVUs gemeldet.

PersonRolleSeitIssues (90d)Bug-AnteilDone%Bewertung
Ana CvitkovicBusiness Engineer2021-0878niedrighochTOP — Anker des Teams
Jasmin KeskinFrontend Dev2021-084542%mittelBug-anfaellig
Emmanuel Kontcheu TagneFrontend Dev2021-084269%mittelKRITISCH
Diego Da Costa SouzaFrontend Dev2021-0941mittelmittelSpring Boot 4 Portal
Leon HoerpelDev?3571%mittelKRITISCH
Dominik RueckerBackend Dev?31mittelmittel
Annette HalbhuberLead Dev2021-0926niedrighochStabil, Lead
Simon ReitingerDev2025-11150%100%Exzellenter Start
Marcel HufgardPO2021-128Product Owner
Luca CaraccioloQA2021-095Wenig aktiv

Kernproblem: Emmanuel (69% Bugs) und Leon (71% Bugs) arbeiten beide im Frontend. Das Portal-Frontend hat ein systematisches Qualitaetsproblem. QA (Luca) ist wenig aktiv — Testabdeckung unzureichend.

Team CIB (Prozesse/Backend) — Erfolgsgeschichte

Bug-Rate von 36% (Jan) auf 9% (Apr) gesunken. Backend stabilisiert sich nach Go-Live.

PersonRolleSeitIssues (90d)Bug-AnteilDone%Bewertung
Bishara JaserDev2022-0873niedrig93%TOP — Leistungstraeger
Saurav KumarDev2022-01488%94%TOP — niedrigste Bug-Rate
Jonas KoehlerDev?34niedrig100%Exzellent
Dong-Won HanDev2021-0920mittelmittelVeteran
Hans-Henning RambergerDev2024-0516mittelmittelAuch OPs
Vasileios DimitriadisDev2023-1111mittelmittelWenig aktiv
Christian MeinsPO2021-109Product Owner
Harry BraunDev2023-015mittelmittelSB4 SV
Olaf BeckenBusiness Engineer2024-055
Alexander PetiokyDev2021-101Kaum aktiv

Kern-Trio: Bishara + Saurav + Jonas (155 Issues, >93% Done). Deren Arbeitsweise sollte als Vorbild fuer andere Teams dienen.

Team Zero (TAF/TAP) — Stabil

Niedrigste Bug-Rate (15%), stabiler Output. Beste SonarQube-Qualitaet (4.2 Smells/1K, 91.8% Coverage).

PersonRolleSeitIssues (90d)Bug-AnteilBewertung
Steven MeixnerDev2022-0764 + 27 OPsniedrigTOP — Allrounder (SPOF!)
Bing ShiDev2022-0463niedrigStark
Frank LemkeDev2022-1249niedrigAuch OPs
Kathrin SchleichDev2021-0927niedrigAuch OPs
Michael WeisbergTest2024-112352% offen
Bernd KleblPO2021-0916Auch OPs
Norbert MaurerDev2021-111283% offen — ausgeschieden?

DevOps — SPOF-Risiko

Jan Lubenow = 39% aller DevOps-Issues — kritischster Single Point of Failure im gesamten Programm.

PersonRolleSeitIssues (90d)Anteil
Jan LubenowLead Dev2022-0911439%
David SteinkopffDev2023-03186%
Henrik SchollDev2024-10103%
Christian PrauseDev?72%
Patrick LewandowskiDev?62%
Michael Mh JahnDev?62%
Sebastian GoendoerDev?31%

Tenure vs. Bug-Rate — Korrelation

TeamHypothese: Laenger dabei = weniger Bugs?Ergebnis
Team 404Emmanuel (56 Monate, 69% Bugs), Simon (5 Monate, 0% Bugs)WIDERLEGT — Systematisches Problem
Team CIBSaurav (51 Monate, 8% Bugs), Bishara (44 Monate, niedrig)BESTAETIGT — Erfahrung + gute Prozesse
Team ZeroAlle Veteranen niedrige Bug-Rate, beste SonarQube-WerteBESTAETIGT — Stabiles Team + Praktiken

Fazit: Tenure allein erklaert die Bug-Rate nicht. Team 404 hat ein systematisches Frontend-Qualitaetsproblem, das nicht durch Erfahrung geloest wird. CIB und Zero zeigen, dass gute Prozesse + Erfahrung zusammen wirken.

Risiko-Matrix Personal

KRITISCH (sofort handeln)

RisikoPerson(en)ImpactMassnahme
SPOF DevOpsJan Lubenow (39%)Deployment, CI/CD, InfraWissenstransfer, Dokumentation
SPOF Zero/OPsSteven Meixner (91 Issues)TAF/TAP + InfrastrukturEntlastung, Backup aufbauen
Bug-Verursacher 404Emmanuel (69%), Leon (71%)Portal-QualitaetCode-Reviews, Pair Programming

HOCH (kurzfristig)

RisikoPerson(en)ImpactMassnahme
QA-Engpass 404Luca Caracciolo (5 Issues)Testabdeckung PortalAktivieren oder ersetzen
Test-Backlog ZeroMichael Weisberg (52% offen)Testabdeckung TAF/TAPPriorisierung
Inaktive MitgliederNorbert Maurer, Alexander PetiokyOffene Issues, WissenStatus klaeren

Top 5 Massnahmen (priorisiert)

  1. Jan Lubenow entlasten — Wissenstransfer auf David Steinkopff + Henrik Scholl. DevOps-Runbook beschleunigen. Ziel: Kein Einzelner >25% der Issues.
  2. Portal-Qualitaet steigern (404) — Code-Reviews fuer Emmanuel/Leon verstaerken. Frontend-Testautomatisierung ausbauen. QA aktivieren. Fehlermeldungen-Konzept umsetzen.
  3. Steven Meixner entlasten — OPs-Rotation auf CIB/404 ausweiten. Steven soll sich auf Zero-Kernarbeit konzentrieren.
  4. Inaktive klaeren — Norbert Maurer (Zero), Alexander Petioky (CIB), Sebastian Goendoer (OPs): Status klaeren, offene Issues umverteilen.
  5. CIB Best Practices teilen — Bishara/Saurav/Jonas als Mentoren. Deren Arbeitsweise (>93% Done, <10% Bugs) als Vorbild fuer 404.
"@ # Umlaute: Nutze gleiche Funktion wie confluence-push.ps1 # Schritt 1: Englische Woerter schuetzen, Schritt 2: Ersetzen, Schritt 3: Schutz aufheben function Fix-Umlauts($html) { if ($null -eq $html -or $html -eq "") { return $html } $Protect = @( 'Israel','Michael','Raphael','Emmanuel','Manuel','Daniel','Samuel', 'Maurer','Enabler','enabler','Container','container','Cluster','cluster', 'User','user','Tracing','Staging','Logging','Alerting','Monitoring', 'Deployment','deployment','Security','security','Recovery','Discovery', 'Delivery','Pipeline','pipeline','Release','release', 'Performance','performance','Interface','interface', 'Service','service','Feature','feature','Issue','issue', 'value','true','blue','Due','due','Queue','queue', 'Unique','unique','Continue','continue', 'Funnel','Tunnel','tunnel','Buildpacks','Dockerfile', 'OpenSearch','Gherkin','Kubernetes','Helmfile','Renovate', 'Operate','Template','template','Tasklist', 'Smoke','smoke','Analyse','analyse','Analysis', 'Baseline','baseline','Namespace','namespace', 'Codebase','Database','database','Rescue','rescue' ) foreach ($w in $Protect) { $html = $html.Replace($w, "PROTECT_$w") } # Namen $html = $html.Replace('Hoerpel', 'Hörpel') $html = $html.Replace('Ruecker', 'Rücker') $html = $html.Replace('Koehler', 'Köhler') $html = $html.Replace('Goendoer', 'Göndör') # ue $html = $html.Replace('Ueber', 'Über') $html = $html.Replace('ueber', 'über') $html = $html.Replace('Pruef', 'Prüf'); $html = $html.Replace('pruef', 'prüf') $html = $html.Replace('fuehrung', 'führung'); $html = $html.Replace('Fuehrung', 'Führung') $html = $html.Replace('Verfueg', 'Verfüg'); $html = $html.Replace('verfueg', 'verfüg') $html = $html.Replace('Verschluess', 'Verschlüss'); $html = $html.Replace('verschluess', 'verschlüss') $html = $html.Replace('Schluess', 'Schlüss'); $html = $html.Replace('schluess', 'schlüss') $html = $html.Replace('Verknuepf', 'Verknüpf'); $html = $html.Replace('verknuepf', 'verknüpf') $html = $html.Replace('Unterstuetz', 'Unterstütz'); $html = $html.Replace('unterstuetz', 'unterstütz') $html = $html.Replace('Luecke', 'Lücke'); $html = $html.Replace('luecke', 'lücke') $html = $html.Replace('Rueck', 'Rück'); $html = $html.Replace('rueck', 'rück') $html = $html.Replace('Frueh', 'Früh'); $html = $html.Replace('frueh', 'früh') $html = $html.Replace('Nuetzlich', 'Nützlich'); $html = $html.Replace('nuetzlich', 'nützlich') $html = $html.Replace('Abkuerz', 'Abkürz'); $html = $html.Replace('abkuerz', 'abkürz') $html = $html.Replace('wuerde', 'würde'); $html = $html.Replace('Wuerde', 'Würde') $html = $html.Replace('muessen', 'müssen'); $html = $html.Replace('Muessen', 'Müssen') $html = $html.Replace('fuer ', 'für '); $html = $html.Replace('Fuer ', 'Für ') # oe $html = $html.Replace('Loesung', 'Lösung'); $html = $html.Replace('loesung', 'lösung') $html = $html.Replace('Erhoeh', 'Erhöh'); $html = $html.Replace('erhoeh', 'erhöh') $html = $html.Replace('noetig', 'nötig'); $html = $html.Replace('Noetig', 'Nötig') $html = $html.Replace('moeglich', 'möglich'); $html = $html.Replace('Moeglich', 'Möglich') $html = $html.Replace('geloest', 'gelöst') $html = $html.Replace('hoechst', 'höchst'); $html = $html.Replace('Hoechst', 'Höchst') $html = $html.Replace('koennen', 'können'); $html = $html.Replace('Koennen', 'Können') $html = $html.Replace('Zugehoer', 'Zugehör'); $html = $html.Replace('zugehoer', 'zugehör') $html = $html.Replace('gehoer', 'gehör') # ae $html = $html.Replace('Aenderung', 'Änderung'); $html = $html.Replace('aenderung', 'änderung') $html = $html.Replace('anfaellig', 'anfällig'); $html = $html.Replace('faellig', 'fällig') $html = $html.Replace('faehig', 'fähig') $html = $html.Replace('traeger', 'träger'); $html = $html.Replace('Traeger', 'Träger') $html = $html.Replace('laenger', 'länger'); $html = $html.Replace('Laenger', 'Länger') $html = $html.Replace('erklaer', 'erklär') $html = $html.Replace('klaer', 'klär'); $html = $html.Replace('Klaer', 'Klär') $html = $html.Replace('verstaerk', 'verstärk') $html = $html.Replace('Verstaend', 'Verständ'); $html = $html.Replace('verstaend', 'verständ') $html = $html.Replace('Abhaengig', 'Abhängig'); $html = $html.Replace('abhaengig', 'abhängig') $html = $html.Replace('haeufig', 'häufig'); $html = $html.Replace('Haeufig', 'Häufig') $html = $html.Replace('laeuft', 'läuft'); $html = $html.Replace('Laeuft', 'Läuft') $html = $html.Replace('waere', 'wäre'); $html = $html.Replace('Waere', 'Wäre') $html = $html.Replace('schaerfen', 'schärfen'); $html = $html.Replace('Schaerfen', 'Schärfen') $html = $html.Replace('aufraeumen', 'aufräumen'); $html = $html.Replace('Aufraeumen', 'Aufräumen') $html = $html.Replace('Verlaenger', 'Verlänger'); $html = $html.Replace('verlaenger', 'verlänger') $html = $html.Replace('Naechst', 'Nächst'); $html = $html.Replace('naechst', 'nächst') $html = $html.Replace('Massnahme', 'Maßnahme'); $html = $html.Replace('massnahme', 'maßnahme') $html = $html.Replace('Groesse', 'Größe'); $html = $html.Replace('groesse', 'größe') $html = $html.Replace('gleichmaessig', 'gleichmäßig') $html = $html -replace '([a-z])taet\b', '$1tät' # Schutz aufheben $html = $html.Replace('PROTECT_', '') return $html } $PageId = Create-Or-Update-Page -Title "22. Personal- und Bug-Analyse" -HtmlBody $PersonalHtml -ParentId $ParentPageId Write-Host "" if ($PageId) { Write-Host "FERTIG! $ConfluenceUrl/pages/viewpage.action?pageId=$PageId" -ForegroundColor Green } else { Write-Host "FEHLER beim Erstellen der Seite" -ForegroundColor Red }