- 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).
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).
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.
Nitro auto-import did not pick up findMagicDeviceByToken / listMagicDevices /
countActiveMagicBindings / createAdGuardClient on first build. Added explicit
imports as safety net.
Neuer iOS-Layer-1-Filter: ein NEPacketTunnelProvider-DNS-Sinkhole — MDM-frei,
ab iOS 16, Parität zum Android-VPN-DNS-Filter. Ersetzt den Apple-seitig
blockierten NEURLFilter als Default. NEURLFilter-/PIR-Code bleibt inaktiv als
iOS-26-Upgrade-Pfad erhalten (User-Entscheidung).
Neues Extension-Target RebreakPacketTunnelExtension/:
- PacketTunnelProvider.swift — TUN-Setup (virtuelle DNS-IP 10.0.0.1, nur diese
Route ins TUN), Read-Loop, NXDOMAIN-Sinkhole, Upstream-Forward via
NWConnection zu 1.1.1.1, Blocklist-Reload via Darwin-Notification.
- DnsFilter.swift / HashList.swift / DomainHasher.swift — Swift-Ports der
Android-DNS-Filter-Logik. blocklist.bin-Format (sortierte big-endian UInt64,
SHA-256-Prefix) 1:1 beibehalten, mmap statt Heap-Load.
RebreakProtectionModule.swift:
- activateUrlFilter startet jetzt den Packet-Tunnel via NETunnelProviderManager
(Default-Layer-1, On-Demand-Auto-Reconnect aktiv).
- NEURLFilter-Code in activateNeUrlFilter ausgelagert (inaktiv, behalten).
- getDeviceState/disable lesen bzw. stoppen den Tunnel-Status.
with-rebreak-protection-ios.js: zweites app_extension-Target, klassischer
Embed-Pfad (dstSubfolderSpec 13), packet-tunnel-provider-Entitlement + App-Group.
app.config.ts: zweites appExtensions-Target.
NICHT auf echtem Gerät verifiziert — NE-Packet-Tunnel laufen nicht im
Simulator. Ungetestete Annahmen im Code mit "UNGETESTETE ANNAHME" markiert.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- familyControlsEnabled jetzt default-on (Apple-Distribution-Entitlement
freigegeben); nur REBREAK_ENABLE_FAMILY_CONTROLS=0 schaltet ab.
- gambling-domains.json ins Pod-Verzeichnis verschoben + Podspec resource_bundles
auf within-pod-Pfad korrigiert — CocoaPods buendelt keine Dateien ausserhalb
des Pod-Roots (Bundle blieb sonst leer → Layer 2 griff nicht).
- Layer 2 (webContent-Filter) damit verifiziert funktionierend.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Vorher: stores/auth.ts hatte TODO + fiel auf Supabase-Web-OAuth-Flow zurück,
was fehlschlug mit 400 'Unsupported provider: missing OAuth client ID' weil
der Supabase-Apple-OAuth-Provider nicht konfiguriert ist.
Jetzt: native Flow ohne Supabase-Provider-Config —
- expo-apple-authentication.signInAsync() → identityToken
- supabase.auth.signInWithIdToken({provider:'apple', token}) verifiziert direkt
gegen Apple's Public-Keys (kein Client-Secret-JWT-Setup nötig)
- User-Cancel (ERR_REQUEST_CANCELED) → leeres Resultat statt Error
- Platform-Guard: Apple-Path nur auf iOS
app.config.ts: ios.usesAppleSignIn=true → Expo prebuild generiert das
com.apple.developer.applesignin-Entitlement in die .entitlements. Beim
ersten EAS-Build wird die Capability auto-registriert im Apple-Developer-
Portal für org.rebreak.app.
signin.tsx + signup.tsx: Apple-Button conditional auf Platform.OS==='ios'
gerendert. Android-User sehen nur Google-Button (auf Android gibt es kein
natives Apple Sign-In).
App-Store-Submission-Pflicht (Apple Guideline 4.8 — wer OAuth-Login mit
3rd-Party-Provider anbietet, muss auch Apple Sign-In bieten).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- package.json: 0.2.0 → 0.3.0
- app.config.ts: version 0.2.1 → 0.3.0
- iOS buildNumber: 9 → 10
- Android versionCode: 9 → 10
- CHANGELOG.md: v0.3.0 entry with Duo-Onboarding, DiGA, Stripe-pivot, Arabic+RTL,
NEFilter-robust-disable, anti-auto-reactivation, FC always-on, etc.
Note: Android-Build wird vorerst NICHT submittet — Onboarding-Slides müssen für
Android-Protection-Mechanismus (VPN + a11y statt iOS NEFilter + Family Controls)
mit eigenen Pre-Explainer-Screenshots + Texten angepasst werden. Erst dann
v0.3.1 oder gesammelt mit Android.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Android Theme parent → Theme.MaterialComponents.DayNight.NoActionBar.Bridge
(fix BadgeDrawable crash in react-native-bottom-tabs after AccessibilityService toggle)
- Plugin with-material-theme-android keeps theme idempotent across prebuilds
- Plugin with-release-signing-android wires release signingConfig from key.properties
- Splash: align native splash image with JS BrandSplash (icon.png) to eliminate
double-splash flicker on app start
- DM: reset partner/messages/replyTo state on userId change, disable cache for
history query, switch spinner condition to isLoading||isFetching so reopens
always load fresh and never show empty-state with stale partner
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CHANGELOG entry covers:
- Mac DNS auto-detect (DoH handshake + realtime)
- Device-account-binding (Pro/Legend anti-bypass)
- Custom mail-patterns alongside web-domains (10 + 10 for Legend)
- Unified filter section with single + button + auto-detect sheet
- Chat v1.0 DM-only with unread badge
- Avatar cropper switched to iOS-native UIImagePickerController
- Help/Support pages (FAQ, Contact, About, Crisis hotlines)
- Settings: notification + streak-reminder section
- Game-over modal layout + regenerate suggestion
- Devices page redesign with central <Button> + progress bar
- Pre-check global blocklist before consuming a slot
- Local dev FAMILY_CONTROLS flag defaults on
Marketing download page version bumped to 0.2.0 build 8; sha256 +
apk size will be filled after the EAS build lands and the APK is
uploaded to the download host.
Sync mit Android versionCode 6 (buildNumber 5 wurde nie als iOS-EAS-Build
genutzt, daher direkt auf 6 für konsistente Plattform-Nummerierung).
Changelog für buildNumber 6:
- French app-language for test customers
- Lyra voice picker (legend tier)
- Realtime debug page (DEV-only)
- Mail-filter refactor: Groq removed, deterministic pipeline only
- Bugfix: protectedDevices array guard
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
extra.familyControlsEnabled mirrors the eas.json REBREAK_ENABLE_FAMILY_CONTROLS
build flag — true for development builds (Apple granted the Development Family
Controls entitlement), false for TestFlight/production (Distribution entitlement
still pending). The Blocker page uses it to show "App-Lock — coming soon" instead
of a toggle that throws NSCocoaError 4099, while keeping the protection banner
positive (the URL filter carries it).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Privacy/stigma layer on top of the authenticated Supabase session — re-auth on
open so nobody but the user can open Rebreak. Not a login replacement.
- expo-local-authentication; NSFaceIDUsageDescription in app.config
- stores/appLock.ts: persisted `enabled` pref, in-memory `locked`, device-
capability check (`available`), device-passcode fallback on biometric failure
- AppLockGate wraps the root layout: locks immediately on `background` (not
`inactive` → app-switcher peek doesn't lock), renders LockScreen while
`enabled && locked && session`
- LockScreen: dark brand screen, auto-prompts on mount + on return from
background, "Abmelden" escape hatch (clears session → fresh login next launch)
- Settings: new "Sicherheit" section, native UISwitch; enabling requires a
successful biometric prompt first; row disabled + explained when device has no
biometrics/passcode
- de/en strings
Per product call: the lock gates the whole app incl. SOS (SOS already requires
an authenticated user, so there's no unauthenticated path to carve out).
Cold-start: appLock init blocks the splash → `locked` is set before first paint,
no flash of unlocked content. ios/ is gitignored so EAS prebuilds the new module.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The TestFlight build kept failing with:
error: No profiles for 'org.rebreak.app.RebreakURLFilter' were found ...
Automatic signing is disabled and unable to generate a profile.
(in target 'RebreakURLFilter' from project 'ReBreak')
EAS managed credentials only provision the main app bundle ID. App extensions
must be declared up-front via extra.eas.build.experimental.ios.appExtensions so
the CLI knows to register the extension's App ID (+ app-group + network-extension
capabilities) and generate a distribution provisioning profile for it.
Next step (interactive, needs Apple login): `eas credentials` → iOS → preview
to actually create the extension credentials, then re-run the build.
(FamilyControls entitlement stays commented out in with-rebreak-protection-ios.js
until Apple grants the Distribution entitlement — this build ships without App-Lock.)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EAS iOS build failed: "Starting from Xcode 14, resource bundles are signed by
default, which requires setting the development team for each resource bundle
target." Cause: we build with useFrameworks: "static" (expo-build-properties),
so CocoaPods generates resource-bundle targets for pods with resources, and
Xcode 14+ wants them signed. EAS has no dev team for those.
New plugin with-resource-bundle-signing-fix injects into the Podfile's existing
post_install hook: sets CODE_SIGNING_ALLOWED = 'NO' for every pod resource-bundle
target (they don't need signing). Idempotent; runs as withDangerousMod('ios')
during prebuild so it survives EAS's clean prebuild.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Old adaptiveIcon was a full-bleed dark logo on a #0a0a0a background → the
launcher mask cropped it ("zoomed in" look). Now: white background (matches
the Play Store listing icon look) + the same logo at ~62% on a transparent
canvas → mask has nothing to clip.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- protection.ts: normalize Android device-state keys (vpn/accessibility/
tamperLock) to the iOS-shaped names the UI reads (urlFilter/familyControls/
appDeletionLock) — on Android the layers came back under different keys, so
blocker.tsx saw all toggles as undefined → always off → optimistic toggle
flipped back to off after enabling
- AppHeader.tsx: avatar/bell/back Pressable-with-style-fn → TouchableOpacity
with plain style — style-fn was swallowing width/height on Android → 0×0
+ overflow:hidden → avatar invisible (same pattern as Mac-CTA fix 7d04e42)
- app.config.ts: adaptiveIcon.foregroundImage → padded adaptive-foreground.png
(logo in ~66% safe zone, was full-bleed → clipped by launcher mask);
icon → icon.png (clean 1024 opaque, was the 512px alpha variant)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EAS Cloud prebuild ignores local android/build.gradle pins (android/ is gitignored).
Plugin compileSdk 35 → 36 satisfies new androidx.core dependency requirements.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>