Skip to content

Email — Resend + template matrix (draft) ​

Job: one send pipeline in Middleware. Frontend never holds the Resend key. Core does not send mail.

v1 stub still says emails are not live. Sibling routes.json and the explorer already have the folder. Proposed winner after promotion:

Middleware Backend · proposed winner · live on explorer

POST https://middleware-dev.bookdirect.live/api/v1/bookdirect/emails/send

http
Authorization: Bearer {access_token}
Content-Type: application/json
json
{
  "template": "booking_confirmed_guest",
  "booking_uuid": "{booking_uuid}"
}

JWT must be the booking guest or the property owner. Middleware loads Core booking + property, renders HTML, sends via Resend (SMTP fallback), writes email_event_{template} on the booking.

Payments / refunds call the same service in-process — do not HTTP-loop.

Do not publish the 146 KB React Email source dump. Port templates in the Middleware templates/ package. This page is keys, recipients, and CTAs.


ENV (names only) ​

NameLayerPurpose
RESEND_API_KEYMiddlewareSend. Alias SMTP_API_KEY during cutover
RESEND_FROMMiddlewareDefault From. Alias SMTP_FROM
SMTP_ENDPOINTMiddlewareDefault https://api.resend.com/emails if still named SMTP
SITE_URLMiddlewareCTA base (https://bookdirect.ng)
EMAIL_RENDER_SECRETMiddleware + admin previewPreview render only

Guest mail stays BookDirect-branded (reservation@send.bookdirect.ng). Partner signup CTAs may point at MelonQ. Decide @melonq.com From later — not for guest booking mail.


Live template keys (implement these first) ​

Middleware EMAIL_TEMPLATES today:

KeyToWhen
booking_pending_guestGuestCreate / modify (guest HTML)
booking_awaiting_response_guestGuestWaiting on hotel
booking_awaiting_response_ownerOwnerNew booking — hotel first
booking_confirmed_guestGuestAccept / confirm
booking_confirmed_ownerOwnerConfirmed
booking_rejected_guestGuestReject
booking_cancelled_guestGuestCancel
booking_cancelled_ownerOwnerCancel

Product fact to keep: a new stay emails the hotel first. Guest create HTML is mainly modifications.

Booking ref in the body is Core booking.meta_key (see booking ID).


Legacy matrix → live keys (focus) ​

Do not rename live keys. Map Convex / hub triggerIds when you port.

Legacy / hub idLive key(s)Port now?
new_booking_pending / booking_email_htmlbooking_awaiting_response_owner (+ guest pending on modify)Yes
accepted_booking / booking_confirmedbooking_confirmed_guest + _ownerYes
rejected_bookingbooking_rejected_guestYes
cancelled_bookingbooking_cancelled_*Yes
booking_payment / refund / payoutnot in EMAIL_TEMPLATES yetAfter payments wire
user_signup / password_resetCore auth mail or later keysAuth stays Core until a guest-mail trigger exists
new_booking_demandpro_flexi—Only if Flexi plans survive MelonQ
Unsigned marketing 14–23—Product gate; not lodging v1
Recon / invoice / no-show—Finance workstream

Full numbered file list stays in the legacy repo (lib/emails/templates/0x-*.tsx). Do not copy those files into DevDocs.


CTAs ​

AudienceButtonURL
GuestView / manage{SITE_URL}/manage-booking?ref={reference}
GuestConfirmation{SITE_URL}/booking/confirmation?ref=
GuestCancel / modify/cancel-booking?ref= · /modify-booking?ref=
HotelAccept / RejectMiddleware token confirm — not a Next /api winner

Proposed token URL (after you add it):

POST https://middleware-dev.bookdirect.live/api/v1/bookdirect/bookings/action

or keep GET .../emails/action?token= on Middleware. Flexi “sign up” hrefs go to onboarding.bookdirect.melonq.com / melonq.com/signin. Token confirm stays on the booking host.

Idempotent send key: (template, booking_uuid, eventVersion).


Defaults (copy rules) ​

  • Hotel To → CC reservation@ unless suppressed
  • Guest To → BCC reservation@ unless suppressed
  • Payment / refund → CC finance@; no reservation BCC
  • Marketing / internal → suppress auto reservation copy

Communication hub (MelonQ admin) can override enable / Reply-To / CC later. Do not rename live template keys without a migration.


IDOR ​

  • Public browse key must not POST .../emails/send
  • Bearer: guest of that booking or property owned_by
  • No card data in logs. Store Resend id + email_event_* only

Called by Middleware, not by frontend ​

Resend POST https://api.resend.com/emails

Core PUT .../meta-data/entity/booking/{uuid} for email_event_*

Promote into v1 Middleware when the activation matrix row leaves “to implement.”

API-first. Middleware Backend wins over Core Backend when both exist.