Files
cannamanage/docs/sprint-12/cannamanage-sprint12-analysis.md
Patrick Plate be932c1930 docs: Sprint 12 planning, analysis, reviews, and code review
- sprint12-analysis.md (full page audit)
- sprint12-plan.md (button fix plan)
- sprint12-testplan.md (button fix test plan)
- sprint12-phase2-integration-tests.md (v3, expert-approved)
- sprint12-phase2-panel-review.md (3 review cycles, 95% confidence)
- sprint12-code-review.md (approved with comments, blockers fixed)
2026-06-18 14:43:25 +02:00

145 lines
7.0 KiB
Markdown

# Sprint 12 Analysis: "Golden Test Standard — Everything Present Must Work"
**Datum:** 18.06.2026
**Autor:** Patrick Plate / Lumen (Planner)
**Status:** v1
**Prinzip:** Jeder sichtbare Button muss funktionieren — sonst warum ist er da?
---
## 1. Audit-Zusammenfassung
| Seite | Status | P0 (broken) | P1 (UX) | P2 (polish) |
|-------|--------|-------------|----------|-------------|
| `/documents` | ❌ Kritisch | 3 | 2 | 0 |
| `/board` | ❌ Kritisch | 3 | 0 | 0 |
| `/dashboard` | ✅ OK | 0 | 0 | 0 |
| `/members` | ✅ OK | 0 | 0 | 0 |
| `/distributions` | ✅ OK | 0 | 0 | 0 |
| `/stock` | ✅ OK | 0 | 0 | 0 |
| `/grow` | ✅ OK | 0 | 0 | 0 |
| `/reports` | ✅ OK | 0 | 0 | 0 |
| `/calendar` | ✅ OK | 0 | 0 | 0 |
| `/forum` | ✅ OK | 0 | 0 | 0 |
| `/info-board` | ✅ OK | 0 | 0 | 0 |
| `/finance` | ✅ OK | 0 | 0 | 0 |
| `/assemblies` | ✅ OK | 0 | 0 | 0 |
| `/compliance` | ✅ OK | 0 | 0 | 0 |
| `/audit-log` | ✅ OK | 0 | 0 | 0 |
| `/settings/staff` | ✅ OK | 0 | 0 | 0 |
| `/settings/billing` | ⚠️ TBD | 0 | 0 | 0 |
| `/settings/privacy` | ⚠️ TBD | 0 | 0 | 0 |
**Gesamt: 6 P0-Defekte, 2 P1-Defekte** — alle konzentriert auf 2 Seiten.
---
## 2. P0 Findings — Komplett defekte Buttons
### 2.1 Documents Page (`documents/page.tsx`)
| # | Element | Zeile | Problem | Service vorhanden? |
|---|---------|-------|---------|-------------------|
| P0-1 | Upload-Button im Dialog | 217 | `onClick={() => setUploadOpen(false)}` — schließt nur den Dialog, ruft nie `uploadDocument()` auf | ✅ Ja: `uploadDocument()` in `services/documents.ts:31` |
| P0-2 | Download-Button pro Datei | 307-308 | `<Button variant="ghost" size="icon">`**kein onClick handler** | ✅ Ja: `downloadDocument()` in `services/documents.ts:73` |
| P0-3 | Delete-Button pro Datei | 310-313 | `<Button variant="ghost" size="icon">`**kein onClick handler** | ✅ Ja: `deleteDocument()` in `services/documents.ts:79` |
**Root Cause:** Die Documents-Seite wurde als statische Mock-Darstellung gebaut. Die Service-Schicht (`services/documents.ts`) existiert vollständig mit `uploadDocument()`, `downloadDocument()`, `deleteDocument()` und `listDocuments()` — aber keine dieser Funktionen wird von der Page aufgerufen. Die Seite nutzt nicht mal React Query (nur `useState` mit hartkodierten Mock-Daten).
### 2.2 Board Page (`board/page.tsx`)
| # | Element | Zeile | Problem | Service vorhanden? |
|---|---------|-------|---------|-------------------|
| P0-4 | "Position speichern" Button | 189-191 | `onClick={() => setPositionDialogOpen(false)}` — schließt nur Dialog, kein API-Call | ✅ Ja: `createPosition()` in `services/board.ts` |
| P0-5 | "Wahl bestätigen" Button | 244-248 | `onClick={() => setElectDialogOpen(false)}` — schließt nur Dialog, kein API-Call | ✅ Ja: `electBoardMember()` in `services/board.ts` |
| P0-6 | Mitglied absetzen (UserMinus) | 269-273 | `<Button variant="ghost" size="icon">`**kein onClick handler** | ✅ Ja: `removeBoardMember()` in `services/board.ts` |
**Root Cause:** Identisches Pattern wie Documents — die Seite zeigt Mock-Daten, die Dialoge sammeln Formulardaten, aber der Submit-Button schließt nur den Dialog ohne die Service-Schicht aufzurufen.
---
## 3. P1 Findings — UX-Issues (Documents speziell)
### 3.1 Documents: Fehlende visuelle Kategorie-Unterscheidung
**Problem:** Die `getCategoryBadgeVariant()` Funktion nutzt nur 4 generische Badge-Varianten (`default`, `secondary`, `destructive`, `outline`) für 6 Kategorien. Mehrere Kategorien teilen sich denselben Stil:
- VERTRAG und VERSICHERUNG → beide `outline` (identisch)
- PROTOKOLL und SONSTIGES → beide `secondary` (identisch)
**Lösung:** Eigene Farben pro Kategorie + Icons:
- SATZUNG → Blau + BookOpen-Icon
- PROTOKOLL → Lila + FileText-Icon
- VERTRAG → Amber + FileSignature-Icon
- VERSICHERUNG → Cyan + Shield-Icon
- GENEHMIGUNG → Grün + CheckCircle-Icon
- SONSTIGES → Grau + File-Icon
### 3.2 Documents: Table-Layout ohne min-width
**Problem:** Die Table-Zellen haben keine `min-w-*` oder `w-*` Constraints. Bei langen Dateinamen/Titeln stretcht sich die Name-Spalte über die gesamte verfügbare Breite, während kurze Zellen (Size, Date) zusammengedrückt werden.
**Lösung:**
- Name-Spalte: `max-w-[300px] truncate`
- Access-Spalte: `w-[120px]`
- Size-Spalte: `w-[80px]`
- Date-Spalte: `w-[100px]`
- Actions-Spalte: `w-[80px]`
---
## 4. Funktionale Seiten (kein Handlungsbedarf)
Die folgenden Seiten sind korrekt mit ihren Service-Layern verdrahtet:
| Seite | Pattern | Mutations/Actions |
|-------|---------|-------------------|
| Members | React Query + TanStack Table | Edit navigiert zu `/members/[id]` ✅ |
| Distributions | `useDistributionsQuery()` + TanStack Table | "New" verlinkt korrekt ✅ |
| Stock | `useBatchesQuery()` + `useRecallBatchMutation()` | Recall mit AlertDialog ✅ |
| Reports | `useMonthlyReportQuery()` etc. | Download-Buttons mit try/catch + Blob ✅ |
| Calendar | `useEventsQuery()` + `useCreateEventMutation()` + `useCancelEventMutation()` | Create-Form + Cancel funktional ✅ |
| Forum | `useCreateTopic()` + `useLockTopic()` etc. | Alle Moderation-Buttons verdrahtet ✅ |
| Info-Board | `useCreatePostMutation()` + `useDeletePostMutation()` etc. | CRUD komplett ✅ |
| Finance | `useRecordPaymentMutation()` + `useRecordExpenseMutation()` | PaymentForm/ExpenseForm mit `onSubmit` ✅ |
| Assemblies | `createAssembly()` + `getAssemblies()` | Create-Dialog mit Service-Call ✅ |
| Compliance | `getComplianceDashboard()` + `completeDeadline()` | Deadline-Buttons funktional ✅ |
| Audit-Log | `useAuditLogQuery()` + `useExportAuditPdfMutation()` | Export mit Loading-State ✅ |
| Staff | `useInviteStaffMutation()` + `useRevokeStaffMutation()` | Invite/Revoke/Permissions komplett ✅ |
---
## 5. Architektur-Analyse: Documents Page Refactoring
Die Documents-Seite braucht ein komplettes Refactoring von "static mock display" zu "React Query powered":
**Ist-Zustand:**
```
useState(mockDocuments) → static render → buttons do nothing
```
**Soll-Zustand:**
```
useQuery(['documents']) → dynamic data
useMutation(uploadDocument) → upload with progress
downloadDocument(id) → blob download + save-as
useMutation(deleteDocument) → confirm dialog + optimistic update
```
**Vorhandene Service-Funktionen (alle bereits implementiert in `services/documents.ts`):**
- `listDocuments(clubId, category?, accessLevel?)``GET /documents`
- `uploadDocument(clubId, title, category, accessLevel, description, file)``POST /documents/upload` (multipart)
- `downloadDocument(id)``GET /documents/{id}/download` → Blob
- `deleteDocument(id, clubId)``DELETE /documents/{id}`
- `getStorageUsage(clubId)``GET /documents/usage`
---
## 6. Empfehlung
**Scope ist sehr fokussiert:** Nur 2 Seiten brauchen Arbeit — Documents und Board. Alle anderen 16+ Seiten sind funktional korrekt verdrahtet.
Geschätzter Aufwand:
- Documents Page Refactoring: ~3h (React Query integration + download/delete handlers + UX fixes)
- Board Page Wiring: ~1.5h (3 handlers verdrahten + Confirmation-Dialogs)
- **Gesamt: ~4.5h**