# Phase 0 – Performance-Baseline (Shinkan Jinkendo)

**Zweck:** Reproduzierbarer Startpunkt **vor** Phase 2 (Backend-Lesepfade, Summary-API).  
**Stand:** 2026-05-13 · Backend-App-Version laut `backend/version.py`: **0.8.110**

Nach grösseren Deployments oder Schema-Änderungen: Bundle-Abschnitt neu erfassen (`npm run build`); API-/k6-Werte bei Bedarf aktualisieren.

---

## 1. Frontend-Bundle (`npm run build`)

Messung: Repo-Root → `cd frontend && npm run build` (Vite Production).  
**Hinweis:** Dateinamen mit Hash (`index-*.js`) ändern sich pro Build; relevant sind Grössenordnungen und gzip.

### 1.1 Einstieg & globale Vendor-Chunks (Auszug letzter Lauf CI-lokal)

| Asset (Muster) | raw kB | gzip kB | Rolle |
|----------------|--------|---------|--------|
| `index.html` | 1.84 | 0.73 | Einstieg |
| `index-*.css` | 127.55 | 21.58 | Globale Styles |
| `index-*.js` (App-Shell / Router) | 64.83 | 17.45 | Haupteinstieg nach Code-Splitting |
| `vendor-react-*.js` | 142.42 | 45.67 | React + DOM |
| `vendor-router-*.js` | 65.94 | 22.51 | react-router |
| `vendor-markdown-*.js` | 161.54 | 49.31 | Markdown-Stack (wird mit Routen geladen) |
| `vendor-pdf-*.js` | 390.80 | 128.98 | jsPDF (Route-bezogen) |

### 1.2 Schwerste Route-Chunks (lazy, nach Route)

| Bereich | typ. Chunk-Grösse (raw / gzip) | Datei-Muster (Beispiel) |
|---------|-------------------------------|-------------------------|
| Trainingsplanung | 71.81 kB / 18.67 kB | `TrainingPlanningPage-*.js` |
| Übung bearbeiten | 91.31 kB / 22.49 kB | `ExerciseFormPage-*.js` |
| Medienbibliothek | 59.42 kB / 13.69 kB | `MediaLibraryPage-*.js` |
| Dashboard | 19.97 kB / 5.93 kB | `Dashboard-*.js` |

**Abnahme Phase 0 (Bundle):** Zahlen dokumentiert; Re-Run: `npm run build` und Tabelle abgleichen.

---

## 2. API-Latenz (p95) – Top-Routen

**Messung** erfolgt auf **Zielumgebung** (z. B. dev.shinkan / prod) mit gleicher Topologie wie Nutzer (HTTPS, Proxy). Nicht aus dem leeren Arbeitsverzeichnis ohne laufendes Backend messbar.

### 2.1 Vorgehen (empfohlen)

- **Access-Logs** des Reverse-Proxy (Request-Zeit), oder
- **APM** / OpenTelemetry, oder
- **k6** mit authentifizierten Szenarien (Token aus Testaccount; Header `X-Auth-Token`, ggf. `X-Active-Club-Id`), oder
- manuell: wiederholte `curl -w '%{time_total}\n'` mit gleichem Token

### 2.2 Vorlage (aus Umgebung ausfüllen)

| Route (Beispiel) | Methode | p95 (ms) | Datum / Umgebung | Bemerkung |
|------------------|---------|----------|------------------|-----------|
| `/api/profiles/me` | GET | *—* | *nach Messung* | |
| `/api/exercises` (Liste, typ. Query) | GET | *—* | *nach Messung* | |
| `/api/training-units` (Liste, typ. Query) | GET | *—* | *nach Messung* | |
| `/api/media-assets` (Liste) | GET | *—* | *nach Messung* | |
| `/health` | GET | *—* | *nach Messung* | k6: siehe `scripts/load/` |

**Abnahme Phase 0 (API):** Verfahren steht; Tabelle mindestens für **`/health`** nach erstem k6-Lauf befüllbar; übrige Zeilen bei nächstem Monitoring-Export.

---

## 3. Lasttestszenario

### 3.1 E2E-Smoke (fachlicher Pfad)

