rebreak-monorepo/ops/RELEASE_READINESS.md
chahinebrini e76be7ee78 feat(profile): Profile-Page komplett + Header-Dropdown + UI-Pattern-Fixes
Profile (3 Iterationen):
- app/profile/index.tsx + components/profile/* (Header, StatsBar, Approved,
  Streak, UrgeStats, Demographics, DigaMissionBanner)
- echte Live-Daten via useMe-Hook (Avatar/Nickname/Plan/Email/Provider-Pill)
- Demographics mit echten Inputs (TextInput + Bottom-Sheet-Selects),
  debounced auto-save, Pro-Trial-Reward-Banner, Mikro-Why-Texte
- Approved Domains als plain integer (KEIN Plan-Slot/Cap)
- Friendly Hint-Text statt Progress-Bar (alignSelf:'stretch' Pattern)
- StatsBar zentriert mit 3 prominenten Cards (vertikale Dividers)
- Cooldown-Timeline als Liste mit 1px-Rail
- ApprovedDomainsList: Collapse-Chevron rechts in Title-Row (Pattern-Fix)
- Eigene vs fremde Profile-Ansicht streng getrennt (DSGVO/Anonymität)

Header-Dropdown (kein 3-Punkte-Icon):
- Avatar als Trigger im AppHeader (User-Wunsch)
- Custom-Modal beide Plattformen, Card-Style
- SOS prominent oben (nur Wort 'SOS' rot, Tagline 'wir sind für dich da' klein darunter)
- Profile/Settings/Games/Debug(__DEV__)/Logout
- Logout neutral (nicht rot — Recovery-tonal)
- AppHeader: neue showBack + title Props für Sub-Routes

Routes (Stub bis Phase C):
- app/profile/[userId].tsx — anonym (nur public-Stats)
- app/settings.tsx — Coming-Soon-Skeleton
- app/games.tsx — Standalone Games-Page mit GameCard-Grid
- app/debug.tsx — __DEV__-only

Game-Picker (Migration aus Nuxt):
- components/games/{GameCard, StarRating, GameRatingStars}
- 2x2 Grid, 56pt SVG-Icons (inline aus components/urge/gameSvgs.ts)
- Live-Backend /api/games/ratings (silent-fail)
- Re-use UrgeGames.tsx ohne TTS/Cooldown-Loop

UI-Pattern-Fixes (alle aus screenshot-User-Feedback 2026-05-07):
- Snake-Bug (food-pellet React-18-StrictMode-Reducer-double-call) gefixt
- Snake-Buttons platform-native (iOS-blue / Android-ripple)
- Tetris-Margins (16px paddingHorizontal)
- PostCard-Buttons Apple-44pt-Hit-Area (Image-Select, Image-Remove,
  Cancel, Share-Pill — via hitSlop)
- ProfileHeader Demographics-Hint: alignSelf:'stretch' Pattern
- ApprovedDomainsList Collapse: Title flex:1 + Chevron rechts
- ProtectionDetailsSheet FAQ-Items: alignSelf:'stretch' defensive
- AppHeader Back-Button: neue showBack-Prop + chevron-back

Memory + Plan-Docs:
- 17 Memory-Files dokumentieren System-Wissen + Patterns
- ops/{CUTOVER, UI_MIGRATION, PROFILE_PAGE, WEBHOOK, GAMES_1V1,
  RELEASE_READINESS, TESTING_STATE, MAESTRO_HOSTING}_*.md

Backend bleibt unverändert (Tier-LLM + Nickname + sort:latency
sind seit gestern deployed).
2026-05-07 18:22:58 +02:00

217 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# RELEASE_READINESS — TestFlight Internal + Play Internal Testing
**Owner:** zied (Release-/Rollout-Engineer)
**Stand:** 2026-05-07 (Donnerstag)
**Deadline:** Wochenende 2026-05-09/10 — iOS auf TestFlight Internal, Android auf Play Console Internal Testing
**Stack:** Expo SDK 53 + React Native 0.79.6 (NICHT Capacitor — alte zied.md ist veraltet)
**Repo-Pfad:** `/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-native/`
> Ziel "Internal Only": kein Apple-Review, kein Google-Review nötig. Apple TestFlight Internal Tester (≤100, App-Store-Connect-User) sind direkt installierbar. Play Console Internal Testing Track lässt bis zu 100 Tester per Email-Liste sofort builden.
---
## Status-Quo-Tabelle
Legende: ✅ ready / 🟡 vorhanden aber Anpassung nötig / 🔴 fehlt blockierend / ⚪ User-Bestätigung nötig
### iOS
| Item | Status | Detail |
|---|---|---|
| Bundle-ID | ✅ | `org.rebreak.app` (app.config.ts:22 + Info.plist) |
| App Store Connect entry | ⚪ | Existiert? Apple-Login nötig — User-Bestätigung |
| Apple Developer Account aktiv | ⚪ | TestFlight setzt aktiven $99/Jahr-Account voraus |
| Provisioning Profile + Cert | ⚪ | EAS managed credentials kann das, aber Account muss connected sein |
| `eas.json` | 🔴 | **fehlt komplett** — muss generiert werden für `eas build` |
| iOS Native-Folder (`ios/`) | ✅ | Existiert via expo prebuild, Workspace + Pods sind drin |
| `Info.plist` Versions | 🟡 | `CFBundleShortVersionString=0.1.0`, `CFBundleVersion=1` — für TF muss CFBundleVersion bei jedem Re-Upload steigen |
| `PrivacyInfo.xcprivacy` | ✅ | vorhanden (Pflicht seit April 2024); declared APIs FileTimestamp/UserDefaults/DiskSpace/SystemBootTime + `NSPrivacyTracking=false` |
| Entitlements | 🟡 | `aps-environment=development` — für TestFlight production-Build muss auf `production` (oder via EAS-Profile gesetzt). Family-Controls + Network-Extension + App-Group sind drin |
| Apple Sign-In | 🟡 | Code-Stub in `stores/auth.ts:82-87` mit TODO. UI zeigt "via Apple Sign-In"-Pill (`components/profile/ProfileHeader.tsx:55`). Capability fehlt im entitlements file. **Apple-Review-Risk:** Apple verlangt Sign-In-with-Apple wenn andere 3rd-Party-Logins (Google) vorhanden. Für TestFlight Internal nicht zwingend, aber für External + Production blocker |
| App-Icon (1024×1024) | ✅ | `ios/Rebreak/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png` + Contents.json |
| Splash | ✅ | `SplashScreen.storyboard` + Image-Assets im Xcasset |
| Stripe-IAP-Konflikt | 🟡 | Code prüft Pro/Legend (`stores/auth.ts`, `app/(app)/blocker.tsx:268`). UI hat KEINEN Upgrade-Button in App — alle Upgrade-Pfade sind `Alert.alert(...)` ohne Stripe-Link → für TestFlight Internal OK, aber bei External/Prod muss klar dokumentiert werden: Subscription nur via rebreak.org/web (nicht in App). Apple-Reviewer-Notes nötig |
### Android
| Item | Status | Detail |
|---|---|---|
| Package-ID | ✅ | `org.rebreak.app` (app.config.ts:38 + AndroidManifest.xml + build.gradle:90/92) |
| Google Play Developer Account | ✅ | Validiert 2026-05-05 (siehe trucko-memory `project_google_dev_account.md`) |
| Play Console App-Entry | ⚪ | User-Bestätigung: existiert "ReBreak"-App im Play Console schon mit Internal-Track? |
| Android Native-Folder (`android/`) | ✅ | Existiert, gradle-Setup ok |
| Keystore (Production) | 🔴 | `android/app/build.gradle:113` signed Release-Build mit **debug.keystore** — Play Store akzeptiert das nicht. Production-Keystore muss erzeugt werden. **Alternativ (empfohlen):** EAS managed Android Credentials → EAS hält Keystore, kein User-Custody-Risk |
| versionCode/versionName | 🟡 | `versionCode=1, versionName="0.1.0"` — versionCode muss bei jedem Play-Upload steigen |
| AAB-Build-Konfig | 🟡 | Keine custom AAB-Targets, default `bundleRelease` würde laufen — aber mit debug-keystore. EAS erzeugt automatisch AAB bei production-Profile |
| `eas.json` | 🔴 | fehlt — siehe iOS |
| Adaptive Icon (foreground/background) | ✅ | `adaptive-icon-android.png` (foreground only, ohne Schrift wegen Mask) + `adaptiveIcon.backgroundColor=#0a0a0a`. mipmap-xxxhdpi etc. via prebuild generiert |
| Notification-Icon (24×24 monochrome) | 🟡 | nicht explizit gesetzt — Expo nutzt fallback. Für expo-notifications im Push-Use-Case sollte ein dedicated white-icon hinterlegt werden |
| Manifest Permissions | ✅ | INTERNET, BIND_VPN_SERVICE, BIND_ACCESSIBILITY_SERVICE, FOREGROUND_SERVICE, POST_NOTIFICATIONS, RECORD_AUDIO etc. drin |
| VpnService + AccessibilityService | ✅ | im Manifest deklariert (Zeile 38-48). **Risk:** Google Play prüft AccessibilityService-Apps streng (Use-Disclosure-Form pflicht). Empfehlung unten |
| Data-Safety-Form | 🔴 | Pflicht-Form in Play Console — User muss DSGVO-Selbstauskunft ausfüllen |
| Content-Rating | 🔴 | Erwartet PEGI 12+ wegen Glücksspiel-Thematik; Form muss vor Internal-Submit ausgefüllt werden |
### Cross-Platform
| Item | Status | Detail |
|---|---|---|
| Versionierung sync (app.config.ts ↔ ios ↔ android) | 🟡 | `app.config.ts:7 version="0.1.0"` ↔ Info.plist `CFBundleShortVersionString=0.1.0` ↔ android `versionName="0.1.0"`. Synchron, aber mehrfache Locations → Sync-Skript fehlt |
| Privacy-Policy URL (öffentlich erreichbar) | 🔴 | NICHT gefunden im App-Code. **Pflicht** für App Store + Play Store. URL z.B. `https://rebreak.org/privacy` muss live sein |
| Imprint/Impressum URL | 🔴 | dito |
| Test-Account-Credentials für Reviewer | 🔴 | Erst External-Review-relevant, für Internal not blocking |
| `apiUrl`-Default im Build | 🟡 | `https://staging.rebreak.org` als fallback in app.config.ts:91 — für TF/Play-Internal sollte ein Production-API gewählt werden ODER explizit dokumentiert werden, dass Tester Staging-Backend nutzen |
| Supabase-Anon-Key hardcoded | 🟡 | app.config.ts:103 hat hardcoded staging anon-key (Comment sagt: temp bis BFF-Migration in Phase 5). Anon-Key ist designed für Client-Ship, RLS protected — aber für Production-Build sollte besser via env-Var injected werden |
---
## Internal-Only-Pfad (3 Tage — realistisch für Wochenende)
**Nötiger Minimalumfang für TestFlight Internal + Play Console Internal Testing:**
1. **`eas.json` schreiben** mit 2-3 Profilen (development, preview, production-internal)
2. **Apple Developer Account** aktiv + ASC-App "ReBreak" erstellen (User-Action)
3. **Play Console** App-Entry für `org.rebreak.app` erstellen, Internal Testing Track aktiv (User-Action)
4. **EAS Login** + projekt initialisieren (`eas init` → projectId in app.config.ts speichern)
5. **EAS managed credentials**: `eas credentials` für iOS (cert + provisioning) und Android (Keystore generieren lassen ODER existing hochladen)
6. **iOS APS-Environment** → für production-Build via EAS-Profile auf `production` setzen
7. **Build triggern:** `eas build --platform ios --profile production` + `eas build --platform android --profile production` (kostet je 1 Build-Quota — User-Approval)
8. **Submit:** `eas submit --platform ios` (lädt automatisch zu TestFlight) + `eas submit --platform android --track internal`
9. **TestFlight Internal Tester** in ASC einladen (User per Email-Liste)
10. **Play Console Internal Tester** in Play Console einladen (Email-Liste oder Google-Group)
**Was Internal NICHT braucht (im Gegensatz zu External/Production):**
- Apple-Review (nur External Beta + Public)
- Google-Review (nur Closed/Open Testing + Production)
- Privacy-Policy-URL hardcoded sichtbar (nur für Listing)
- Screenshots, Feature-Graphic, Beschreibung
- Data-Safety-Form (technisch ja, aber für Internal nicht streng durchgesetzt — sollte trotzdem ausgefüllt werden)
- Content-Rating
---
## External-Beta-Pfad (zusätzlich, ~1 Woche)
Wenn ihr nach Internal-Test auf External (TestFlight Public Link / Play Closed-Test) gehen wollt:
- ✅ Privacy-Policy-URL live unter `https://rebreak.org/privacy` (DSGVO-konform, mit Lyra-Memory + Auto-Extract-Klauseln, Hans-Müller-DSB review)
- ✅ Imprint live unter `https://rebreak.org/imprint`
- ✅ App Store Listing: 8+ Screenshots (iPhone 6.5", 5.5"), App-Beschreibung DE/EN
- ✅ Play Store Listing: 8+ Screenshots Phone, Feature-Graphic 1024×500, Beschreibung DE/EN
- ✅ Data-Safety-Form Play Console
- ✅ App-Content-Rating Play Console (~PEGI 12+)
- ✅ Apple-Review Notes: Demo-Account-Credentials, Hinweis dass Subscription über Web läuft (nicht IAP)
- ✅ Apple Sign-In wirklich implementiert (nicht TODO) — wenn Google-OAuth bleibt, Apple-Sign-In-Pflicht
- ✅ AccessibilityService Disclosure-Form Play Console (warum BIND_ACCESSIBILITY_SERVICE nötig — App-Schutz vor Glücksspiel-Apps)
---
## Risk-Assessment
### R1 — Stripe-IAP-Konflikt (HOCH für External, MITTEL für Internal)
Apple lehnt Apps für "digital goods" ab wenn nicht via IAP gekauft. Rebreak hat Pro/Legend-Subscription via Stripe. **Aktueller App-Code zeigt KEINEN Upgrade-Button** — nur `Alert.alert("Upgrade nötig")` ohne Stripe-Link. Das ist Apple-konformer Workaround:
- App informiert User dass Pro nötig ist
- Kein Link zur Web-Bezahlseite (Apple verbietet das im App-Body)
- User abonniert auf rebreak.org/web (extern)
- App nutzt aktiviertes Abo
**Empfehlung:** für Internal-Build OK lassen. Vor External-Submit Apple-Reviewer-Note schreiben: *"Subscriptions are sold exclusively on rebreak.org. The app does not contain purchase flows. Pro features unlock automatically when the user's web account holds an active subscription."*
### R2 — VPN-Filter-Inclusion im Build (MITTEL)
Native Module `rebreak-protection` ist via `app.config.ts plugins`-Block aktiv. iOS NEFilter Extension + Android VpnService + AccessibilityService sind im Build mit drin. Für **erstes Internal-TestFlight** ist das Risiko:
- iOS: NEFilterDataProvider braucht spezielle Entitlement-Approval von Apple (Network Extensions). Falls Apple Account das nicht hat → Build schlägt beim Codesign fehl.
- Android: AccessibilityService braucht in Play Console eine Use-Disclosure beim Submit; ohne Form lehnt Google ab.
**User-Decision nötig:** Soll VPN-Filter im ersten TestFlight/Play-Internal-Build sein, oder erst V2? **Empfehlung:** für Internal Test OK behalten (kein Review), für External/Prod muss Disclosure-Form + Apple-Entitlement-Antrag laufen.
### R3 — Apple Sign-In TODO (MITTEL für External)
`stores/auth.ts:82-87` ist TODO. UI zeigt aber Apple-Pill. Bei External-Beta verlangt Apple Sign-In-with-Apple wenn andere 3rd-Party-Logins (Google) da sind — Pflicht-Guideline 4.8. Für Internal ist das egal (kein Review).
### R4 — Production-Keystore-Custody (HOCH)
Aktuell ist nur Debug-Keystore eingerichtet. Bei eigenem Keystore: User hält Passwort, Backup-Pflicht (verloren = Update-Path tot). **Empfehlung:** EAS managed Credentials (EAS hält Keystore, ist Industry-Standard, kein User-Custody-Stress).
### R5 — Hardcoded Supabase Anon-Key in app.config.ts (NIEDRIG)
`app.config.ts:103` hat hardcoded staging anon key. Anon-keys sind designed for client-ship (RLS protected DB). Aber für Production sollte env-injection. Internal-Build OK.
### R6 — Backend-API-Pointer für Tester (MITTEL)
`apiUrl` default ist `https://staging.rebreak.org`. Tester nutzen also Staging-DB. Wenn Prod-DB getrennt: Datenstand divergent. **User-Decision:** Internal-Tester gegen Staging oder schon Prod-Backend?
---
## TODO-Liste sortiert nach Tag
### Donnerstag 2026-05-07 (HEUTE — Recon + Doc)
- [x] `RELEASE_READINESS.md` schreiben
- [ ] **User:** Antworten auf Open Questions (siehe unten)
- [ ] **User-Bestätigung:** TestFlight & Play-Internal-Targeting (Internal-only oder gleich External?)
### Freitag 2026-05-08 (Setup + Configs, alles ohne Build-Trigger)
- [ ] zied: `eas.json` mit production-Profile schreiben (User reviewt vor Commit)
- [ ] zied: `app.config.ts` cleanup wenn nötig (env-vars für apiUrl)
- [ ] zied: Privacy-Policy + Imprint Stub-Pages (oder im rebreak-backend webroot deployen — Koordination mit rebreak-ops)
- [ ] **User:** Apple Developer Account-Status verifizieren ($99/Jahr aktiv?)
- [ ] **User:** ASC-App "ReBreak" erstellen (Bundle org.rebreak.app)
- [ ] **User:** Play Console App-Entry erstellen + Internal-Test-Track + Tester-Liste
- [ ] **User:** `eas login` + `eas init` (nur User kann sich einloggen)
- [ ] **User:** Decision EAS-managed Credentials vs eigener Keystore
- [ ] zied: VersionCode-Bump-Pattern dokumentieren
### Samstag 2026-05-09 (Build + Submit, alles mit User-Approval)
- [ ] **User-Approval + Trigger:** `eas build --platform ios --profile production-internal`
- [ ] **User-Approval + Trigger:** `eas build --platform android --profile production-internal`
- [ ] zied: Build-Output validieren (size, sha)
- [ ] **User-Approval + Trigger:** `eas submit --platform ios` (TestFlight) + `eas submit --platform android --track internal`
- [ ] **User:** TestFlight Tester-Emails einladen via ASC
- [ ] **User:** Play Console Internal-Tester-Emails einladen
- [ ] zied: Smoke-Test-Plan auf User-Device (Install, Login, Streak, Lyra-Chat 1 Roundtrip)
### Sonntag 2026-05-10 (Buffer + Iteration)
- [ ] Bugfix-Round 1 falls Tester-Feedback (rebreak-native-ui handled UI-Bugs)
- [ ] Falls neue Build nötig: versionCode++ → re-upload
---
## Top-5 User-Actions die nicht verschoben werden können
1. **Apple Developer Account login + ASC-App-Entry erstellen** (org.rebreak.app, Bundle-ID, App-Name "ReBreak"). Ohne ASC-Entry kein TestFlight.
2. **Play Console App-Entry + Internal-Track aktivieren** für `org.rebreak.app`. Ohne Track kein Internal-Upload.
3. **`eas login` + `eas init`** im `apps/rebreak-native/` ausführen — registriert Projekt + speichert projectId.
4. **Decision EAS-managed-Credentials vs eigener Keystore** + ggf. Keystore-Passwort generieren/sichern (User-Custody, NIEMALS commit).
5. **Privacy-Policy + Imprint live unter rebreak.org-URLs** — auch für Internal empfohlen (Vermeidet Hick-Up beim späteren External-Switch). Für External strikt Pflicht.
---
## Realistischer Wochenend-Plan — Machbarkeit
**Ja, Internal-TestFlight + Play-Internal sind machbar bis Sonntag 2026-05-10**, sofern:
- Apple Dev Account heute/morgen früh reaktiviert/bestätigt
- User Freitag Mittag verfügbar für `eas login` + ASC/Play-Console-Setup
- Keine Apple-Entitlement-Hick-Ups beim ersten iOS-Codesign (NEFilter braucht Entitlement-Approval — falls Apple Account das nicht hat, müssen wir die Plugin-Aktivierung temporär entfernen für Internal Build → V2 mit VPN-Filter)
- EAS-Build-Quota verfügbar (Free-Tier hat ~30 Builds/Monat — sollte reichen)
**Realistischer Risk-Pfad:** Falls iOS-NEFilter-Entitlement nicht da ist, Plan B = Internal-TestFlight ohne VPN-Filter-Plugin (1-Line plugin-comment-out) → User-Test der Core-Loop (Streak/Lyra/Posts/Games) ohne Blocker-Feature. VPN-Filter dann V2.
**External-Beta (TestFlight Public Link / Play Closed-Test) Wochenend-Ziel = NICHT realistisch.** Privacy-Policy-Live + Apple-Review-Process + Sign-In-with-Apple-Implementierung würden mind. 1 weitere Woche brauchen.
---
## 3 wichtigste Open Questions an User
### Q1 — VPN-Filter im ersten Build dabei oder rauslassen?
Plugins `with-rebreak-protection-ios` (NEFilter Extension) + `with-rebreak-protection-android` (VpnService + AccessibilityService) sind aktiv. Risk bei NEFilter: braucht spezielle Apple-Entitlement (Network Extensions Capability), die nicht im Standard-Dev-Account drin ist — muss von Apple separat genehmigt werden (1-2 Wochen Wartezeit historisch).
**Optionen:**
- (A) NEFilter+VpnService dabei → erstmaliger Build kann an Codesign scheitern, falls Entitlement fehlt
- (B) Plugins temporär raus (1-Line Comment in app.config.ts), Core-App testflighten, VPN-Filter V2 mit eigenem Build-Cycle
- (C) Erst Apple-Entitlement-Status prüfen (User-Login ASC), dann entscheiden
### Q2 — Backend-API-Pointer für Internal-Tester: Staging oder Prod?
Default `apiUrl=https://staging.rebreak.org`. Tester schreiben dann in Staging-DB. Wenn Prod-DB schon läuft: Daten-Inkonsistenz. Wenn Test-DB OK: weiter mit Staging.
**Meine Empfehlung:** Internal-Tester auf Staging (klarer Test-Modus, keine Vermischung mit Production-User). Externe Beta dann auf Prod.
### Q3 — Keystore-Strategie Android: EAS managed oder eigener Custody?
EAS managed = EAS speichert keystore verschlüsselt, kein User-Custody, automatisch im Build verwendet. Industry-Standard. Recovery via Expo-Account.
Eigener = User generiert keystore lokal, hält Passwort, lädt zu EAS hoch via `eas credentials`. Mehr Kontrolle, mehr Custody-Risk.
**Meine Empfehlung:** EAS managed für Wochenend-Speed, später kann User keystore mit `eas credentials --platform android` exportieren wenn Custody gewünscht.