Baustein 2: Inhalte einlesen und pruefen, Handouts, Suche, Glossar

Die fachlichen Inhalte liegen als Dateien unter content/ und werden beim
Start eingelesen, geprueft und in den Speicher geladen.

- Inhaltslader mit Zod-Schemata und Querverweispruefung
- Fehlermeldungen nennen Datei und Zeile, gesammelt statt beim ersten
  Fehler geworfen; die Anwendung startet bei Fehlern nicht
- npm run inhalte:pruefen prueft ohne Start
- Handout-Ansicht mit festem Aufbau, Uebersicht nach Themenbloecken
- Volltextsuche mit Gewichtung und Trefferausschnitt
- Gelesen-Markierung je Handout
- Glossar mit Suche und automatischer Verlinkung in den Handouts
- Beispielinhalte: 4 Wochen, 12 Handouts, 24 Merkkarten, 4 Aufgaben,
  4 Checklisten, 2 Lernzielkontrollen, 24 Glossareintraege
- rahmenplan.yaml aus FIAusbV 2020 und KMK-Rahmenlehrplan, mit Fundstellen
- gray-matter entfernt, YAML-Kopf wird selbst herausgeloest
- npm run screenshots nimmt die Bilder fuer die Anleitung auf
- 39 neue Tests, insgesamt 68

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Florian Wilde
2026-09-10 07:56:38 +02:00
co-authored by Claude Opus 5
parent e856349cd4
commit 1af5613e9b
70 changed files with 4779 additions and 124 deletions
+57
View File
@@ -0,0 +1,57 @@
/**
* Prüft alle Dateien unter content/, ohne die Anwendung zu starten.
*
* npm run inhalte:pruefen
*
* Endet mit 0, wenn alles in Ordnung ist, sonst mit 1 – so lässt sich das
* Skript in einen Prüflauf oder einen Git-Haken einhängen.
*/
import { ladeInhalte } from '../src/lib/inhalte/laden';
import { InhaltsFehler } from '../src/lib/inhalte/fehler';
import { inhaltWurzel } from '../src/lib/pfade';
function main() {
try {
const alle = ladeInhalte(inhaltWurzel);
const kartenJeBlock = alle.bloecke.map((b) => {
const anzahl = alle.karten.filter((k) => k.block === b.id).length;
return `${b.titel}: ${anzahl}`;
});
console.log('Inhalte in Ordnung.');
console.log('');
console.log(` Wochen ${alle.wochen.length}`);
console.log(` Handouts ${alle.handouts.length}`);
console.log(` Merkkarten ${alle.karten.length} (${kartenJeBlock.join(', ')})`);
console.log(` Praxisaufgaben ${alle.aufgaben.length}`);
console.log(` Checklisten ${alle.checklisten.length}`);
console.log(` Lernzielkontrollen ${alle.kontrollen.length}`);
console.log(` Glossareinträge ${alle.glossar.length}`);
console.log(` Berufsbildpositionen ${alle.positionen.length}`);
console.log(` Lernfelder ${alle.lernfelder.length}`);
console.log('');
const ohneAbdeckung = alle.positionen.filter(
(p) =>
!alle.handouts.some((h) => h.rahmenplan.includes(p.id)) &&
!alle.aufgaben.some((a) => a.rahmenplan.includes(p.id)),
);
if (ohneAbdeckung.length > 0) {
console.log(` Hinweis: ${ohneAbdeckung.length} Berufsbildpositionen sind von keinem Inhalt berührt:`);
console.log(` ${ohneAbdeckung.map((p) => p.id).join(', ')}`);
console.log(' Das ist kein Fehler – nur etwas, das im Laufe der Ausbildung geschlossen werden sollte.');
console.log('');
}
process.exit(0);
} catch (fehler) {
if (fehler instanceof InhaltsFehler) {
console.error(fehler.message);
process.exit(1);
}
throw fehler;
}
}
main();