diff --git a/docs/superpowers/specs/2026-03-12-process-model-overhaul-design.md b/docs/superpowers/specs/2026-03-12-process-model-overhaul-design.md new file mode 100644 index 0000000..40a90f6 --- /dev/null +++ b/docs/superpowers/specs/2026-03-12-process-model-overhaul-design.md @@ -0,0 +1,101 @@ +# Process Model Overhaul (Issue #2, Sub-project 2) + +## Goal + +Replace the manually-synced `aktueller_schritt` enum with a data-driven process model. Support multiple Erstgespräche (one per therapist, multiple sessions each), conditional TSS step, and transparent prerequisite indicators on all steps. + +## Process flow + +4 steps, all visible (except TSS which is conditional). Status derived from data, not stored flags. + +### Step 1 — Erstgespräch durchführen + +One Erstgespräch per therapist, each spanning one or more sessions (date entries). The Erstgespräch carries a diagnosis (text, e.g. "F32.1") and an optional Dringlichkeitscode (boolean). Both can be set or edited after the initial session — PTV11 often arrives later. + +**Status = erledigt** when at least one sprechstunde has a non-NULL diagnosis. + +**UI:** List of existing Erstgespräche (therapist name, diagnosis, Dringlichkeitscode badge, session count). Each expandable to show session dates with "Sitzung hinzufügen". An "Erstgespräch hinzufügen" button opens a form: select therapist, first session date, optional diagnosis + Dringlichkeitscode. + +### Step 2 — TSS kontaktieren (conditional) + +Only visible when any sprechstunde has `dringlichkeitscode = TRUE`. The TSS (Terminservicestelle, reached via 116117) searches for therapists on the user's behalf. + +**Status = erledigt** when `nutzer.tss_kontaktiert_datum IS NOT NULL`. + +**UI:** Single "TSS kontaktiert" button that stamps today's date. Once done, shows the contact date. + +### Step 3 — Eigensuche durchführen + +Independent therapist search, documenting contact attempts. + +**Status = erledigt** when `COUNT(kontakt WHERE ergebnis IN ('absage','keine_antwort')) >= 5`. + +**UI:** Contact stats + link to /kontakte (unchanged from current). + +### Step 4 — Kostenerstattung beantragen + +Terminal step. Available when steps 1 + 3 are erledigt, and step 2 is erledigt if visible. + +**UI:** Link to antrag checklist (unchanged, but checklist derives checks from data). + +## Status derivation + +Each step independently computes its status: + +| Query | SQL | +|---|---| +| hasErstgespraech | `SELECT EXISTS(SELECT 1 FROM sprechstunde)` | +| hasDiagnose | `SELECT EXISTS(SELECT 1 FROM sprechstunde WHERE diagnose IS NOT NULL)` | +| hasDringlichkeit | `SELECT EXISTS(SELECT 1 FROM sprechstunde WHERE dringlichkeitscode = TRUE)` | +| tssKontaktiert | `nutzer.tss_kontaktiert_datum IS NOT NULL` | +| absagenUndKeineAntwort | `SELECT COUNT(*) FROM kontakt WHERE ergebnis IN ('absage','keine_antwort')` | + +Step status mapping: +- **erledigt:** prerequisite met (green badge) +- **aktuell:** visible and not yet erledigt +- **offen:** visible but upstream prerequisites not met +- Step 2 not rendered at all when hasDringlichkeit = FALSE + +## Schema changes (migration 002) + +### Drop from `nutzer` + +`aktueller_schritt`, `dringlichkeitscode`, `dringlichkeitscode_datum`, `tss_beantragt`, `tss_beantragt_datum` + +### Add to `nutzer` + +`tss_kontaktiert_datum DATE` — nullable, presence = contacted + +### Modify `sprechstunde` + +- Drop `datum` (moves to sitzung) +- Drop `ergebnis` (was always 'erstgespraech', unused) +- Keep: `id`, `therapeut_id`, `diagnose` (text), `dringlichkeitscode` (boolean), `erstellt_am`, `aktualisiert_am` + +### New table `sitzung` + +```sql +CREATE TABLE sitzung ( + id SERIAL PRIMARY KEY, + sprechstunde_id INTEGER NOT NULL REFERENCES sprechstunde(id) ON DELETE CASCADE, + datum DATE NOT NULL, + erstellt_am TIMESTAMPTZ DEFAULT NOW() +); +``` + +### Drop + +`prozessSchrittEnum` type and `ProzessSchritt` TypeScript type — no longer needed. + +## Files changed + +- **New:** `src/shared/db/migrations/002_process_model.sql` — schema migration +- **Modify:** `src/shared/db/schema.ts` — remove `prozessSchrittEnum`/`ProzessSchritt`, add `Sitzung` type +- **Modify:** `src/shared/lib/constants.ts` — remove `PROZESS_SCHRITTE` array +- **Delete:** `src/shared/lib/constants.test.ts` — stale test for removed array +- **New/Rewrite:** `src/features/prozess/hooks.ts` — `useProcessStatus()` hook deriving status from data +- **Rewrite:** `src/features/prozess/components/process-stepper.tsx` — data-driven steps, Erstgespräch list/form, conditional TSS +- **Modify:** `src/features/prozess/components/phase-card.tsx` — adapt to new status model if needed +- **Modify:** `src/features/antrag/components/antrag-checklist.tsx` — derive checks from data instead of `nutzer` flags +- **Modify:** `src/features/einstellungen/scenarios.ts` — seed data rows instead of setting `aktueller_schritt` +- **Modify:** `src/features/onboarding/components/onboarding-form.tsx` — remove `aktueller_schritt` from INSERT