Geviertstriche aus Text, Kommentaren und Doku entfernen

467 Stellen. Nicht durch einen anderen Strich ersetzt, sondern durch das
Satzzeichen, das an der jeweiligen Stelle richtig ist: Doppelpunkt, wo eine
Erlaeuterung folgt; Komma, wo der Satz weiterlaeuft; Punkt, wo zwei
Hauptsaetze aneinanderstiessen. Ein Halbgeviertstrich waere nur derselbe
Griff mit kuerzerem Strich gewesen.

Regelbasiert ersetzt und danach nachgeprueft, weil eine Regel allein nicht
reicht. Gefunden und einzeln korrigiert:

- Eingeschobene Saetze mit Strichpaar. Nur der oeffnende Strich passte ins
  Muster, der schliessende blieb als "—," stehen. Drei Stellen, jetzt mit
  Klammern oder als eigener Satz.

- Doppelte Doppelpunkte, wo beide Striche eines Paars zu Doppelpunkten wurden
  ("Globale Regeln: Schrift, Groessen, Abstaende: kommen aus HiveGrid").
  Sieben Stellen in Doku und Oberflaeche, jetzt in Klammern.

- Pfade, denen ein Komma statt eines Doppelpunkts folgte.

- Ausgerichtete Kommentartabellen, in denen der Strich eine Spalte war.

Nicht angefasst: drei Geviertstriche, die keine Prosa sind, sondern
Tabellenplatzhalter fuer "kein Wert" (Trichter, Auftraege, Kunden). Dort ist
der Strich die Angabe selbst; ihn zu entfernen liesse leere Zellen zurueck.

tsc, lint, build, verify:carbon und verify:layout laufen sauber.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
This commit is contained in:
dejanandClaude Opus 5 committed 2026-08-31 20:51:19 +02:00
1 parent e998231fed
commit 6a0b36ddcc
75 files changed
+471 -471

No files matched your search

