kundenportal-demo · Konzept

Architektur — Ist-Stand des Portals#

Stand: 2026-09-30 · Beschreibt den Ist-Stand des Codes (Phase 1 bis 4 abgeschlossen, Release v0.4.0), nicht die Zielarchitektur. Kennzeichnung: [B] belegt (offizielle Quelle oder Messung), [A] Annahme, [E] Einschätzung.

Fachbegriffe sind in jedem Abschnitt beim ersten Vorkommen mit dem Glossar verlinkt (Erklärung und Entsprechung außerhalb von AWS).

Die Zielarchitektur steht in Machbarkeit & Kosten; diese Seite zeigt, was davon tatsächlich gebaut ist:

Wie der Kontoinhaber das Ganze aufbaut, steht in der Anleitung Fundament und der Anleitung Anwendung.

1. Überblick#

Anfrage- und Ereignisfluss (Stand Phase 2)
NutzerBrowsernur Cookies,keine TokensRandCloudFronteine Domain,TLS-Zertifikataus us-east-1EinstiegShell und ZonenNext.jsstandalone,Function URLsmit OACS3/_next/static/*,/widgets/*API GatewayHTTP API /api/*,JWT, Scopes,10/20Upload-BucketPresigned PUTDiensteCognitoManaged Login,Pre-Token-LambdacustomerGET/PATCH /mecontract,consumption,documentsAPI-Funktion +Worker jeServicenotification-APIGET/PATCH/notificationsEreignisseEventBridgeBuskundenportal,Standard-Bus(S3), SchedulerWirkungWorker (direkt)Retry-Policy,DLQ, AlarmSQS →notificationPostfach,Hinweis an denInhaberDynamoDBeine Tabelle,provisioned 5/5
Daten als Tabelle
SchichtKomponente
NutzerBrowser (nur Cookies, keine Tokens)
RandCloudFront (eine Domain, TLS-Zertifikat aus us-east-1)
EinstiegShell und Zonen (Next.js standalone, Function URLs mit OAC)
EinstiegS3 (/_next/static/*, /widgets/*)
EinstiegAPI Gateway (HTTP API /api/*, JWT, Scopes, 10/20)
EinstiegUpload-Bucket (Presigned PUT)
DiensteCognito (Managed Login, Pre-Token-Lambda)
Dienstecustomer (GET/PATCH /me)
Dienstecontract, consumption, documents (API-Funktion + Worker je Service)
Dienstenotification-API (GET/PATCH /notifications)
EreignisseEventBridge (Bus kundenportal, Standard-Bus (S3), Scheduler)
WirkungWorker (direkt) (Retry-Policy, DLQ, Alarm)
WirkungSQS → notification (Postfach, Hinweis an den Inhaber)
WirkungDynamoDB (eine Tabelle, provisioned 5/5)

Ablauf in Worten (Kern aus Phase 1): Der Browser spricht nur mit CloudFront unter kundenportal-demo.rypox.com. CloudFront verteilt nach Pfad: /_next/static/* aus einem privaten S3-Bucket, /api/* an das API Gateway, alles andere an die Shell — den Next.js-Server in einer Lambda mit dem Lambda Web Adapter und Response Streaming. Die Shell leitet zur Anmeldung an Cognito (Managed Login) weiter und ruft die API serverseitig mit dem Access Token auf. Der Dienst customer legt beim ersten Aufruf von GET /me das Profil an und veröffentlicht CustomerRegistered auf dem eigenen EventBridge-Bus. Eine Regel legt das Ereignis in eine SQS-Queue; der notification-Konsument schreibt daraus eine Willkommensnachricht ins Postfach (DynamoDB) und schickt dem Inhaber einen Hinweis per SNS-E-Mail.

Phase 2 ergänzt: Pfade unter /vertraege und /verbrauch gehen an eigene Zonen-Lambdas (Architektur: Zonen und Frontend); drei weitere Services reagieren auf Ereignisse, ohne Queue direkt von EventBridge aufgerufen (Abschnitt 6); der Browser lädt Dateien mit einer Presigned URL direkt in einen Upload-Bucket.

Vier CloudFormation-Stacks, alle mit Tag project=kundenportal-demo; Aufteilung und Lebensdauer in Abschnitt 7a. Outputs: PortalUrl und DistributionDomain (Ziel des CNAME) am Edge-Stack, UserPoolId und ManagedLoginUrl am Base-Stack.

2. Anmeldung#

Die Shell ist ein BFF: Tokens verlassen den Server nie.

Sprache der Anmeldeseiten: Die Shell übergibt an /oauth2/authorize lang (Cognito) und ui_locales (OIDC-Standard) mit de oder en. Laut AWS-Dokumentation gilt [B, ebenda]:

3. Mandant im Token#

Ein Pre-Token-Generation-Trigger (Ereignisversion 2) ergänzt das Access Token um:

Claim Quelle
tenant_id Attribut custom:tenant_id (unveränderlich, nur die Plattform setzt es); fehlt es, gilt der Mandant owner. Seit Phase 4 tragen Konten eines Pass-Mandanten dessen Kennung, und der Trigger lehnt Anmeldungen zu nicht mehr nutzbaren Pässen ab
email nur wenn email_verified = true
locale Attribut locale, falls gesetzt
name Attribut name, falls gesetzt

Die Dienste lesen nur diese Claims und sub aus dem vom API Gateway bereits geprüften Token (packages/service-kit). Sie kennen Cognito nicht; ein anderer OIDC-Anbieter (z. B. Auth0 mit einer Action) muss nur dieselben Claims ausstellen. Der Mandant kommt nie aus der URL.

4. Scopes aus dem API-Vertrag#

Der OpenAPI-Vertrag (packages/api-contract/openapi.yaml) nennt je Operation den nötigen Scope. Die CDK-App liest ihn und erzeugt daraus

Operation Pfad Scope Service
getMe, updateMe GET/PATCH /me profile.read / profile.write customer
listNotifications, markNotificationRead GET /notifications, PATCH /notifications/{id} notifications.read / notifications.write notification
listContracts, getContract, updateContract GET /contracts, GET/PATCH /contracts/{id} contracts.read / contracts.write contract
listMeterReadings, submitMeterReading GET/POST /contracts/{id}/readings readings.read / readings.write consumption
getDataUsage GET /contracts/{id}/usage readings.read consumption
listDocuments, createUploadUrl GET /documents, POST /documents/upload-url documents.read / documents.write documents
createInvitation, listPasses, revokePass POST /tenancy/invitations, GET /tenancy/passes, POST /tenancy/passes/{id}/revoke tenancy.admin (zusätzlich Gruppe owner) tenancy
getOwnPass GET /tenancy/pass tenancy.read tenancy
getRedeemChallenge, redeemInvitation GET /tenancy/challenge, POST /tenancy/redeem keiner (security: [], ohne Authorizer) tenancy

Fehlt ein Scope, antwortet das API Gateway mit 403, bevor eine Lambda läuft. Die beiden öffentlichen Tenancy-Operationen sind die einzigen Routen ohne JWT; sie schützen sich selbst (ALTCHA, Begrenzung je IP, einmaliger Link). Die Shell fordert openid email profile und alle API-Scopes an (der SSM-Parameter /kundenportal/base/oidc-scopes enthält die Liste).

5. Daten#

Eine DynamoDB-Tabelle (Schlüssel PK/SK, provisioned 5/5, AWS-verwalteter Schlüssel) für alle Services. Jeder Partition Key beginnt mit dem Mandanten — mit einer begründeten Ausnahme (SCHEDULE#DATAVOLUME):

PK SK Besitzer Inhalt
TENANT#<t>#CUST#<c> PROFILE customer Profil (E-Mail, Anzeigename, Sprache, Herkunft)
TENANT#<t>#SUBJ#<sub> CUSTOMER customer welche Kundennummer zu einer Anmelde-Identität gehört
TENANT#<t>#SUBJ#<sub> MAILBOX notification eigene Projektion aus dem Ereignis: wessen Postfach eine Identität öffnet
TENANT#<t>#CUST#<c> MAILBOX notification Projektion: Sprache des Kunden für die Postfach-Texte (DE/EN)
TENANT#<t>#CUST#<c> NOTE#<id> notification Postfach-Einträge; <id> = Zeitstempel + eventId
TENANT#<t>#CUST#<c> CONTRACT#<sparte>#<contractId> contract Verträge je Sparte (Tarif, Option, Abschlag mit Spanne, Zähler, Version)
TENANT#<t>#SUBJ#<sub> CONTRACTS contract Projektion aus CustomerRegistered: Identität → Kunde
TENANT#<t>#CONTRACT#<contractId> CONSUMPTION consumption Projektion aus ContractChanged mit Versionsschutz
TENANT#<t>#CONTRACT#<contractId> READING#<readAt>#<readingId> consumption Zählerstände, sortiert nach Ablesedatum
TENANT#<t>#CONTRACT#<contractId> USAGE#<yyyy-mm> consumption Merker: Datenvolumen-Warnung für diesen Monat verschickt
TENANT#<t>#SUBJ#<sub> CONSUMPTION consumption Projektion aus CustomerRegistered
SCHEDULE#DATAVOLUME TENANT#<t>#CONTRACT#<contractId> consumption Mobilfunkverträge, die der tägliche Lauf prüft
TENANT#<t>#CUST#<c> DOC#<documentId> documents Dokument-Metadaten; die ID beginnt mit dem Zeitpunkt, der Sort Key ordnet also nach Datum
TENANT#<t>#SUBJ#<sub> DOCUMENTS documents Projektion aus CustomerRegistered

Der Abgleich mit dem geplanten Datenmodell steht im Fachkonzept §7.1.

6. Ereignisse und Services#

6.1 Weg zum Postfach (seit Phase 1)#

6.2 Services aus Phase 2#

Jeder Service besteht aus einer API-Funktion (hinter dem HTTP API) und einem Worker (reagiert auf Ereignisse). Alle Geldbeträge sind ganze Cent; Ereignisse werden vor dem Veröffentlichen gegen die Schemas aus packages/events geprüft.

Service Fachlich Worker reagiert auf
contract Verträge je Sparte mit Tarif und Tarifoption; Kunden wählen den Abschlag in ganzen Euro zwischen 80 % und 150 % des berechneten Werts; Tarifoption wechseln CustomerRegistered → drei Demo-Verträge (Strom und Gas mit Zähler, Mobilfunk mit 20 GB), Beginn 180 Tage vor der Registrierung; MeterReadingSubmitted → Jahresverbrauch hochrechnen (ab 30 Tagen Abstand), Abschlag neu berechnen, bei Änderung InstallmentAdjusted
consumption Zählerstände mit Plausibilitätsprüfung (Vertrag aktiv und mit Zähler, Datum nicht in der Zukunft, weder Datum noch Wert unter dem letzten Stand); Datenvolumen für Mobilfunk (Demo-Werte: 40 % am Monatsanfang, linear bis 100 %) CustomerRegistered, ContractChanged → eigene Projektionen; täglicher EventBridge Scheduler 07:00 Europe/Berlin → bei 80 % DataVolumeThresholdReached, höchstens einmal je Vertrag und Monat
documents Dokumentliste; POST /documents/upload-url legt ein Dokument „pending" an und gibt eine Presigned PUT URL für genau diese Datei zurück (Typ und Größe signiert, 5 Minuten gültig, JPEG/PNG/PDF bis 5 MB) CustomerRegistered → Projektion; S3 „Object Created" → Größe prüfen, dann DocumentUploaded; unangekündigte oder abweichende Dateien werden gelöscht

6.3 Ereignisfluss#

Ereignis Quelle Ziel Zustellung Wirkung
CustomerRegistered customer notification Regel → SQS Willkommensnachricht, Hinweis an den Inhaber
CustomerRegistered customer contract, consumption, documents Regel → Worker direkt Demo-Verträge; Projektionen Identität → Kunde
ContractChanged contract consumption Regel → Worker direkt Vertragsprojektion; Mobilfunkvertrag in SCHEDULE#DATAVOLUME aufnehmen
ContractChanged contract notification Regel → SQS Bestätigung (nicht bei Demo-Verträgen)
MeterReadingSubmitted consumption contract Regel → Worker direkt Abschlag neu berechnen
MeterReadingSubmitted consumption notification Regel → SQS Bestätigung des Zählerstands
InstallmentAdjusted contract notification Regel → SQS neuer Abschlag im Postfach
Zeitplan 07:00 Scheduler consumption direkt (2 Wiederholungen, DLQ) Datenvolumen aller Mobilfunkverträge prüfen
DataVolumeThresholdReached consumption notification Regel → SQS Warnung im Postfach
S3 „Object Created" Upload-Bucket, Standard-Bus documents Regel → Worker direkt Upload prüfen
DocumentUploaded documents notification Regel → SQS Eingangsbestätigung

Folgeereignisse tragen IDs, die aus dem auslösenden Ereignis abgeleitet sind (UUID Version 8 aus einem SHA-256); eine erneute Zustellung erzeugt also dieselben IDs, und jeder Schritt bleibt idempotent.

6.4 Direktaufruf statt Queue#

Nur notification hat eine SQS-Queue. Die Worker von contract, consumption und documents ruft EventBridge direkt auf (asynchroner Aufruf). Grund sind die Kosten nach dem Free Plan [E]:

Die Zuverlässigkeit sichern stattdessen drei Stufen, je Service mit eigener DLQ und eigenem Alarm:

Stufe Einstellung
EventBridge kann nicht zustellen Retry-Policy am Regelziel: bis zu 8 Versuche, höchstens 24 h; danach DLQ
Worker wirft einen Fehler Lambda wiederholt asynchrone Aufrufe 2-mal (Ereignisse höchstens 6 h alt); danach On-Failure-Destination in dieselbe DLQ
Nachricht in einer DLQ Alarm …DlqNotEmpty (5 Minuten, Schwelle > 0) per SNS an den Inhaber; 14 Tage Aufbewahrung

Damit gibt es vier Alarme (notification, contract, consumption, documents). Ohne Queue fehlt die Stapelverarbeitung; bei Demo-Last spielt das keine Rolle [E].

6.5 Uploads#

Der Upload-Bucket liegt im dauerhaften Stack KundenportalBase, damit Uploads eine Pause der Anwendung überstehen:

7. Leitplanken#

Leitplanke Umsetzung
Laufzeit Node.js 24, arm64, 256 MB (Shell 1024 MB)
Kostendeckel Lambda Reserved Concurrency je Funktion: Worker und Trigger aus CDK-Kontext reservedConcurrency (Standard 2, 0 = gar nicht reservieren), API-Funktionen apiReservedConcurrency (Standard 5, seit Phase 4), Next.js-Funktionen (Shell, Zonen) webReservedConcurrency (Standard 10 seit v0.4.1, vorher 5); Stand v0.4.1: Base 4 × 2 + App-Worker 8 × 2 + API-Funktionen 8 × 5 + Next.js 4 × 10 = 104 (v0.4.0: 84, Phase 3: 52, Phase 2: 35, Phase 1: 10)
Kostendeckel API Throttling der Stage: 10 Anfragen/s, Spitze 20
Kostendeckel Datenbank provisioned 5/5 statt On-Demand
Logs eigene Log-Gruppen mit 3 Tagen Aufbewahrung; Reste löscht der Teardown
Abbau RemovalPolicy.DESTROY für Tabelle, User Pool, Bucket, Logs; cdk destroy hinterlässt nichts außer dem Bootstrap
Kennzeichnung Tag project=kundenportal-demo auf allem (CDK und Terraform)
Bewusst weggelassen kein VPC, kein NAT Gateway, kein ALB, kein RDS, keine WAF, kein Route 53, kein Secrets Manager

Hinweis zur Reserved Concurrency: AWS lässt höchstens „nicht reservierte Kontokapazität minus 100" reservieren [B: https://docs.aws.amazon.com/lambda/latest/dg/configuration-concurrency.html]. Neue Konten haben oft ein Limit von 10 [B: https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html]; dann ist gar keine Reservierung möglich. Faustregel: Kontolimit ≥ 100 + Summe der Reservierungen, derzeit also ≥ 100 + 8 + 16 + 40 + 40 = 204; jeder weitere Worker erhöht den Wert um 2, jede weitere API-Funktion oder Zone um 5. Das Konto hat nach genehmigter Erhöhung ein Limit von 1.000 [B]. Weg bei zu kleinem Limit: Quotenerhöhung oder reservedConcurrency=0 (Anleitung Kapitel 4.5).

Die 20 Funktionen im App-Stack: acht API-Funktionen (customer, notification, contract, consumption, documents, migration, tenancy-API und die öffentliche Einlöse-Funktion von tenancy), acht Worker (customer-Worker, notification-Konsument, Worker von contract, consumption, documents, migration-Worker und -Record-Processor, tenancy-Worker), Shell und drei Zonen. Im Base-Stack vier: die drei Cognito-Trigger (Pre Token Generation, Migrate User, Post Authentication) und die Aufräum-Funktion der Pass-Mandanten (Abschnitt 11).

Zusätzlich legt CDK Hilfs-Lambdas an (Kopieren der statischen Dateien nach S3, Leeren des Buckets beim Löschen, regionsübergreifende Werte zwischen den zwei Stacks). Sie laufen nur beim Deploy bzw. Abbau und haben keine Reserved Concurrency [E].

7a. Stacks und Lebensdauer#

Stack Region Inhalt Lebensdauer
KundenportalCertificate us-east-1 TLS-Zertifikat für CloudFront dauerhaft
KundenportalBase eu-central-1 Cognito (User Pool, Client, Trigger), DynamoDB, Upload-Bucket, Hinweis-Topic; seit Phase 4 die Mandanten-Rolle für Token Vending, die Zeitplangruppe kundenportal-passes und Custom::PassTenantCleanup dauerhaft — Nutzer, Daten, Uploads (bis zu 7 Tage), Pass-Mandanten und bestätigtes Abo bleiben
KundenportalApp eu-central-1 Services mit Workern, Shell- und Zonen-Lambdas, HTTP API, EventBridge-Bus und -Regeln, Scheduler, SQS, DLQs mit Alarmen wird bei einer Pause abgebaut
KundenportalEdge eu-central-1 CloudFront mit Verhalten für Shell, Zonen, /api/*, /_next/static/*, /widgets/*; statische Dateien und Widget; Aufrufrechte für Shell und Zonen dauerhaft — Domain und DNS-Eintrag ändern sich nie

Die Stacks tauschen Werte über SSM-Parameter (/kundenportal/base/…, /kundenportal/app/…) statt über CloudFormation-Exports aus; dadurch lässt sich KundenportalApp jederzeit abbauen und neu anlegen. deploy.sh aktualisiert KundenportalEdge nach jedem App-Deploy mit --force, damit dieselbe Distribution auf die neuen Ursprünge zeigt. Nur ein Vollabbau entfernt auch Edge, Base und Zertifikat — danach ist ein neuer DNS-Eintrag nötig.

8. Pipelines#

Was Werkzeug Wer löst aus AWS-Zugang Freigabe
Prüfen (Format, Lint, Typen, Tests, Build, Synth) GitHub Actions CI jeder Push und Pull Request keiner —
Anwendung aufbauen GitHub Actions Deploy → scripts/deploy.sh (unbeaufsichtigt) Inhaber, manuell OIDC-Rolle kundenportal-github-deploy → CDK-Bootstrap-Rollen Environment production
Anwendung abbauen GitHub Actions Teardown → scripts/teardown.sh (Pause: nur App; Ende: alle Stacks, Log-Reste) Inhaber, Eingabe destroy dieselbe Rolle Environment production
DLQ-Weg prüfen GitHub Actions DLQ probe (ungültiges Ereignis) Inhaber, manuell dieselbe Rolle (events:PutEvents nur auf den eigenen Bus) Environment production
Fundament (OIDC, Rollen, Budget, SSM) GitLab CI im Projekt saas/kundenportal-demo/platform Push auf main → plan; apply per Klick OIDC-Rolle kundenportal-gitlab-foundation manueller Job
Fundament Erstlauf und Abbau Terraform lokal Inhaber aws login —
CDK-Bootstrap cdk bootstrap lokal Inhaber, einmalig aws login —

Beide CI-Rollen tragen die Permissions Boundary kundenportal-ci-boundary. Die GitLab-Rolle darf Rollen nur mit dieser Boundary anlegen oder ändern und die Boundary selbst nie anfassen; Änderungen daran macht nur der Inhaber lokal. Die GitHub-Rolle vertraut nur dem unveränderlichen Subject repo:janpfeil@5345175/kundenportal-demo@1395090655:environment:production (Besitzer- und Repository-ID statt Name, damit ein umbenanntes oder neu angelegtes Repository gleichen Namens die Rolle nicht übernehmen kann), die GitLab-Rolle nur project_path:saas/kundenportal-demo/platform:ref_type:branch:ref:main.

9. Messwerte#

Gemessen beim ersten Durchstich am 29./30.09.2026 und mit dem Stand von Phase 2 am 30.09.2026 (Quelle: Zusammenfassungen der GitHub-Actions-Läufe, CloudFormation-Ereignisse, curl und der Playwright-Lauf gegen die Live-Umgebung).

Messgröße Wert Gemessen am Anmerkung
Build inkl. Synth (GitHub Actions) 32 s 29.09.2026 BUILD_SECONDS
Zertifikats-Stack (us-east-1), erster Aufbau 1.144 s 29.09.2026 fast nur Warten auf den DNS-Eintrag des Inhabers
Anwendungs-Stack, erster Aufbau 343 s 29.09.2026 cdk deploy, ohne DNS-Wartezeit
davon CloudFront-Anlage 222 s 29.09.2026 CloudFormation-Ereignisse
Update-Deploy (neuer Shell-Code) 72–83 s 29./30.09.2026 Stack 46 s
Kaltstart Shell (erster Seitenaufruf) 1,6 s 29.09.2026 curl direkt nach dem Deploy, inkl. CloudFront-Miss
Seitenaufruf warm 0,05–0,07 s 30.09.2026 curl, Startseite
Erstanmeldung → Willkommensnachricht 1,9 s / 3,3 s 30.09.2026 Playwright, ab Anzeige von „Mein Konto" (zwei Läufe)
ungültiges Ereignis → DLQ 201 s 30.09.2026 drei Zustellversuche à 60 s Sichtbarkeit
Pause (teardown.sh, nur App) 143 s 30.09.2026 GitHub Actions; Domain liefert währenddessen 403
Neuaufbau nach Pause 328 s 30.09.2026 Build 32 s, Kern 191 s, Edge 105 s; keine DNS-Änderung
Vollabbau (teardown.sh --all) 437 s 30.09.2026 App, Edge, Base, Zertifikat
Neuaufbau nach Vollabbau 610 s 30.09.2026 Build 33 s, Kern 322 s, Edge 255 s; danach neuer Portal-CNAME (30 s bis sichtbar)
erster cdk destroy (ein Stack, alte Aufteilung) 243 s 29.09.2026 vor der Aufteilung in vier Stacks
Deploy mit den Services aus Phase 2 484 s 30.09.2026 Build 42 s, Kern 302 s, Edge 140 s
Deploy nur der Zonen (lokal) 212 s 30.09.2026 Zonen und Frontend §7
Erstanmeldung → Willkommensnachricht, kaltes System 7,3 s 30.09.2026 Playwright gegen ein kaltes System; mehr Kaltstarts als in Phase 1 (1,9 s / 3,3 s)
Pause mit Phase 3 (Abbau App-Stack) 257 s 30.09.2026 GitHub-Workflow Teardown; Portal antwortet währenddessen 403
Neuaufbau mit Phase 3 464 s 30.09.2026 17 App-Funktionen, 3 Cognito-Trigger; gleiche Distribution, keine DNS-Änderung
Neuaufbau nach Pause (v0.4.1) 497 s 30.09.2026 Edge zurück vom Pausenmodus auf die neuen Ursprünge; keine DNS-Änderung
Pause mit Pausenseite (v0.4.1) 410 s 30.09.2026 GitHub-Workflow Teardown: erst Edge in den Pausenmodus, dann App-Stack; Portal antwortet währenddessen mit der Seite „Die Demo pausiert gerade“ (503), /api/* mit Problem Details (503)
E2E gesamt (16 Journeys inkl. J2, J3, J7, J8) 1,8 min 30.09.2026 warm; direkt nach dem Neuaufbau brauchte J4 länger als die 5 s der Prüfung (Wartezeit auf 30 s erhöht)
Migrations-Journeys allein (9 Schritte) 1,3 min 30.09.2026 lokal gegen live, inkl. zweimal Demo-Reset, Bulk-Import beider Altsysteme und Redrive

Befunde beim ersten Deploy, jetzt im Code berücksichtigt: GitHub signiert OIDC-Tokens mit unveränderlichen IDs (repo:owner@id/name@id), die Vertrauensstellung prüft dieses Format; Function URLs brauchen seit 10/2025 zusätzlich lambda:InvokeFunction; das Lambda-Paket der Shell muss die pnpm-Symlinks behalten (eigenes Zip statt CDK-Kopie).

10. Altsysteme und Migration (Phase 3)#

Zwei simulierte Altsysteme auf eigenem Server, Übernahme der Kundenkonten per Migrate-User-Trigger (J2) und Bulk-Import mit DLQ und Redrive (J7), Dublettenerkennung und Account-Linking (J3) sowie das Migrations-Cockpit (J8) beschreibt die eigene Seite Architektur: Altsysteme und Migration.

11. Mandanten und Demo-Pass (Phase 4)#

Jeder eingeladene Besucher bekommt einen eigenen Mandanten im Bridge-Modell: geteilte Lambdas, API und Bus; eigene Tabelle kp-tenant-<kennung>, eigener Altsystem-Datenstand, eigenes Upload-Präfix und eigene Konten.

Einrichtung ≈ 10 s, Rückbau ≈ 10 s nach Ablauf, E2E 25/25 grün [B: 30.09.2026, v0.4.1]. Einzelheiten, Messwerte und offene Punkte: Architektur: Mandanten und Demo-Pass; die Seiten in Shell und Cockpit: Zonen & Frontend §8.

Quellen#