13 KiB
phase, plan, subsystem, tags, status, requires, provides, affects, tech-stack, key-files, key-decisions, duration, completed, commits, plan_head_before, plan_head_after, actuals
| phase | plan | subsystem | tags | status | requires | provides | affects | tech-stack | key-files | key-decisions | duration | completed | commits | plan_head_before | plan_head_after | actuals | |||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quick-260929-if2 | 01 | dashboard-widgets, api-reminders, desktop-notifications |
|
complete |
|
|
|
|
|
about 1 h 15 min | 2026-09-29 | 3 | cd1f8f6cda |
8027c4857080790bf9994553fbda8036d81f8eb3 |
|
Phase quick-260929-if2 Plan 01: Erinnerungen-Widget mit Benachrichtigung Summary
Persoenliche einmalige Erinnerungen als Dashboard-Widget: Benachrichtigung zur Faelligkeit im Browser und als native Windows-Meldung in der Desktop-App (auch im Infobereich), optional eine E-Mail, die der Server genau einmal je Faelligkeit ueber einen atomaren Anspruch versendet.
Commits (lokal, nicht gepusht)
| Task | Hash | Betreff |
|---|---|---|
| 1 (Tracer) | 26f8f0f | feat(260929-if2): Erinnerungen anlegen und zur Faelligkeit benachrichtigen (Tracer) |
| 2 | 580c31c | feat(260929-if2): faellige Erinnerungen erledigen, spaeter erinnern, bearbeiten und loeschen |
| 3 | 8027c48 | feat(260929-if2): Erinnerung zusaetzlich per E-Mail, Doku und Aenderungsliste |
commits: gemessen mit git rev-list --count cd1f8f6..HEAD = 3. Der Tracer-Feedback-Gate (Auto-Modus: <verify> erneut ausfuehren) lief vor Task 2: API-, Web-, cargo-Tests, migrate diff und die curl-End-to-End-Kette waren gruen, also wurde erweitert.
Gemessene Gates (nach Task 3)
| Gate | Ergebnis |
|---|---|
| API vitest komplett | 91 Dateien, 1570 Tests, alle gruen |
| Web vitest komplett | 108 Dateien, 1069 Tests, alle gruen |
pnpm turbo run type-check lint --force |
9/9 Tasks erfolgreich |
| Biome-Warnungen | web 55 (max 55), api 82 (max 82), also exakt die Grundlinie |
| cargo test --lib | 57 gruen, davon 12 server_origin_* (Plan verlangte mindestens 10) |
| cargo fmt --check / clippy -D warnings | sauber |
| rls-coverage + rls-access-inventory | gruen (30 Zusicherungen im Inventar) |
prisma migrate diff --exit-code |
"No difference detected" (Exit 0), Migration lokal angewendet |
| Gate-Schleife (Rohtreffer, ohne spec) | Summe 61 / 235 / 7 (ungebunden / gebunden / System); Bereich reminders 0 / 12 / 1 |
| Bestandsaufnahme-Doku | 83 Paare (44 muss-mandantengebunden, 21 keine-mandantengebundene-tabelle, 16 beides, 2 bewusst-uebergreifend), mit grep -cE '^| apps/api/src/' nachgezaehlt |
| FORSYSTEM_ALLOWED_CALL_SITES | neu reminder-mail.scheduler.ts = 1, Summe 6 Dateien / 7 Aufrufe |
curl-Ergebnisse (lokal, gegen die neu gebauten Container)
- Tracer: testuser POST + GET ok, admin sieht das Tracer-Test nicht (
tracer e2e ok); Vergangenheit ergibt 400. - Task 2: admin bekommt fuer PATCH, snooze und DELETE auf eine testuser-id je 404; testuser: snooze auf nicht faellige Erinnerung 409, PATCH 200. Alle Test-Zeilen geloescht.
- Task 3:
GET /reminders/email-statusliefert{"smtpConfigured":true,"hasEmail":true}(lokal ist SmtpConfig aufmailhog:1025gesetzt, testuser hattestuser@example.com); POST mitemailEnabled:trueergibt 201./healthok. - Planerlauf gegen die echte Datenbank: eine Erinnerung mit E-Mail wurde 1 Minute nach Anlage faellig; der Planer versuchte den Versand im 30-s-Takt genau dreimal (mailhog-Container laeuft lokal nicht, also Transportfehler und Freigabe), danach
emailAttempts = 3und keine weiteren Versuche. Damit ist Anspruch, Freigabe und die Grenze von 3 Versuchen live belegt. Alle Test-Zeilen danach geloescht (count(*) = 0).
Deviations from Plan
- [Rule 3 - Blocking] Bestehende Tests an die neue Kachel angepasst.
widget-registry.test.tsx(Typliste, Groessentabelle, Zaehler 40 auf 44) undwidget-catalog-modal.test.tsx(letzte Kachel nunreminder) pruefen die exakte Kachelliste. Ohne Anpassung waere die Suite rot. Commit 26f8f0f. - [Rule 3]
reminder-time.tsschon in Task 1. Der Plan legtelocalInputsToIsozuerst in die Kachel und verschob sie in Task 2; ich habe sie gleich inreminder-time.tsangelegt und in Task 2 nur erweitert (isoToLocalInputs,snoozeTarget). Kein Verhalten anders. - [Rule 2 - Lesbarkeit] "Faellig"-Abzeichen mit 20 % Flaeche. Der Plan nannte
bg-status-warn text-status-warn-fg; die Schrift-Variante erreicht auf voller Warnflaeche nur rund 2,6:1 (globals.css-Kommentar). Verwendet wirdbg-status-warn/20 text-status-warn-fg(die dokumentierte Pillen-Form). Bitte im Dunkelmodus mitpruefen. - [Rule 2]
lässtauf die Umlaut-Allowlist (umlaut-dictionary.ts), weil der TextalreadyDue"lässt sich nicht mehr bearbeiten" korrektes Deutsch ist, das der Guard sonst meldet (im Plan vorgesehen, "nur wenn der Guard warnt"). - Formular-Details:
emailEnabledwird beim Bearbeiten nur gesendet, wenn es sich aendert (sonst kippt eine unveraenderte Alt-Einstellung das Speichern mit 400, wenn SMTP inzwischen fehlt); ein bereits angehaktes Feld bleibt bedienbar, damit man es abwaehlen kann. Beim Bearbeiten wird nie die Browser-Erlaubnis abgefragt (D-04: nur beim ersten Anlegen). Zusaetzlich bekamReminderFormModaldie PropsemailStatusundonStale(409 beim Bearbeiten laedt neu). - Commit-Zeile: Die Co-Authored-By-Zeile ist
Claude Sonnet 5.5 <noreply@anthropic.com>(das laufende Modell, wie die Umgebung sie vorgibt), nicht "Claude Opus 5.5 (1M context)" wie in der Aufgabenbeschreibung. Bei Bedarf per Umschreiben anzupassen, bevor gepusht wird.
Stop-Regel des Plans: nach jedem Commit lag der Kontext weit unter der Haelfte, daher alle drei Segmente in einem Lauf.
Known Stubs
Keine. Alle Daten der Kachel kommen aus der API; keine Platzhalter.
Threat Flags
Keine neue Flaeche ausserhalb des Plan-Threat-Models. Zur Beachtung (T-IF2-03, im Plan akzeptiert): nach einem Serverwechsel behaelt der alte Ursprung sein Benachrichtigungsrecht bis zum App-Neustart.
Nicht messbar ohne GUI (bitte pruefen)
- Das Rust-Laufzeitrecht (
add_capabilitymitremote) ist per Unit-Tests der Musterbildung abgesichert (Escaping, Selbstpruefung, exakte 3er-Menge), aber der echte Toast in der Desktop-App ist nur auf der Windows-VM pruefbar (siehe Schritte 10 bis 12 unten).
Manuelle Pruefschritte fuer den Orchestrator
Angepasst an den Ist-Zustand: lokal ist SMTP auf mailhog:1025 gesetzt, der mailhog-Container laeuft aber NICHT (docker ps zeigt keinen). Die E-Mail-Checkbox ist also aktiv (nicht ausgegraut), Mails scheitern lokal beim Transport, bis mailhog laeuft (z. B. aus docker-compose.dev.yml starten).
Browser (Playwright MCP, dunkel per Theme-Knopf; nie per fetch aus der Seite messen):
- Als
testuser/Test1234!testanmelden. Benachrichtigungen fuer den Ursprung im Playwright-Kontext erlauben (grantPermissions(['notifications'])), sonst bleibt die Abfrage "default". Einmal auch mit neuem Kontext ohne Erlaubnis: die Abfrage erscheint erst nach Klick auf "Speichern" beim ersten Anlegen, nicht beim Laden der Seite. - "Bearbeiten" -> "Widget hinzufuegen" -> Katalog zeigt "Erinnerungen" mit Glocken-Symbol -> hinzufuegen -> "Fertig". Dunkel-Screenshot: Kopfzeile mit Symbol-Chip, Leerzustand, Knopf "Neue Erinnerung".
- Erinnerung mit Faelligkeit in 2 Minuten anlegen (Titel + Beschreibung). Die Liste zeigt sie mit lokaler Zeit; der E-Mail-Haken ist bedienbar.
- Vor der Faelligkeit einen Spion in die Seite legen (
page.evaluate,window.Notificationumhuellen und Aufrufe zaehlen). Auf eine andere Portalseite (z. B. Marktplatz) wechseln und die Faelligkeit abwarten. Erwartet: genau ein Aufruf mit Titel "Erinnerung: ...", obwohl das Dashboard nicht sichtbar ist (der Melder ist global). Zurueck auf dem Dashboard: Zeile hervorgehoben, Abzeichen "Faellig", Knoepfe "Erledigt" und "Spaeter erinnern". Dunkel-Screenshot der hervorgehobenen Zeile (Lesbarkeit des Abzeichens beurteilen). - Zweiten Tab derselben Sitzung oeffnen und 20 s warten: keine zweite Benachrichtigung fuer dieselbe Erinnerung.
- "Spaeter erinnern" -> "In 10 Minuten": Zeile ist wieder kuenftig mit neuer Zeit (Bearbeiten/Loeschen sichtbar). "Bearbeiten": Titel aendern, speichern. Loeschen mit Rueckfrage (Ja/Nein). Eine weitere Erinnerung faellig werden lassen, dann "Erledigt": sie verschwindet.
- E-Mail: lokal ist SMTP gesetzt (mailhog:1025), Checkbox ist bedienbar. Fuer den echten Mailfluss zuerst mailhog starten, dann eine Erinnerung mit Haken faellig werden lassen: genau eine Mail mit Zeit in Europe/Berlin. Nach "In 10 Minuten" kommt nach Ablauf eine zweite. (Den ausgegrauten Zustand mit Erklaerungstext kann man pruefen, indem man in Einstellungen -> SMTP die Einrichtung entfernt; danach wiederherstellen.)
- Als
admin(admin123): das Widget zeigt keine Erinnerungen von testuser. - Am Ende alle Test-Erinnerungen entfernen.
Windows-VM (Proxmox 8233, laut VM-Notizen):
Die Rust-Aenderung wirkt nur in einem Desktop-Client, der aus diesem Stand gebaut ist. Da nichts gepusht wurde, baut CI keinen; der Windows-Test braucht entweder Push + CI-Paket oder ein lokal gebautes NSIS-Paket. Ein aelterer Client zeigt das Widget und bekommt E-Mails, aber keine Toasts (im CHANGELOG vermerkt).
10. Mit dem neuen Client, verbunden mit dem Server mit diesem Code: Erinnerung in 3 Minuten anlegen, Fenster mit X schliessen (Infobereich), warten. Ein Windows-Toast von "Tessera" mit "Erinnerung: ..." erscheint innerhalb rund einer Minute nach der Faelligkeit (WebView2 drosselt versteckte Timer, E-01). Danach das Fenster oeffnen: die Erinnerung zeigt "Faellig".
11. Desktop-App und Browser gleichzeitig offen: jede zeigt die Benachrichtigung genau einmal.
12. Nach "Server-Adresse aendern..." auf denselben Server funktionieren die Benachrichtigungen weiter (Berechtigung wird in save_server_url erneut erteilt).
Self-Check: PASSED
- Erstellte Dateien vorhanden: Migration,
apps/api/src/reminders/*(inkl.reminder-mail.scheduler.ts),reminders-api.ts,reminder-notify.ts,reminder-time.ts,reminder-notifier.tsx,reminder-widget.tsx,reminder-form-modal.tsx(alle in den Commits enthalten). - Commits 26f8f0f, 580c31c, 8027c48 liegen auf
main(git log cd1f8f6..HEAD);git statuszeigt ausser dem.planning-Verzeichnis nichts Uncommittetes. - Nichts gepusht.
Browser-Pruefung (Orchestrator, 29.09., dunkel, testuser)
- Katalog zeigt „Erinnerungen“; Widget hinzugefuegt, Leerzustand + „Neue Erinnerung“.
- „Kaffee holen“ faellig 14:14 mit E-Mail-Haken, danach auf den Marktplatz gewechselt: genau eine Browser-Benachrichtigung „Erinnerung: Kaffee holen“ um 14:14:08 (global, nicht nur auf dem Dashboard).
- MailHog (lokal gestartet, Alias mailhog im backend-net): genau eine Mail an testuser@example.com um 14:14:15, Text „Dienstag, 29. September 2026 um 14:14 Uhr“ (Berlin).
- Zweiter Tab derselben Sitzung, 20 s: keine zweite Benachrichtigung.
- Faellig-Zustand dunkel gut lesbar (Rahmen + Abzeichen „Fällig“, Erledigt / Später erinnern).
- Später erinnern: Menue In 10 Minuten / In 1 Stunde / Morgen um 14:14; „In 10 Minuten“ -> 14:26. Bearbeiten (Titel) ok. Löschen mit Rueckfrage Ja/Nein ok.
- „Wasser trinken“ (ohne E-Mail) faellig -> Erledigt -> verschwindet; keine zweite Mail.
- Aufgeraeumt: Reminder-Tabelle leer, MailHog-Container entfernt.
- Offen: Windows-Toast der Desktop-App (braucht CI-Paket nach Push), Erlaubnisabfrage-erst-nach-Speichern nur per Komponententest belegt (Playwright-Kontext hatte die Erlaubnis vorab).