# Changelog Alle nennenswerten Änderungen an diesem Projekt werden hier dokumentiert. Format angelehnt an [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), Versionierung nach [Semantic Versioning](https://semver.org/lang/de/). ## [1.8.1] – 2026-07-20 ### Hinzugefügt - `update.sh`: Update-Skript für Linux-Deployments – stoppt den Docker- Stack, sichert lokale Änderungen an `docker-compose.yml` per `git stash` (falls vorhanden), führt `git pull` aus, spielt die Änderungen zurück und startet den Stack neu im Build-Modus. Bricht bei einem `git pull`- oder Stash-Konflikt kontrolliert ab, statt mit einem halb aktualisierten Stand weiterzumachen. In DEPLOYMENT.md unter „Updates einspielen“ dokumentiert. ## [1.8.0] – 2026-07-19 ### Hinzugefügt - Umschaltbarer Hinweismodus für Allergene/Zusatzstoffe: Auf der Seite „Allergene & Zusatzstoffe“ kann zwischen der bisherigen detaillierten Auswahl je Gericht und einem einfachen, in Deutsch/Englisch/Polnisch editierbaren Hinweistext (z. B. „Bei Fragen zu Allergenen und Zusatzstoffen wenden Sie sich bitte an das Kantinen-Team.“) umgeschaltet werden. Im Hinweismodus entfällt auf der öffentlichen Speisekarte die Legende und die Kürzel an den Gerichten, und in der Gerichte-Verwaltung wird die Allergen-/Zusatzstoff-Auswahl beim Bearbeiten ausgeblendet (bereits zugeordnete Daten bleiben in der Datenbank erhalten). Umschalten und Hinweistext bearbeiten dürfen sowohl Kantinenpersonal als auch Admins. ## [1.7.0] – 2026-07-19 ### Hinzugefügt - CSV-Import/-Export für Gerichte, Allergene und Zusatzstoffe (Buttons „Exportieren“/„Importieren“ auf den jeweiligen Verwaltungsseiten). Export lädt die aktuelle Liste als CSV herunter (Gerichte: `name,name_en,name_pl,price,allergens,additives`, Allergene/ Zusatzstoffe: `code,name,name_en,name_pl`; Kürzel bei Gerichten Semikolon-getrennt in einer Zelle, z. B. `A;G`). Import liest dieselbe Spaltenstruktur (Reihenfolge egal, Groß-/Kleinschreibung der Kopfzeile wird ignoriert) und aktualisiert bestehende Einträge (Abgleich über Kürzel bei Allergenen/Zusatzstoffen, über den exakten Namen bei Gerichten) bzw. legt neue an. Zeilen mit fehlenden Pflichtfeldern, ungültigem Preis oder mehrdeutigem Gerichtsnamen (mehrere Gerichte mit demselben Namen) werden übersprungen und mit Grund in der Erfolgsmeldung aufgelistet, statt den ganzen Import abzubrechen. ### Behoben - RSS-Feed (`/feed.xml`): Mehrere Feed-Reader (u. a. Outlook, Thunderbird) behandeln `` als kurze Vorschau und kürzen sie eigenmächtig – dadurch war bei Tagen mit mehreren Essenszeiten oft nur die erste sichtbar, obwohl der Server bereits alle Essenszeiten des Tages in der Beschreibung lieferte. Zusätzlich zu `` wird jetzt auch `` (RSS-Content- Modul) mit demselben vollständigen Inhalt ausgeliefert – von den meisten Readern als vollständiger Artikeltext erkannt und ungekürzt angezeigt. ## [1.6.3] – 2026-07-18 ### Behoben - `docker-compose.yml`: Der `app`-Dienst setzte `BRANDING_DIR` nicht, sodass `lib/branding.ts` beim Hochladen von Logo/Favicon auf den Fallback-Pfad `${cwd}/data/branding` (= `/app/data/branding`) statt auf das im Dockerfile vorbereitete, gemountete Verzeichnis `/data/branding` auswich. `/app` gehört im Container `root`, der App-Prozess läuft aber als nicht-root-Nutzer `nextjs` – das Anlegen des Fallback-Verzeichnisses scheiterte mit `EACCES`, der Upload endete mit „Upload fehlgeschlagen: 500". Jetzt wird `BRANDING_DIR=/data/branding` explizit gesetzt, passend zum Volume-Mount und zum in `Dockerfile` per `chown` freigegebenen Verzeichnis. ## [1.6.2] – 2026-07-18 ### Behoben - `scripts/bootstrap-admin.mjs`: Konnte `ZUGANGSDATEN.md` nicht geschrieben werden (z. B. `EACCES`, weil die per Bind-Mount eingebundene Host-Datei root gehört und der App-Container als nicht-root läuft), brach das Skript ab, nachdem der Admin-Benutzer bereits in der Datenbank angelegt war – das generierte Passwort war dann nirgends mehr zu finden. Schreibt jetzt bei einem Fehler stattdessen E-Mail/Passwort ins Log und beendet sich weiterhin erfolgreich. - DEPLOYMENT.md: Schritt 2 fehlte `chmod 666 ZUGANGSDATEN.md` (der eigentliche Auslöser des Bugs oben). Neue Fehlerbehebung-Einträge für `ECONNREFUSED` beim Start (harmlose Start-Reihenfolge, löst sich durch den automatischen Neustart von selbst) und für diesen `EACCES`-Fall inkl. Recovery-Anleitung für einen bereits verwaisten Admin-Account. ## [1.6.1] – 2026-07-18 ### Geändert - PostgreSQL-Container ist nicht mehr über einen Host-Port erreichbar (`docker-compose.yml`: `ports: 5433:5432` beim `db`-Dienst entfernt). App und Dev-Server erreichen die Datenbank weiterhin über das von Docker Compose automatisch angelegte interne Netzwerk (Hostname `db`) – reduziert die Angriffsfläche, ohne den Betrieb zu ändern. Debugging/Backup weiterhin über `docker compose exec db psql`/ `pg_dump` möglich. ### Behoben - DEPLOYMENT.md: Fehlerbehebung-Abschnitt für `password authentication failed for user "postgres"` ergänzt (tritt auf, wenn `docker compose up` vor dem Setzen von `LOCAL_PG_PASSWORD` läuft oder ohne `--env-file .env.local` – PostgreSQL übernimmt das Passwort nur beim allerersten Start auf leerem Datenverzeichnis). `.env.example` warnt jetzt vor Sonderzeichen in `LOCAL_PG_PASSWORD`, die beim `.env`-Parsing zu stillen Fehlern führen können. ## [1.6.0] – 2026-07-18 ### Hinzugefügt - RSS-Feed des Speiseplans (`/feed.xml`, ein Eintrag pro Tag mit den Gerichten je Essenszeit für die aktuelle und die nächste Woche) zum Abonnieren in einem Feedreader. Autodiscovery-Link im Seiten-`` sowie sichtbares RSS-Icon im Kopfbereich der öffentlichen Speisekarte. - Kantinen-Bereich: „Vorschläge“-Navigationspunkt zeigt jetzt die Anzahl offener Rezeptvorschläge als Zahl im roten Kreis. - Neues [DEPLOYMENT.md](DEPLOYMENT.md): Schritt-für-Schritt-Anleitung für die Inbetriebnahme auf einem neuen Server (Docker Compose, Konfiguration, Reverse-Proxy/HTTPS, Updates, Backup). ### Geändert - Letzte Erwähnungen von Supabase in aktiven Doku-Texten und Code-Kommentaren entfernt/umformuliert (README, Migrationsschema, Passkey-Konfiguration, Branding-Ablage) – die App läuft seit v1.5 vollständig ohne Supabase, das sollte sich jetzt auch durchgängig in der Dokumentation widerspiegeln. Historische CHANGELOG-Einträge bleiben unverändert. - `.env.example`: `LOCAL_PG_PASSWORD` (von `docker-compose.yml` verwendet, um die Datenbank-Verbindung der App-Container zusammenzubauen) war bisher nirgends dokumentiert – beim Schreiben der Deployment-Anleitung aufgefallen und ergänzt. ## [1.5.0] – 2026-07-18 ### Hinzugefügt - Wochenplan: „Mahlzeit hinzufügen" bietet jetzt ein Suchfeld mit gefilterter Trefferliste statt einer langen Dropdown-Liste zum Durchscrollen. - `db/seed-demo.sql` (`npm run db:seed-demo`): spielt für lokale Entwicklung/Demos den ursprünglichen Beispieldatensatz ein (Essenszeiten, Allergene, Zusatzstoffe, Testgerichte, zwei Beispielwochen) – kein Teil der automatischen Migrationen, frische Deployments starten weiterhin leer. ### Geändert - **Supabase vollständig entfernt** – die App läuft jetzt komplett selbst gehostet, einzige externe Abhängigkeit bleibt optional DeepL. - Datenbank: selbst gehostetes PostgreSQL statt Supabase-Cloud-Postgres. Schema in `db/migrations/*.sql`, wird beim Start automatisch und idempotent angewendet (`db/migrate.mjs`). - Anmeldung: eigene Session-Verwaltung (opake, in der DB gespeicherte Tokens, `httpOnly`/`sameSite=lax`-Cookie) statt Supabase Auth. Passwörter werden mit Node-eigenem `crypto.scrypt` gehasht (keine neue Abhängigkeit). - Passkeys: `@simplewebauthn` ersetzt Supabase's bisher experimentelles WebAuthn-API. Die RP-Domain wird direkt aus `APP_URL` abgeleitet – kein externer Konfigurationsschritt mehr nötig. - Logo/Favicon: lokale Dateiablage (Docker-Volume) statt Supabase-Storage-Bucket, ausgeliefert über `/branding/[filename]`. - Autorisierung (öffentlich lesbar / Kantinen-Team schreibt / nur Admin für Einstellungen & Benutzer) läuft jetzt in den API-Routen statt über Postgres-Row-Level-Security. - E-Mail-Änderung im eigenen Konto läuft direkt nach Passwort-Bestätigung statt über eine Supabase-Bestätigungsmail (kein SMTP-Server vorhanden). - Datenbank startet beim allerersten Deployment leer; beim ersten Start wird automatisch genau ein Admin-Benutzer mit zufällig generiertem Passwort angelegt, die Zugangsdaten landen in `ZUGANGSDATEN.md`. ### Behoben - „Mindestens 1 Passkey nötig, um die Passwort-Anmeldung zu deaktivieren" wurde bisher nur clientseitig geprüft; ein manuell gebauter Request hätte die Passwort-Anmeldung auch ohne Passkey deaktivieren können. Jetzt zusätzlich serverseitig erzwungen. - Logo-/Favicon-Upload akzeptierte anhand des vom Browser gemeldeten Dateityps auch SVG-Dateien. Da diese (anders als beim vorherigen Supabase-Storage-Bucket auf fremder Domain) jetzt auf der eigenen Origin ausgeliefert werden, hätte eine SVG mit eingebettetem `