+10 -10
View File
@@ -2,7 +2,7 @@
* Kennzahlen-Berechnungen.
*
* Alle Funktionen sind pure functions über dem gefilterten Datensatz
* (Anforderung INFRA-06) — die Entwicklung kann sie unverändert übernehmen
* (Anforderung INFRA-06): die Entwicklung kann sie unverändert übernehmen
* und lediglich die Datenquelle austauschen.
*
* Die Definition jeder Kennzahl steht in docs/KPI-KATALOG.md.
@@ -46,7 +46,7 @@ export function umsatz(rechnungen: Rechnung[], zeitraum: ZeitraumPreset): number
.reduce((summe, r) => summe + r.betrag, 0);
}
/** Gleiche Berechnung für die Vorperiode — Basis der Trend-Badges. */
/** Gleiche Berechnung für die Vorperiode: Basis der Trend-Badges. */
export function umsatzVorperiode(rechnungen: Rechnung[], zeitraum: ZeitraumPreset): number {
const fenster = vorperiode(zeitraum);
return rechnungen
@@ -54,7 +54,7 @@ export function umsatzVorperiode(rechnungen: Rechnung[], zeitraum: ZeitraumPrese
.reduce((summe, r) => summe + r.betrag, 0);
}
/** Beschriftung eines Buckets — eine Stelle fuer alle drei Zeitreihen. */
/** Beschriftung eines Buckets, eine Stelle fuer alle drei Zeitreihen. */
function bucketLabel(key: string, art: "tag" | "woche" | "monat"): string {
if (art === "monat") return formatMonatKurz(key);
if (art === "woche") return formatWoche(key);
@@ -171,7 +171,7 @@ export function zahlungsdauer(rechnungen: Rechnung[], zeitraum: ZeitraumPreset):
* Zusammensetzung des OFFENEN Bestands.
*
* Nicht zu verwechseln mit rechnungenNachStatus(): dort steht der kumulierte
* Umsatz aus zwei Jahren gegen den heutigen Forderungsbestand — dabei entfallen
* Umsatz aus zwei Jahren gegen den heutigen Forderungsbestand, dabei entfallen
* über 90 % auf "Bezahlt", und der Ring zeigt nichts mehr. Der offene Bestand
* ist ein echtes Ganzes: alles, was heute noch aussteht.
*/
@@ -205,13 +205,13 @@ export function auftraegeImZeitraum(auftraege: Auftrag[], zeitraum: ZeitraumPres
return auftraege.filter((a) => imFenster(a.angelegtAm, fenster));
}
/** "Aktiv" = beauftragt oder in Arbeit — das, was das Team gerade bindet. */
/** "Aktiv" = beauftragt oder in Arbeit: das, was das Team gerade bindet. */
export function aktiveAuftraege(auftraege: Auftrag[]): Auftrag[] {
return auftraege.filter((a) => a.status === "beauftragt" || a.status === "in_arbeit");
}
export function ueberfaelligeAuftraege(auftraege: Auftrag[]): Auftrag[] {
// Einen Termin gibt es erst ab der Beauftragung — eine offene Anfrage kann
// Einen Termin gibt es erst ab der Beauftragung, eine offene Anfrage kann
// nicht "über Termin" sein.
return auftraege
.filter(
@@ -264,7 +264,7 @@ export function umsatzNachGewerk(
* Verlorene Aufträge zählen nur bis zu ihrer letzten erreichten Stufe.
*/
/**
* Vertriebstrichter — bewusst nur über das Angebotsgeschäft.
* Vertriebstrichter: bewusst nur über das Angebotsgeschäft.
*
* Wartung, Notdienst und E-Check laufen ohne Angebot direkt in die Ausführung.
* Zählte man sie mit, würde der Trichter unten breiter als oben und die
@@ -335,7 +335,7 @@ export function neueKunden(kunden: Kunde[], zeitraum: ZeitraumPreset): number {
return kunden.filter((k) => imFenster(k.angelegtAm, fenster)).length;
}
/** Gleiches Fenster davor — Basis fuer den Trend an der Neukunden-Karte. */
/** Gleiches Fenster davor: Basis fuer den Trend an der Neukunden-Karte. */
export function neueKundenVorperiode(kunden: Kunde[], zeitraum: ZeitraumPreset): number {
const fenster = vorperiode(zeitraum);
return kunden.filter((k) => imFenster(k.angelegtAm, fenster)).length;
@@ -455,7 +455,7 @@ export interface AlertEintrag {
text: string;
detail: string;
art: "kritisch" | "warnung" | "hinweis";
/** Betrag, um den es geht — macht die Zeilen untereinander vergleichbar. */
/** Betrag, um den es geht: macht die Zeilen untereinander vergleichbar. */
betrag?: number;
/**
* Die Handlung, nicht die Beobachtung. Eine Liste ohne Verb ist ein Bericht;
@@ -538,7 +538,7 @@ export function handlungsbedarf(daten: Datensatz): AlertEintrag[] {
*
* Bezugsgröße sind ausschließlich förderfähige Leistungen (Wärmepumpe, PV,
* Speicher, Lüftung). Über alle Aufträge gerechnet läge die Quote im
* einstelligen Bereich und wäre wertlos — eine Badwartung war nie förderfähig.
* einstelligen Bereich und wäre wertlos, eine Badwartung war nie förderfähig.
*/
export function foerderQuote(auftraege: Auftrag[]): {
quote: number;
+3 -3
View File
@@ -26,7 +26,7 @@ export const FILTER_RELEVANZ: Record<SeitenId, FilterFeld[]> = {
/**
* Setzt alle für die Seite irrelevanten Filter zurück, ohne sie im
* globalen State zu löschen — wechselt man die Seite, sind sie wieder da.
* globalen State zu löschen: wechselt man die Seite, sind sie wieder da.
*/
export function wirksameFilter(filter: FilterState, seite: SeitenId): FilterState {
const erlaubt = new Set(FILTER_RELEVANZ[seite]);
@@ -41,7 +41,7 @@ export function wirksameFilter(filter: FilterState, seite: SeitenId): FilterStat
}
/**
* Wendet die Dimensionsfilter an — bewusst OHNE Zeitfilter.
* Wendet die Dimensionsfilter an: bewusst OHNE Zeitfilter.
*
* Grund: Kennzahlen brauchen unterschiedliche Zeitbezüge (Umsatz im Zeitraum,
* offene Rechnungen dagegen stichtagsbezogen). Der Zeitraum wird deshalb
@@ -77,7 +77,7 @@ export function wendeFilterAn(daten: Datensatz, filter: FilterState): Datensatz
return { mitarbeiter, kunden, auftraege, rechnungen, zeiten };
}
/** Anzahl aktiver Einschränkungen — für das Badge am Filter-Button. */
/** Anzahl aktiver Einschränkungen, für das Badge am Filter-Button. */
export function anzahlAktiverFilter(filter: FilterState, seite: SeitenId): number {
const wirksam = wirksameFilter(filter, seite);
return (
+2 -2
View File
@@ -1,5 +1,5 @@
/**
* Der angemeldete Benutzer — im Prototyp eine Attrappe.
* Der angemeldete Benutzer, im Prototyp eine Attrappe.
*
* In HiveGrid Cloud kommt das aus der Sitzung (`requireMember`) und steht dem
* Loader zur Verfügung, bevor die Seite rendert. Hier ist es eine Konstante,
@@ -16,7 +16,7 @@ export const NUTZER = {
* Für die Anrede. In eckigen Klammern und nicht als erfundener Name:
* „Guten Tag, Dejan" sieht in einer Abnahme aus wie ein fest verdrahteter
* Wert, und irgendwann fragt jemand, warum dort immer derselbe Name steht.
* „[Vorname]" sagt stattdessen, was an dieser Stelle eingesetzt wird — beim
* „[Vorname]" sagt stattdessen, was an dieser Stelle eingesetzt wird: beim
* Einbau kommt er aus der Sitzung.
*/
vorname: "[Vorname]",
+10 -10
View File
@@ -3,7 +3,7 @@
*
* Bewusst deterministisch (fester Seed): Die Zahlen bleiben über Reloads,
* Screenshots und Abstimmungsrunden identisch. Für die echte Software wird
* diese Datei durch Entity-Builder-Queries ersetzt — das Interface `Datensatz`
* diese Datei durch Entity-Builder-Queries ersetzt, das Interface `Datensatz`
* bleibt gleich.
*
* Betriebsprofil (fiktiv):
@@ -32,7 +32,7 @@ import { HEUTE, addTage, toISO } from "../utils/dateUtils";
/* ------------------------------------------------------ Zufall mit Seed */
/** mulberry32 — kleiner, schneller PRNG mit reproduzierbarer Sequenz. */
/** mulberry32: kleiner, schneller PRNG mit reproduzierbarer Sequenz. */
function prng(seed: number) {
let a = seed;
return function random(): number {
@@ -177,7 +177,7 @@ function baueKunden(anzahl: number): Kunde[] {
umsatzGesamt: 0,
auftraegeGesamt: 0,
// Die meisten zahlen nahe am Zahlungsziel; ein kleiner Teil schleppt.
// Gleichverteilt wäre jeder zweite Kunde auffällig — das wäre kein Betrieb,
// Gleichverteilt wäre jeder zweite Kunde auffällig, das wäre kein Betrieb,
// sondern ein Inkassofall.
zahlungsmoralTage: gewichtet([
{ wert: zahl(5, 14), gewicht: 42 },
@@ -217,7 +217,7 @@ const WERT_SPANNEN: Record<string, [number, number]> = {
"E-Check": [140, 390],
};
/** Bezugsgröße der Förderquote — zentral in types.ts definiert. */
/** Bezugsgröße der Förderquote: zentral in types.ts definiert. */
const FOERDERFAEHIG = FOERDERFAEHIGE_KATEGORIEN;
/**
@@ -225,12 +225,12 @@ const FOERDERFAEHIG = FOERDERFAEHIGE_KATEGORIEN;
*
* Die Verteilung bildet einen realistischen Trichter ab:
* von 100 Anfragen werden rund 55 zum Angebot und rund 24 zum Auftrag.
* Verlorene Vorgänge merken sich, auf welcher Stufe sie abgesprungen sind —
* Verlorene Vorgänge merken sich, auf welcher Stufe sie abgesprungen sind,
* sonst zeigt der Trichter oben zu wenig und unten zu viel.
*/
function ergebnisFuerAlter(
tageAlt: number,
/** Große Vorhaben werden angeboten und oft verglichen — kleine kaum. */
/** Große Vorhaben werden angeboten und oft verglichen: kleine kaum. */
grossauftrag: boolean
): {
status: AuftragStatus;
@@ -297,7 +297,7 @@ function ergebnisFuerAlter(
/**
* Leistungsart innerhalb eines Gewerks.
* Wartung, Notdienst und E-Check sind im Alltag die häufigsten Aufträge —
* Wartung, Notdienst und E-Check sind im Alltag die häufigsten Aufträge,
* gleichverteilt zu ziehen würde den Durchschnittswert massiv verzerren.
*/
function kategorieFuer(gewerk: Gewerk): string {
@@ -451,7 +451,7 @@ function baueRechnungen(auftraege: Auftrag[]): Rechnung[] {
let bezahltAm: string | null = null;
if (gestellt > HEUTE) {
// Rechnung existiert noch nicht — z. B. Schlussrechnung eines laufenden Auftrags.
// Rechnung existiert noch nicht: z. B. Schlussrechnung eines laufenden Auftrags.
status = "entwurf";
} else if (ueberfaelligTage < 0) {
// Noch innerhalb des Zahlungsziels; ein Teil zahlt sofort.
@@ -473,7 +473,7 @@ function baueRechnungen(auftraege: Auftrag[]): Rechnung[] {
status = "ueberfaellig";
}
} else if (ueberfaelligTage <= 120) {
// Mahnstufe erreicht — der Großteil zahlt spätestens jetzt.
// Mahnstufe erreicht, der Großteil zahlt spätestens jetzt.
if (rnd() < 0.94) {
status = "bezahlt";
bezahltAm = toISO(addTage(faellig, zahl(-8, 70)));
@@ -489,7 +489,7 @@ function baueRechnungen(auftraege: Auftrag[]): Rechnung[] {
status = "ueberfaellig";
}
} else {
// Älter als sieben Monate: eingebracht oder ausgebucht — in beiden
// Älter als sieben Monate: eingebracht oder ausgebucht, in beiden
// Fällen steht die Forderung nicht mehr in der offenen Liste.
status = "bezahlt";
bezahltAm = toISO(addTage(faellig, zahl(-8, 150)));
+4 -4
View File
@@ -18,7 +18,7 @@ export const GEWERKE = [
] as const;
export type Gewerk = (typeof GEWERKE)[number];
/** Leistungsarten je Gewerk — Grundlage für "Umsatz nach Kategorie". */
/** Leistungsarten je Gewerk: Grundlage für "Umsatz nach Kategorie". */
export const KATEGORIEN: Record<Gewerk, string[]> = {
Heizung: ["Wärmepumpe", "Gastherme", "Heizkörper", "Wartung Heizung"],
Sanitär: ["Bad-Sanierung", "Rohrleitungen", "Armaturen", "Notdienst"],
@@ -65,7 +65,7 @@ export interface Kunde {
ort: string;
angelegtAm: string;
letzterAuftragAm: string | null;
/** Aggregiert aus Rechnungen — wird in seed.ts nachberechnet. */
/** Aggregiert aus Rechnungen: wird in seed.ts nachberechnet. */
umsatzGesamt: number;
auftraegeGesamt: number;
zahlungsmoralTage: number;
@@ -94,7 +94,7 @@ export const AUFTRAG_STATUS_LABEL: Record<AuftragStatus, string> = {
/**
* Leistungsarten, für die BAFA-/KfW-Förderung in Frage kommt.
* Bezugsgröße der Förderquote — sonst rechnet man Wartungsaufträge
* Bezugsgröße der Förderquote, sonst rechnet man Wartungsaufträge
* in eine Quote hinein, die für sie gar nicht gilt.
*/
export const FOERDERFAEHIGE_KATEGORIEN = new Set([
@@ -137,7 +137,7 @@ export interface Auftrag {
/**
* Bei verlorenen Vorgängen: die zuletzt erreichte Trichterstufe.
* Ohne dieses Feld müsste der Trichter raten, wo ein Vorgang abgesprungen
* ist — und würde die oberen Stufen systematisch zu klein zeigen.
* ist, und würde die oberen Stufen systematisch zu klein zeigen.
*/
verlorenAb: AuftragStatus | null;
/**