# CHANGELOG.md, Änderungshistorie

Alle wichtigen Änderungen an diesem Projekt werden hier dokumentiert.
Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/).
Neueste Einträge stehen oben.

---

## [v1.0.6], 2026-05-07, Lesbarkeit Newsletter-Editor plus zentrale Quill-Styles

### Behoben
- **Newsletter-Editor war kaum lesbar**: Quill-Editor lief ohne Dark-Theme-Styles, Text auf dunklem Hintergrund unleserlich, Placeholder kaum sichtbar.
- **Doppelte CSS-Pflege** in `admin/pages.php` und `admin/newsletter-edit.php`: jede Page hatte ihren eigenen Quill-Style-Block. Wenn ich's an einer Stelle gefixt hab, war's an der anderen vergessen.

### Geändert
- **Zentrale Quill-Dark-Theme-Styles** sind jetzt einmalig in `admin/css/admin.css` gepflegt. Alle Quill-Editoren (jetzt Pages plus Newsletter, künftig auch beliebige neue) bekommen automatisch:
  - Lesbaren Text (`.ql-editor` mit `color: var(--text-main)`)
  - Sichtbarer Placeholder (`.ql-editor.ql-blank::before`)
  - Toolbar plus Picker im Dark-Theme
  - Active/Hover-States mit Primary-Farbe
  - Tooltip plus Code-Blocks plus Blockquote im Theme

---

## [v1.0.5], 2026-05-07, UX-Refactor Settings, Update-Sidebar, Hub-Upload

### Geändert
- **Admin-Einstellungen mit Tabs**: `admin/settings.php` ist jetzt klar strukturiert in 4 Tabs: Allgemein, Stream, E-Mail (SMTP), Funktionen plus Social. War vorher eine endlose Liste.
- **Newsletter-Einstellungen** sind aus Settings rausgezogen und bei `Admin → Newsletter → Tab Einstellungen` integriert. Newsletter ist eigenes Modul, gehört nicht in die globalen Settings.
- **System-Update Sidebar-Link**: Superadmins sehen jetzt direkt in der Admin-Sidebar einen Punkt „System-Update", müssen nicht mehr über Banner+Klick navigieren.
- **Hub-Admin: ZIP-Upload** in `/admin/cms-versions.php`: ZIP kann direkt hochgeladen werden statt nur Download-URL einzutippen. Datei landet automatisch unter `/radiocms/downloads/radiocms-community-VERSION-update.zip`, URL wird automatisch gesetzt. Externe URL bleibt als Alternative.

---

## [v1.0.4], 2026-05-07, Tester-Feedback Runde 2

### Behoben
- **HTML-Doppel-Encoding bei Track-Titeln**: SHOUTcast 7.html liefert HTML-Entities (`&amp;` etc.) im Body, der Code holte sie roh raus. Jetzt wird mit `html_entity_decode()` korrekt dekodiert. Track wie „C & J Street Mix" wird wieder normal angezeigt statt „C &amp; J Street Mix".
- **„Jetzt hören"-Button auf Startseite** funktionierte nicht zuverlässig. Inline-onclick durch sauberen Event-Listener in `main.js` ersetzt, der zusätzlich zum Player-Footer scrollt.

### Geändert
- **Live-Badge-Farben**: gerader Live-DJ aktiv → grün (vorher rot), AutoDJ aktiv → rot (vorher cyan), offline → grau. Badge plus On-Air-Indicator in Hero-Card werden jetzt synchron mit Status umgeschaltet (`autodj`/`offline` CSS-Klassen).

---

## [v1.0.3], 2026-05-07, Newsletter-System plus Auto-Updater

