Skip to content

API-Evolution (Framework-Leitfaden)

Wie Handler, Schemas und Events sich weiterentwickeln koennen, ohne in Versions-Zoo zu verfallen. Kumiko liefert Client und Server zusammen aus — die meisten “klassischen” API-Versionierungs-Probleme treten gar nicht auf. Was uebrig bleibt ist schlank.

Grundannahme

Kumiko-Apps shippen Client + Server zusammen. Die Mobile-App gehoert zur gleichen Deployment-Einheit wie der Server. Damit:

  • Es gibt keine externen API-Clients die das Framework bedienen muss
  • Wenn jemand eine externe API will, baut er die als eigenes Feature — mit seinen eigenen Versions-Regeln. Nicht Aufgabe des Frameworks.
  • Die verbleibenden Evolution-Probleme sind interne: Refactoring, Aufraeumen, Long-Tail-Updates.

Dieses Dokument beschreibt die fuenf Werkzeuge die fuer genau diese internen Probleme Sinn machen. Nicht mehr.

1. Additive Aenderungen — ohne Ceremony

Der Regelfall. 95% der Schema-Aenderungen sind additiv:

// Vorher
r.writeHandler("order.create", z.object({ customerName: z.string() }), ...);
// Nachher — einfach Feld dazu
r.writeHandler("order.create", z.object({
customerName: z.string(),
notes: z.string().optional(), // NEU
}), ...);

Was additiv ist:

  • Neues optionales Feld im Input
  • Neues Feld im Output (Client ignoriert unbekannte Felder)
  • Neuer Handler
  • Neue Entity
  • Neues Event
  • Erweiterte Validierung die bisherige gueltige Werte weiterhin akzeptiert

Kein Marker, keine Version, keine Migration. Framework erkennt additive Aenderungen als ok.

2. Boot-Time Breaking-Change-Detection (opt-in Sicherheitsnetz)

Fuer Apps die einen Baseline-Schnappschuss ihrer API pflegen:

kumiko.config.ts
schemaBaseline: "schema-baseline.json",

Beim Boot vergleicht das Framework das aktuelle Registry-Schema mit der Baseline-Datei:

DiffReaktion
Additive AenderungInfo-Log, Baseline-Update-Hinweis
Breaking AenderungBoot-Fehler mit Liste was genau breaking ist

Beispiel-Output:

BREAKING CHANGES detected vs schema-baseline.json:
order.create:
- Field "customerName" removed (was required)
- Field "customer.name" is now required (was optional)
If these changes are intentional:
1. Update affected clients (or use Deprecation-Marker for old field)
2. Regenerate baseline: yarn kumiko schema baseline-update

Nutzen: im CI sichtbar, bevor Code-Review fertig ist. Entwickler sieht “ups, das wollte ich nicht breaking machen”.

Opt-in — nicht jedes Projekt will das pflegen.

3. Deprecation-Marker

Fuer den Fall wo du etwas aufraeumen willst, aber nicht sofort wegwerfen:

r.writeHandler("order.create", schema, handler, {
deprecated: {
since: "2026-04-01",
until: "2026-10-01", // geplantes Entfern-Datum
replacedBy: "order.submit", // optional, fuer Report
reason: "Umbenennung zu konsistenter Nomenklatur",
},
});

Wirkung:

  • Response-Header X-Kumiko-Deprecated: true; until=2026-10-01; replacedBy=order.submit
  • Log-Warning bei jedem Aufruf (rate-limited, nicht pro Request)
  • Report-Handler meta.deprecated.usage:
[
{ handler: "order.create", lastUsed: "2026-04-14T10:00:00Z", calls7d: 142, distinctUsers: 12, until: "2026-10-01" },
...
]

→ Operator sieht am Stichtag “wer nutzt das noch” und entscheidet ob’s jetzt wirklich weg kann.

Der Handler wird einfach entfernt wenn das Datum da ist. Kein v1/v2-Parallelbetrieb noetig.

4. Min-Client-Version-Gate — Hebel fuer Long-Tail

Nicht fuer “frisch deployed und alte Apps aussperren”, sondern fuer “nach 6 Monaten koennen wir endlich v1-Support droppen”.

kumiko.config.ts
clientVersions: {
minimum: "1.5.0", // strikter Cut-Off
recommended: "2.0.0", // Warning-Hinweis
}

Flow:

Client sendet Header: X-Client-Version: 1.3.0
Server: 426 Upgrade Required
Body: { minVersion: "1.5.0", currentVersion: "1.3.0", reason: "..." }
→ Client-UI zeigt Update-Screen
Client sendet Header: X-Client-Version: 1.7.0
Server: OK
Response-Header: X-Kumiko-Client-Status: outdated-warning; recommended=2.0.0
→ Client-UI zeigt Banner "Update verfuegbar"
Client sendet Header: X-Client-Version: 2.1.0
Server: OK, keine Warnungen

Einsatz-Szenarien (alle Monate nach initialer Aenderung):

  • “6 Monate sind rum, v1 droppen” → Gate umlegen
  • “v1.2 hat einen Bug, Mindestversion v1.3” → Gate
  • “Compliance verlangt neue UI → Mindestversion v2.0”

