Ein Wochenbericht kann plausible Zahlen enthalten und trotzdem für eine Entscheidung ungeeignet sein. Ein fehlender Support-Export oder ein alter CRM-Stand verändert, was der Bericht ehrlicherweise aussagen kann.
Ich habe eine kleine Berichts-Demo für MadeBy.Expert gebaut, um diese Zustände sichtbar zu machen. Sie nutzt synthetische Stände aus Abrechnung, CRM und Support, deterministische Berechnungen und einen Text aus einer Vorlage. In dieser Version gibt es keine Live-Integrationen und keine Aufrufe eines Sprachmodells.
Erst die Kennzahlen festlegen, dann den Bericht automatisieren
Das Beispiel unterscheidet den monatlich wiederkehrenden Umsatz vom in der Woche eingenommenen Umsatz. Die offene Pipeline ist der ungewichtete Wert offener Verkaufschancen, keine Umsatzprognose. Support-Kennzahlen unterscheiden zwischen offenen Tickets zum Zeitpunkt des Stands und Tickets, die im Berichtszeitraum gelöst wurden.
Jede Kennzahl enthält einen Quellverweis und eine Definition. Diese Angaben geben der prüfenden Person etwas Konkretes, das sie mit den Eingangsdaten abgleichen kann.
Für einen Workflow bei Kunden würde ich diese Definitionen vereinbaren, bevor die Quellsysteme angebunden werden.
Eine fehlende Quelle ist ein Zustand des Berichts
In der Browser-Demo können Sie zwischen vollständigen Quellen, fehlenden Support-Daten und veralteten CRM-Daten wechseln. Der Bericht behält die Kennzahlen, die er berechnen kann, lässt die nicht verfügbaren weg und hält einen Blocker fest. Einen fehlenden Wert ersetzt er nicht durch null.
Der endgültige Status ergibt sich aus dieser Liste der Blocker:
status: blockers.length ? "blocked" : "draft",
In diesem Beispiel sind alle drei Quellen für eine Freigabe erforderlich. Ein Stand gilt als veraltet, wenn er vor dem Ende des Berichtszeitraums oder mehr als 24 Stunden vor dem asOf-Zeitpunkt des Berichts erfasst wurde. Ein Zeitstempel in der Zukunft wird als ungültige Eingabe abgelehnt.
Das sind Entscheidungen für diesen Workflow. Ein täglicher Betriebsbericht bräuchte vielleicht ein engeres Aktualitätslimit; ein anderer Bericht wäre auch mit einer ausdrücklich optionalen Quelle nützlich. Die Schwellenwerte müssen mit der Person abgestimmt werden, die das Ergebnis nutzt.
Hier ist der tatsächliche Test, der alle drei Quellen und beide Fehlerfälle abdeckt. Er verwendet den eingebauten Test-Runner von Node und strikte Assertions. fixture() lädt die synthetischen Eingangsdaten für jeden Fall neu:
test("missing/stale sources are unavailable and block approval", () => {
for (const kind of ["billing", "crm", "support"])
for (const mode of ["missing", "stale"]) {
const input = fixture();
if (mode === "missing") delete input.sources[kind];
else input.sources[kind].capturedAt = "2026-09-12T08:00:00Z";
const r = buildReport(input);
assert.equal(r.status, "blocked");
assert.ok(r.blockers.some((b) => b.startsWith(kind + ":")));
assert.equal(
r.metrics.some((m) => m.sourceId === fixture().sources[kind].id),
false,
);
assert.throws(
() => approveReport(r, r.digest, "Demo reviewer"),
/Blocked/,
);
}
});
Die letzte Assertion ist entscheidend: Das Problem in der Ausgabe zu melden reicht nicht, wenn die Freigabefunktion den Bericht trotzdem annimmt.
Die Freigabe gilt für genau eine Version des Berichts
Die Implementierung berechnet einen SHA-256-Digest über den Berichtsinhalt, der wiederum einen Digest der Eingangsdaten enthält. Die prüfende Person gibt bei der Freigabe eines lokalen Exports den Digest des Berichts an. Die Freigabefunktion berechnet ihn neu und prüft, ob der Bericht noch ein Entwurf ohne Blocker ist:
export function approveReport(
report,
digest,
reviewer,
now = new Date().toISOString(),
) {
const { digest: stored, ...content } = report;
if (hash(content) !== stored || digest !== stored)
fail("Approval digest does not match the current report");
if (report.status !== "draft" || report.blockers.length)
fail("Blocked reports cannot be approved");
if (
typeof reviewer !== "string" ||
reviewer.trim().length < 2 ||
reviewer.length > 100 ||
/[\r\n]/.test(reviewer)
)
fail("A named reviewer is required");
return {
...report,
status: "approved",
approval: { reviewer: reviewer.trim(), at: now, digest },
};
}
Dabei ist hash SHA-256 über JSON.stringify(value), und fail wirft einen Fehler. Das ist ein Auszug aus dem lokalen Prototyp, kein eigenständiger Freigabedienst.
Wird der Bericht nach einer Änderung der Eingangsdaten neu erstellt, entsteht ein anderer Digest, sodass der vorherige Digest den neuen Bericht nicht freigeben kann. Die Tests verändern außerdem direkt eine berechnete Kennzahl und prüfen, dass die Freigabe den veränderten Inhalt ablehnt.
Dieser Ansatz hat Grenzen. Der Digest ist eine Konsistenzprüfung, keine Signatur und kein Nachweis, wer den Bericht geprüft hat. Der Name der prüfenden Person wird als Text übergeben; es gibt keine Authentifizierung und keine Berechtigungsprüfung. Auch die JSON-Serialisierung ist spezifisch für diese Implementierung und kein kanonisches Format für unabhängige Erzeuger.
Ein produktiver Freigabedienst müsste die Identität und die Berechtigungen der prüfenden Person feststellen, das Prüfereignis speichern und den Versand an die freigegebene Version binden. Diese Teile sind hier nicht umgesetzt.
Die Browserseite zeigt die Datenzustände und den Bericht. Das lokal ausführbare Beispiel übernimmt Freigabe und Export; keines von beiden verschickt einen Bericht automatisch.
Wo KI später passen könnte
Ein Sprachmodell könnte helfen, Kommentare aus geprüften Fakten zu formulieren. Das ist eine mögliche Erweiterung, keine umgesetzte Funktion dieser Demo. Die Berechnung der Kennzahlen, die Quellenprüfung und die Freigabegrenze würde ich unabhängig davon explizit halten, wie der Text entsteht.
Der aktuelle Prototyp trifft keine Aussage über Zeitersparnis bei Kunden, die Zuverlässigkeit von Live-Konnektoren oder die Qualität eines Modells. Das muss an einem tatsächlichen Workflow gemessen werden.
Probieren Sie die Demo aus, auch mit fehlender und veralteter Quelle.
Wenn Ihr Team einen ähnlichen Bericht von Hand zusammenstellt, beschreiben Sie den Workflow: welche Tools die Daten liefern, wie oft der Bericht gebraucht wird und wer ihn prüft. Dann können wir besprechen, ob ein kleiner bezahlter Pilot mit klaren Erfolgskriterien passt.