### Hinzugefügt
- **Auto-Update-System**: Admin-UI unter Einstellungen → System-Update zeigt verfügbare Versionen plus Changelog. Ein-Klick-Update lädt das ZIP vom Hub, macht Backup der zu überschreibenden Files plus DB-Dump, spielt das Update ein, ruft die Migration auf und aktualisiert die SITE_VERSION-Konstante. Plus Rollback-Knopf pro Backup.
- **Newsletter-System** mit Double-Opt-In:
  - Frontend `/newsletter.php` mit Subscribe-Form, DSGVO-Checkbox plus Confirm-Mail-Workflow.
  - Frontend-Pages für Confirm und 1-Klick-Unsubscribe via Token.
  - Admin `/admin/newsletter.php` mit Subscriber-Liste plus Kampagnen-Übersicht.
  - Admin `/admin/newsletter-edit.php` mit Quill-Editor, Test-Versand, „An alle senden"-Button.
  - Drei Versand-Engines konfigurierbar: SMTP (eigene Mail-Settings), Resend (3000/Monat gratis), Brevo (300/Tag gratis).
  - Cron-Skript `cron/newsletter-tick.php` für Batch-Versand (50 pro Tick).
  - Optionaler Auto-Newsletter „wöchentliche Sendeplan-Vorschau", konfigurierbar Wochentag plus Uhrzeit.
  - Permission `manage_newsletter`, Default an admin und superadmin gehängt.
  - Settings-UI in Admin → Einstellungen für alle Newsletter-Optionen plus Versand-Service-Wahl.

### Behoben
- **Demo-Block auf Login-Seite** war hardcodiert auf jeder Installation sichtbar. Jetzt host-gegated, nur noch auf radio.dgnshop.com.
- **Manuelles Now-Playing** überschreibt jetzt nur wenn das Feld auch befüllt ist. Leeres Feld plus Toggle aktiv = der echte Stream-Titel wird durchgereicht (statt leer).

### Datenbank
- Neue Tabellen `newsletter_subscribers`, `newsletter_campaigns`, `newsletter_log`
- Neue Settings `newsletter_*` (15 Stück, plus Service-Wahl, Auto-Schedule etc.)
- Neue Permission `manage_newsletter` plus Auto-Zuweisung an admin/superadmin

---

## [v1.0.2], 2026-05-07, Tester-Feedback Runde 1

### Behoben
- **MariaDB-Kompatibilität**: `ANY_VALUE()` durch `MAX()` ersetzt in `admin/chat-stats.php`. Chat-Statistik lief vorher nur unter MySQL, nicht unter MariaDB (Plesk-Standard).
- **SHOUTcast v1 Title-Bug**: Off-by-One-Fehler im 7.html-Parser. Aktueller Track wurde nie gelesen weil Code Index 7 nahm, Shoutcast aber nur 7 Felder liefert. Robust für 7- und 8-Feld-Varianten gemacht (`includes/functions.php`).
- **HTTPS-Schema-Support** in allen drei Status-Funktionen (`getIcecast2Status`, `getShoutcastV1Status`, `getShoutcastV2Status`). Für SSL-Tunnel-Setups wie Plesk oder Centova nötig.
- **`api/now-playing.php`** auf `getIcecastStatus()`-Wrapper umgestellt. Vorher hardcoded Icecast-Polling, jetzt respektiert es den Server-Typ-Toggle.
- **Demo-Modus-Fallback** aus dem Frontend-Player entfernt. Bei offline-Stream wird jetzt sauber „Stream offline" angezeigt statt erfundener Songtitel aus einem statischen Demo-Songs-Array (`assets/js/main.js`).
- **Hardcodierte Demo-Banner** aus `impressum.php` und `datenschutz.php` entfernt. Wirkten als „Demo-Version, kein rechtsgültiges Impressum" auch wenn der User längst eigene Daten eingetragen hatte.
- **DJ-Bereich Server-Typ-Display**: Badge, Protokoll-Anzeige und Broadcast-Software-Tipps richten sich dynamisch nach `stream_server_type` (vorher hardcoded „Icecast2" und „Icecast / Shoutcast v1").
- **Tabellen-Kontrast** im Admin-Theme. Bootstrap-Default-Tabellen waren auf dunklem Theme schlecht lesbar (Team-Page, Pages-Liste).
- **Permission-Bug-Audit**: 6 Admin-Seiten hatten nur `requireLogin()`, keinen Permission-Check. DJs hätten via direkter URL-Eingabe Zugriff gehabt. Gefixt: `settings.php`, `news.php`, `news-edit.php`, `requests.php`, `schedule-edit.php`, `api-docs.php`.
- **Manual-Override-Logik**: Manuelles „Jetzt läuft" überschreibt jetzt nur den Track-Titel, nicht mehr den kompletten Stream-Status. Online-Status, Hörerzahl und Bitrate kommen weiterhin aus dem echten Polling.

