# Changelog

All notable changes to rebreak-native will be documented in this file.
## v0.3.13 (Build 76 / versionCode 59) — 2026-06-04\n\n### Fixes

- DM image viewer: opening a shared photo no longer jitters — the image now fills the screen smoothly instead of snapping from a square placeholder to its real size on load
- DM info sheet: tapping a shared image now opens the full-screen viewer on top of the sheet and returns to the sheet when you close it, instead of kicking you back to the DM
- DM header status: the online / typing indicator no longer flickers. "Online" is now held steady through brief presence hiccups (no more rapid switching to "last seen"), and "typing…" stays stable while the other person is composing instead of dropping out on every thinking pause
- Lyra Coach chat: Lyra no longer pulls in leftover content from your last SOS crisis session — the SOS flow and the casual Coach chat are now fully separated. Stray internal prompts and raw text that could surface as chat bubbles are filtered out, and any already-affected chat history cleans itself up the next time you open the Coach
- Chat list: conversations now sort newest-first and re-order live — as soon as a new message or call comes in (from the other person or sent from any of your devices), that chat jumps to the top, instead of the list staying in a fixed order
- Chat list: removed the phone emoji in front of "Audio call" in the conversation preview for a cleaner look
- DM typing indicator: moved out of the header into an Instagram-style in-thread bubble at the bottom of the conversation (partner avatar + animated wave dots). The header now stays on online / last-seen, and the "typing…" bubble auto-scrolls into view\n
## v0.3.13 (Build 76 / versionCode 59) — 2026-06-04\n\n### Fixes

- DM image viewer: opening a shared photo no longer jitters — the image now fills the screen smoothly instead of snapping from a square placeholder to its real size on load
- DM info sheet: tapping a shared image now opens the full-screen viewer on top of the sheet and returns to the sheet when you close it, instead of kicking you back to the DM
- DM header status: the online / typing indicator no longer flickers. "Online" is now held steady through brief presence hiccups (no more rapid switching to "last seen"), and "typing…" stays stable while the other person is composing instead of dropping out on every thinking pause
- Lyra Coach chat: Lyra no longer pulls in leftover content from your last SOS crisis session — the SOS flow and the casual Coach chat are now fully separated. Stray internal prompts and raw text that could surface as chat bubbles are filtered out, and any already-affected chat history cleans itself up the next time you open the Coach
- Chat list: conversations now sort newest-first and re-order live — as soon as a new message or call comes in (from the other person or sent from any of your devices), that chat jumps to the top, instead of the list staying in a fixed order
- Chat list: removed the phone emoji in front of "Audio call" in the conversation preview for a cleaner look
- DM typing indicator: moved out of the header into an Instagram-style in-thread bubble at the bottom of the conversation (partner avatar + animated wave dots). The header now stays on online / last-seen, and the "typing…" bubble auto-scrolls into view\n
## v0.3.13 (Build 71 / versionCode 54) — 2026-06-04\n\n### Fixes

- Voice calls: in-call speaker button now actually routes audio to the phone speaker (instead of being a no-op). The route is re-applied after WebRTC has set up its audio session, so it survives the call-connect transition
- DM screen: keyboard really stays open now when tapping the send button — the previous fix only handled the keyboard-Enter case. Send button stays mounted while the message is being uploaded so the touch target doesn't disappear underneath your finger
- DM screen: tuned the gap above the input bar so the last message sits at a comfortable middle distance (not too tight, not floating too high)
- DM info sheet: the partner avatar now renders correctly for users with a default/list avatar (not just custom photo uploads), using the same avatar component as the header. The chevron now sits inline right next to the name
- DM info sheet: tapping a shared image now opens the same full-screen viewer as in the chat (rounded corners + save button) instead of doing nothing behind the sheet

### Features

