addcefe70b
Implements Phase 1 of groombook/groombook#4 — automated email reminders for upcoming appointments, with booking confirmations sent immediately on creation. - **DB**: new `reminder_logs` table tracks sent reminders per appointment (unique on appointmentId+type prevents duplicates); `clients` gains `email_opt_out` boolean (migration 0004_reminder_logs) - **Email service**: `apps/api/src/services/email.ts` — nodemailer SMTP transport (disabled when SMTP_HOST is unset, so self-hosted installs without email config are unaffected); confirmation and reminder email templates included - **Reminder scheduler**: `apps/api/src/services/reminders.ts` — node-cron job runs every minute, checks for appointments in the upcoming reminder windows (default: 24 h and 2 h), sends emails for opted-in clients, and records sends in reminder_logs (idempotent via ON CONFLICT DO NOTHING) - **Confirmation email**: sent fire-and-forget after successful appointment creation (both single and recurring); never blocks the API response - **Config**: SMTP_HOST, SMTP_PORT, SMTP_SECURE, SMTP_USER, SMTP_PASS, SMTP_FROM, REMINDER_HOURS_EARLY, REMINDER_HOURS_LATE env vars documented in .env.example; all optional — feature is silently disabled without them - **Types**: Client.emailOptOut field added to shared types package Co-authored-by: Groom Book CTO <cto@groombook.app> Co-authored-by: Paperclip <noreply@paperclip.ing>
12 lines
467 B
SQL
12 lines
467 B
SQL
-- Add email opt-out flag to clients
|
|
ALTER TABLE "clients" ADD COLUMN "email_opt_out" boolean NOT NULL DEFAULT false;
|
|
|
|
-- Track sent reminders to prevent duplicate sends
|
|
CREATE TABLE "reminder_logs" (
|
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
"appointment_id" uuid NOT NULL REFERENCES "appointments"("id") ON DELETE CASCADE,
|
|
"reminder_type" text NOT NULL,
|
|
"sent_at" timestamp DEFAULT now() NOT NULL,
|
|
UNIQUE ("appointment_id", "reminder_type")
|
|
);
|