Day 12 β nobody misses appointments. π§ Money's moving, reviews are live β now ClipBook talks to its users. This morning: transactional emails β booking confirmed, a 24h reminder before the cut, a review request after completion, and cancellation notices.
Paste this into Claude Code / Cursor (agent mode): β¬οΈ
Build transactional emails for ClipBook (Next.js 14 App Router, TypeScript, Tailwind CSS, Supabase). Use Resend for sending β add RESEND_API_KEY to .env.local (test key first).
1. BRANDED TEMPLATE β components/email/EmailLayout.tsx:
- HTML email template (email clients are stuck in 2005 β use table-based layout, inline styles, no Tailwind).
- ClipBook header (logo text + brand color bar), footer with unsubscribe + app links. Works in Gmail, Outlook, Apple Mail.
- Preview all emails locally before wiring them up.
2. EMAIL SENDER β lib/email.ts:
- sendEmail(to, subject, html) helper with error handling and logging. Queue failures for retry β never let a send error break the booking flow.
- One function per email type: bookingConfirmedEmail(booking), bookingReminderEmail(booking), reviewRequestEmail(booking), cancellationEmail(booking, reason).
3. THE FOUR EMAILS:
- Booking confirmed (fires from the booking flow after payment succeeds β Day 11A): service, barber, date/time, price paid, "Add to calendar" note, refund policy line.
- Reminder 24h before (cron or Supabase edge function scheduled daily at 8 AM, querying bookings where start_time is tomorrow): "Your cut with {barber} is tomorrow at {time}."
- Review request (fires when booking β 'completed', from Day 6 status flow): deep link to the booking page with the review modal pre-opened (Day 10A).
- Cancellation notice (fires from the cancel flow, Day 11B): refund amount + timeline if refunded, or the 24h policy note if not.
- All four must be idempotent: an emails_sent table (booking_id, email_type, sent_at) with a unique constraint so retries and double-fires never send duplicates.
4. TRIGGERS: wire each send call into the existing flow that produces the event β do NOT build a separate event system. The 24h reminder runs on a daily schedule (Vercel cron or Supabase cron, documented in the README).
5. PREFERENCES: customer profile gets an email_preferences JSON column {reminders: true, review_requests: true, promotions: false}. Respect it in sendEmail β a user who opted out of reminders gets no reminder. One toggle UI per preference on /profile.
ACCEPTANCE CRITERIA:
- Booking a service sends exactly one confirmation email within 30 seconds
- The 24h reminder fires for tomorrow's bookings and no others
- Completing a booking sends the review request with the deep link opening the review modal
- Double-firing an event sends nothing twice (emails_sent constraint)
- Opting out of reminders stops reminders but not confirmations
- `npm run build` passes with no errors
What you'll get when it works π