chahinebrini
ac605dce33
feat(onboarding,diga): TTS auto-play preference + 90 more DiGA test codes
...
## TTS Auto-Play Preference
User-Request: wenn Voice einmal aktiviert, soll Lyra auf jeder Slide
automatisch sprechen — nicht jede Slide extra antippen.
- stores/lyraVoice.ts: zustand-store mit AsyncStorage-Persistence
(@rebreak/lyraVoiceEnabled). Default OFF.
- LyraBubble auto-plays on text-change wenn enabled
- Audio-Button toggled die Preference + stoppt current playback
- Visuell: Button ist orange-filled wenn voice ON, ghost-bordered wenn OFF
- Icon: volume-mute-outline (OFF) / volume-medium / hourglass / stop
- Cleanup beim Unmount (stopLyraSpeech) + bei text-change
Initialisiert via init() in app/_layout.tsx (analog language/theme/appLock).
Locale-keys: audio_play → "Stimme einschalten", neu audio_disable → "Stimme
ausschalten" in 4 Sprachen.
## DiGA Test Codes 011-100
Aktuell 10 Codes (REBREAK-TEST-001..010), aber 100 Android-Tester kommen
morgen onboarding. Migration 20260518_extend_diga_test_codes seeded 90
zusätzliche Codes via generate_series(11, 100) + LPAD-Padding.
- Label: 'test_batch_2026-05-android' für Auditbarkeit (vs '...2026-05'
für die ersten 10)
- grants_plan: 'legend' wie die ersten 10
- ON CONFLICT DO NOTHING — idempotent
Distribution-Pattern: Tester N kriegt Code REBREAK-TEST-<NNN-padded>.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 22:39:18 +02:00
chahinebrini
22385d7d67
feat(stripe,onboarding): tier-rename + TTS audio button in lyra bubble
...
## Stripe Checkout Rename
Alte Legacy-Tier-Namen 'standard/pro' (von alter Tier-Struktur) waren
irreführend — heute heißt es 'pro/legend'. Cleanup:
- ENV-Var-Namen: STRIPE_PRICE_<PLAN>_<BILLING> (computed) statt
hardcoded STANDARD/PRO Mapping. Erwartet:
STRIPE_PRICE_PRO_MONTHLY
STRIPE_PRICE_PRO_YEARLY
STRIPE_PRICE_LEGEND_MONTHLY
STRIPE_PRICE_LEGEND_YEARLY
- 'quarterly' billing entfernt (Strategist-Verdict: nur monthly + yearly,
'2 Monate gratis' bei yearly).
- metadata enthält jetzt billing zusätzlich zu plan.
Webhook-Audit: bereits korrekt (mapped session.metadata.plan → pro/legend/free
via simple switch).
User-Action benötigt (Stripe Test-Dashboard):
- 4 Products + Prices anlegen mit 14-Tage-Trial
- Pricing pro Strategist: Pro 3,99/Mo + 39,90/Yr (2mo gratis),
Legend 7,99/Mo + 79,90/Yr
- Webhook-Endpoint: https://staging.rebreak.org/api/stripe/webhook
(Events: checkout.session.completed, customer.subscription.{updated,deleted})
- ENV-Vars (incl. STRIPE_WEBHOOK_SECRET) in Infisical pflegen
## TTS Audio-Button in LyraBubble
DiGA-Accessibility: Screen-Reader-Alternative + Lese-Hürden-Mitigation.
- lib/lyraSpeech.ts: one-shot TTS-Helper (vereinfacht aus SosTtsQueue)
- Fetch /api/coach/speak mit Auth-Token
- Bytes → Base64 → temp-file → expo-av Audio.Sound
- Stop-fn: abortet in-flight fetch + unloaded sound
- Status-callback: idle | loading | playing
- LyraBubble: Audio-Button rechts oben (orange Pill, 34×34)
- Icon: volume-medium / hourglass / stop je nach status
- Auto-stop bei text-change (Slide-Switch) + unmount
- A11y-Labels in 4 Sprachen (audio_play / audio_loading / audio_stop)
Bubble-paddingRight erhöht auf 50 für Button-Platz.
## Locales
de/en/fr/ar: onboarding.lyra.audio_play / audio_loading / audio_stop
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 20:51:11 +02:00
chahinebrini
b23bd6d29f
feat(onboarding,protection): Duo-style flow + cooldown auto-disable fix + Family Controls live
...
## Duo-Style Onboarding (Foundation + alle Slides)
Self-contained Onboarding-Flow mit Lyra-Mascot ersetzt das Spotlight-POC vom
vorherigen Iteration. Slides leben unter `components/onboarding/slides/`.
- Foundation: OnboardingShell (Progress + ScrollView + sticky CTABar),
LyraBubble (Rive-Avatar + animierte Speech-Bubble), SlideProgress, CTABar
- Slides: Welcome, Privacy (4 Versprechen), Nickname (inline + PATCH /me),
DigaChoice (Ja/Nein-Branch), DigaCode (redeem-Endpoint + inline-Errors),
Plan (Pro/Legend cards, monthly/yearly toggle, 2 Monate gratis, Härtefall-
Mailto), Payment (RevenueCat-Dev-Stub bis Phase-0), Protection (activate +
PermissionDeniedSheet-Wiring), Done (animierter Checkmark + Streak-Day-1)
- State-Machine in app/onboarding/index.tsx: 9 Slides, DiGA-Branch, Resume-
on-launch via slideFromStep(me.onboardingStep)
- Routing-gate in (app)/_layout.tsx: step != 'done' → /onboarding
- Backend Profile.onboardingStep enum extended:
welcome | account | plan | pre_protection | done (+ legacy nickname/block)
- Backend diga redeem: step='pre_protection' (NICHT 'done') — User muss noch
durch Protection-Slide für NEFilter/VPN-Aktivierung
- Locale-Keys (de/en/fr/ar): onboarding.lyra.<slide>.body, .cta_primary,
Plan-Tier-Details (3,99/7,99 €/Mo, 39,90/79,90 €/Jahr mit 2 Monaten gratis),
Härtefall-Link, DiGA-Code-Errors, Protection-Feat-Descriptions
## Cooldown Auto-Disable Race-Fix
Bug: nach Cooldown-Ablauf bleib URL-Filter installiert (NEFilter in iOS-
Settings sichtbar als "Läuft..."). Root-cause: `/api/cooldown/status` GET
auto-resolved beim ersten expired-Hit; zweiter Call in
applyCooldownDisableIfElapsed sah cooldownEndsAt=null → bail → forceDisable
nie aufgerufen.
- useProtectionState.fetchState: lokalen next.cooldown.endsAt state nutzen
statt redundantem API-Call. Atomarer, race-frei.
- AppState-Listener-Path unverändert (dort ist es der erste API-Call, kein
Race).
- lib/protection.forceDisable: console.log für Debug-Visibility.
## iOS NEFilter Robust-Disable (Native)
`removeFromPreferences()` alleine ist auf iOS 18+ unzuverlässig — Settings-
UI zeigt "Läuft..." obwohl Provider beendet sein sollte. 2-Step-Pattern:
1. loadFromPreferences
2. isEnabled = false + saveToPreferences (stoppt Filter-Daemon)
3. removeFromPreferences (Config-Eintrag aus Settings)
Quelle: Apple-Developer-Forums + eigene Empirie. Pattern wird auch in
PermissionDeniedSheet's resetUrlFilter genutzt (analog).
## Family Controls jetzt immer aktiv
Apple-Entitlement seit 2026-05 für ReBreak approved (TestFlight-akzeptiert).
`familyControlsEnabled: true` hart in app.config.ts (kein Env-Var-Gating mehr).
"Bald verfügbar"-Placeholder in blocker.tsx entfernt — App-Lock-Toggle ist
jetzt voll funktional auf iOS.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 17:48:05 +02:00