Files
claude-codeandmhoennig 4356eb00ca
werkator/jvm build succeeded after 08:15
Erinnerungszeit je Konto einstellbar statt fest um 20:00 (#10)
Die Arbeitserinnerung kam bis hierher ausschließlich um 20:00 Ortszeit des Geräts und wurde bis 22:00 nachgeholt; beide Zeiten standen als Konstanten in `ReminderWindow`. Der Beginn ist jetzt je Konto einstellbar, das Nachholfenster leitet sich daraus ab.

## Entscheidungen

- **Kontoeinstellung, nicht Geräteeinstellung.** Der Ein-/Ausschalter für Push bleibt pro Gerät; die Uhrzeit gilt für alle Geräte desselben Kontos und steht neben Sprache und Arbeitstracker im gemeinsamen Formular mit Versionsprüfung.
- **Viertelstundenschritte zwischen 06:00 und 23:00**, Vorgabe 20:00. Ein Konto, das nichts ändert, wird unverändert erinnert.
- **Nachholen bleibt zwei Stunden, endet aber spätestens um Mitternacht.** Eine Erinnerung nennt das Datum, um das es geht, und darf nicht in den Folgetag wandern: bei 23:00 bleibt eine Stunde statt zwei. Push-TTL und `reminder_delivery.expires_at` folgen demselben Ende.
- Montag bis Freitag und die Prüfung unmittelbar vor dem Versand bleiben unverändert.

`ReminderWindow` hält Vorgabe, Grenzen, Schrittweite und Nachholdauer an einer Stelle. Dienst, Spaltenbedingung und `TimePicker` prüfen jeweils dagegen. Ein gespeicherter Wert außerhalb der angebotenen Zeiten hält die Erinnerung zurück, statt eine Stunde zu raten.

## Migration

`werkjournal:reminder-time` fügt `app_user.reminder_minute` mit `DEFAULT 1200 NOT NULL` hinzu; bestehende Zeilen behalten damit ihren Zeitplan, keine andere Spalte wird angefasst.

## Nachweise

Branch-Pipeline lokal grün (`tools/ci-jvm --without-firefox`): 25 Browser-Szenarien, 14 Push-Service-Szenarien, 22 Frontend-Tests, 68 Operations-Tests, JVM-Smoke PASS.

- `ReminderWindowTest`: Vorgabe erzeugt dasselbe Fenster wie zuvor; eine gewählte Zeit verschiebt Beginn und Ende; eine späte Zeit behält ihr Datum und verliert Nachholzeit an Mitternacht.
- `SettingsServiceTest`, `ReminderTimeMigrationTest`: Speichern, Ablehnen und der erhaltende Migrationsschritt mit befülltem Vorgängerstand.
- WJ-073/WJ-074 mit echtem Scheduler, Warteschlange und Testtransport; WJ-075 im Browser für Formular, Gerätehinweis und abgelehnte Eingabe.
- `tests/frontend/push-settings.test.cjs`: der Gerätehinweis nennt die übergebene Zeit statt einer festen Stunde.

Details: `docs/implementation/reminder-time.md`.

## Nebenbei

Die Erhaltungsprüfung in `AccountDeletionProofsTest` verglich ganze Zeilen und schlug deshalb bei jedem additiven Changeset an. Sie vergleicht jetzt die Spalten, die es vorher gab, und prüft die Zeilenzahl — die Absicht bleibt, ein zusätzliches Feld sieht nicht mehr wie eine Datenänderung aus.

## Offen

`docs/plans/ui-refresh-selectors.md` hat die neuen Selektoren bekommen; seine `BS:`-Zeilennummern und die Tag-Liste in Abschnitt 0 waren schon vorher veraltet und sind hier nicht nachgezogen.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: mhoennig <michael@hoennig.de>
Reviewed-on: #10
Co-authored-by: claude-code <4+claude-code@noreply.git.javagil.de>
2026-10-21 13:47:23 +02:00

95 lines
3.9 KiB
Gherkin

Feature: Device-local work reminders
@WJ-028 @service
Scenario: Remind only an opted-in smartphone
Given Alice enabled reminders on her smartphone but not her tablet
And it is Monday at 20:00 in the smartphone's last known timezone
And Alice has no work entry or day-off marker for that date
When the scheduler evaluates due reminders
Then one logical reminder is sent to the smartphone subscription
And none is sent to the tablet
@WJ-029 @service
Scenario Outline: Suppress an ineligible reminder
Given it is a weekday at 20:00 in the device's last known timezone
And <condition>
When the scheduler evaluates due reminders
Then no reminder is sent
Examples:
| condition |
| work is already recorded for that date |
| the date is marked as a day off |
| the work tracker is disabled |
| the account is disabled |
| the subscription is disabled |
@WJ-030 @service
Scenario: Catch up after maintenance
Given a reminder was due at 20:00 during maintenance
And it is now 21:00 on the same local date
And no work or day-off marker exists for that date
When the released application resumes scheduling
Then that reminder is sent
And another scheduler run does not create another logical reminder
@WJ-031 @service
Scenario: Do not catch up after the window closes
Given a reminder was missed during an outage
And it is after 22:00 in the device's last known timezone
When scheduling resumes
Then that missed reminder is discarded
@WJ-032 @service
Scenario: Use the last observed timezone while the app is closed
Given the smartphone last reported Europe/Berlin
And its owner travels without reopening the app
When the server schedules the reminder
Then it uses Europe/Berlin
When the app opens and reports a new valid timezone
Then subsequent scheduling uses the newly reported timezone
@WJ-033 @browser
Scenario: Open an old notification
Given a reminder refers to 2026-09-08
When Alice taps it on 2026-09-09
Then the work entry form opens for 2026-09-08
And the normal customer and project defaults apply
@WJ-034 @service
Scenario: Do not remind at weekends
Given an opted-in device has no recorded work or day-off marker today
And today is Saturday or Sunday in its last known timezone
When the scheduler evaluates reminders at 20:00
Then no reminder is sent
@WJ-035 @service
Scenario: Work recorded on another device suppresses a reminder
Given Alice's smartphone is opted in for reminders
And Alice records work on her desktop for the smartphone's current date
When the smartphone reminder becomes due
Then no reminder is sent
@WJ-060 @service
Scenario: Removing a day-off marker restores reminder eligibility
Given Alice's smartphone is opted in for reminders
And Alice marks the current date as a day off and then removes the marker
When the smartphone reminder becomes due
Then one logical reminder is sent to the smartphone subscription
@WJ-073 @service
Scenario: Remind at the time the account chose instead of the former fixed one
Given Alice's smartphone is opted in for reminders
And Alice sets her reminder time to 17:30
When the scheduler evaluates due reminders
Then no reminder is sent
When the next weekday reaches 17:30 in the device's last known timezone
Then one logical reminder is sent to the smartphone subscription
And its catch-up ends two hours after the chosen time
@WJ-074 @service
Scenario: Keep a late reminder on its own date
Given Alice's smartphone is opted in for reminders
And Alice sets her reminder time to 23:00
When the next weekday reaches 23:00 in the device's last known timezone
Then one logical reminder is sent to the smartphone subscription
And its catch-up ends at midnight instead of reaching the next day