Es gibt zwei Arten von Changelogs.
Die erste wird aus Commit-Messages generiert. Darin stehen Zeilen wie fix: handle null in resolver und chore: bump deps. Streng genommen ist das eine vollständige Liste aller Änderungen, und kein Nutzer hat sie je ein zweites Mal gelesen.
Die zweite ist für die Person geschrieben, die dein Produkt benutzt. Sie sagt, was jetzt geht und letzte Woche noch nicht ging. Sie ist kurz. Leute abonnieren sie.
Der Unterschied liegt nicht im Tooling. Er liegt darin, dass jemand entschieden hat: Der Changelog gehört zum Produkt.
Gib jedem Eintrag einen Typ
Die Änderung mit der größten Hebelwirkung: Jeder Eintrag bekommt einen Typ. Kookee kennt sieben:
feature · fix · improvement · breaking · security · deprecated · other
Das ist keine Dekoration. Erst dadurch lässt sich der Changelog filtern, und erst dadurch nützt er mehr als einer Zielgruppe:
// Was ist neu – für Nutzer
const features = await kookee.changelog.list({
filter: { changelogType: 'feature' },
limit: 10,
});
// Was kaputtgehen wird – für Integratoren
const breaking = await kookee.changelog.list({ filter: { changelogType: 'breaking' } });
Ein Entwickler, der deine API anbindet, achtet auf breaking und deprecated und auf sonst nichts. Ein Nutzer achtet auf feature. Ein Security-Team will security auf einer eigenen Seite. Eine Liste mit Typen bedient alle drei, eine flache Liste keinen von ihnen gut.
Der Typ ist ein strukturiertes Feld und keine Spalte des Eintrags, und das spielt beim Rendern eine Rolle. entry.type ist der String 'changelog'; den Release-Typ holst du aus dem Array fields:
import { fieldOptionKey, fieldStringValue } from '@kookee/sdk';
const releaseType = fieldOptionKey(entry.fields, 'changelogType'); // 'feature'
const version = fieldStringValue(entry.fields, 'version'); // '1.6.0'
Gib jedem Eintrag eine Version
Ein Typ beantwortet die Frage „Was für eine Änderung ist das?“. Eine Version beantwortet „Habe ich sie schon?“, und genau das will ein Nutzer wissen, der über einen Support-Thread hierherkommt.
Versionen sind Freitext, also passt jedes Schema, das du verwendest: 1.6.0, 2024.11, v3-beta. Zwei Gewohnheiten machen sie wertvoll: Setz bei jedem Eintrag eine, und nutze für alle dasselbe Schema. Ein Changelog, in dem nur die Hälfte der Einträge eine Version hat, wirkt wie ein Versehen, und es ist auch eins.
Wenn jemand fragt, was in einem bestimmten Release kam, filterst du nach der exakten Version:
const release = await kookee.changelog.list({ filter: { version: '1.6.0' } });
Die Einträge kommen nach Datum zurück, die neuesten zuerst. Willst du stattdessen streng nach Version sortieren – und für eine Release-Seite willst du das wahrscheinlich, denn bei zurückportierten Patches und verschobenen Releases führt das Datum in die Irre –, dann sortier selbst. Eine String-Sortierung setzt 1.10.0 nämlich vor 1.9.0:
const { data } = await kookee.changelog.list({ limit: 100 });
const byVersion = [...data].sort((a, b) =>
(fieldStringValue(b.fields, 'version') ?? '').localeCompare(
fieldStringValue(a.fields, 'version') ?? '',
undefined,
{ numeric: true },
),
);
numeric: true sorgt dafür, dass 1.10.0 nach 1.9.0 kommt.
Lass Leute reagieren
Jeder Changelog-Eintrag nimmt Emoji-Reaktionen an:
await kookee.changelog.react(entryId, { reactionType: 'fire', action: 'add' });
Das sieht nach einer kleinen Social-Funktion aus. In Wahrheit ist es die günstigste Feedback-Schleife, die du je bauen wirst. Du lieferst zehn Dinge im Monat aus, siehst, welche zwei alle Reaktionen bekommen haben, und weißt, wofür du den nächsten Monat einsetzt. Den Nutzer kostet das einen Klick statt einer Umfrage.
Schreib den Eintrag mit dem Release
In der Praxis scheitert es nicht an schlechten Einträgen, sondern daran, dass sie eine Woche zu spät entstehen: aus dem Gedächtnis und alle auf einmal. Bis dahin weiß niemand mehr, warum die Änderung wichtig war, und am Ende steht doch wieder der Changelog aus Commit-Messages.
In Kookee entsteht der Entwurf eines Eintrags, solange der Pull Request noch offen ist, und veröffentlicht wird er, wenn das Release live geht: kein Deploy, kein Rebuild, kein Warten auf einen Static-Site-Generator. Schreib den Entwurf im Dashboard oder lass ihn von einem Coding-Assistenten schreiben, der über MCP verbunden ist. Der liest die letzten Einträge und schreibt den nächsten im selben Ton, mit Typ und Version, und du prüfst ihn.
Danach ist er überall, wo du ihn brauchst, nur einen Fetch entfernt:
const { data } = await kookee.changelog.list({ limit: 5 });
Deine Marketing-Website, das „Was ist neu“-Panel in deiner App, deine Release-Mail. Eine Quelle, einmal geschrieben, von der Person, die die Änderung tatsächlich gemacht hat.