# 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.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/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 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 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
