rebreak-monorepo/ops/TESTING_STATE.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

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 typecheck in 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.tsrequireUser() 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/idempotent
  • scores/* (Leaderboard) — Anonymität-Risk via feedback_anonymity_nickname.md
  • notifications/* — Push-Anrede mit firstName statt nickname = 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/server bundle. Alternativ: pnpm dev als Sidecar in CI starten und gegen localhost:3001 fetchen.
  • Mocking: Prisma via vi.mock('../../server/utils/prisma', …) wie in trucko. Supabase-Client per vi.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.md als 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 installpnpm --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 via workflow_dispatch, Maestro-Cloud-Token aus Secrets, gegen Staging-Build.
  • 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

  1. 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.
  2. 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.
  3. 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.
  4. Pro-Trial-Reward kommt ohne Tests — Stripe-Revenue-Leak-Risiko, Phase C ist Pflicht-TDD-Zone.
  5. 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

  1. 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.
  2. Pen-Test-Provider für DiGA-Pflicht? Jährlich, ca. 5-15k EUR. Ahmed kann Vorschläge sammeln (Cure53, SektionEins, CrowdStrike-Partner) — User-Decision.
  3. Demographics + Pro-Trial: TDD oder Test-after? Empfehlung TDD, weil Reward-Logik in Stripe + DSGVO-relevante Pfade. Bestätigung gewünscht?
  4. Coverage-Threshold-Strategie: soft (warning, kein Block) oder hard (PR-Block bei Drop)? Empfehlung: erste 6 Wochen soft, danach hard auf 60 %.
  5. 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