- **Befehl:** Repository-Root, `npm run test:e2e` (setzt `PLAYWRIGHT_BASE_URL`, Testuser per Env, siehe `.gitea/workflows/test.yml`).
- **Abdeckung:** Login, Dashboard, Navigation u. a. – entspricht grob „Login → Dashboard → weitere Screens“.
- **Baseline notieren:** Dauer eines vollen Laufs, Anzahl passed (z. B. 26 Tests), Datum.

| Messung | Wert | Datum |
|---------|------|-------|
| Playwright Gesamtlauf (lokal/CI) | *—* | *nach Messung* |
| passed / total | 26 / 26 (Ziel) | |

### 3.2 EXPLAIN (Phase 2 – Lesepfade)

- **Datei:** **`scripts/load/explain-readpaths.sql`** — repräsentative Statements für `list_exercises` / Stufenfilter / `training_units`; auf der Ziel-DB mit `EXPLAIN (ANALYZE, BUFFERS)` ausführen (Token/Tenant nicht im Skript; wie bei echten API-Queries filtern).

### 3.3 k6 – parallele /health

- **Skript:** `scripts/load/k6-health-baseline.js`
- **CI:** Läuft **automatisch** im Gitea-Workflow im Job **`k6-health-baseline`** (eigenständig, ohne Playwright; `.gitea/workflows/test.yml`). Parallel dazu **Playwright** im Job **`playwright-tests`**.
- **Lokal:** siehe `scripts/load/README.md`
- **Baseline notieren:** k6-Ausgabe `http_req_duration` p(95), Checks succeeded.

| Szenario | p95 / Fehlerquote | Datum / BASE_URL |
|----------|-------------------|------------------|
| 10 VUs, 30 s `/health` | *—* | *nach Messung* |

### 3.4 Aus dem Deployment-/CI-Log übernehmen (k6 `k6-health-baseline`)

Das Skript `scripts/load/k6-health-baseline.js` nutzt **10 VUs**, **30 s**, Ziel **`GET {BASE_URL}/health`** (siehe Workflow-Env für `BASE_URL`).

**In die Tabelle oben (Abschnitt 3.3) eintragen — aus der k6-Zusammenfassung am Ende des Jobs:**

| Feld in BASELINE_SNAPSHOT | Wo im k6-Log (typisch) |
|---------------------------|-------------------------|
| **p95** (Latenz ms) | Zeile **`http_req_duration`** → Wert **`p(95)=…`** (ganze Zahl oder ms mit Einheit wie `12.34ms`) |
| **Fehlerquote** | Zeile **`http_req_failed`** → z. B. `0.00%` bzw. `✓ 0%` — oder kurz „0 %“ notieren |
| **Checks** (optional) | Zeile **`checks`** → Anteil **`✓`** (soll **100 %** sein, sonst Hinweis) |
| **Datum / BASE_URL** | Deploy-Datum + die **öffentliche** Basis-URL des Laufs (wie im Workflow gesetzt, z. B. `https://dev.shinkan.jinkendo.de`) |
| **App-Version** (optional) | dieselbe wie im Deploy (`backend/version.py` / Release), damit M2-Vergleich ressortfähig bleibt |

**Zusätzlich (Abschnitt 2.2):** nur die Zeile **`/health` GET`** mit dem **gleichen** p95 befüllen, wenn ihr dort noch Platzhalter habt — echte API-Routen (`/api/...`) kommen weiter aus Monitoring/k6 mit Auth, nicht aus diesem Job.

---

## 4. Nächster Schritt (Roadmap)

- **Phase 0** ist für den Pipeline-Teil **abgeschlossen**: Bundle dokumentiert; **k6** läuft in CI nach jedem relevanten Deploy (mit Test-Suite); API-p95-Tabellen kann das Team aus Monitoring weiter befüllen (optional, kein Deploy-Blocker).
- **Phase 2** (Backend Lesepfade) ist **abgeschlossen** — siehe [UMSETZUNGSPLAN_ROADMAP.md](./UMSETZUNGSPLAN_ROADMAP.md); nach Deploy **p95 erneut messen** und mit den Werten aus Abschnitt 2 dieser Datei vergleichen (**Meilenstein M2**).

---

## Verweise

- Roadmap: [UMSETZUNGSPLAN_ROADMAP.md](./UMSETZUNGSPLAN_ROADMAP.md)
- k6: [scripts/load/README.md](../../scripts/load/README.md)
