feat: automated appointment reminders via email #29

Merged
ghost merged 1 commits from feat/automated-reminders into main 2026-03-17 20:46:49 +00:00
ghost commented 2026-03-17 20:45:34 +00:00 (Migrated from github.com)

Summary

Implements groombook/groombook#4 Phase 1 — automated email reminders with SMTP.

  • DB: new reminder_logs table (unique on appointment_id + reminder_type) prevents duplicate sends; clients gains email_opt_out boolean (migration 0004_reminder_logs)
  • Email service (services/email.ts): nodemailer SMTP transport — silently disabled when SMTP_HOST is unset, so deployments without email config are unaffected; confirmation and reminder HTML/text templates included
  • Reminder scheduler (services/reminders.ts): node-cron job runs every minute, scans for appointments in configurable reminder windows (default 24 h and 2 h), sends emails for opted-in clients, records sends idempotently via ON CONFLICT DO NOTHING
  • Confirmation email: sent fire-and-forget after successful appointment creation (single and recurring); never blocks the API response
  • Configuration: SMTP_HOST, SMTP_PORT, SMTP_SECURE, SMTP_USER, SMTP_PASS, SMTP_FROM, REMINDER_HOURS_EARLY, REMINDER_HOURS_LATE documented in .env.example — all optional

Phase 2 out of scope (SMS, two-way messaging, waiting list) — tracked in the original GitHub issue.

Test plan

  • Without SMTP_HOST set — no emails sent, no errors, API functions normally
  • Book an appointment for a client with email — confirmation email sent
  • Book an appointment for a client with email_opt_out=true — no email sent
  • Scheduler runs — 24 h and 2 h reminder emails sent for upcoming appointments
  • Reminder not sent twice — reminder_logs dedup prevents duplicates on re-run
  • REMINDER_HOURS_EARLY/REMINDER_HOURS_LATE env vars override default windows
  • CI passes

Closes #4

🤖 Generated with Claude Code

## Summary Implements [groombook/groombook#4](https://github.com/groombook/groombook/issues/4) Phase 1 — automated email reminders with SMTP. - **DB**: new `reminder_logs` table (unique on `appointment_id` + `reminder_type`) prevents duplicate sends; `clients` gains `email_opt_out` boolean (migration `0004_reminder_logs`) - **Email service** (`services/email.ts`): nodemailer SMTP transport — silently disabled when `SMTP_HOST` is unset, so deployments without email config are unaffected; confirmation and reminder HTML/text templates included - **Reminder scheduler** (`services/reminders.ts`): `node-cron` job runs every minute, scans for appointments in configurable reminder windows (default 24 h and 2 h), sends emails for opted-in clients, records sends idempotently via `ON CONFLICT DO NOTHING` - **Confirmation email**: sent fire-and-forget after successful appointment creation (single and recurring); never blocks the API response - **Configuration**: `SMTP_HOST`, `SMTP_PORT`, `SMTP_SECURE`, `SMTP_USER`, `SMTP_PASS`, `SMTP_FROM`, `REMINDER_HOURS_EARLY`, `REMINDER_HOURS_LATE` documented in `.env.example` — all optional **Phase 2 out of scope** (SMS, two-way messaging, waiting list) — tracked in the original GitHub issue. ## Test plan - [ ] Without `SMTP_HOST` set — no emails sent, no errors, API functions normally - [ ] Book an appointment for a client with email — confirmation email sent - [ ] Book an appointment for a client with `email_opt_out=true` — no email sent - [ ] Scheduler runs — 24 h and 2 h reminder emails sent for upcoming appointments - [ ] Reminder not sent twice — `reminder_logs` dedup prevents duplicates on re-run - [ ] `REMINDER_HOURS_EARLY`/`REMINDER_HOURS_LATE` env vars override default windows - [ ] CI passes Closes #4 🤖 Generated with [Claude Code](https://claude.com/claude-code)
ghost commented 2026-03-17 20:46:47 +00:00 (Migrated from github.com)

CI passed ✓. Self-review complete — implementation follows the same patterns as the rest of the codebase. Merging.

CI passed ✓. Self-review complete — implementation follows the same patterns as the rest of the codebase. Merging.
This repo is archived. You cannot comment on pull requests.