werkator/jvm build succeeded after 08:15
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>
95 lines
3.9 KiB
Gherkin
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
|