# Report Viewer (Inline-Expansion) Implementation Plan > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. **Goal:** Berichte in der Berichteseite als Inline-Expansion mit 5 Tabs (wie Excel-Sheets) anzeigen, statt nur als Download. **Architecture:** Neuer Backend-Endpoint `GET /reports/{id}/data` liefert gespeichertes `report_data`-JSON. Frontend rendert mit Inline-Expansion und 5-Tab-Viewer-Komponente. Daten bereits in DB vorhanden, kein Neuberechnen nötig. **Tech Stack:** FastAPI, SQLAlchemy, React 19, TanStack Query v5, shadcn/ui (Tabs, Table), Tailwind CSS 4 --- ### Task 1: Backend — `GET /reports/{id}/data` Endpoint **Files:** - Modify: `backend/app/api/reports.py` (nach dem `/download/{report_id}` Endpoint, ca. Zeile 211) **Step 1: Endpoint implementieren** In `backend/app/api/reports.py` nach dem `download_report`-Endpoint einfügen: ```python @router.get("/{report_id}/data") def get_report_data( report_id: int, db: Session = Depends(get_db), user: User = Depends(get_current_user), ): """Return the stored report_data JSON for a given report. Accessible to both admin and dak_mitarbeiter users. """ report = db.query(WeeklyReport).filter(WeeklyReport.id == report_id).first() if not report: raise HTTPException(status.HTTP_404_NOT_FOUND, "Report not found") if not report.report_data: raise HTTPException(status.HTTP_404_NOT_FOUND, "Report data not available") return report.report_data ``` **WICHTIG:** Dieser Endpoint MUSS vor dem bestehenden `@router.delete("/delete")` und `@router.get("/list")` stehen — aber er hat den Pfad `/{report_id}/data` mit einem Path-Parameter. Da FastAPI Routen in der Reihenfolge prüft, und `/list` und `/delete` statisch sind (und vor `/{report_id}` definiert sind), gibt es kein Routing-Konflikt. Einfach nach `download_report` (Zeile ~211) einfügen. **Step 2: Testen** Manuell (oder cURL): `curl -H "Authorization: Bearer " http://localhost:8000/api/reports/1/data` **Step 3: Commit** ```bash git add backend/app/api/reports.py git commit -m "feat: add GET /reports/{id}/data endpoint for report viewer" ``` --- ### Task 2: Frontend — `useReportData` Hook **Files:** - Modify: `frontend/src/hooks/useReports.ts` **Step 1: Hook hinzufügen** Am Ende von `frontend/src/hooks/useReports.ts` einfügen: ```typescript export function useReportData(reportId: number | null) { return useQuery({ queryKey: ['report-data', reportId], queryFn: () => api.get>(`/reports/${reportId}/data`).then(r => r.data), enabled: reportId !== null, }) } ``` **Step 2: Build prüfen** ```bash cd frontend && pnpm build ``` **Step 3: Commit** ```bash git add frontend/src/hooks/useReports.ts git commit -m "feat: add useReportData hook for fetching report JSON" ``` --- ### Task 3: Frontend — ReportViewer-Komponente **Files:** - Create: `frontend/src/components/ReportViewer.tsx` **Step 1: Komponente erstellen** Die Komponente empfängt `data: Record` (das `report_data`-JSON) und rendert 5 Tabs. Datenstruktur (aus `report_service.py`): - `data.sheet1` → `{ summary: {...}, weekly: [{kw, erstberatungen, unterlagen, ablehnungen, keine_rm, gutachten}, ...] }` - `data.sheet2` → `{ weekly: [{kw, onko: {anzahl, gutachten, keine_rm}, kardio: {...}, ...}, ...] }` - `data.sheet3` → `{ weekly: [{kw, gesamt: {gutachten, alternative, bestaetigung}, onko: {...}, ...}, ...] }` - `data.sheet4` → `{ weekly: [{kw, gutachten, ta_ja, ta_nein, diagnosekorrektur, unterversorgung, uebertherapie}, ...] }` - `data.sheet5` → `{ icd_codes: [{icd, count}, ...] }` Implementiere die Komponente mit: - shadcn/ui `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent` - shadcn/ui `Table`, `TableHeader`, `TableRow`, `TableHead`, `TableBody`, `TableCell` - Leere KW-Zeilen (alle Werte 0) ausfiltern - Summenzeile am Ende (fett) - Deutsche Spalten-Header - Fallgruppen-Labels: `{ onko: 'Onkologie', kardio: 'Kardiologie', intensiv: 'Intensivmedizin', galle: 'Gallenblase', sd: 'Schilddrüse' }` Sheet 2 und 3 haben verschachtelte Spalten (pro Fallgruppe). Nutze grouped headers mit `colSpan`. **Step 2: Build prüfen** ```bash pnpm build ``` **Step 3: Commit** ```bash git add frontend/src/components/ReportViewer.tsx git commit -m "feat: add ReportViewer component with 5-tab sheet display" ``` --- ### Task 4: Frontend — ReportsPage mit Inline-Expansion **Files:** - Modify: `frontend/src/pages/ReportsPage.tsx` **Step 1: Expansion-State und Klick-Handler** Änderungen: 1. Import `useReportData` und `ReportViewer` 2. Neuer State: `const [expandedId, setExpandedId] = useState(null)` 3. `useReportData(expandedId)` aufrufen 4. Tabellenzeile klickbar machen: `onClick={() => setExpandedId(expandedId === r.id ? null : r.id)}` 5. Cursor-Pointer auf der Zeile: `className="cursor-pointer hover:bg-muted/50"` 6. Nach jeder `` eine bedingte Expansion-Zeile: ```tsx {expandedId === r.id && ( {reportDataLoading ? (
) : reportData ? (
) : (
Keine Berichtsdaten verfügbar.
)}
)} ``` **Step 2: Build und Tests prüfen** ```bash pnpm build && pnpm test ``` **Step 3: Commit** ```bash git add frontend/src/pages/ReportsPage.tsx git commit -m "feat: add inline report viewer expansion to ReportsPage" ``` --- ### Task 5: Verifikation und finaler Commit **Step 1: Build** ```bash cd /home/frontend/dak_c2s/frontend && pnpm build ``` **Step 2: Tests** ```bash pnpm test ``` Alle 128+ Tests müssen bestehen. **Step 3: Finaler Commit (falls noch unstaged changes)** ```bash git add -A && git commit -m "feat: complete report viewer inline expansion" ```