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).
20 KiB
Rebreak — Testing State Audit & Roadmap
Author: Ahmed (QA) · Stand: 2026-05-07 · Status: Initial Audit, READ-ONLY
Dieses Dokument ist eine ehrliche Bestandsaufnahme. Antwort auf User-Frage: „was und wie testen wir, welche Abdeckungsrate, wo drückt der Schuh".
Kurzfassung in einem Satz: Im neuen rebreak-monorepo existiert null automatisierte
Test-Coverage. Nicht „wenig" — Null. Die alte trucko-Suite (114 Vitest-Tests +
Postman + Playwright) deckt eine andere Architektur (Nuxt + Capacitor) ab und ist
nicht 1:1 portierbar.
1. Status quo (rebreak-monorepo)
1.1 Backend (backend/, Nitro standalone, Prisma + Supabase)
| Aspekt | Stand |
|---|---|
| Test-Verzeichnis | nicht vorhanden (tests/, __tests__/, *.test.ts = leer) |
| Test-Framework | nicht installiert |
| Coverage-Tool | keins |
package.json test |
kein test-Script vorhanden |
| API-Endpoints | 122 Files in server/api/** — 0 abgedeckt |
| DB-Layer | 16 Files in server/db/** — 0 abgedeckt |
| Utils | 11 Files in server/utils/** — 0 abgedeckt |
| Middleware | cors.ts — 0 abgedeckt |
Coverage-Schätzung Backend: 0 %.
1.2 Frontend (apps/rebreak-native/, Expo SDK 53 + RN 0.79)
| Aspekt | Stand |
|---|---|
| Test-Verzeichnis | nicht vorhanden |
.maestro/ |
nicht vorhanden |
| Test-Framework | weder jest-expo noch @testing-library/react-native installed |
package.json test |
nur lint + typecheck, kein test |
| Components | 58 Files — 0 abgedeckt |
| Hooks | 13 Hooks (useMe, useUserPlan, …) — 0 abgedeckt |
| Stores | 4 Zustand-Stores (auth, coach, community, notifications) — 0 abgedeckt |
| Lib (sosStream, llmProvider, ttsProvider, lyraResponse) | 17 Files — 0 abgedeckt |
| App-Routes | 11 Top-Level (urge.tsx, lyra.tsx, auth/*, (app)/*, profile/*) — 0 abgedeckt |
Coverage-Schätzung Frontend: 0 %.
Native-Module-Pfad apps/rebreak-native/modules/rebreak-protection/android/src/test
existiert als leerer Gradle-Skeleton, ohne reale Test-Klassen — Backyard's Scope.
1.3 CI / CD
.github/workflows/existiert nicht im rebreak-monorepo.- Es gibt keinen
rebreak-unit-Job (existierte in trucko-monorepo, wurde nicht migriert). xgit-Deploy-Pipeline buildet ohne Tests durchzulaufen.- Pre-commit-Hooks: keine.
- TypeScript ist die einzige stille Schutzlinie (
pnpm typecheckin beiden Paketen).
1.4 Zusammenfassung
0 Tests, 0 CI-Gate, 0 Coverage. Die Auth-Middleware-500-Cascade dieser Woche wäre mit einem 8-Zeilen-Vitest-Test für
requireUser()verhindert worden.
2. Heritage aus trucko-monorepo (was portierbar / inspirierend ist)
Pfad: ~/mono/trucko-monorepo/apps/rebreak/tests/
2.1 Vitest Unit-Suite — gold-wert, ~70 % portierbar
tests/unit/ — 6 Dateien, 114 Tests, alle grün (geprüft 2026-04-28):
| Datei | Was getestet | Portierbar? |
|---|---|---|
cooldown.test.ts |
signCooldownToken, verifyCooldownToken, DB-Layer |
Ja, 1:1 |
domain-blocklist.test.ts |
getBlocklistedDomainsSet Subdomain-Matching |
Ja, 1:1 |
domain-limits.test.ts |
Plan-Limit-Enforcement bei Custom-Domains | Ja, 1:1 |
domain-validation.test.ts |
Domain-Regex + Sanitisierung | Ja, 1:1 |
domain-vote.test.ts |
castDomainVote Auto-Approve-Logik |
Ja, 1:1 |
plan-features.test.ts |
PLAN_LIMITS, getPlanLimits für free/pro/legend |
Ja, mit Tier-Update |
Alle nutzen vi.mock('../../server/utils/prisma', …) — keine echte DB nötig, läuft
in Sekunden, kein Secret-Setup. Quick win: copy + adjust import-paths
(apps/rebreak/server/... → backend/server/...).
2.2 Postman-Collection — sofort wiederverwendbar
tests/postman/rebreak.postman_collection.json deckt 12 Domains (Auth, Profile,
Streaks, Posts, Chat, Lyra, Notifications, Cooldown, Domain-Submissions,
Blocklist, Scores, Sicherheit-401-Sammlung).
Anpassungs-Aufwand:
{{baseUrl}}ist URL-only, funktioniert für Nitro-standalone identisch.- Auth-Pfad bleibt
POST /api/auth/login— selbe Route in neuem Backend. - Token-Auto-Extract-Skript funktioniert, da Backend Bearer-Token zurückgibt.
- Eventuell veraltete Endpoints (
/api/blocklist/*,/api/scores/*) gegen neue routes der Standalone-API verifizieren.
2.3 Playwright Smoke (tests/e2e/smoke/)
Nicht portierbar für Native-App. Nuxt-DOM-Selektoren, Browser-only, irrelevant
für Expo. fixtures/auth.ts (loginAs(page, …)) ist konzeptuell wiederverwendbar
für Maestro JS-onFlowStart — aber neu schreiben.
2.4 Cypress-Suite (apps/rebreak/cypress/e2e/)
01-smoke.cy.ts, 02-a11y.cy.ts — Capacitor-Webview, irrelevant für RN. Skip.
3. Risk-Matrix — Top 10 ungetestete Critical Paths
Bewertung: Risk = max(DSGVO-Risk, User-Trust-Risk, DiGA-Risk, Recovery-Risk).
| # | Pfad | Risk | Why | Empf. Test-Form |
|---|---|---|---|---|
| 1 | server/utils/auth.ts → requireUser() |
KRITISCH | Diese Woche 500-Cascade durch Bug. Jeder Endpoint hängt dran. | Unit (vitest) + supertest |
| 2 | coach/sos-stream.get.ts (Tier-LLM-Switch) |
KRITISCH | Free/Pro=Groq, Legend=Haiku. Falscher LLM für falschen User = User-Trust-Bruch + Brand-Voice-Bruch. | Integration mit Plan-Mock |
| 3 | coach/sos-stream.get.ts (SSE-Stream + Chip-JSON) |
KRITISCH | SOS ist Recovery-Schutz. Stream-Bruch oder Chip-Parse-Fail = User in Krise allein. | Integration + Stream-Snapshot |
| 4 | community/post.post.ts + posts.get.ts (Anonymität) |
KRITISCH | DSGVO Art. 9 + Glücksspiel-Stigma. Wenn UI plötzlich firstName/username statt nickname liefert = Disaster. |
Unit (DB-select-shape) + e2e |
| 5 | cooldown/{request,status,cancel}.post/get.ts |
HOCH | DiGA-relevant Recovery-Schutz. Token-Sign/Verify war in trucko getestet — muss in neue Codebase portiert. | Unit (vitest, gemockt) |
| 6 | urge/index.post.ts + lib/sosTtsQueue.ts |
HOCH | Urge-Logging ist Recovery-Kern-Feature. TTS-Queue = aktuell offen-modifiziert (siehe git status). |
Unit + Component-Test |
| 7 | auth/login.post.ts + auth/me.get.ts/me.patch.ts |
HOCH | Profile-Update = Demographics = DiGA-Daten. Bug = falsche Kohorten-Daten in BfArM-Antrag. | Unit (Zod-validate) + Postman |
| 8 | stripe/webhook.post.ts + Pro-Trial-Reward-Trigger |
HOCH | Pro-Trial-Logik (Phase C, kommt). Missing Test = Free-User bekommen versehentlich Lifetime-Pro oder umgekehrt. | Unit + Integration mit Stripe-mock |
| 9 | lib/llmProvider.ts + lib/sosStream.ts (Frontend) |
HOCH | Resolved-Provider-Logik passt zum Backend. Wenn Drift entsteht, sehen User falschen LLM-Pill (UX-Lüge). | Unit (RN-jest) |
| 10 | mail/scan.post.ts + mail/connect.post.ts |
MITTEL | Mo's Scope, aber Recovery-relevant. Mail-Scan-Bug = User bekommt Casino-Newsletter durchgelassen. | Integration |
Nicht in Top 10 aber erwähnenswert:
protection/*(URL-Filter-Blocklist) — DiGA-relevant, aber binär/idempotentscores/*(Leaderboard) — Anonymität-Risk viafeedback_anonymity_nickname.mdnotifications/*— Push-Anrede mitfirstNamestattnickname= Anonymitäts-Bruch
4. Roadmap
4.1 Pre-TestFlight (Wochenende, Mai 2026) — absolutes Minimum
Ziel: App stürzt im TestFlight nicht beim Launch ab + die zwei kritischsten User-Journeys (Login + SOS-Trigger) funktionieren auf einem echten iPhone-Build.
| Task | Form | Aufwand |
|---|---|---|
Maestro CLI installieren + apps/rebreak-native/.maestro/ anlegen |
Setup | 30 min |
Smoke-Flow auth/sign-in.yaml (Username + Pwd → App-Shell) |
Maestro | 1 h |
Smoke-Flow sos/start.yaml (Login → SOS-Button → Chat-Stream sieht 1+ Token) |
Maestro | 1.5 h |
Smoke-Flow community/feed-loads.yaml (Login → Feed → 1+ Post sichtbar) |
Maestro | 1 h |
| Manueller Postman-Run der 12-Domain-Collection gegen Staging | manuell | 1 h |
Backend-Sanity: pnpm build:backend + curl-Smoke gegen 5 wichtigste Endpoints (/api/auth/me, /api/coach/sos-stream, /api/community/posts, /api/cooldown/status, /api/urge) |
manuell | 30 min |
Wichtig: das ist NUR Smoke. Keine Plan-Tier-Permutationen, keine Edge-Cases. „Stürzt nicht ab + Happy-Path geht durch" ist das einzige Bestehen-Kriterium.
4.2 Post-TestFlight (Woche 1-2 nach Wochenend-Cutover)
| Task | Form | Aufwand |
|---|---|---|
Vitest setup im backend/ (vitest.config.ts, pnpm add -D vitest @vitest/coverage-v8) |
Setup | 30 min |
Port cooldown.test.ts von trucko nach backend/tests/unit/ |
Port + adjust | 1 h |
Port plan-features.test.ts (mit Tier-Update legend-Pfad) |
Port + adjust | 1 h |
Port domain-{blocklist,limits,validation,vote}.test.ts |
Port + adjust | 2 h |
NEU auth-requireUser.test.ts — Bug-Replikation (Bearer fehlt, Bearer invalid, Plan-Lookup fail) |
Unit | 2 h |
NEU lyraMemoryExtract.test.ts — Klarnamen-Replacement-Pipeline |
Unit | 1 h |
Supertest-Setup für Integration (Nitro .output/server startable im Test) |
Setup | 2 h |
Integration: auth/login + auth/me Happy + 401-Pfad |
Integration | 2 h |
GitHub Action rebreak-test.yml — Job backend-unit (vitest run + coverage) |
CI | 1 h |
Postman-Collection nach backend/tests/postman/ portieren + {{baseUrl}} auf staging.rebreak.org |
Port | 2 h |
Coverage-Ziel nach Phase 2: 40 % Backend-Statements, 100 % der utils/-Files,
100 % requireUser-Branches.
4.3 Phase C (Demographics + Pro-Trial) — TDD parallel
User-Auftrag steht: Demographics-Form + 1-Woche-Pro-Trial-Reward. Hier MUSS Test parallel zur Implementation laufen, weil:
- Reward-Trigger-Bug = Free-Lifetime-Pro oder Trial-nie-revoked (Stripe-revenue-leak)
- DSGVO-Wording-Pflicht („nicht Daten-gegen-Geld")
- DiGA-Daten-Integrität
| Test | Form |
|---|---|
profile/me/demographics.patch.test.ts — alle 5 Felder gesetzt → Trial |
Unit |
profile/me/demographics.patch.test.ts — Free + bereits Trial-used → kein Re-Trial |
Unit |
profile/me/demographics.patch.test.ts — Pro/Legend → kein Trial-Trigger |
Unit |
Cron-Test: pro-trial-revoke.cron.test.ts — nach 7d zurück auf free, sofern kein Stripe-Abo |
Unit |
Maestro profile/demographics-fill.yaml — Free-User füllt alle Felder, sieht Pro-Reward-Banner |
E2E |
4.4 DiGA-Pathway — Hans-Müller-Frage
BfArM erwartet für DiGA-Approval (laut hans-mueller.md Scope):
- Penetrationstest-Bericht (jährlich) — externer Anbieter, nicht Ahmed's Scope
- DSFA-Dokument (Datenschutz-Folgenabschätzung) — Hans-Müller's Scope
- ISO 27001 oder BSI-Grundschutz — DevOps/Backyard's Scope
Was BfArM nicht direkt verlangt aber bei Audit fragt:
- „Ist Ihre Software automatisiert getestet? Welche Coverage?"
- „Wie verhindern Sie Regressionen bei Updates?"
- „Wie testen Sie Crisis-Detection-Logik?"
Ahmed-Empfehlung: für DiGA-Antrag streben wir an: 70 % Backend-Coverage, 60 % Frontend-Coverage, 100 % Crisis-Detection-Recall (Lyra-Eval-Suite), dokumentierter Test-Plan + CI-Pipeline-Gate. Das ist nicht Pflicht aber glaubwürdigkeits-prägend. Frage an User: soll Hans-Müller das im DSFA-Dokument explizit machen?
5. Tooling-Empfehlungen
5.1 Backend
- Test-Framework: vitest 2.x. Schnell (esbuild), TS-nativ,
vi.mock-Pattern matched 1:1 unsere trucko-Heritage. Kein Jest (langsamer, schlechtere TS-DX in Nitro-Welt). Bun-test ist verlockend aber nitro+prisma stack ist node-validiert. - Coverage:
@vitest/coverage-v8. Built-in, schnell, accurate. - Integration-Tests: supertest gegen ein in-process Nitro-
.output/serverbundle. Alternativ:pnpm devals Sidecar in CI starten und gegenlocalhost:3001fetchen. - Mocking: Prisma via
vi.mock('../../server/utils/prisma', …)wie in trucko. Supabase-Client pervi.mock('@supabase/supabase-js', …). - Test-DB: NICHT setzen in Phase 1+2. Mock reicht. Wenn später Migration-Tests gebraucht: Postgres-Container in CI.
5.2 Frontend (Native)
- Component-Tests:
jest-expo+@testing-library/react-native. Standard Expo-Stack, gut dokumentiert. Snapshot-Tests sparsam (nur für stabile Strings, kein i18n-Output). - E2E: Maestro. Bereits in
ahmed.mdals Standard definiert. iOS+Android YAML-Flows, kein Detox-Maintenance-Hell. Cloud-Run möglich für CI. NICHT Detox — Setup-Aufwand zu hoch für unsere Team-Größe. testID-Konvention:<area>-<element>-<action>, z.B.auth-username-input,urge-sos-trigger-btn. Component-Edits dafür sind erlaubt (in ahmed.md geregelt).
5.3 CI
- GitHub Actions
.github/workflows/rebreak-test.yml:- Job
backend-unit:pnpm install→pnpm --filter rebreak-backend test→ Coverage-Upload als Artifact. Läuft auf jedem PR. - Job
frontend-unit:pnpm --filter rebreak-native test. PR-only. - Job
maestro-cloud: nur main-Branch + manuell viaworkflow_dispatch, Maestro-Cloud-Token aus Secrets, gegen Staging-Build.
- Job
- Coverage-Threshold (vitest): Phase 2 weich (40/40), Phase C streng
(70 % critical paths in
server/utils/,server/api/coach/,server/api/auth/).
6. Konkrete TODOs nach Priorität
Hoch (vor TestFlight, Wochenende)
| # | TODO | Aufwand | Owner |
|---|---|---|---|
| 1 | Maestro CLI auf Mac + Android-Emulator + iOS-Sim installieren | 30 min | User |
| 2 | apps/rebreak-native/.maestro/auth/sign-in.yaml schreiben |
1 h | Ahmed |
| 3 | .maestro/sos/start.yaml schreiben (testID's am SOS-Button + LLM-Pill nötig — Edit-Approval) |
1.5 h | Ahmed + UI |
| 4 | .maestro/community/feed-loads.yaml schreiben |
1 h | Ahmed |
| 5 | Postman-Collection nach backend/tests/postman/ kopieren + Staging-Env |
1 h | Ahmed |
| 6 | Manueller Curl-Smoke-Sheet der Top-5-Endpoints + Erwartungs-Status-Codes | 30 min | Ahmed |
Mittel (Woche 1-2 nach TestFlight)
| # | TODO | Aufwand |
|---|---|---|
| 7 | Vitest setup backend/ + erste Test plan-features.test.ts portiert |
1.5 h |
| 8 | Port der 5 weiteren trucko-unit-Tests | 4 h |
| 9 | Neuer Test auth-requireUser.test.ts (Bug-Replikation diese Woche) |
2 h |
| 10 | GitHub Action rebreak-test.yml Job backend-unit |
1 h |
| 11 | Supertest + Integration-Setup, dann auth/login.integration.test.ts |
2 h |
| 12 | jest-expo + @testing-library/react-native setup im apps/rebreak-native |
1 h |
| 13 | Erster RN-Test: lib/llmProvider.test.ts (Plan-Tier-Resolve-Logik) |
1.5 h |
| 14 | Erster Component-Test: components/profile/ProfileHeader.test.tsx |
1.5 h |
Niedrig (Woche 3+)
| # | TODO | Aufwand |
|---|---|---|
| 15 | Lyra-Eval-Suite (Crisis-Detection Golden-Prompts) aus trucko porten | 4 h |
| 16 | Maestro-Flow für Phase-C Demographics + Pro-Trial-Reward | 2 h |
| 17 | Stripe-Webhook-Test mit Stripe-Mock + Test-Mode | 3 h |
| 18 | DSFA-Anhang: Test-Coverage-Statement mit Hans-Müller abstimmen | 1 h |
| 19 | Penetrationstest-Provider auswählen (DiGA-Pflicht, jährlich) | User-Decision |
| 20 | Coverage-Threshold in CI-Gate hochziehen auf 70 % critical paths | 1 h |
7. Wo der Schuh am stärksten drückt — TL;DR
- Auth-Middleware ungeschützt. Der 500-Cascade dieser Woche war ein Lehrgeld-Bug. Ein 50-Zeilen-Vitest-File hätte ihn vor Deploy gefangen. Höchste Priorität.
- SOS-Stream + Tier-LLM-Routing ungeschützt. Wenn ein Free-User den falschen LLM bekommt oder der Stream bricht ab in der Krise — wir verlieren Vertrauen plus das ist ein DiGA-Recovery-Risk.
- Anonymität-Pattern ungeschützt. Wenn jemand bei einem Refactor versehentlich
select: { firstName: true }schreibt statt{ nickname: true }, sehen plötzlich alle User echte Namen. DSGVO Art. 9 + Stigma + DiGA = sofortige Krise. - Pro-Trial-Reward kommt ohne Tests — Stripe-Revenue-Leak-Risiko, Phase C ist Pflicht-TDD-Zone.
- Kein CI-Gate. Jeder Push kann grün durchdeployen, auch wenn die Codebase tot ist. Das muss als erstes nach TestFlight kommen.
8. Open Questions an User
- Maestro Cloud Account oder lokale Runs? Cloud kostet ~10 EUR/Monat, gibt parallele iOS+Android-Runs in CI. Lokal ist gratis aber blockt Mac-CPU.
- Pen-Test-Provider für DiGA-Pflicht? Jährlich, ca. 5-15k EUR. Ahmed kann Vorschläge sammeln (Cure53, SektionEins, CrowdStrike-Partner) — User-Decision.
- Demographics + Pro-Trial: TDD oder Test-after? Empfehlung TDD, weil Reward-Logik in Stripe + DSGVO-relevante Pfade. Bestätigung gewünscht?
- Coverage-Threshold-Strategie: soft (warning, kein Block) oder hard (PR-Block bei Drop)? Empfehlung: erste 6 Wochen soft, danach hard auf 60 %.
- Hans-Müller-Frage: Soll die DSFA explizit eine Test-Coverage-Quote für DiGA-Antrag committen? Wenn ja — dann müssen wir vor BfArM-Submission beweisbar sein.
Ende. — Ahmed