Installierbar: Manifest, Symbole aus dem eigenen Zeichen erzeugt (scripts/symbole.ts, kein Bilddienst), Verknuepfungen zu Lernmodus, Berichtsheft und Handouts. Offline gilt eine Regel, und die steht im Dienstarbeiter: Nur das Lernmaterial liegt im Browserspeicher - Handouts, Merkkarten, Glossar, die eigene Woche. Lernzielkontrollen, Berichtsheft, Bewertungen, Feedbackgespraeche, Anhaenge und jedes PDF niemals. Das ist keine Sparsamkeit: Was im Browsercache liegt, ist an der serverseitigen Rechtepruefung vorbei. Bewertungen ohne Netz gehen in eine Warteschlange und werden nachgereicht. Die Schlange haengt an der Benutzerkennung, nicht am Geraet - auf einem geteilten Werkstattgeraet bekaeme sonst der Zweite die offenen Bewertungen des Ersten aufs Konto. Der Tag der Bewertung kommt vom Geraet und wird auf heute gedeckelt (tagDerBewertung, 4 Tests): Eine vorgestellte Uhr darf das Wiederholen nicht wegstellen. Druck: Wer die dunkle Fassung eingestellt hatte, druckte bisher schwarze Flaechen. Im Druck wird jetzt die komplette helle Palette gesetzt, dazu A4-Raender, keine Umbrueche mitten in Karten und Zeilen, aufgeklappte details. Druckknoepfe bei Handout, Glossar und Auswertung. Durchstich in scripts/pruefungen/baustein-10.mjs mit echtem Abschalten des Netzes: 33 Pruefungen, darunter der Nachweis, dass nichts Bewertungsrelevantes im Speicher landet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Lern-Bar
Selbst gehostete Anwendung für die betriebliche Ausbildung zum/zur Fachinformatiker/-in für Systemintegration. Sie ersetzt den Stapel PDFs: Wochenplan, Handouts, Merkkarten, Praxisaufgaben, Checklisten, Lernzielkontrollen und – der wichtigste Teil – den gesetzlich vorgeschriebenen Ausbildungsnachweis („Berichtsheft").
Gebaut für einen Ausbilder und ein bis drei Auszubildende. Kein Lernplattform-Baukasten, keine Mandanten, keine Cloud.
Stand: Bausteine 1 bis 9 von 10 sind fertig. Es fehlt nur noch der Feinschliff: PWA, Offlinebetrieb, Druckansichten und die Anleitung mit Screenshots. Der Fahrplan zeigt, was folgt, das Änderungsprotokoll, was schon drin ist.
In fünf Minuten zum laufenden System
Voraussetzungen
- Betrieb: Docker mit Compose-Erweiterung (Docker 24 oder neuer)
- Entwicklung: Node.js 22 oder neuer, Git
- Ein Reverse Proxy, der TLS beendet (nginx, Caddy, Traefik) – die Anwendung selbst spricht nur HTTP und lauscht nur auf der Schleife
Betrieb mit Docker
git clone <repository-url> lernbar
cd lernbar
docker compose up -d --build
Die Anwendung lauscht danach auf 127.0.0.1:3000. Erstes Ausbilderkonto
anlegen:
docker compose exec lernbar node -e "1" >/dev/null # Container erreichbar?
docker compose exec lernbar sh -c \
'node werkzeuge/konto.js --name "Vorname Nachname" --email ausbilder@betrieb.de --rolle ausbilder'
Solange das Konto-Werkzeug im Abbild noch nicht liegt, geht es vom Entwicklungsrechner aus:
npm run konto:anlegen -- --name "…" --email … --rolle ausbilder
Danach im Browser anmelden, unter Verwaltung das Azubikonto anlegen und das Ausbildungsverhältnis mit Beginndatum einrichten.
Entwicklung
npm install
npm approve-scripts better-sqlite3 esbuild unrs-resolver # nur beim ersten Mal
npm run konto:anlegen -- --name "Vorname Nachname" --email du@betrieb.de --rolle ausbilder
npm run dev
Ohne npm approve-scripts bleiben better-sqlite3 und esbuild unübersetzt –
npm blockiert seit Version 11 die Installationsskripte fremder Pakete.
Die Anwendung läuft dann auf http://localhost:3000. Datenbank und Anhänge
landen unter daten/ (nicht im Repository).
Beispiel für einen Reverse Proxy
server {
listen 443 ssl http2;
server_name lernbar.betrieb.local;
ssl_certificate /etc/ssl/lernbar.crt;
ssl_certificate_key /etc/ssl/lernbar.key;
client_max_body_size 30m; # Fotos vom Aufbau als Anhang (Grenze der Anwendung: 25 MB)
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Inhalte pflegen
Die fachlichen Inhalte sind Dateien im Repository, keine
Datenbankeinträge – Bearbeiten in VS Code, Versionieren mit Git, Sichern mit
git clone.
content/
wochen/ 01-arbeitsalltag.yaml …
handouts/ N3-subnetting-rechnen.md …
aufgaben/ 2.2-notebooks-vergleichen.md …
checklisten/ 02-windows-installieren.yaml …
lernzielkontrollen/ woche-03.yaml …
glossar.yaml
feedbackgespraech.yaml Leitfaden und Kriterien für das Gespräch
rahmenplan.yaml Berufsbildpositionen und Lernfelder
Ein Handout ist Markdown mit YAML-Kopf:
---
id: N3
titel: Subnetting rechnen – der Weg in vier Schritten
block: netzwerk
woche: 3
worum: Eine Adresse und eine Maske reichen, um Netz, Broadcast und Hostbereich zu bestimmen.
rahmenplan: [B2, A8]
lernfeld: LF3
merksatz: Blockgröße finden, Vielfache aufschreiben, eigene Adresse einsortieren.
karten:
- frage: Zu welchem Netz gehört 192.168.10.200 bei der Maske 255.255.255.224?
antwort: Blockgröße 32, Netze bei .192 und .224 – die Adresse gehört zu 192.168.10.192/27.
---
## Das Wesentliche
…
Beim Start werden alle Inhalte eingelesen und geprüft: Jede Kennung muss es
geben, jedes Handout gehört zu einer Woche, jede Rahmenplanposition steht in
rahmenplan.yaml. Passt etwas nicht, startet die Anwendung nicht und nennt
Datei und Stelle. Prüfen ohne Start:
npm run inhalte:pruefen
Datensicherung
Gesichert werden Datenbank und Anhänge. Die Inhalte stecken im Repository und brauchen keine eigene Sicherung.
Sicherung ziehen
# im laufenden Container
docker compose exec lernbar /app/werkzeuge/sicherung.sh /daten/sicherungen
# aus dem Volume herausholen
docker compose cp lernbar:/daten/sicherungen ./sicherungen
Auf dem Entwicklungsrechner:
LERNBAR_DATEN=./daten npm run backup -- ./sicherungen
Das Archiv heißt lernbar-JJJJMMTT-HHMMSS.tar.gz und enthält
lernbar.sqlite, anhaenge/ und eine kurze Beschreibung. Die Kopie der
Datenbank entsteht über die Sicherungsschnittstelle von SQLite, ist also auch
im laufenden Betrieb in sich stimmig.
Zurückspielen
docker compose stop lernbar
docker compose cp ./sicherungen/lernbar-20260910-0300.tar.gz lernbar:/tmp/
docker compose start lernbar
docker compose exec lernbar /app/werkzeuge/wiederherstellen.sh /tmp/lernbar-20260910-0300.tar.gz
docker compose restart lernbar
Der bisherige Stand wird nicht gelöscht, sondern nach
/daten/verdraengt-<zeitstempel>/ verschoben.
Nächtlich per Cronjob
/etc/cron.d/lernbar-sicherung:
# Jede Nacht um 03:00 sichern, Archive älter als 30 Tage wegräumen.
SHELL=/bin/sh
PATH=/usr/local/bin:/usr/bin:/bin
0 3 * * * root cd /opt/lernbar && docker compose exec -T lernbar /app/werkzeuge/sicherung.sh /daten/sicherungen >> /var/log/lernbar-sicherung.log 2>&1
30 3 * * * root cd /opt/lernbar && docker compose exec -T lernbar find /daten/sicherungen -name 'lernbar-*.tar.gz' -mtime +30 -delete
Liegt das Volume auf einem Pfad, den die Sicherung des Servers ohnehin
mitnimmt, ist damit alles erledigt. Sonst zusätzlich mit docker compose cp
herauskopieren und wegschaffen.
Aktualisieren
Auf dem Linux-Server:
cd /opt/lernbar
./update.sh
Das Skript sichert zuerst, holt den Quelltext, baut das Abbild neu, schaltet um und wartet auf das Lebenszeichen. Meldet sich die neue Fassung nicht gesund, schaltet es selbsttätig auf das vorherige Abbild zurück und zeigt die letzten Protokollzeilen.
| Angabe | Wirkung |
|---|---|
| (ohne) | sichern, holen, bauen, umschalten |
--ohne-git |
nur neu bauen und neu starten |
--ohne-sicherung |
Sicherung überspringen (nicht empfohlen) |
--zweig main |
einen bestimmten Git-Zweig holen |
--hilfe |
Kurzhilfe |
Umgebungsvariablen
| Name | Vorgabe im Container | Bedeutung |
|---|---|---|
PORT |
3000 |
Lauschport |
TZ |
Europe/Berlin |
Zeitzone |
LERNBAR_DATEN |
/daten |
Wurzel für Datenbank und Anhänge |
LERNBAR_DB |
<daten>/lernbar.sqlite |
abweichender Pfad der Datenbank |
LERNBAR_INHALTE |
/app/content |
Wurzel der Inhaltsdateien |
LERNBAR_MIGRATIONEN |
/app/migrationen |
Verzeichnis der SQL-Migrationen |
Prüfen und Testen
npm run typecheck # TypeScript
npm run lint # ESLint
npm run test # Vitest – Logik, die wehtut
npm run e2e # Playwright – der Hauptweg von Anfang bis Ende
Aufbau
src/
app/ Seiten und Serveraktionen (App Router)
komponenten/ wiederverwendete Bausteine der Oberfläche
lib/
auth/ Passwörter, Sitzungen, Rechteregeln
db/ Verbindung, Schema, Migrationen
repos/ der gesamte Datenzugriff – nur hier wird SQL gesprochen
zeit/ Europe/Berlin, ISO-Kalenderwochen
content/ fachliche Inhalte als Markdown und YAML
scripts/ Werkzeuge für die Kommandozeile
im-container/ Sicherung und Wiederherstellung (Shell, läuft überall)
Weiterführend: Fahrplan · Änderungsprotokoll · Arbeitstagebuch · Entscheidungen