"""Pusht Team-Uebersicht inkl. TrassenOrder als Confluence-Seite.""" import urllib.request, json, ssl, urllib.parse secrets = {} with open("project-audit/.secrets", "r", encoding="utf-8-sig") as f: for line in f: if "=" in line and not line.startswith("#"): k, v = line.strip().split("=", 1) secrets[k.strip()] = v.strip() TOKEN = secrets.get("CONFLUENCE_TOKEN", "") BASE = "https://arija-confluence.jaas.service.deutschebahn.com/rest/api" SPACE = "BES" PARENT = "581013135" TITLE = "26. Teams inkl. TrassenOrder" ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE html = """

Team-Landschaft pathOS + TrassenOrder

Stand: 2026-04-30 | Kontext: Reorganisations-Planung

TrassenOrder (TraPo) ist ein Testballon, um zu pruefen ob eine andere Herangehensweise (entkoppelt, UX-first, klein) schneller, besser und sicherer funktioniert als der pathOS-Ansatz (Microservice-Monolith, 167 Repos, 35+ Personen).

Aktuelle Team-Landschaft

TeamPersonenFokusServicesDeploymentBesonderheit
Team 404~10Portal UI + Middleware2 (68K LoC)pathOS Release-Zug33% Bug-Rate, kundenseitig
Team CIB~13Prozesse, Camunda, Backend~15 (122K LoC)pathOS Release-ZugSV-Monolith, Abrechnung
Team Zero~9TAF/TAP Schnittstellen~9 (38K LoC)pathOS Release-ZugBeste Qualitaet, OPs-Rotation
OPs Squad2 fest + rot.Betrieb, InfrastrukturInfra-RepospathOS Release-ZugSeit PI 39 (ex-STeam)
DevOps~7CI/CD, Tooling, PipelinesPipelines, HelmpathOS Release-ZugJan Lubenow = 39% SPOF
TrassenOrder (TraPo)~5 (klein)GelV-Portal (UX-first)1 (neu)Unabhaengig!Testballon, Discovery-Phase

TrassenOrder vs. pathOS — Vergleich der Ansaetze

DimensionpathOS (aktuell)TrassenOrder (Testballon)
ArchitekturMicroservice-Monolith (synchrone Releases, 167 Repos)Externes System, eigene Schnittstellen, unabhaengig deploybar
Teamgroesse~35+ Personen, 5 Teams~5 Personen, 1 Team
ZielgruppeAlle EVUs (Experten + Anfaenger)Kleine EVUs, Ein-Mann-Betriebe ("WhatsApp-Nutzer")
UX-Ansatz240+ Formularfelder, Experten-Tool3 Angaben fuer eine Bestellung, radikal vereinfacht
DeploymentRelease-Zug (alle Services zusammen)Unabhaengig, eigener Rhythmus
AbhaengigkeitenHoch (Kafka, Camunda, 15+ Services)Minimal (nur API-Schnittstellen zu Primaerquellen)
GeschwindigkeitPI-getaktet (10 Wochen)Kontinuierlich, Feature-basiert
ScopeNetzfahrplan + GelV + ujBau + AbrechnungNur GelV (Gelegenheitsverkehr)
PhaseProduktiv seit Dez 2025Discovery seit Jan 2026, Livegang Q4 2026

Was testet der Testballon?

Hypothesen
  1. Schneller: Kann ein kleines, entkoppeltes Team schneller liefern als ein grosses im Release-Zug?
  2. Besser: Fuehrt UX-first + radikale Vereinfachung zu besserer Nutzerzufriedenheit?
  3. Sicherer: Reduziert Entkopplung das Risiko (kein Dominoeffekt bei Fehlern)?

Wenn der Testballon erfolgreich ist: Das Modell koennte auf weitere Bereiche uebertragen werden (Netzfahrplan, ujBau). Langfristig koennte TrassenOrder das pathOS-Portal abloesen.

Schnittstellen zwischen pathOS und TrassenOrder

SchnittstelleRichtungZweck
Trassenanmeldung APITraPo → pathOSBestellung absetzen
Stammdaten APITraPo ← PrimaerquelleDirekt, NICHT ueber pathOS
Angebots-RueckmeldungpathOS → TraPoErgebnis der Konstruktion
TrassenfinderTraPo ← BVURouting, Validierung (Fernziel)

Architekturentscheidung: TrassenOrder greift auf Primaerquellen direkt zu — nicht ueber eine pathOS-Zwischenschicht. Das vermeidet Abhaengigkeiten vom pathOS Release-Zug.

Implikationen fuer Team-Reorganisation

SzenarioAuswirkung auf pathOS-Teams
TraPo erfolgreich → GelV wandert zu TraPopathOS kann sich auf Netzfahrplan + ujBau + Abrechnung konzentrieren. Vereinfacht den fachlichen Schnitt erheblich. Click&Ride (ADR-72) wird obsolet.
TraPo erfolgreich → Modell wird uebertragenWeitere kleine Teams fuer spezifische Domaenen. pathOS wird zum API-Backend-Layer. Portal-Team (404) wird langfristig obsolet.
TraPo scheitert → GelV bleibt bei pathOSKeine Aenderung. Click&Ride Anbindung (ADR-72) wird weiter von CIB gebaut.

Offene Fragen

Team-Kennzahlen (Vergleich)

MetrikpathOS gesamtTrassenOrderFaktor
Personen~35~57x
Services~40 aktiv140x
Lines of Code~260K~0 (Discovery)
Jira-Projekte6 (O2C*, TTTI)1 (TRAPO)6x
Release-Frequenz~2x/Monat (KTU)Kontinuierlich (Ziel)
Bug-Rate20-33%0% (noch kein Code)
Deployment-AbhaengigkeitenHoch (17+ Umgebungen)Keine
""" # Push search_url = f"{BASE}/content?spaceKey={SPACE}&title={urllib.parse.quote(TITLE)}&type=page" req = urllib.request.Request(search_url) req.add_header("Authorization", f"Bearer {TOKEN}") resp = urllib.request.urlopen(req, context=ctx, timeout=30) search_data = json.loads(resp.read().decode("utf-8")) if search_data.get("results"): page_id = search_data["results"][0]["id"] ver_url = f"{BASE}/content/{page_id}?expand=version" req2 = urllib.request.Request(ver_url) req2.add_header("Authorization", f"Bearer {TOKEN}") ver_data = json.loads(urllib.request.urlopen(req2, context=ctx, timeout=30).read().decode("utf-8")) version = ver_data["version"]["number"] + 1 body = json.dumps({"version": {"number": version}, "title": TITLE, "type": "page", "body": {"storage": {"value": html, "representation": "storage"}}}).encode("utf-8") req3 = urllib.request.Request(f"{BASE}/content/{page_id}", method="PUT", data=body) req3.add_header("Authorization", f"Bearer {TOKEN}") req3.add_header("Content-Type", "application/json") result = json.loads(urllib.request.urlopen(req3, context=ctx, timeout=30).read().decode("utf-8")) print(f"Aktualisiert: https://arija-confluence.jaas.service.deutschebahn.com/pages/viewpage.action?pageId={result['id']}") else: body = json.dumps({"type": "page", "title": TITLE, "space": {"key": SPACE}, "ancestors": [{"id": PARENT}], "body": {"storage": {"value": html, "representation": "storage"}}}).encode("utf-8") req3 = urllib.request.Request(f"{BASE}/content", method="POST", data=body) req3.add_header("Authorization", f"Bearer {TOKEN}") req3.add_header("Content-Type", "application/json") result = json.loads(urllib.request.urlopen(req3, context=ctx, timeout=30).read().decode("utf-8")) print(f"Erstellt: https://arija-confluence.jaas.service.deutschebahn.com/pages/viewpage.action?pageId={result['id']}")