Playbook · Case Study TINA
Legacy → Angular: Frontend-Migration durch KI-Agenten
Legacy → Angular:
Frontend-Migration durch KI-Agenten
Ein übertragbares Rezept, wie eine KI-Agenten-Session ein komplettes Legacy-Frontend (~4.500 LOC Aurelia/VoltoSPA, ~1 % Testabdeckung) selbständig in eine Angular-21-App mit ~90 % Coverage portiert — inklusive der Härtefälle, die wirklich wehtun.
Angular 21 (Signals, zoneless) · PrimeNG 21 · Tailwind 4 · Node 22 — ersetzt Aurelia/VoltoSPA, Webpack 4, Node 11 · Zahlen-Stand 2026-07-05
Die Case Study in Zahlen
Portierungsstand
10/12 in drei Tagen
Die Reihenfolge macht den Unterschied: Quick Wins zuerst härten die Muster, der größte Brocken (stammdaten) kommt zuletzt, wenn das Rezept sitzt. contractors und admin sind bewusst vertagt — der User entscheidet, ob sie überhaupt portiert werden.
10 Bereiche portiert 2 vertagt (User-Entscheidung)
Der Umfang
Der Agent-Loop
Die vier Phasen
-
Phase 0 · 2026-07-03
Design-Gate — vor jeder View-Portierung
Zwei wirklich unterschiedliche, klickbare HTML-Mockups bauen; der User wählt, die Entscheidung wird protokolliert; erst danach werden Theme und Views umgesetzt. Nicht-visuelle Fundamentarbeit darf parallel laufen.
Proposal A/B als Mockups User wählte B „Editorial" Gate protokolliert
-
Phase 1 · 2026-07-03
Fundament vor Features
Vitest mit Coverage-Gate (80 % Lines) im Maven-Build · ESLint strict · Playwright mock-first (
page.routeauf/rest/**, Auth-Bypass über Config-Mock, optionales @smoke-Set) · NSwag-Client aus OpenAPI (generiert = nie editieren, coverage-/lint-exkludiert) · Core-Services (Notifications, Error-Interceptor, Loading, Downloads, Dates) · Shared-UI (TinaTable, FilterBar, ConfirmService, PageHeader, EmptyState).Vitest 47/47 · 98 % Lines Playwright 8/8 NSwag + experimentalDecorators
-
Phase 2 · 2026-07-03
Ein End-to-End-Meilenstein
Genau einen komplexen Bereich komplett fertig bauen — Liste, Detail, Wizards, Aktionen, Export — inklusive Definition of Done. Das etabliert Muster und DoD für alles Weitere.
Auftragsübersicht Ende-zu-Ende DoD als Muster für alle Bereiche
-
Phase 3 · 2026-07-03–05
Portierungs-Rezept
Reihenfolge: Quick Wins zuerst, Muster wiederholen, der größte Brocken zuletzt. Je Bereich eine feste Checkliste: Legacy lesen → Gerüst → Data-Layer → UI → Texte → Tests → DoD → abhaken.
reports → maildomaene → btmappings → zwg produkttypen → produktuebersicht → communication stammdaten + netzsegmente
Agentic Practice
Design-Auswahl, NSwag-Generierung, Scope-Entscheidungen: Der Mensch entscheidet, der Agent baut. Das Design-Gate liegt vor jeder View-Portierung.
Nach jedem Bereich ein Meldepunkt an den User, manuelle Validierung am Dev-Server — statt einer großen Enthüllung am Ende.
Commits macht der User. Das hält die Kontrolle über den Verlauf dort, wo sie hingehört.
Das Legacy-Frontend hatte ~1 % Tests. Das Sicherheitsnetz entsteht in der neuen App: 80 % Line-Coverage, sonst bricht der Build.
Playwright mit page.route auf alle /rest/**-Calls:
deterministisch ohne Backend; ein optionales @smoke-Set läuft gegen echtes BFF +
Keycloak.
13 prüfbare Regeln, u. a. Standalone + Signals, kein any,
Smart/Dumb-Trennung, Dateigrößen-Limits — nachprüfbar, nicht nur Appelle.
Je Bereich inklusive fachlicher Paritäts-Checkliste gegen die Legacy-Views — „fertig" heißt funktionsgleich, getestet und abgenommen.
Plan-Checkliste, Zwischenberichte, Session-Memory. Lektion: Drei Bereiche waren codiert, aber nirgends verzeichnet — die Inventur gegen das Legacy-Verzeichnis brachte es ans Licht.
Bei jeder Unklarheit stoppen und den User fragen, statt zu raten — billiger als ein falsch geratenes Verhalten.
Coding Hardness — die Härtefälle, die wirklich wehtun
-
1 Falle
Blob-Falle im Error-Interceptor. NSwag requestet alles als
blob—error.errorwar ein Blob, nie einTinaErrorDTO. Die Unit-Tests waren grün, weil sie JSON direkt flushten. Fix: Blob-Body parsen und diecauses(ErrorHelper) mit anzeigen. -
2 Backend
Backend-NPE-Pflichten. Sortierung und Sortierfeld sind Pflicht mit exakten Werten (
"Descending", nichtDESC) — sonst NullPointerException im Backend. Solche Pflichten stehen nur im Legacy-Code, nicht in der OpenAPI. -
3 Falle
Plain-Object-Falle. Suchergebnis-Items sind Plain Objects — ohne
DTO.fromJS()-Normalisierung crashttoJSON()am verschachtelten Vertragspartner. Generierte Clients sind keine Garantie. -
4 Lint
Native-Event-Kollisionen. Outputs wie
searchodertogglekollidieren mit nativen DOM-Events (ESLintno-output-native) —searchChangeundzelleTogglewaren die Lösung. -
5 Builder
vi.mock-Hoisting vs. Angular-Builder.
vi.mock-Factories brechen unter dem Builder (Hoisting) — die Lösung war ein DI-Token (AUTO_LOGIN_GUARD) statt Mock-Factories. -
6 zoneless
zoneless-Falle.
computed()auf Formularwerten ist nicht reaktiv — Ableitungen laufen übertoSignal(form.valueChanges)und werden als Inputs gereicht. -
7 Tooling
Playwright-Fallen. npm schluckt
--(webServer-Command brauchtnpx ng serve --port 4300), undworkers: 1verhindert parallele goto-Timeouts gegen den lokalen Dev-Server.