From 4b2c9164073f1dbf2f6f7f9d276534710ab09c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20F=C3=B6rtsch?= Date: Thu, 12 Mar 2026 19:09:06 +0100 Subject: [PATCH] update process model spec: fix reviewer issues, add data migration, dynamic numbering, antrag checklist Co-Authored-By: Claude Opus 4.6 --- ...026-03-12-process-model-overhaul-design.md | 54 +++++++++++++------ 1 file changed, 38 insertions(+), 16 deletions(-) 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 index 40a90f6..fc4c5b6 100644 --- a/docs/superpowers/specs/2026-03-12-process-model-overhaul-design.md +++ b/docs/superpowers/specs/2026-03-12-process-model-overhaul-design.md @@ -10,11 +10,11 @@ Replace the manually-synced `aktueller_schritt` enum with a data-driven process ### 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. +One Erstgespräch per therapist (enforced by UNIQUE constraint), 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. +**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 (from kontakte list — if no therapists exist, show message directing user to create one under Kontakte first), first session date, optional diagnosis + Dringlichkeitscode. ### Step 2 — TSS kontaktieren (conditional) @@ -22,7 +22,7 @@ Only visible when any sprechstunde has `dringlichkeitscode = TRUE`. The TSS (Ter **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. +**UI:** Single "TSS kontaktiert" button that stamps today's date. Once done, shows the contact date. No undo (matches current behavior for all advance actions). ### Step 3 — Eigensuche durchführen @@ -44,20 +44,41 @@ 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 +### Step status logic + +| Step | erledigt | aktuell | offen | visible | +|---|---|---|---|---| +| 1 — Erstgespräch | hasDiagnose | always (no prerequisites) | never | always | +| 2 — TSS | tssKontaktiert | step 1 erledigt | step 1 not erledigt | only if hasDringlichkeit | +| 3 — Eigensuche | absagenUndKeineAntwort >= 5 | step 1 erledigt | step 1 not erledigt | always | +| 4 — Kostenerstattung | — (terminal) | steps 1+3 erledigt (and 2 if visible) | otherwise | always | + +Step numbering is dynamic: when TSS is hidden, steps display as 1, 2, 3. When TSS is visible, steps display as 1, 2, 3, 4. + +### Antrag checklist (updated) + +The antrag checklist derives all checks from data: + +1. "Erstgespräch durchgeführt" — `EXISTS(SELECT 1 FROM sprechstunde WHERE diagnose IS NOT NULL)` +2. "Dringlichkeitscode erhalten" — `EXISTS(SELECT 1 FROM sprechstunde WHERE dringlichkeitscode = TRUE)` (informational, not blocking) +3. "TSS kontaktiert" — `nutzer.tss_kontaktiert_datum IS NOT NULL` (only shown if hasDringlichkeit) +4. "Therapeutensuche dokumentiert" — `COUNT(kontakt WHERE ergebnis IN ('absage','keine_antwort')) >= 5` +5. "Absagenliste exportiert" — tracked locally (unchanged) ## Schema changes (migration 002) +### Data migration + +Before dropping columns, migrate existing data: +1. Copy `nutzer.tss_beantragt_datum` → `nutzer.tss_kontaktiert_datum` +2. Create `sitzung` rows from existing `sprechstunde.datum` values +3. Then drop old columns + ### Drop from `nutzer` `aktueller_schritt`, `dringlichkeitscode`, `dringlichkeitscode_datum`, `tss_beantragt`, `tss_beantragt_datum` @@ -68,9 +89,10 @@ Step status mapping: ### 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` +- Drop `datum` (migrated to sitzung first) +- Drop `ergebnis` (was always 'erstgespraech', vestigial) +- Add `UNIQUE(therapeut_id)` constraint (one Erstgespräch per therapist) +- Keep: `id`, `therapeut_id`, `diagnose` (text), `dringlichkeitscode` (boolean), `erstellt_am` ### New table `sitzung` @@ -89,13 +111,13 @@ CREATE TABLE sitzung ( ## Files changed -- **New:** `src/shared/db/migrations/002_process_model.sql` — schema migration +- **New:** `src/shared/db/migrations/002_process_model.sql` — schema migration with data 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 +- **Rewrite:** `src/features/prozess/components/process-stepper.tsx` — data-driven steps, Erstgespräch list/form, conditional TSS, dynamic step numbering +- **Modify:** `src/features/prozess/components/phase-card.tsx` — remove index prop, accept dynamic step number +- **Modify:** `src/features/antrag/components/antrag-checklist.tsx` — derive checks from data (see updated checklist above) - **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