feat(maintenance): schema for reminders dedup log

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>
This commit is contained in:
2026-04-27 16:11:34 +07:00
parent 435bcb981f
commit b4108c5a36
5 changed files with 4765 additions and 2 deletions
+14
View File
@@ -0,0 +1,14 @@
CREATE TYPE "public"."maintenance_reminder_kind" AS ENUM('due_soon', 'overdue');--> statement-breakpoint
ALTER TYPE "public"."notification_kind" ADD VALUE 'maintenance_due_soon' BEFORE 'generic';--> statement-breakpoint
ALTER TYPE "public"."notification_kind" ADD VALUE 'maintenance_overdue' BEFORE 'generic';--> statement-breakpoint
CREATE TABLE "maintenance_reminders_sent" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"schedule_id" uuid NOT NULL,
"kind" "maintenance_reminder_kind" NOT NULL,
"due_at" timestamp with time zone NOT NULL,
"fired_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
ALTER TABLE "maintenance_reminders_sent" ADD CONSTRAINT "maintenance_reminders_sent_schedule_id_maintenance_schedules_id_fk" FOREIGN KEY ("schedule_id") REFERENCES "public"."maintenance_schedules"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE UNIQUE INDEX "mrs_schedule_kind_due_uq" ON "maintenance_reminders_sent" USING btree ("schedule_id","kind","due_at");--> statement-breakpoint
CREATE INDEX "mrs_by_schedule" ON "maintenance_reminders_sent" USING btree ("schedule_id","kind");
File diff suppressed because it is too large Load Diff
+7
View File
@@ -134,6 +134,13 @@
"when": 1777268985448,
"tag": "0018_checklist_scope_property",
"breakpoints": true
},
{
"idx": 19,
"version": "7",
"when": 1777281036233,
"tag": "0019_maintenance_reminders",
"breakpoints": true
}
]
}