Apex-only-Format (bare domain) blockte nur z.B. bet365.com, NICHT
www.bet365.com — Casino-Content + Google-Ad-Links liegen aber auf www.
Adblock-Syntax ||domain^ deckt Domain + alle Subdomains ab.
Betrifft alle DNS-Plattformen (Mac/Windows/DoH-Server).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Schliesst hans-muellers K1-Befund (Datenschutz-Audit): der Coach-Prompt
sendete Identifier + Art.9-nahe Daten an US-LLMs (Gemini/OpenAI/Anthropic).
- message.post.ts: Geburtsjahr/exaktes Alter -> Altersgruppe (Dekaden-Bucket);
Stadt komplett entfernt (Bundesland bleibt). Geschlecht/Familienstand/Beruf/
Nickname unveraendert (gewollte Personalisierung; Nickname = Pseudonym).
- lyraMemoryExtract.ts: Extraction-Prompt reduziert Dritt-Klarnamen auf Rolle
("Frau Maria" -> "seine Frau"), keine Orte/Arbeitgeber im Memory-Content.
- 08-datenschutz-audit: Payload-Audit-Platzhalter durch Vorher/Nachher-Tabelle
ersetzt, K1 erledigt, ZDR-Update (DPA/SCCs deemed-signed, TIA offen).
Pseudonymisierung zaehlt jetzt als zweite Schutzmassnahme neben ZDR fuer die TIA.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
iOS no-erase Supervision als therapeutisches Selbstbindungs-/Commitment-Device-
Argument formuliert (Schutz im Drang-Moment nicht löschbar, nur via Vertrauens-
person/Cooldown, ohne Geräte-Reset). Maßvoll positioniert: in DE/für Glücksspiel-
sucht einzigartig, gratis im Legend-Tier (vs. kostenpflichtige US-Tools wie TechLockdown).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Android self-bind protection auf nahezu MDM-Niveau ohne Device-Owner:
- Device-Admin (RebreakDeviceAdminReceiver) blockt Uninstall OS-seitig, aktiv ab
Boot ohne Prozess/a11y. Deaktivierung nur via 24h-Cooldown (removeDeviceAdmin in
forceDisable). a11y blockt die DeviceAdminAdd-Settings-Seite (Class-Match, auf
Samsung One UI per Logcat verifiziert).
- Boot-Receiver (RebreakVpnBootReceiver) startet VPN+a11y nach Reboot, damit der
Tamper-Lock ohne manuellen App-Start hochkommt.
- Manifest-Wiring (Device-Admin-Receiver, Boot-Receiver, RECEIVE_BOOT_COMPLETED,
device_admin.xml) ins with-rebreak-protection-android Config-Plugin verlagert →
ueberlebt 'expo prebuild' (android/ ist gitignored).
- a11y-Detection zurueck auf die funktionierende Version: zu breites 'loeschen'-
Uninstall-Keyword raus (blockte halbe Settings); a11y-Label jetzt 'ReBreak Schutz'.
- a11y-Deeplink behaelt den Samsung-Step-Guide (openAccessibilitySettings).
Session-Frontend in diesem Batch:
- Avatar-Placeholder: neutrales clarity-avatar-line SVG statt dominantem Blau.
- DiGA-Milestone folgt kumulativen protectedDays (erreicht rueckfall-anfaellige User).
- Dev-Build crasht nicht mehr ohne CallKit-Native-Modul.
- VPN-Permission-Dialog nur noch im Bypass-Fall.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New 'erinnerung' topic for manual Lyra community posts that gently remind
users they can add optional, anonymous profile details. Wording stays
jargon-free (no 'DiGA'/'data'/'study'). Manual-only, not in the auto-cron
catalog.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Domain/display-name adds now force a full re-scan so newly-added gambling
senders are caught immediately instead of waiting for the incremental UID
window. IMAP-idle NOOP tick lowered 2min -> 30s to close the Junk-folder gap
faster (Outlook drops straight into Junk, which IDLE does not watch).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The old streak was non-functional: streaks.current_days was always 0 (never
computed/incremented), and the profile page read me.streak (0) + account
created_at as the "since" date — showing "0 days protected since <signup>"
for everyone. This is the DiGA key metric, so it had to be rebuilt.
New model: optimistic protection-coverage based on actual VPN/MDM protection
state, never resets to 0.
- backend: append-only protection_state_log + migration; POST /api/protection/event
(ingestion, deduped) + GET /api/protection/coverage (read-time compute, no cron);
server-side cooldown_disable event on cooldown resolve. Generous >6h-off/day rule.
- frontend: report protection on/off transitions (initial + flips, deduped) from
useProtectionState; rewrote profile StreakSection → half-donut (protected vs
unprotected) + progress bar (current streak → personal record) + empty state.
- coverage starts fresh from deploy (no historical backfill — clean data for DiGA).
- spec: docs/specs/protection-coverage-streak.md (shared contract).
- old streaks/streak_events/profiles.streak left intact (coach/scores consumers).
Also adds go-to-market one-pagers under docs/marketing/.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Calls: an incoming call that ended without the in-app /call screen ever
mounting (iOS shows the native CallKit banner, not our screen) left the
call store stuck in 'ended' forever — the ended→idle reset only lived in
the /call screen. A stuck 'ended' then blocked every subsequent incoming
call (RING + VoIP push were received but dropped by the status!=='idle'
guard), so accepting from the banner produced a phantom CallKit call that
ticked as active with no connection, and the caller saw a missed call.
- store self-heals back to 'idle' after a call ends (teardown fallback)
- receiveIncoming + ring handler tolerate a stale 'ended' state
- onAnswer ends the native CallKit call when store has no incoming call
- RNCallKeep.endAllCalls() on launch clears leftover CallKit zombies
DM online dot: the green avatar dot used follow-gated presence while the
"online" text used raw presence → dot hidden for non-followed partners
even when online. DM header avatar now uses raw presence (rawPresence
prop) → consistent with the text on both platforms.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der inkrementelle Scan-Pfad rief imap.search({ uid: 'X:*' }) ohne das
zweite { uid: true }-Argument auf → ImapFlow sendet "SEARCH UID X:*"
statt "UID SEARCH UID X:*" → Server antwortet mit Sequence-Numbers.
Die nachfolgende fetchAll(..., { uid: true }) interpretiert diese als
UIDs → fetcht die falschen (alten) Mails → neu eingegangene Gambling-
Mail (höchste echte UID) wird nie klassifiziert/gelöscht (>15min Lag).
Auch Ursache des "Command Error. 10" Log-Spams (Mega-UID-Liste).
Fix: { uid: true } als zweites search()-Argument.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
imapflow.status() liefert uidValidity als BigInt. Der Code reichte den BigInt in
JSON.stringify (patchFolderScanState) → 'TypeError: Do not know how to serialize
a BigInt' → vom stummen connection-level catch verschluckt → weder
patchFolderScanState noch markFullSweepDone liefen je → folder_scan_state blieb
{} + last_full_sweep_at NULL → inkrementeller Scan aktivierte nie (immer Full-Sweep).
Fix:
- serverUidValidity: Number((status).uidValidity ?? 0) — BigInt → number vor JSON.
- Stumme catches (auth/lock/conn) loggen jetzt; Persist-Calls (patchFolderScanState
x2, markFullSweepDone) in eigene try/catch mit console.error — Diagnostik bleibt
drin für Post-Deploy-Verify.
Lokal verifiziert: Build EXIT 0, imapflow extern.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der inline-Negative-Lookahead (/^(?!...)(?!imapflow)/) griff nur auf den nackten
Specifier, nicht auf aufgelöste node_modules-Pfade. Bei Module-Graph-Shifts
(Phase-2 Prisma-Felder) wurde imapflow doch gebundlet → CJS-inherits-Bruch
(util.inherits: superCtor.prototype undefined) → scan-internal 500 → Mail-Filtern
(USP) down (Incident 2026-06-05).
Fix: expliziter external-Eintrag mit Pfad-Regex /(^|node_modules/)imapflow(/|$)/
erzwingt imapflow robust extern. Lokal verifiziert: imapflow landet in
.output/server/node_modules + output-package.json, NICHT als chunk.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase-2-Rebuild reaktivierte den bekannten imapflow/node-apn util.inherits-Bundle-
Bruch → scan-internal warf 500 → Mail-Filtern (USP) down. Rollback von
scan-internal.post.ts + db/mail.ts auf den funktionierenden Stand (5b57bea).
Schema (folder_scan_state, last_full_sweep_at) + Migration BLEIBEN angewendet —
kein Prisma-Drift; die Spalten warten ungenutzt auf den gefixten Phase-2-Retry.
Root-Cause (warum der inkrementelle imap.status/search-Pfad das Bundle bricht)
muss vor erneutem Phase-2-Deploy in der nitro-Externalize-Config gelöst werden.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backend-Lag-Fix Phase 1 — entlastet die CPU-Dauerschleife im Mail-Stack:
- delete mail-scan-cron.ts: der 30-Min-Nitro-Cron scannte alle User parallel
(Promise.allSettled) und war redundant zum IMAP-IDLE-Daemon (Single Source
of Truth). Reine Dauerlast ohne Mehrwert.
- imap-idle: In-Flight-Guard (scanInFlight + coalescePending). triggerScan ist
jetzt re-entry-safe — pro Connection max. 1 aktiver + 1 pending Scan statt
bis zu 8 gestapelt pro 2-Min-NOOP-Tick. Gilt für NOOP + exists-Event.
- plan-features: Pro mailAgents 3->2 (+ Math.min-Hack in coach/message aufgeräumt).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Root cause: iOS CallKit auto-dismisses incoming-call UI after ~5s when the
app is in foreground (because AppDelegate.didReceiveIncomingPush MUST call
reportNewIncomingCall — Apple requirement). That CallKit dismiss fires an
endCall event which our useCallKeepEvents.onEnd translated to declineCall,
unmounting the in-app /call screen before the user could tap accept/decline.
Fixes:
- useCallKeepEvents.onEnd: ignore CallKit endCall when iOS app is foreground
AND status==='incoming' (in-app UI is authoritative there). Comment with
big warning not to remove this again.
- call.tsx closeScreen: replace('/') instead of router.back() to avoid
GO_BACK action errors when navigation stack is inconsistent after long
calls (manifested as wrap-jsx.js crash in react-native-css-interop).
- useIncomingCalls: log CANCEL receive events for future diagnostics.
- call.ts: clog hangup/declineCall/closeScreen with reason+status for trace.
Verified: foreground call screen stays up the full UNANSWERED_MS (35s) and
caller-side hangup('unanswered') correctly triggers iPhone closeScreen via
cancel-broadcast.
- ring.post: log [ring] when triggered
- voip-push: log [voip-push] sent on success with env (prod/sandbox) + callId
- chat.ts sendDirectMessage: when attachmentType=='call' parse audio:<state>:<sec>
into proper preview (Verpasster Anruf, Anruf abgelehnt, Anruf (m:ss), \u2026)
so post-call push has body text instead of empty.
- callkit.startOutgoingCall: skip on Android (telecomManager opens dialer UI \u2014
wrong for in-app WebRTC; iOS-CallKit only for audio-session mgmt).
- voip-push: build both APNs Provider (production+sandbox) and try each per
token with memoization. Fixes BadDeviceToken on Xcode-Dev-Builds where the
token is Sandbox-only.
- stores/call: only call callkit.displayIncomingCall when app NOT in foreground
\u2014 in foreground the /call route handles ringing UI, otherwise double UI
(system banner + fullscreen).
- patch react-native-callkeep: New-Arch TurboModule compatibility (no overloads,
no Bundle params in @ReactMethod).
- pushTokenRegistration: more verbose [voip] diagnostics.
- backend: skip Expo alert push to iOS devices that already received VoIP push
(CallKit + banner = double ring)
- native: receiveIncoming no longer triggers InCallManager.startRingtone —
CallKit/ConnectionService play their own ring. Dedup if same callId
arrives twice (Realtime + VoIP-Push race).
- MediaLightbox component extracted from dm.tsx. Image now fills a fixed
full-screen box with contentFit=contain instead of an onLoad-computed
aspect ratio, removing the square->real-size jump ("jitter") on open.
- Info-sheet images: render a nested MediaLightbox inside the FormSheet
(stacks above the sheet modal) and track lightboxSource. Removes the
close-sheet-then-reopen workaround that switched context back to the DM.
- Typing indicator: heartbeat (every 2s while focused + non-empty) instead
of keystroke-only sends, so "typing…" holds through thinking pauses;
receiver clear raised to 6s. stop on blur/send/empty.
- Presence: debounce going offline by 12s (online immediate) so brief
presence-sync gaps no longer flicker "Online" <-> "last seen".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SOS (urge.tsx) uses /api/coach/message as a stateless LLM proxy for game
comments, share drafts and the stream fallback — sending SOS_BOOT +
[INTERN:] prompts. The endpoint persisted the full messages array into
coachSession for pro/legend users, so those internal prompts and the raw
JSON replies leaked into the Coach chat history as visible bubbles.
- Reactivate the sosMode flag (already sent by all three SOS call-sites):
when set, the endpoint skips coachSession persistence, memory extraction
and feedback detection — pure LLM proxy, no shared state.
- Add a defensive filter on /api/coach/history that strips internal
messages (SOS_BOOT, [INTERN:], [SYSTEM-HINT], raw JSON / [[CHIPS]]
replies) so already-contaminated sessions self-heal on next load.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backend (voice-call groundwork, no call engine yet):
- Profile.callsEnabled (Boolean default true) + migration
- canCall(caller,callee): mutual-follow AND callee.callsEnabled — server-side hard guard
- POST /api/me/calls-enabled (opt-out toggle), GET /api/chat/can-call/:userId
- expose callsEnabled in /api/auth/me
Frontend:
- "Allow calls" toggle in Profile privacy section (default on, optimistic+rollback)
- Me.callsEnabled + i18n DE/EN/FR/AR
Bundled DM UI work from this session:
- image lightbox is now a swipeable carousel over all shared images (+ counter)
- keyboard stays open after sending (input ref refocus)
- voice notes: Instagram-style waveforms (own=white/mint, other=black/grey),
removed the blue progress dot; lazy-load expo-media-library with clean fallback
- expo-linear-gradient + expo-media-library deps
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Magic-Mac-Hub (/api/magic/devices):
- Filter boundToPlan war zu eng \u2014 iPhone/iPad ohne aktiven Plan-Lock
fielen raus. Jetzt: alle UserDevice-Rows des Users ausser den
magic-enrolled, plus ProtectedDevice mit Dedupe.
Native /devices Page:
- MacBook erschien doppelt: einmal als UserDevice (registriert via
Magic-Mac, model=Mac14,9) und einmal als ProtectedDevice (alter
DNS-Flow). Dedupe per platform-key (mac/ios/android/win):
wenn UserDevice mit gleicher Plattform existiert, blende
ProtectedDevice aus.
- Slot-Counter zaehlt jetzt nach dedupe (totalRegistered).
- GET /api/magic/devices fetcht jetzt parallel listMagicDevices()
+ listProtectedDevices() und merged beide Quellen in eine
Response. Items haben neues 'source' Feld (magic|protected).
- ProtectedDevice (alter Native-DNS-Flow) wird auf gleiche
Shape gemappt: label->hostname, platform->model.
- Mac-App MagicDevice: source-Feld optional + resolvedSource
Fallback fuer Backwards-Compat. id mit source-Prefix gegen
Collisions zwischen Tabellen.
- DeviceHubView Row: protected-Geraete bekommen graues
'Native-App' Badge und Hinweis 'Verwaltung in der
ReBreak-App' statt Trash-Button (Release laeuft dort).
- getDmConversations: DISTINCT ON (partner) ORDER BY partner, created_at DESC
→ one row per conversation in a single indexed query instead of fetching
up to 500 rows and de-duplicating in JS
- add indexes on direct_messages (sender_id,created_at DESC),
(receiver_id,created_at DESC), (receiver_id,read_at) — table had none, so
every conversation-list load (runs per user on app launch for the badge)
was a full-table scan + sort
- lyra.tsx: drop the welcome-back greeting that fired on every first coach
open per session regardless of protection status/language (always German,
unconditional). Endpoint kept for future conditional use
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Redesign:
- Nach Login landet User direkt im neuen DeviceHubView statt
Auto-Mac-Registrierung. Hub zeigt: User-Email, X/5-Slot-Counter,
Liste aller registrierten Geraete + 'Geraet hinzufuegen' mit
iPhone/iPad vs Mac Wahl.
- Mac wird NUR registriert wenn User aktiv 'Mac' im Hub waehlt
(frueher: auto on app-start, frass Slot).
- iOS-Pfad: Hub -> Welcome/Preflight/Supervise/Enroll/Configure
-> Done -> 'Zurueck zur Geraete-Uebersicht'.
- Mac-Pfad: Hub -> MacRegistrationView (Register+DNS-Install)
-> 'Fertig -> Hub'.
- Wizard-Header hat jetzt Grid-Icon 'Zur Geraete-Uebersicht' als
Escape-Hatch jederzeit.
- Per-Device-Loeschung im Hub: Trash-Icon -> Confirm-Dialog
('Auf X muss Freigabe bestaetigt werden, 24h Cooldown') ->
request-release-Endpoint (existing infra).
- Device-Limit 3 -> 5 in backend (Staging-Testing + Legend-Wert
fuer spaeter).
- StepIndicator/Step-Counter: macRegistration zaehlt nicht im
iOS-Flow.
Zwei Bugs:
1) 'profiles install -path' wurde mit macOS 15+ entfernt
('profiles tool no longer supports installs. Use System Settings
Profiles to add configuration profiles.'). Auf macOS 26 (Tahoe)
ist das Hard-Removal.
-> Switch zu NSWorkspace.shared.open(profileURL): \u00f6ffnet die
.mobileconfig in System Settings -> Profile-Pane. User best\u00e4tigt
manuell + gibt Admin-PW. Einziger Weg ohne MDM-Enrollment.
-> success-Text passt: 'Bitte in System Settings Installieren
klicken'.
2) Doppelte 'Mac registriert'-Karte: successMessage-Card UND
strukturierte Registration-Status-Card beide sichtbar nach
register. Auto-Profile-Install nach Register war eh totes
Verhalten (DNS jetzt optional).
-> successMessage wird nicht mehr in handleRegistration gesetzt,
nur noch in handleProfileInstall. Eine Karte.
Design-Klarstellung: Magic ist primaer fuer iOS-Supervision/MDM-
Enrollment. Mac-Registrierung dient als Setup-Bruecke. DNS-Filter
auf dem Mac bleibt eine optionale Self-Service-Option fuer den
User — kein Gate mehr fuer den iPhone-Flow.
- Intro-Text neu: erklaert Magic = iOS-Setup, Mac als Bruecke
- Nach Register: 'Weiter -> iPhone-Setup' immer sichtbar
- 'DNS-Schutz installieren' ist jetzt sekundaerer Bordered-Button
mit '(optional)' im Label
- Bisheriger Template-Download-Fix vom letzten Commit bleibt
natuerlich bestehen — Download funktioniert wieder, ist nur
nicht mehr Pflicht
serverAssets approach didn't bundle the template into the Nitro
output (no .output-staging/server/chunks/raw/ dir, no asset-storage
mount in nitro.mjs). Logs confirm: '[Magic] Profile template missing
in serverAssets'.
Drop serverAssets entirely. Inline the template (~2KB) as a TS
constant in backend/server/utils/magic-profile-template.ts. Build-
robust, no FS/storage dependency at runtime. Canonical source of
truth remains ops/mdm/rebreak-mac-dns-filter.mobileconfig — keep in
sync manually until/unless we add a codegen step.
Previously read template via process.cwd() + 'ops/mdm/…' — but pm2
runs the bundled output from /root, not the repo root, so the path
resolved to /root/ops/mdm/… (does not exist) → HTTP 500 'Profile
template not found' after Mac registration.
Switch to Nitro's serverAssets (baseName 'mdm', dir '../ops/mdm')
which is bundled at build-time and read via
useStorage('assets:server'). cwd-independent + survives any deploy
layout change.
Adds NITRO_ADGUARD_BASE_URL / NITRO_ADGUARD_USER / NITRO_ADGUARD_PASSWORD
exports so Nitro runtimeConfig picks up the AdGuard admin credentials at
runtime. Required for /api/magic/register to provision DoH clients on
dns.rebreak.org.
Nitro auto-import did not pick up findMagicDeviceByToken / listMagicDevices /
countActiveMagicBindings / createAdGuardClient on first build. Added explicit
imports as safety net.
- previewNode: add audio case → VoiceNoteBubble renders correctly in blur
overlay when long-pressing a voice message (was rendering empty/null)
- MessageActionMenu: account for input bar (bottomInset=90) in positioning —
menu no longer slides behind input bar on bottom messages; barTop clamped
to never overlap the menu; both above/below paths respect usableH
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>