/** * Der Meldetext zu einer Frage. * * ## Wozu * * Fehler im amtlichen Fragenkatalog oder in einer Erklärung findet, wer * davorsitzt. Der Rückmeldeweg steht seit 0.10.0 unter „Über diese Software“ * und im Handbuch – aber wer mitten in einer Sitzung einen Fehler bemerkt, * müsste ihn sich merken, die Ansicht verlassen, die Fragennummer nachschlagen * und die Fassung heraussuchen. Diese Datei stellt den Block zusammen, der * das abnimmt. * * ## Warum die Kennung mitläuft und nicht nur die amtliche Nummer * * Die amtliche Nummer ist **nicht eindeutig**: Nachgezählt über den Katalog * teilen 227 der 575 Fragen ihre Nummer mit mindestens einer anderen – „01“ * gibt es als `II-01`, `III-01` und `IV-01`. Wer nur „Frage 01“ meldet, meldet * dreideutig. Die interne Kennung `I.1-01` ist eindeutig und steht deshalb * daneben, in Klammern und ohne Erklärungsbedarf. * * ## Was hier ausdrücklich **nicht** hineingehört * * Der Text verlässt später das Gerät – von Hand, aber er verlässt es. Also * gilt dieselbe Strenge wie für alles andere in dieser Anwendung: **kein * Personenbezug.** Kein Profilname, kein Lernstand, keine gegebene Antwort, * kein Dateipfad, kein Rechnername, kein Zeitstempel. Was hier steht, muss * einen Zweck für die Bearbeitung der Meldung haben; alles andere fliegt * raus. Die Bauart sichert das: Diese Funktion nimmt **einzelne Felder** * entgegen und keine ganzen Zustandsobjekte, aus denen versehentlich mehr * mitreist, als jemand wollte. * * ## Warum kein `mailto:` * * Die Anwendung öffnet von sich aus keine Verbindung nach außen – siehe * `shared/kontakt.ts`. Der Text wird kopiert; verschickt wird er vom Menschen. */ import { KONTAKT } from './kontakt'; /** Die Angaben zur Frage, die in den Text gehören. */ export interface MeldeFrage { /** Eindeutige Kennung, z. B. „I.1-01“. */ readonly id: string; /** Amtliche Nummer, z. B. „1.01“ – nicht eindeutig, siehe Modulkopf. */ readonly amtliche_nummer: string; /** Seite in der amtlichen Vorlage. */ readonly seite: number; } /** Herkunft des Katalogs, aus `katalog.meta`. */ export interface MeldeKatalog { readonly herausgeber: string; /** ISO-Datum, z. B. „2024-12-16“. */ readonly stand: string; readonly quelldatei_sha256: string; } /** * Angaben zum Programm. * * Bewusst drei einzelne Zeichenketten und **nicht** `AnwendungsInfo`: Dort * hängt `datenbank.meldung` mit dran, die im Fehlerfall einen Dateipfad * enthalten kann. Ein Typ, der das gar nicht erst annimmt, ist die * verlässlichere Sperre als ein Vorsatz. */ export interface MeldeProgramm { readonly fassung: string; readonly baukennung: string; /** ISO-Datum des Baus, darf leer sein. */ readonly baustand: string; } /** ISO-Datum als deutsches Datum; unlesbare Werte bleiben, wie sie sind. */ function deutschesDatum(iso: string): string { const zeit = Date.parse(iso); if (Number.isNaN(zeit)) { return iso; } return new Date(zeit).toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', }); } /** * Wie viele Zeichen der Prüfsumme in den Text kommen. * * Zwölf genügen, um zwei Katalogfassungen auseinanderzuhalten, und lassen die * Zeile lesbar. Die vollständige Summe steht unter „Über diese Software“. */ const PRUEFSUMME_ZEICHEN = 12; /** * Stellt den Meldeblock zusammen. * * Zeilenenden immer `\n`, kein Markup, keine Spaltenausrichtung durch * Leerzeichen: Der Text soll in einer Nur-Text-Mail genauso aussehen wie in * einem Forum, und ausgerichtete Spalten halten nur in Festbreitenschrift. */ export function meldetextBauen( frage: MeldeFrage, katalog: MeldeKatalog, programm: MeldeProgramm, ): string { const bau = programm.baukennung === '' ? '' : `, Bau ${programm.baukennung}${ programm.baustand === '' ? '' : ` vom ${deutschesDatum(programm.baustand)}` }`; return [ 'Fehlermeldung zur Waffensachkunde-Lernsoftware', `Senden an: ${KONTAKT.epost}`, '', `Frage: ${frage.amtliche_nummer} (Kennung ${frage.id}), Seite ${String(frage.seite)} der Vorlage`, `Fragenkatalog: ${katalog.herausgeber}, Stand ${deutschesDatum(katalog.stand)}, ` + `Prüfsumme ${katalog.quelldatei_sha256.slice(0, PRUEFSUMME_ZEICHEN)} (gekürzt)`, `Programm: Fassung ${programm.fassung}${bau}`, '', 'Diese Angaben hat die Lernsoftware zusammengestellt. Sie enthalten nichts über die', 'meldende Person und nichts über ihren Lernstand.', '', 'Was nicht stimmt (bitte hier beschreiben):', '', ].join('\n'); }