package auth import ( "context" "log/slog" ) // EmailSender delivers transactional auth emails (verification, reset, // collaborator-invite). Block A ships LogSender so dev environments work // without Twilio/SES. Tier 1 Block D replaced this with a real SES-backed // sender; Tier 2 Block C added the collaborator-invite method. type EmailSender interface { SendVerification(ctx context.Context, to, name, link string) error SendPasswordReset(ctx context.Context, to, name, link string) error SendCollaboratorInvite(ctx context.Context, to, inviterName, eventName, role, link string) error // SendRSVPEditLink delivers a one-time edit link to a guest who's // reopened their invitation from a device the Gate didn't recognise. // Tier 2 Block G follow-up. The link carries a short-lived nonce // (~30 min) that lets the guest see + change their existing RSVP // without exposing it to anyone who got hold of the original // invitation token. SendRSVPEditLink(ctx context.Context, to, guestName, eventName, link string) error } type LogEmailSender struct { Logger *slog.Logger } func (l LogEmailSender) SendVerification(_ context.Context, to, name, link string) error { l.Logger.Info("auth email (stub): verification", "to", to, "name", name, "link", link, ) return nil } func (l LogEmailSender) SendPasswordReset(_ context.Context, to, name, link string) error { l.Logger.Info("auth email (stub): password reset", "to", to, "name", name, "link", link, ) return nil } func (l LogEmailSender) SendCollaboratorInvite(_ context.Context, to, inviterName, eventName, role, link string) error { l.Logger.Info("auth email (stub): collaborator invite", "to", to, "inviter", inviterName, "event", eventName, "role", role, "link", link, ) return nil } func (l LogEmailSender) SendRSVPEditLink(_ context.Context, to, guestName, eventName, link string) error { l.Logger.Info("auth email (stub): rsvp edit link", "to", to, "guest", guestName, "event", eventName, "link", link, ) return nil }