### Hinzugefügt
- **Manuelles Now-Playing-Override** als Admin-Setting (Toggle plus Eingabefeld in `admin/settings.php`). Gedacht für Hoster die Stream-Metadata nicht durchreichen.
- **Manueller Track-Setter im DJ-Bereich**: Wenn der Admin den Manual-Override aktiviert hat, sehen DJs/Mods im DJ-Bereich eine Eingabe-Card „Aktueller Track" und können den Titel selbst pflegen während sie senden (`admin/dj-area.php`).
- **Sendungs-Banner** pro Sendung im Sendeplan: JPG/PNG/WebP/GIF-Upload bis 3 MB, wird im Frontend-Sendeplan über der Sendung angezeigt. Neue Spalte `schedule.banner_image`, Verzeichnis `assets/img/schedule-banners/` mit `.htaccess`-PHP-Block.
- **Pages-System** mit strukturiertem Editor: Impressum und Datenschutz werden über dedizierte Eingabefelder (Name, Adresse, E-Mail, Steuernummer etc. plus Toggles für Cookies/Analytics/Logfiles) gepflegt. CMS rendert daraus automatisch sauberes HTML mit allen Pflicht-Texten (§ 5 TMG, § 18 MStV, Haftungsausschluss, Streitschlichtung, DSGVO-Sections). Eigene Seiten weiterhin per Quill-WYSIWYG. Neue Tabelle `pages` mit `page_type` und `structured_data`-Spalte. Frontend-Renderer `page.php`. `impressum.php` und `datenschutz.php` redirecten automatisch zur DB-Page.
- **DJ aus registriertem User anlegen**: Dropdown-Picker in `admin/djs-edit.php` zeigt alle aktiven Users ohne DJ-Profil, Auswahl füllt Name plus E-Mail vor und verknüpft den Login-Account direkt.
- **HTTPS-Stream-Polling Toggle** in den Stream-Settings (`stream_use_https`).
- **SHOUTcast v1 Single-Source-Hinweis** in der DJ-Area: kein nutzloser persönlicher Mountpoint mehr, stattdessen klare Info dass v1 nur einen Sender gleichzeitig erlaubt.
- **Sendeplan-Minutengenauigkeit** explizit markiert (`step="60"` plus Hinweistext „HH:MM, z.B. 14:30 bis 16:45").

### Datenbank
- Neue Tabelle `pages` (id, slug, page_type, title_de/en, content_de/en, structured_data, is_active, in_footer, sort_order, created_at, updated_at)
- Neue Spalte `schedule.banner_image VARCHAR(255) DEFAULT NULL`
- Neue Settings: `stream_use_https`, `manual_now_playing_enabled`, `manual_now_playing_title`, `cms_db_version`
- Pages-Vorlagen für Impressum und Datenschutz werden beim Migrieren angelegt

### Migration
- `migrate.php` legt automatisch fehlende Spalten und Tabellen an, idempotent. Nach erfolgreichem Lauf vom Webroot löschen.

---

## [2026-04-05], Runde 3: System-Nachrichten, Chat-Umfragen, Chat-Statistiken

### Hinzugefügt
- **System-Nachrichten**: Wenn DJ live geht oder Sendung beendet, erscheint automatisch eine zentrierte System-Message in allen aktiven Chat-Räumen (admin/dj-area.php, chat.php)
- **System-Nachrichten** werden in `chat_messages` als `message_type = 'system'` gespeichert und zentriert ohne Avatar dargestellt (chat/api/messages.php, chat.php)
- **Chat-Umfragen**: Mods können im Mod-Panel Polls starten (Frage + 2-6 Optionen + optionale Laufzeit); Ergebnisse live sichtbar mit Fortschrittsbalken (chat.php)
- **Chat-Umfragen**: Neue API-Endpunkte poll-create.php, poll-vote.php, poll-get.php, poll-end.php (chat/api/)
- **Chat-Umfragen**: Poll-Bar unterhalb der Pinned-Message-Bar; Abstimmung für Gäste und eingeloggte User; UNIQUE-Constraint verhindert Doppelabstimmung
- **Chat-Statistiken**: Neue Admin-Seite admin/chat-stats.php mit Gesamt-Kennzahlen, Nachrichten-Chart (30 Tage), Top-10-User, Raum-Verteilung, Reaktions-Stats, Nachrichten-Typen
- Admin-Navigation: Link "Chat-Statistiken" in der Sidebar ergänzt (admin/includes/admin-header.php)
- DB: Tabellen `chat_polls` und `chat_poll_votes` angelegt; Setting `chat_system_messages` hinzugefügt

### Geändert
- System-Nachrichten können via Setting `chat_system_messages` (Admin → Einstellungen) deaktiviert werden

---

## [2026-04-05], Chat UX-Fixes: User-Liste, DMs, Chat-Befehle

### Geändert
- Chat-Befehle / Regeln: `?`-Button direkt in der Eingabe-Toolbar hinzugefügt (sichtbar für alle User) (chat.php)
- Heartbeat-Interval von 30s auf 15s reduziert → Nutzer werden schneller als online erkannt (chat.php)
- `chat_online`-Timeout von 90s auf 45s reduziert → verlassene User verschwinden schneller (chat/api/heartbeat.php, chat/api/users.php)
- DM-Button in Online-Liste immer leicht sichtbar (nicht mehr rein nur bei Hover) (chat.php)
- DM-Hinweistext in Sidebar erklärt wie DMs gestartet werden (chat.php)

### Hinzugefügt
- `chat/api/leave.php`, neuer Endpoint; wird via `navigator.sendBeacon` beim Verlassen der Seite aufgerufen, entfernt Nutzer sofort aus Online-Liste (chat/api/leave.php, chat.php)
- Admin-Setting `chat_dms_enabled` in Einstellungen → Chat-Direktnachrichten können global deaktiviert werden (admin/settings.php, chat.php)

---

## [2026-04-05], Runde 2: Pinned Messages, Desktop-Notifications, /wunsch Command

### Hinzugefügt
- `chat/api/pin.php`, Mod-API: Nachricht anpinnen/losl per Raum
- `chat/api/wish.php`, Song-Wunsch aus Chat: parsed `Künstler - Titel`, Rate-Limit 60s, prüft requests_open
- `chat.php`, **Pinned Message Bar**: gelbe Bar unter Chat-Header zeigt angepinnte Nachricht, Klick scrollt hin
- `chat.php`, **Pin-Button** in Nachrichtenaktionen für Mods (Anpinnen/Losl)
- `chat.php`, **Desktop-Benachrichtigungen**: Browser-Push bei `@Mention` (Tab inaktiv) + bei neuer DM
- `chat.php`, **`/wunsch Künstler - Titel`** Command: landet direkt in `song_requests` DB → DJs sehen's sofort
- `chat.php`, **Chat-Befehle im Regeln-Modal**: Abschnitt "Chat-Befehle" mit `/wunsch` und `@Name` Erklärung

### Geändert
- `chat/api/messages.php`, `pinned` + `pinned_id` in Response aufgenommen (JOIN auf chat_messages)

### DB
- `chat_rooms.pinned_message_id INT NULL`, Spalte hinzugefügt (via tmp_runde2_setup.php)

---

## [2026-04-05], Runde 1: Slow-Mode, @-Mentions, Unread-Counter, Wort-Filter

### Hinzugefügt
- `chat/api/slow-mode.php`, Neuer API-Endpunkt: Mod setzt Slow-Mode per Raum (0-300s)
- `admin/word-filter.php`, Admin-Seite für Wort-Filter (CRUD: hinzufügen, aktivieren/deaktivieren, löschen)
- `chat.php`, **Slow-Mode Badge** im Chat-Header: zeigt aktiven Slow-Mode des Raums an
- `chat.php`, **Slow-Mode Mod-Panel Section**: Select + Setzen-Button zum Ändern des Slow-Mode per Raum
- `chat.php`, **@-Mention Autocomplete**: Dropdown erscheint bei `@`-Eingabe, zeigt Online-User, Klick/Enter fügt Mention ein
- `chat.php`, **@-Mention Highlight**: `@name` in Nachrichten wird farbig hervorgehoben (`.chat-mention`)
- `chat.php`, **Unread-Counter**: Tab-Titel zeigt `(3) Radio Chat` wenn Tab inaktiv und neue Nachrichten eintreffen
- `chat.php`, **Slow-Mode Countdown**: Send-Button wird nach Slow-Mode-Error für `wait`-Sekunden deaktiviert
- `chat.php`, Löschen- und Ban-Dialoge jetzt als Modal (`chatConfirm()`) statt Browser-`confirm()`/`prompt()`
- `admin/includes/admin-header.php`, Sidebar-Links für "Chat-Räume" und "Wort-Filter" hinzugefügt

### Geändert
- `chat/api/send.php`, Slow-Mode Check: letzte Nachricht des Users im Raum wird geprüft, Mods ausgenommen
- `chat/api/send.php`, Wort-Filter wird vor dem Speichern angewendet: `replace` → ersetzt, `block` → sendet Error
- `chat/api/messages.php`, `slow_mode`-Sekunden in Response aufgenommen
- `chat/api/messages.php`, `$isMod` prüft jetzt auch `moderate_chat`-Berechtigung (nicht nur `edit_users`)
- `admin/includes/admin-header.php`, Chat-Sidebar-Link sichtbar für `edit_users` ODER `moderate_chat`

### DB (bereits via tmp_runde1_setup.php ausgeführt)
- `chat_rooms.slow_mode_seconds INT DEFAULT 0`, Spalte hinzugefügt
- `chat_word_filters`, Neue Tabelle: id, word, replacement, action, is_active, created_at

---

## [2026-04-05], Chat UI-Fixes, Emoji-Picker, GIF-Funktion

### Hinzugefügt
- `chat.php`, **Emoji-Picker** im Eingabefeld: 😊-Button öffnet Panel mit 5 Kategorien (~100 Emojis), Einfügen an Cursor-Position
- `chat.php`, **GIF-Funktion**: GIF-Button neben Textarea, Tenor API (Trending + Suche mit Debounce), Grid-Vorschau, Klick sendet GIF direkt
- `chat.php`, **Gast-Gate Overlay**: Vollscreen-Blocker (z-index:9000) zwingt Gäste zur Nicknamenwahl vor Chat-Zugang
- `chat/api/send.php`, GIF-Typ-Unterstützung: `message_type='gif'`, Domain-Whitelist (Tenor/Giphy), URL-Validierung

### Geändert
- `chat.php`, **DJ-Name Fix**: PHP holt jetzt `djs.name` für eingeloggte User → Admin sieht seinen DJ-Namen statt "Administrator"
- `chat/api/messages.php`, SQL geändert: `IFNULL(d.name, u.name) AS user_name`, DJ-Profilname hat Vorrang vor Account-Name
- `chat/api/messages.php`, GIF-Nachrichten laufen nicht durch `htmlspecialchars` (URL bleibt URL), aber FILTER_VALIDATE_URL-Check
- `chat.php`, **Layout-Zentrierung**: Nachrichten und Input max 900px breit, auf großen Screens zentriert via `max()` CSS-Funktion
- `chat.php`, **Nachrichten unten**: `justify-content: flex-end` auf `.chat-messages`, neue Nachrichten erscheinen unten, Leerraum oben
- `chat.php`, **Input-Row Redesign**: GIF + 😊 + Senden als normale Flex-Elemente im Row (kein `position:absolute` mehr), alle bündig nebeneinander
- `chat.php`, `position: relative` auf `.chat-input-area` fehlte, Emoji-Panel hat sich nicht korrekt geöffnet (jetzt gefixt via `.chat-input-inner`)
- `chat.php`, `buildMessage()`: GIF-Typ rendert `<img class="chat-gif">` statt Text

### Behoben
- Bug: Emoji-Panel öffnete sich nicht (fehlende `position: relative` auf Elternelement)
- Bug: DJ-Name zeigte "Administrator" statt DJ-Profilname
- Bug: GIF- und Emoji-Buttons lagen weit auseinander (position:absolute Problem)
- Bug: Nachrichten erschienen oben statt unten im Chat-Bereich

---

## [2026-04-04], Vollwertiges Chat-System

### Hinzugefügt
- `chat.php`, Vollwertiger Chat: Gastzugang + Login, Räume, Reaktionen, Reply, DMs, Moderations-Tools
- `chat/api/messages.php`, GET-API: Nachrichten pollen (Polling alle 2s, nach letzter ID)
- `chat/api/send.php`, POST-API: Nachricht senden (Rate-Limit: 5/10s, Ban-Check, Room-Check)
- `chat/api/react.php`, POST-API: Reaktionen hinzufügen/entfernen (Toggle, 7 Emojis)
- `chat/api/users.php`, GET-API: Online-Nutzer abrufen (90s Timeout)
- `chat/api/heartbeat.php`, POST-API: Online-Status aktuell halten (alle 30s)
- `chat/api/delete.php`, POST-API: Nachricht löschen (eigene oder als Mod)
- `chat/api/ban.php`, POST-API: User/Gast sperren mit Dauer (nur Mods)
- `chat/api/dm-list.php`, GET-API: DM-Gespräche auflisten (Login erforderlich)
- `chat/api/dm-messages.php`, GET-API: DM-Nachrichten zwischen zwei Usern laden
- `chat/api/dm-send.php`, POST-API: Direktnachricht senden (Rate-Limit: 10/Min)
- `admin/chat.php`, Chat-Admin: Übersicht, letzte Nachrichten, Bans aufheben, Räume leeren
- `admin/chat-rooms.php`, Chat-Räume CRUD: Name, Slug, Icon, Login-Pflicht, Reihenfolge
- `includes/header.php`, Chat-Link in Navbar ergänzt

### Datenbank
- Tabelle `chat_rooms`, Räume mit Slug, Icon, Sort-Order, Login-Pflicht
- Tabelle `chat_messages`, Nachrichten mit Reply-Referenz, Soft-Delete, Typ-Enum
- Tabelle `chat_reactions`, Emoji-Reaktionen (UNIQUE per User/Gast + Message + Emoji)
- Tabelle `chat_bans`, Sperren mit IP-Hash, User-ID oder Gast-Token, Ablaufzeit
- Tabelle `chat_dms`, Direktnachrichten zwischen eingeloggten Usern
- Tabelle `chat_online`, Online-Tracking (90s Timeout, UNIQUE per User/Gast)
- 4 Standard-Räume direkt eingefügt: Allgemein, Musik, Off-Topic, DJ-Lounge

### Server
- Alle 6 Chat-Tabellen + 4 Standardräume auf 23.88.48.74 migriert
- Alle Chat-Dateien hochgeladen, PHP-Syntax geprüft ✅

---

## [2026-04-04], SMTP-Mailversand

### Hinzugefügt
- `includes/functions.php`, zentrale `sendSmtpMail()` Funktion (STARTTLS/SSL, UTF-8, Fallback auf mail())
- `admin/settings.php`, SMTP-Konfigurationsblock (Host, Port, Verschlüsselung, User, Passwort, Absender)
- `install.php`, optionaler SMTP-Schritt in Schritt 5 (Grundeinstellungen)

### Geändert
- `admin/applications.php`, `mail()` durch `sendSmtpMail()` ersetzt
- `bewerbung.php`, `mail()` durch `sendSmtpMail()` ersetzt
- `api/contact.php`, `mail()` durch `sendSmtpMail()` ersetzt
- `admin/users-edit.php`, `mail()` durch `sendSmtpMail()` ersetzt

### Server
- SMTP-Credentials (Gmail + App-Passwort) direkt in DB settings eingetragen (nicht im Code)
- Test erfolgreich: Mail an me@heikodeutsch.io gesendet

---

## [2026-04-04], Mehrsprachigkeit, Voting, Charts, Push & Swipe

### Hinzugefügt
- `lang/de.php` + `lang/en.php`, Vollständige Sprachdateien (DE + EN) inkl. JS-Keys
- `includes/lang.php`, `initLang()` liest jetzt DB-Setting `default_language` als Fallback
- `includes/footer.php`, `window.radioLang` JSON-Objekt injiziert; Cookie-Banner (DSGVO, localStorage)
- `assets/js/main.js`, Alle hardcodierten deutschen Strings durch `window.radioLang` ersetzt
- `index.php`, CTA-Section jetzt zweisprachig via `t()` Keys
- `admin/settings.php`, Dropdown für `default_language` (DE / EN)
- `install.php`, `default_language` in Step 5; `song_request_votes`, `playlist_history` Tables; `liquidsoap_token` Default-Setting
- `api/vote.php`, Song-Wunsch-Voting API (POST, CSRF, IP-Schutz, Duplicate-Check)
- `api/track-played.php`, Liquidsoap Metadata-Endpoint (POST, Token-Auth, Deduplizierung)
- `sitemap.php`, Dynamische XML-Sitemap (Static Pages + News + DJ-Slugs + hreflang DE/EN)
- `wunsch.php`, Voting-Buttons (Herz-Icons), Playlist-History Sidebar, Requests nach Votes sortiert
- `sendeplan.php`, Mobile Swipe-Navigation (touchstart/touchend), Swipe-Hinweis-Banner
- `admin/index.php`, Hörerzahl-Chart (Chart.js, letzte 24h stündlich, Ø + Max)
- `admin/includes/admin-footer.php`, Chart.js 4.4.2 via CDN eingebunden
- `admin/dj-area.php`, Browser Push Notification (Notification API) beim Live-Gehen
- `assets/css/style.css`, Styles für Cookie-Banner, Vote-Button, Swipe-Hint, History-Track
- `liquidsoap-hook.liq`, Referenz-Konfiguration für Liquidsoap on_metadata Hook
- `deploy.bat`, Alle neuen Dateien ergänzt (api/vote.php, api/track-played.php, sitemap.php usw.)

### Geändert
- `admin/settings.php`, `default_language` Feld ergänzt
- `install.php`, `song_requests` Tabelle um `votes INT DEFAULT 0` erweitert
- `FEATURES.md`, Alle neuen Features dokumentiert, Erledigte-Liste aktualisiert

### Datenbank (neue Tabellen / Spalten nötig via ALTER oder Neuinstallation)
- `song_requests.votes INT DEFAULT 0`, Vote-Zähler pro Song-Wunsch
- `song_request_votes (id, request_id, voter_ip, created_at)`, IP-basierter Vote-Schutz
- `playlist_history (id, title, artist, album, duration, played_at)`, Gespielte Tracks
- `settings.liquidsoap_token`, Secret für Liquidsoap API-Aufrufe

---

## [2026-04-04], Stream-Credentials & DJ Handover-System

### Hinzugefügt
- `admin/dj-area.php`, Per-DJ Stream-Credentials (persönlicher Mountpoint + Passwort) statt globaler Settings
- `admin/dj-area.php`, Live-Steuerungskarte: „Jetzt live gehen" / „Sendung beenden" mit adminConfirm-Modal
- `admin/dj-area.php`, „Wer ist live?"-Widget zeigt aktuell live markierten DJ mit Foto
- `admin/dj-area.php`, „Übergabe vorbereiten"-Button → Modal mit DJ-Auswahl → Benachrichtigung an Ziel-DJ
- `admin/dj-area.php`, POST-Multi-Action-Router: `toggle_requests`, `go_live`, `end_stream`, `handover`
- `admin/djs-edit.php`, Stream-Credentials Karte (Mount, Passwort mit Show/Hide + Copy, Icecast-XML-Snippet)
- `admin/djs-edit.php`, Auto-Generierung von stream_mount und stream_password bei DJ-Anlage
- `admin/djs-edit.php`, „Passwort neu generieren"-Button für Admins (mit Bestätigungsmodal)

### Geändert
- `admin/dj-area.php`, Song-Wünsche Toggle nutzt jetzt action-basierten POST (action=toggle_requests)
- `admin/dj-area.php`, Software-Tipps zeigen persönlichen Mountpoint statt globalem /stream

### Datenbank
- Spalten `stream_mount`, `stream_password`, `is_live` in `djs` Tabelle bereits migriert
- Alle 5 Test-DJs haben automatisch generierte Credentials bekommen

---

## [2026-04-04], Session 2 abgeschlossen

### Hinzugefügt
- `admin/applications.php`, DJ-Bewerbungen verwalten (annehmen/ablehnen/Notiz)
- `admin/podcasts.php` + `admin/podcasts-edit.php`, Podcast/Aufnahmen CRUD mit Audio-Upload
- `admin/api-docs.php`, vollständige API-Dokumentation mit Codebeispielen (JS/Python/PHP/OBS)
- `admin/notifications.php`, Benachrichtigungen-Übersicht mit Lesen/Löschen
- `podcasts.php`, Frontend: Podcast-Archiv mit Audio-Player
- `bewerbung.php`, DJ-Bewerbungsformular (Frontend), Daten in DB + Admin-Notification
- `api/now-playing.php` + `api/.htaccess`, JSON-API für aktuellen Sendestatus
- `cron/stats.php`, Hörer-Statistik alle 5 Min (in Crontab aktiv)
- `cron/backup.php`, täglicher DB-Backup um 03:00 (in Crontab aktiv)
- Countdown-Banner in `sendeplan.php`, "Jetzt live" + "Nächste Sendung" mit Sekunden-Countdown
- Top-Wünsche + Status "Wunschbox geschlossen" in `wunsch.php`
- Notifications-Badge in Admin-Sidebar + Topbar (Unread-Count in Echtzeit)
- Bewerbungen-Widget im Dashboard wenn offene Bewerbungen vorhanden
- Welcome-E-Mail beim Anlegen neuer Benutzer in `admin/users-edit.php`
- `.badge-draft` CSS-Klasse in `admin/css/admin.css`

### Datenbank
- `applications.notes` Spalte hinzugefügt
- Neue Permissions: `view_podcasts`, `edit_podcasts`, `view_applications` (für admin/superadmin/dj)

### Server
- Verzeichnisse angelegt: `/backups/db/`, `/assets/audio/`, `/assets/img/podcasts/`
- Cronjobs eingerichtet: stats alle 5 Min, backup tägl. 03:00

<!-- Claude fügt hier automatisch neue Einträge hinzu -->
<!-- Format pro Tag:

## [YYYY-MM-DD]
### Hinzugefügt
- Beschreibung (datei.php)

### Geändert
- Beschreibung (datei.php:zeile)

### Behoben
- Bug: Beschreibung (datei.php:zeile)

### Entfernt
- Beschreibung (Grund)

### Sicherheit
- Beschreibung (datei.php)

### Performance
- Beschreibung (datei.php)

-->
