From 373987292fc1556fe151ae2763283a2753c76d9e Mon Sep 17 00:00:00 2001 From: Sandro Date: Thu, 29 Oct 2026 16:35:26 +0100 Subject: [PATCH] fix(capture): hold-to-record works by keyboard, confirms only after saving; drop FLAW-16 The + button lost its click handler for pointer events, so keyboard, VoiceOver and switch control could no longer open the capture sheet; a click without pointer (detail 0) now taps. "Im Quick Dump gespeichert" appears after the save succeeded, and the cancel state uses an existing border color. FLAW-16 (setup open until the first account, demo accounts) is removed from the list: intended behaviour, not a flaw. Co-Authored-By: Claude Opus 5.5 --- Doku/flaws.md | 6 ------ frontend/src/features/capture/HoldToRecordFab.tsx | 10 +++++++--- .../capture/__tests__/HoldToRecordFab.test.tsx | 9 +++++++++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Doku/flaws.md b/Doku/flaws.md index c948352..efadda6 100644 --- a/Doku/flaws.md +++ b/Doku/flaws.md @@ -25,7 +25,6 @@ Schweregrade: **Hoch** (Datenabfluss oder Rechteumgehung möglich), **Mittel** ( | FLAW-13 | Datenbank | ~~Keine Schema-Versionierung; Migrationsfehler werden verschluckt; `migrations/001_init.sql` ist toter Code~~ | **Behoben** | | FLAW-14 | Backend | ~~Fehler von Schreiboperationen werden häufig ignoriert (`_, _ =`)~~ | **Behoben** | | FLAW-15 | Realtime | ~~`WriteTimeout` von 30 s beendet SSE-Streams~~ | **Behoben** | -| FLAW-16 | Setup | `/auth/setup` ist bis zum ersten Konto offen; Demo-Modus legt `admin/admin` an | Mittel | | FLAW-17 | Workspace | ~~Bearbeiter-Freigaben für Notizen nicht wählbar~~ | **Behoben** | | FLAW-18 | Suche | ~~Nur eigene Gedanken und Dokumente, `LIKE` ohne Escaping, keine FTS~~ | **Behoben** | | FLAW-19 | Qualität | ~~Frontend-Tests nur für den Outliner, `lint` ist ein Platzhalter~~ | **Behoben** | @@ -146,11 +145,6 @@ Schweregrade: **Hoch** (Datenabfluss oder Rechteumgehung möglich), **Mittel** ( - **Problem:** Go beendet nach diesem Zeitraum das Schreiben der Antwort. Für den SSE-Fallback (`ServeSSE`) bedeutet das voraussichtlich einen Verbindungsabbruch alle 30 s. WebSockets sind durch Hijacking nicht betroffen. Der Client verbindet sich neu, daher fällt es kaum auf. - **Maßnahme:** Im SSE-Handler `http.ResponseController.SetWriteDeadline(time.Time{})` setzen oder `WriteTimeout` für diese Route aufheben. -### FLAW-16: Ersteinrichtung und Demo-Modus -- **Fundstellen:** `handleFirstBootSetup`, `Store.EnsureDemoAccounts`, `config.Load` (`MINDA_DEMO`, `MINDSIFT_DEMO`, `DEMO_MODE`). -- **Probleme:** Solange kein Konto existiert, kann jeder `POST /auth/setup` aufrufen und wird Administrator. Mit gesetztem Demo-Flag entstehen Konten `admin/admin` und `user/user`; versehentlich auf einer öffentlichen Instanz aktiv wäre das eine Komplettübernahme. -- **Maßnahme:** Setup per einmaligem Token aus dem Server-Log absichern; Demo-Modus nur zusammen mit expliziter Warnung/Bestätigung. - ### FLAW-17: Schreibgeschützte Dokumentfreigaben - **Status: Behoben.** Zwangsmigration entfernt, Backend prüft Bearbeiter-Rechte (`DocRole`, `/docs/{id}/sync`), der Editor speichert über die Sync-Engine, und der Freigabe-Dialog bietet „Bearbeiten“ an. Browser-Test: `e2e/share.e2e.mjs`. - **Fundstellen:** Migration in `Store.migrate` (`UPDATE doc_shares SET permission = 'read' …`, ebenso `doc_team_shares`, `workspace_folder_shares`), `PatchDocumentBlocks`/`UpdateDocument` (nur Eigentümer). diff --git a/frontend/src/features/capture/HoldToRecordFab.tsx b/frontend/src/features/capture/HoldToRecordFab.tsx index 43b2f7a..1b82f88 100644 --- a/frontend/src/features/capture/HoldToRecordFab.tsx +++ b/frontend/src/features/capture/HoldToRecordFab.tsx @@ -91,10 +91,10 @@ export const HoldToRecordFab: React.FC = ({ onTap, onTrans return; } - triggerHaptic(25); - showToast('Im Quick Dump gespeichert'); try { await onTranscript(text); + triggerHaptic(25); + showToast('Im Quick Dump gespeichert'); } catch { showToast('Fehler beim Speichern'); } @@ -300,7 +300,7 @@ export const HoldToRecordFab: React.FC = ({ onTap, onTrans
@@ -340,6 +340,10 @@ export const HoldToRecordFab: React.FC = ({ onTap, onTrans onPointerUp={handlePointerUp} onPointerCancel={handlePointerCancel} onContextMenu={(e) => e.preventDefault()} + // Keyboard, screen readers and switch control produce a click without pointer events (detail 0) + onClick={(e) => { + if (e.detail === 0) onTap(); + }} className={ isRecording ? 'w-14 h-14 -mt-6 rounded-full bg-status-err text-on-accent shadow-lg flex items-center justify-center transition-transform border-4 border-panel cursor-pointer touch-none select-none animate-pulse' diff --git a/frontend/src/features/capture/__tests__/HoldToRecordFab.test.tsx b/frontend/src/features/capture/__tests__/HoldToRecordFab.test.tsx index 4ee6863..4fe1494 100644 --- a/frontend/src/features/capture/__tests__/HoldToRecordFab.test.tsx +++ b/frontend/src/features/capture/__tests__/HoldToRecordFab.test.tsx @@ -255,3 +255,12 @@ describe('HoldToRecordFab', () => { ); }); }); + +describe('HoldToRecordFab keyboard access', () => { + it('opens the capture sheet when activated without a pointer (keyboard, screen reader)', () => { + const onTap = vi.fn(); + const { getByRole } = render(); + fireEvent.click(getByRole('button'), { detail: 0 }); + expect(onTap).toHaveBeenCalledTimes(1); + }); +});