Ohne Mobile-App braucht’s das Gate gar nicht — Web-App kriegt den Refresh bei jedem Deploy.

5. Event-Schema-Version in Outbox

Das einzige Framework-interne Cross-Version-Szenario: Outbox-Events haben Zeit-Puffer. Ein Event kann 5 Minuten (oder laenger bei Dead-Letter) in der Outbox liegen, bevor ein Subscriber es verarbeitet. Wenn dazwischen deployed wurde, kann Subscriber v2 sein und das Event noch v1-Format.

Loesung: jeder Event-Payload traegt schemaVersion:

{
"type": "order.created",
"schemaVersion": 1,
"data": { "orderId": "...", "customerName": "..." }
}

Subscriber koennen:

  • Additiv-kompatibel: unbekannte Felder ignorieren, alte Version akzeptieren
  • Strict: bei Unterschied ablehnen → Event geht ins Dead-Letter, Operator-Entscheidung

Default-Verhalten: Framework-Subscriber sind additiv-tolerant. Feature-Autor kann strict setzen wenn wichtig.

Bump der schemaVersion bei wirklich breaking-Changes am Event-Payload. Additive Aenderungen: gleiche Version, Subscriber ignoriert neue Felder.

Was NICHT im Scope ist

  • Parallel-Versionen im selben Handler-Namen (order.create v1 + v2 gleichzeitig). Wenn wirklich mal gebraucht: zwei Handler mit verschiedenen Namen (order.create + order.submit). Kein Framework-Magic noetig.
  • Schema-Auto-Migration beim Request (v1-Request wird zu v2 transformiert). Zu komplex, Fehlerquelle, praktisch ueberfluessig.
  • Auto-Version-Negotiation via Accept-Header / URL-Segment. Gibt’s in externen-API-Frameworks — Kumiko braucht’s nicht, weil keine externen Clients.
  • Externe-API-Versionierung ueberhaupt. Wenn eine Kumiko-App eine externe HTTP/REST/GraphQL-API anbieten will: eigenes Feature, mit eigener Versions-Logik. Nicht Framework-Aufgabe.

Beispiel: Typischer Deprecation-Zyklus

Woche 0: Umbenennung beschlossen. order.create wird zu order.submit.
- order.submit neu geschrieben (Kopie + Aufraeumen)
- order.create bekommt deprecated-Marker: until "in 6 Monaten"
- Client-Code nutzt bereits order.submit fuer alle neuen Aufrufe
- order.create bleibt voll funktional
Woche 4: Mobile-App v2.0 released, nutzt order.submit
- Adoption laeuft, User updaten
Woche 20: Report zeigt: 98% nutzen order.submit, nur 12 Aufrufe/Woche zu order.create
- Entscheidung: "duerfte egal sein" ODER "lassen wir noch 4 Wochen"
Woche 24: order.create entfernt
- Client auf v1.x sendet → 404, weiss aber schon dass er veraltet ist via X-Kumiko-Client-Status
- Min-Version-Gate optional auf v2.0 gesetzt: alle verbliebenen User kriegen Update-Prompt

Kein Parallel-Betrieb, keine Versions-Zoo, keine Migration. Nur: additiv, deprecated markieren, warten, wegnehmen.

Framework-Ausbau

AusbauWarum
deprecated-Option auf Handler-DefinitionMarker-System
Response-Header-Injection bei deprecated-CallClient-seitige Sichtbarkeit
Report-Handler meta.deprecated.usageOperator-Sicht
Breaking-Change-Detection + Baseline-ToolDev-Sicherheitsnetz (opt-in)
X-Client-Version-Header-Parsing + Gate-MiddlewareMin-Version-Gate
Event-Payload-Wrapper mit schemaVersionOutbox-Kompatibilitaet
CLI: yarn kumiko schema baseline-updateDev-Flow

Alles klein, additiv zum bestehenden Framework.

Tests

Unit / Integration

  • Additive Schema-Aenderung → gruen im Baseline-Check
  • Breaking-Change → Boot-Fehler mit klarer Message
  • Deprecated-Handler-Call → Response hat X-Kumiko-Deprecated-Header
  • Deprecated-Report zeigt letzten Aufruf, Count, User-Anzahl
  • Client mit Version unter Min → 426 mit strukturierter Response
  • Client mit Version zwischen Min und Recommended → 200 mit Warning-Header
  • Event mit schemaVersion=1 landet in Subscriber der v2 erwartet — additiv-tolerant geht durch, strict landet im Dead-Letter

Sample

Sample demonstriert Deprecation-Zyklus: altes Feld markieren, Report ansehen, nach Ablauf entfernen.

Build-Reihenfolge

  1. deprecated-Option auf Handler + Response-Header
  2. Deprecation-Report-Handler
  3. Schema-Baseline-Tool + Boot-Check (opt-in Config)
  4. X-Client-Version-Header + Gate-Middleware
  5. Event-Payload-Versioning
  6. Docs + Sample-Zyklus