Repository navigation
feat: email the owner on bookings, leads, and tickets - #124
Merged
Merged
Conversation
Only visitors were ever emailed, so a booked consult was missed. Bookings add calendar events, zone-labeled times, and a working cancel link; public form text is stripped of control characters.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The founder missed a booked consult. When someone booked, the app emailed only the booker. Nothing ever notified the business about a booking, a client cancellation, a lead-magnet download, or a support ticket; they all landed silently in the dashboard.
What changes
Owner notifications (
server/email/notify-owner.ts)Calendar events (
lib/ics.ts, RFC 5545)METHOD:PUBLISHto both sides. Client cancellation:METHOD:CANCELto both, same UID.Bugs fixed in the same flow
/book/cancel); it now goes to/portal/appointments/cancel. The reminder email shares the same builder.allSettledplus an async wrapper). A failure, even a throw while building the client's email, never blocks the owner's notice and never fails a saved booking. Each failure is logged with the appointment id.Verified against the production image + Mailpit
text/calendar; method=PUBLISHparts, zone-labeled times, working cancel link (200).method=CANCELto both.Pat\r\nBcc: attackeras a name: no Bcc header, no extra recipient; escaped in the event.Review note: the adversarial review hit a session limit. The correctness lens completed and all 8 of its findings were checked by hand: 7 real, fixed here; the 8th is operator guidance (Gmail self-send, below). The security lens didn't run, so I covered it by hand. Header, HTML and ICS injection plus control characters are tested above. Spam-relay exposure is unchanged: the confirmation to a visitor-supplied address predates this change, and all three forms stay rate-limited.
After deploy (operator)
🤖 Generated with Claude Code