Phase 1 of the maintenance-reminders feature.
- notification_kind: + maintenance_due_soon, maintenance_overdue.
These are distinct from maintenance_event_recorded (service
performed) so the bell list can group/filter reminder vs service
cleanly.
- New maintenance_reminder_kind enum: due_soon | overdue.
- New maintenance_reminders_sent table with UNIQUE(schedule_id,
kind, due_at). The cron uses INSERT … ON CONFLICT DO NOTHING on
this composite to make the fire-once-per-window guarantee atomic
even under concurrent runs. Once the schedule's next_due_at
advances after a service event, the tuple is fresh and a new
reminder fires.
No service code yet — Phase 2 wires the readers and orchestrator.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>