- Voice calls now show up in the chat: after every call the conversation bubbles up to the top of the chat list with "📞 Audio call" as the last-message preview, and an inline call-note row appears in the chat thread itself (Instagram-style — with duration if the call connected, or "Missed call" / "Call declined" / "No answer" if it didn't)
- Voice calls: new speaker button in the call screen between Mute and Hangup (volume-medium icon → volume-high when active). Works on both iOS (AVAudioSession route override) and Android (AudioManager speakerphone)
- Mobile dev tooling: new `./dev.sh mobile` command auto-detects connected iPhone (USB) + Android (ADB) and builds + launches dev clients on both in parallel, sharing a single Metro bundler
- DM image viewer is now a swipeable gallery — tapping any photo (in the chat or the info sheet) opens a carousel of all images shared in that conversation, starting at the one you tapped. Swipe left/right to browse, with a position counter (e.g. 2 / 6); the save button always targets the current image

### Changes

- DM chat background is now always the clean solid style (white in light mode, black in dark) — removed the per-chat background picker again for simplicity
- DM voice notes restyled to Instagram-style waveforms: incoming notes have black bars on a light grey bubble, your own notes have white bars on a mint-green bubble. While playing, the upcoming part dims to grey and fills back in as it progresses\n
## v0.3.13 (Build 70 / versionCode 53) — 2026-06-03\n\n### Fixes

- DM screen: tuned the gap above the input bar so the last message sits at a comfortable middle distance (not too tight, not floating too high)
- DM screen: the keyboard now stays open after sending a message (Instagram/WhatsApp style) — it only dismisses when you tap elsewhere, instead of closing on every send
- DM info sheet: the partner avatar now renders correctly for users with a default/list avatar (not just custom photo uploads), using the same avatar component as the header. The chevron now sits inline right next to the name
- DM info sheet: tapping a shared image now opens the same full-screen viewer as in the chat (rounded corners + save button) instead of doing nothing behind the sheet

### Features

- DM image viewer is now a swipeable gallery — tapping any photo (in the chat or the info sheet) opens a carousel of all images shared in that conversation, starting at the one you tapped. Swipe left/right to browse, with a position counter (e.g. 2 / 6); the save button always targets the current image

### Changes

- DM chat background is now always the clean solid style (white in light mode, black in dark) — removed the per-chat background picker again for simplicity
- DM voice notes restyled to Instagram-style waveforms: incoming notes have black bars on a light grey bubble, your own notes have white bars on a mint-green bubble. While playing, the upcoming part dims to grey and fills back in as it progresses\n
## v0.3.13 (Build 69 / versionCode 52) — 2026-06-03\n\n### Fixes

- DM screen: fixed the last message being half-hidden behind the input bar on initial open. The keyboard-closed clearance now accounts for the input bar's safe-area shift (insets.bottom), matching the comfortable gap of the keyboard-open state

### Features

- DM chat background is now per-chat customizable (Instagram-style). Default is a clean solid background (white in light mode, black in dark) instead of the patterned WhatsApp-style background. In the chat's info sheet you can switch each conversation between "Clean" and "Pattern" — stored locally per chat on your device. Incoming bubbles get a subtle grey tint on the clean background so they stay readable. Localized DE/EN/FR/AR\n
## v0.3.13 (Build 68 / versionCode 51) — 2026-06-03\n\n### Fixes

- DM screen: bottom gap on initial open tightened — the last message now sits directly above the input bar. The keyboard-closed padding was double-counting the input bar's own layout slot, leaving a large empty gap every time you opened a chat
- DM image lightbox: photos now actually show rounded corners — the viewer container is sized to the image's real aspect ratio (via onLoad), so the rounding lands on the visible photo instead of the empty letterbox margins of a fixed square
- Lyra coach: removed the "welcome back" greeting that popped up on every first open of the coach each session, regardless of protection status or language (it was always German and unconditional). Will return later only when it's actually warranted
- Chat list performance: the conversation list + unread badge now load via a single indexed query (one row per conversation) instead of pulling up to 500 messages and de-duplicating on the fly — added DB indexes on direct messages. Invisible to users, keeps the chat tab fast as message volume grows

### Features

- DM image lightbox: tap a shared photo → opens with a "Save" button that stores the image to your Photos library (downloads remote images first, asks for photo-add permission once). Localized DE/EN/FR/AR\n
## v0.3.13 (Build 67 / versionCode 50) — 2026-06-03\n\n### Fixes

- DM screen: bottom gap on open tightened — the last message now sits directly above the input bar instead of leaving a visible gap (reduced the keyboard/input-bar clearance padding)

### Features

- DM image lightbox: tap a shared photo → it now opens with rounded corners and a "Save" button that stores the image to your Photos library (downloads remote images first, asks for photo-add permission once). Localized DE/EN/FR/AR\n
## v0.3.13 (Build 65 / versionCode 50) — 2026-06-03\n\n### Fixes

- DM screen: message text bumped a tick larger (14 → 15px, line height 21 → 22) for better readability
- DM screen: faster open — active conversations are now cached in memory for the session (stale-while-revalidate). Reopening a chat shows the messages instantly instead of a loading spinner + full re-fetch every time; the history still refreshes in the background and merges live. Many users reported the chat felt slow to load — this removes the blocking spinner on every open
- DM / tab bar: unread badge no longer stuck — a voice note (or any message) that arrived live via realtime while the chat was already open is now marked read server-side (previously only the history GET marked read), so the count chip on the Chat tab clears correctly after you read & reply and go back
- DM screen: keyboard avoidance — messages now scroll above the keyboard while typing (WhatsApp/Instagram behavior); previously the newest messages were hidden behind the floating input bar
- DM screen: bottom spacing tightened — last message no longer floats too high above the input bar when keyboard is open (was double-counting the input bar height)
- DM screen: voice note replay — playing a finished voice note again now restarts from the beginning (replayAsync) instead of jumping the position dot to the end; resume-after-pause still keeps its position
- DM header: partner online status now reflects real presence live (was gated behind the follow-graph, so DM partners you don't follow never showed as online); updates in realtime via the presence sync channel
- DM screen: voice note waveform redesigned to look natural like WhatsApp — 34 thicker bars (3px, rounded caps) with deterministic per-message amplitude variance + speech envelope (was 80 uniform thin bars that looked hardcoded/solid)

### Features

- Community posts: @mentions are now highlighted — when Lyra posts a thank-you after a custom domain is approved and mentions the requester (e.g. @Hamed), the mention now stands out in the accent color + bold instead of blending into the body text. Works app-wide and unicode-aware (also matches non-latin nicknames)
- DM header: typing indicator — shows "schreibt" with animated pulsing dots when the partner is typing (Instagram/WhatsApp style); ephemeral Supabase broadcast (no DB write), deterministic per-pair channel, throttled send (max 1×/1.5s), auto-clears after 4s, stops immediately on send; neutral-grey color (no green, per online-status convention)
- i18n: presence.typing string added for DE/EN/FR/AR
- Settings → Rebreak Magic: new entry to bind your iPhone via the Rebreak Magic Mac app — generates a 6-digit pairing code (10min TTL, single-use), shows the Mac DMG download, lists connected Macs; no email/password needed on the Mac, the app authenticates purely via the code from your phone
- Add Mac sheet: subtle banner pointing to the new Rebreak Magic flow (existing manual mobileconfig flow stays unchanged for power users)\n
## v0.3.13 (Build 62 / versionCode 50) — 2026-06-03\n\n### Fixes
- DM screen: message text bumped a tick larger (14 → 15px, line height 21 → 22) for better readability
- DM screen: faster open — active conversations are now cached in memory for the session (stale-while-revalidate). Reopening a chat shows the messages instantly instead of a loading spinner + full re-fetch every time; the history still refreshes in the background and merges live. Many users reported the chat felt slow to load — this removes the blocking spinner on every open
- DM / tab bar: unread badge no longer stuck — a voice note (or any message) that arrived live via realtime while the chat was already open is now marked read server-side (previously only the history GET marked read), so the count chip on the Chat tab clears correctly after you read & reply and go back
- DM screen: keyboard avoidance — messages now scroll above the keyboard while typing (WhatsApp/Instagram behavior); previously the newest messages were hidden behind the floating input bar
- DM screen: bottom spacing tightened — last message no longer floats too high above the input bar when keyboard is open (was double-counting the input bar height)
- DM screen: voice note replay — playing a finished voice note again now restarts from the beginning (replayAsync) instead of jumping the position dot to the end; resume-after-pause still keeps its position
- DM header: partner online status now reflects real presence live (was gated behind the follow-graph, so DM partners you don't follow never showed as online); updates in realtime via the presence sync channel
- DM screen: voice note waveform redesigned to look natural like WhatsApp — 34 thicker bars (3px, rounded caps) with deterministic per-message amplitude variance + speech envelope (was 80 uniform thin bars that looked hardcoded/solid)

### Features
- Community posts: @mentions are now highlighted — when Lyra posts a thank-you after a custom domain is approved and mentions the requester (e.g. @Hamed), the mention now stands out in the accent color + bold instead of blending into the body text. Works app-wide and unicode-aware (also matches non-latin nicknames)
- DM header: typing indicator — shows "schreibt" with animated pulsing dots when the partner is typing (Instagram/WhatsApp style); ephemeral Supabase broadcast (no DB write), deterministic per-pair channel, throttled send (max 1×/1.5s), auto-clears after 4s, stops immediately on send; neutral-grey color (no green, per online-status convention)
- i18n: presence.typing string added for DE/EN/FR/AR
- Settings → Rebreak Magic: new entry to bind your iPhone via the Rebreak Magic Mac app — generates a 6-digit pairing code (10min TTL, single-use), shows the Mac DMG download, lists connected Macs; no email/password needed on the Mac, the app authenticates purely via the code from your phone
- Add Mac sheet: subtle banner pointing to the new Rebreak Magic flow (existing manual mobileconfig flow stays unchanged for power users)\n
## v0.3.13 (Build 60 / versionCode 48) — 2026-06-02\n\n### Fixes
- DM screen: keyboard avoidance — messages now scroll above the keyboard while typing (WhatsApp/Instagram behavior); previously the newest messages were hidden behind the floating input bar (KeyboardStickyView moves via transform, viewport didn't shrink — fixed by adding keyboardHeight to FlatList bottom padding)
- DM screen: voice note waveform redesigned to look natural like WhatsApp — 34 thicker bars (3px, rounded caps) with deterministic per-message amplitude variance + speech envelope (was 80 uniform thin bars that looked hardcoded/solid)

### Features
- DM screen: typing indicator in header — shows "schreibt" with animated pulsing dots when the partner is typing (Instagram/WhatsApp style); ephemeral Supabase broadcast (no DB write), deterministic per-pair channel, throttled send (max 1×/1.5s), auto-clears after 4s, stops immediately on send; neutral-grey color (no green, per online-status convention)
- i18n: presence.typing string added for DE/EN/FR/AR\n
## v0.3.13 (Build 56 / versionCode 46) — 2026-06-01\n\n### Features
- DiGA milestone modal: at day 3, 7, 10 clean — celebratory bottom sheet with soft demographic data ask; milestone-specific emoji+color (orange/purple/gold); AsyncStorage tracks per-user/per-milestone shown state; auto-opens DemographicsAccordion in profile; never shows if demographics already filled; dismissed cleanly with "Vielleicht später"
- Lyra coach: gelegentlicher DiGA-Demografie-Hinweis kontextuell im Gespräch — nur bei positiven Momenten, max. einmal pro Session, sofortiges Akzeptieren bei Ablehnung, streng user-initiated (kein heimliches Extrahieren)
- Chat list: search second stage — typed query shows "Neue Unterhaltung" section with user search results below active conversations; debounced 300ms; only shows users not already in conversations; tap → opens DM immediately
- Chat list: last message shows "🎤 Sprachnachricht" / "📷 Foto" fallback when voice/image sent (was showing empty)
- Push notifications: voice messages send "🎤 Sprachnachricht", images "📷 Foto" in preview (was "📎 Anhang" for all)
- DM screen: voice notes (WhatsApp-style) — mic button when input is empty, tap to record, checkmark to send, trash to cancel; audio bubbles with circular play/pause button, position dot, deterministic waveform (played = accent color, unplayed = muted), duration counter, distinct bubble background from text messages
- Shared VoiceRecordingBar component (Coach + DM unified look): trash left, live waveform + timer center, send right; accent color and send icon configurable per context

### Fixes
- Blocker iOS Layer 3 (Screen Time Passcode): card now visible in locked-in state (was hidden once URL filter + App Lock both active — users could never reach it); screentime confirmed status loaded from backend on mount; guarded to unsupervised/VPN+FC path only (not MDM/NEFilter)
- Blocker iOS Layer 3: redesigned card with numbered step instructions (iOS has no deep link to passcode dialog — steps guide user: open ST → tap "Use Passcode" → enter code); URL fallback chain App-Prefs:SCREEN_TIME → App-Prefs:root=SCREEN_TIME → openSettings
- i18n: mic_access permission strings added for DE/EN/FR/AR; Layer 3 step strings added for all 4 languages\n
## v0.3.13 (Build 54 / versionCode 44) — 2026-06-01\n\n### Features
- DM screen: voice notes (WhatsApp-style) — mic button when input is empty, tap to record, checkmark to send, trash to cancel; audio bubbles with circular play/pause button, position dot, deterministic waveform (played = accent color, unplayed = muted), duration counter, distinct bubble background from text messages
- Shared VoiceRecordingBar component (Coach + DM unified look): trash left, live waveform + timer center, send right; accent color and send icon are configurable per context
- DM screen: info sheet (85% height, FormSheet) with shared media grid (3-col), partner profile link, image lightbox
- DM screen: avatar tap in header navigates to partner profile
- DM screen: info icon (ℹ) in header opens info sheet
- Coach: Instagram-style voice recording bar — trash (left) + waveform + timer (center) + send (right)
- Coach: silence/speech detection via audio metering — dots when silent, animated bars when speaking
- Coach: trash button flashes red briefly on cancel (Instagram-style)
- iOS Layer 3: Screen Time Passcode setup flow — generate code, set in iOS Settings, stored on backend

### Fixes
- Blocker iOS Layer 3 (Screen Time Passcode): card now visible in locked-in state (was hidden once URL filter + App Lock both active — users could never reach it); screentime confirmed status loaded from backend on mount; guarded to unsupervised/VPN+FC path only (not MDM/NEFilter)
- Android: Force Stop bypass blocked — Samsung SubSettings/FrameLayout class detection fixed in a11y tamper lock
- Android: Force Stop confirmation dialog now detected and blocked
- Android: a11y service label corrected to "ReBreak — Schutz" (HIGH_CONFIDENCE_KEYWORD match)
- Arabic STT: switched to Deepgram nova-3 (nova-2-general dropped Arabic support)
- DM: scroll-to-bottom now reliable via scrollToOffset(999999) on Android (scrollToEnd miscalculates content height)
- DM: voice recording timer uses Date.now() diff — eliminates Android setInterval jitter
- DM: voice bars fill full width via flex:1 + space-evenly
- DNS filter: own domains (rebreak.org, rebreak.app) bypass blocklist — fixes OAuth Google callback

### Backend
- Mail classifier v1.2: FS-token +20pts, extreme-percent (≥100%) +20pts, casino in sender name +30pts, block threshold lowered 50→40
- Screen Time Passcode API: POST/GET /api/protection/screentime-passcode
- mail_classification_samples row-cap cron: max 100k rows, daily pruning (prevents disk-full)

### Infrastructure
- CI/CD: race condition fixed — deploy lock prevents webhook + GH-Actions colliding
- CI/CD: health check retry loop (12×5s = 60s max) instead of single sleep 5
- Hetzner: 20GB block volume attached, Docker moved to /mnt/data (freed 14GB on root)
- Deepgram nova-2-general → nova-3 for all languages\n
## v0.3.13 (Build 50 / versionCode 40) — 2026-06-01\n\nlayer 3 for ios / fix a11y\n
## v0.3.13 (Build 46 / versionCode 36) — 2026-05-31\n\nDM-Chat: Die letzte Nachricht wird jetzt zuverlässig oberhalb der Eingabezeile angezeigt — kein manuelles Nachscrollen mehr beim Öffnen oder nach dem Senden.

Chat-Übersicht: Zeitangaben sind feiner abgestuft — neben Minuten/Stunden jetzt auch Wochentag (z.B. „Mi"), danach Tage, Wochen, Monate und Jahre statt nur Datum.\n
## v0.3.13 (Build 44 / versionCode 35) — 2026-05-31\n\nDM-Chat: scrollt jetzt zuverlässig zur neuesten Nachricht — auch nach eigenen gesendeten Nachrichten und beim Laden von Bildern.

Lyra-Sprachnachrichten: Wenn du auf Arabisch oder Türkisch sprichst, antwortet Lyra jetzt auch in der richtigen Sprache (Backend-Fix).

Push-Nachrichten bei Direktnachrichten: stabiler — Fehler werden jetzt geloggt, damit verlorene Pushes nicht mehr unsichtbar sind (Backend-Fix).\n
## v0.3.13 (Build 44 / versionCode 33) — 2026-05-31\n\nlyra multilanguage fix\n
## v0.3.13 (Build 42 / versionCode 32) — 2026-05-30\n\nChat-DM: Lange auf eine Nachricht drücken öffnet das Aktions-Menü jetzt direkt an der Nachricht (WhatsApp-Stil) statt zentriert. Neu: Emoji-Reaktionen (oben), Antworten und Kopieren bei fremden Nachrichten, sowie Löschen für eigene Nachrichten (für alle). Reaktionen erscheinen als kleine Bubbles unter der Nachricht. Gelöschte Nachrichten zeigen „Nachricht gelöscht".

Community: Likes an Kommentaren färben sich jetzt sofort und erscheinen in Echtzeit, auch wenn jemand anderes liked.

Optik: Menüs (Profil, Chat-Aktionen) haben jetzt einen sauberen iOS-Blur-Hintergrund. Neuer gebrandeter Startbildschirm beim App-Start.\n
## v0.3.13 (Build 40 / versionCode 31) — 2026-05-30\n\nChat-DM: Lange auf Nachricht drücken öffnet jetzt das native Aktions-Menü (Antworten, Liken, Kopieren). Likes erscheinen Insta-Style als Herz unter der Nachricht.\n
## v0.3.13 (Build 27 / versionCode 18) — 2026-05-30\n\nPush-Notifications für Chat: Du erhältst jetzt Pushes bei neuen Direkt-Nachrichten und Raum-Nachrichten. Abschaltbar in den Einstellungen.\n
## v0.3.13 (Build 26 / versionCode 16) — 2026-05-30\n\nneue push für chat\n
Format: [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
Versioning: `version` follows SemVer, `versionCode` is monotonically increasing.

---

## [Unreleased]

---

## [0.3.6] — buildNumber 15 / versionCode 11 — 2026-05-25

### Changed
- **MDM-managed iPhones**: FC-Authorization-Toggle-UI wird bei MDM-verwalteten Geräten
  ausgeblendet. Der Schutz läuft in diesem Fall vollständig via MDM-managed VPN-Layer —
  kein manueller Toggle nötig oder sinnvoll.

### Backend
- **Layer-2 Country-Curated-Pivot**: Layer 2 ist jetzt ausschliesslich kuratiert (Rebreak-Admin).
  Custom-Domains laufen nur noch über Layer 1 (VPN). Vollständige Entkopplung der beiden
  Schichten; Travel-Detection via Cellular-MCC geplant.

---

## [0.3.5] — buildNumber 14 / versionCode 11 — 2026-05-22

### Fixed
- **Android VPN-Blocklist-Self-Heal** (`9a22bcd`) — Nach der ersten Schutz-Aktivierung
  lud `RebreakVpnService` die Blocklist nicht, wenn sie zur Startzeit noch nicht bereit
  war (0 Domains aktiv). Neuer Self-Heal-Mechanismus: der Service prüft nach Tunnel-Start,
  ob die Blocklist leer ist, und lädt sie mit exponentiellem Backoff nach
  (1 s → 2 s → 4 s, max 3 Versuche). Kein Geräte-Neustart mehr nötig.
- **iOS Layer-1 VPN: File-Protection-Fix** — `blocklist.bin` wird jetzt mit
  `FileProtectionType.completeUntilFirstUserAuthentication` geschrieben statt dem
  strengeren `.complete`. Damit ist die Datei nach dem ersten Entsperren seit Boot
  für die PacketTunnel-Extension dauerhaft lesbar — auch wenn der Tunnel startet,
  während das Gerät gesperrt ist.
- **iOS Layer-1 VPN: Self-Heal** — Blocklist-Retry mit Backoff (3 s → 10 s → 30 s →
  60 s → 120 s → 300 s, max 20 Versuche). War die Blocklist beim Tunnel-Start leer
  (Data-Protection-Fenster), lädt sie sich nach dem ersten Entsperren automatisch nach
  — kein manueller Sync oder VPN-Neustart nötig.

### Added
- **VIP-Liste (Geblockte Domains)**: Eigene Domains und Stichwörter zur persönlichen
  Blocklist hinzufügen. Landabhängige kuratierte Vorschläge (DE, AT, CH, FR, AR).
  Slot-System: 10 Slots für Pro, 20 Slots für Legend — Web und Mail teilen sich einen
  gemeinsamen Pool (kein Free-Tier). Kachel-UI mit Slot-Fortschrittsanzeige.
- **VIP Slot-Replace mit Cooldown**: Bestehende Slots können ersetzt werden; ein
  12-Stunden-Cooldown verhindert schnelles Umgehen der Blocklist.
- **Curated-Domain-Vorschläge**: Beim Hinzufügen einer Domain werden bekannte
  Glücksspiel-Anbieter aus der jeweils passenden Länderliste vorgeschlagen.

### Fixed
- **Chat Inverted-FlatList**: Nachrichten rendern jetzt korrekt von unten nach oben
  (Standard-Chat-Layout). Vorheriges Layout ließ neue Nachrichten oben erscheinen.
- **Chat Listen-Hänger**: FlatList blockierte bei langen Nachrichtenlisten nicht mehr
  den Main-Thread — virtualisierung greift korrekt.

---

## [0.3.0] — versionCode 10 — 2026-05-17

### Added
- **Duo-style Onboarding (9 Slides)**: Vollständiger Onboarding-Flow — Welcome → Privacy → Nickname → DiGA-Choice → DiGA-Code → Plan → Payment → Protection → Done. Lyra-Bubble mit TTS-Audio-Button auf jedem Slide. Pre-Explainer-Screenshots vor iOS-Permission-Dialogen. Confetti-Animation + Top-5-FAQ-Accordion auf Done-Screen.
- **DiGA-Redeem-Endpoint + 100 Test-Codes**: Backend-Endpoint für DiGA-Code-Einlösung. 100 vordefinierte Test-Codes (REBREAK-TEST-001 bis REBREAK-TEST-100) für QA und Reviewer.
- **Lyra Voice TTS Auto-Play + Voice-Button in Bubble**: TTS startet automatisch beim Slide-Einblenden; Voice-Button in der Lyra-Bubble startet/stoppt Audio on-demand. DiGA-Accessibility-Feature.
- **Stripe Web-Checkout-Integration**: Pro 3,99 EUR/Monat, Legend 7,99 EUR/Monat, je 14-Tage-Trial. Checkout-Redirect via `expo-web-browser`, Webhook bestätigt Plan-Aktivierung serverseitig.
- **Arabisch (Arabic) + RTL-Support**: Vollständige arabische Lokalisation mit automatischem RTL-Layout-Switching.
- **NEFilter Robust Disable**: 2-step Apple-Pattern für zuverlässiges Deaktivieren des URL-Filters. `resetUrlFilter` als Recovery-Pfad bei code-5-Fehlern. `ProtectionOffSheet` ersetzt bisherigen Alert.
- **Family Controls always-on**: Kein "Bald"-Placeholder mehr — FamilyControls-Entitlement (Distribution-approved) ist vollständig aktiv.
- **Stripe Tier-Rename + Checkout-Refactor**: Pläne heißen jetzt konsistent `pro` / `legend` (statt alter Naming-Varianten). Checkout-Endpoint neu strukturiert.
- **protectionDisabledAt (Backend)**: Server-seitige Timestamps verhindern Auto-Reaktivierung nach manuellem Deaktivieren durch den User.
- **FaqAccordion-Komponente (shared)**: FAQ-Accordion extrahiert als `components/FaqAccordion` — geteilt zwischen DoneSlide und `help/faq`-Seite.

### Changed
- **ProtectionSlide: Platform.OS-Dispatch**: iOS-Pfad aktiviert NEFilter + FamilyControls. Android-Pfad aktiviert VPN-Permission + a11y-TamperLock (VPN-Permission-Dialog → a11y-Pre-Explainer → a11y-Settings-Open → AppState-Auto-Detect-Return → tamperLock armed → finished).
- **Blocker Single-Banner-Logik**: `lockedIn` ist nur `true` wenn BEIDE Schutz-Ebenen aktiv sind (iOS: urlFilter && appDeletionLock; Android: VPN && a11y). Kein falsches "Locked In" mehr bei Teilschutz.

### Fixed
- **Android Keyboard-Covers-Input (Chat/DM)**: `react-native-keyboard-controller` ersetzt bisherigen KeyboardAvoidingView-Workaround — Input-Feld bleibt beim Tippen korrekt sichtbar.
- **Protection Cooldown Auto-Disable Race**: Stale-State nach Cooldown-Ablauf korrigiert — kein falscher "aktiv"-Zustand mehr.
- **Nickname Validation + Duplicate-Check**: Echtzeit-Prüfung auf bereits vergebene Nicknames im Onboarding.
- **DiGA-Code Auto-Format**: Code-Eingabe formatiert automatisch (Großbuchstaben, Bindestriche).

### i18n
- Französisch (fr) — 3. Sprache (war bereits in v0.2.x als Beta eingeführt, jetzt vollständig).
- Arabisch (ar) + RTL — neu in v0.3.0.

### Backend
- `protectionDisabledAt`-Timestamp auf User-Profil — verhindert Auto-Reactivation nach manuellem Disable.
- DiGA-Code-Redemption-Endpoint (`POST /api/diga/redeem`) — 100 Test-Codes, Plan-Hochstufung auf `legend`.
- Migration `20260517_add_lyra_post_i18n_key`: `i18n_key TEXT` auf `community_posts` (nullable, non-blocking). **Pending Deploy auf Hetzner** — Feature-Flag `USE_TEMPLATE_CATALOG=false` (default) haelt dieses Feature deaktiviert bis Migration deployed ist.

---

## [0.2.1] — versionCode 9 — 2026-05-16

### Fixed
- **Android-Crash nach AccessibilityService-Aktivierung**: BadgeDrawable in der Tab-Bar craste mit `IllegalArgumentException`, weil das Theme `AppCompat` statt `MaterialComponents` nutzte. Theme-Parent auf `Theme.MaterialComponents.DayNight.NoActionBar.Bridge` geändert via Config-Plugin — idempotent nach jedem prebuild.
- **Doppel-Splash auf Android**: Native Android-Splash und JS-Splash sahen unterschiedlich aus (zwei aufeinanderfolgende Splash-Screens). Splash-Image auf `icon.png` umgestellt, matched jetzt exakt den JS-Splash und Landing-Screen.

---

## [0.2.0] — versionCode 8 — 2026-05-16

### Added
- **Mac-DNS-Profil — Vollautomatik**: Die App erkennt per DoH-Handshake, sobald der Mac eine DNS-Anfrage stellt, und springt automatisch auf Schritt 3 im Setup-Flow. Kein manuelles Tippen mehr nötig.
- **Device-Account-Binding**: Pro- und Legend-Konten sind gegen Account-Switch-Bypass geschützt. Wer sich auf einem bereits gebundenen Gerät mit einem anderen Konto anmeldet, bekommt eine Sperre (DEVICE_LOCKED) — und der ursprüngliche Account wird per E-Mail benachrichtigt.
- **Custom Mail-Filter (Cue Avoidance)**: Eigene E-Mail-Adressen oder Domains von Glücksspiel-Anbietern können direkt in der App eingetragen werden. Auto-Detect schlägt bekannte Muster vor. Free/Pro: je 5 Adressen + 5 Domains. Legend: je 10. Die neue Unified-Filter-Section ersetzt alle bisherigen separaten Blocker-Einträge.
- **Like + Kommentar Realtime**: Reaktionen anderer User werden live in der Feed-Karte aktualisiert — kein manuelles Refresh.
- **Chat v1.0 (DM-only)**: Direkt-Nachrichten mit Profilbildern, Suche, Unread-Badge in der Tab-Bar. Gruppen-Chats werden für v1.0 nicht unterstützt.
- **Avatar-Zuschnitt via iOS-Nativ**: Der Profilbild-Zuschnitt nutzt jetzt Apples eigenes UIImagePickerController-Crop statt eines eigenen Sheets — zuverlässiger, native Look.
- **Hilfe-Bereich in Settings**: Neue Seiten für FAQ, Kontakt, Über Rebreak und Krisen-Hotlines. Notifications-Bereich überarbeitet.
- **Global-Blocklist-Vorabprüfung**: Beim Hinzufügen einer Custom-Adresse wird vorab gegen die zentrale Blockliste geprüft — kein Slot wird verbraucht, wenn die Domain sowieso schon global gesperrt ist.
- **FamilyControls standardmäßig aktiv** in lokalen Dev-Builds (`dev-iphone.sh`, `clean-ios.sh`).

### Changed
- **Devices-Seite neu gestaltet**: Zweizeilige Einträge mit animierter Fortschrittsleiste, UIMenu für Mac/Windows-Auswahl, zentrale Button-Komponente durchgehend genutzt.
- **Game-Over-Modal überarbeitet**: Höhenbegrenzung, Keyboard-Avoidance, neuer Regenerate-Button.

### Fixed
- **Mac in Geräteliste-Bug behoben**: Mac-Geräte wurden unter bestimmten Umständen nicht korrekt in der Liste angezeigt.

---

## [0.1.0] — versionCode 7 — 2026-05-15

### Added
- feat(native): device-info API headers — model, name, osVersion sent on every request via lib/api.ts
- feat(native): DeviceLimitSheet visual differentiation — „Dieses Gerät"-Pill distinguishes current device from others in the list

### Changed
- refactor(native): profile-page i18n keys — full sweep of 24 leftover Vue-i18n `{var}` patterns replaced with `%{var}` (vue-i18n-style removed, expo-localization pattern applied consistently)
- chore(native): Google-OAuth always shows account-picker — `prompt=select_account` added to OAuth request, prevents silent re-auth with wrong account
- refactor(native): feed page uses `groupedBg` for card contrast instead of flat background

### Fixed
- fix(native): mail-account-edit modal-conflict + double-click bug — modal coordination corrected, prevents overlapping sheet opens
- fix(native): sign-out now calls `WebBrowser.coolDownAsync` to clear OAuth cookies — prevents stale Google session on next login
- fix(backend): Test-User `charioanouar@gmail.com` correctly identified as MrLonely (device-info schema + merge heuristic + test-user detection, auto-deployed via pipeline)

---

## [0.1.0] — versionCode 6 — 2026-05-15

### Added
- feat(i18n): French as 3rd app language (`fr`) for test customers — full locale file, settings picker, device-locale auto-detect (a981deb-fix)
- feat(native): Lyra voice picker for legend tier — 3 ElevenLabs voices (Default / Voice 1 / Voice 2), backed by PATCH /api/profile/me/lyra-voice (d9bb7ef)
- feat(native): realtime debug page (DEV-only) — connection-state, reconnect-counter, token-expiry countdown, channel list, rolling event-log (a0d67f3)
- feat(backend): Lyra voice TTS-routing — userLyraVoiceId takes priority over default (legend-gated) (76f8595)

### Changed
- refactor(mail): removed Groq LLM borderline layer — deterministic Score+Layer2.5 pipeline only. Resolves DSGVO-P0 items (no third-country data transfer). Layer 2.5 (Brand+Random) continues to catch Apple Hide-My-Email pattern (f2e3c00)

### Fixed
- fix(native): `protectedDevices.filter is not a function` — Array.isArray guard on API response (a0d67f3)

---

## [0.1.0] — versionCode 5 — 2026-05-14

### Added
- feat(mail): multi-layer email classifier — Brand+Random detection, Relay-Decoder (Apple Hide-My-Email), Score-based routing, Groq borderline-review, ML-Sampling pipeline (b2f0471)

### Fixed
- fix(mail): reactive Mail page — stats + connection status refresh on scan/connect (4580a19)
- fix(mail): donut card layout rebuilt from scratch — centered, breathing room, no truncation (2ea0cfe)
- fix(mail): donut card layout justify-start instead of center (aac6c00)
- fix(mail): legend rows justify-between + per-connection bar-chart sparse-data zoom (b47ac24)
- fix(mail): legend takes natural width inside card + bar-chart always trims to hit-range (55cba9a)
- fix(mail): legend vertically centered against donut center number (778d3b6)
- fix(mail): revert marginBottom hack — layout was breaking out of card (1d93ada)
- fix(mail): legend bottom-aligned with donut baseline for visual centering (c218287)
- fix(mail): DSGVO Art. 17 — manual sample cleanup on account delete (be4e163)

---

## [0.1.0] — versionCode 4 — 2026-05-07

### Added
- feat(mail): Outlook OAuth scan + daemon initial-sweep + page polish v4 (8075c8e)

### Fixed
- fix(idle-daemon): sync MS_OAUTH_SCOPES with backend — drop User.Read, add email (fd1cb91)

---
