Skip to content

[DO NOT MERGE] add email notification system#1030

Closed
stevenle wants to merge 4 commits into
alphafrom
alpha-email
Closed

[DO NOT MERGE] add email notification system#1030
stevenle wants to merge 4 commits into
alphafrom
alpha-email

Conversation

@stevenle
Copy link
Copy Markdown
Member

Changes Made

Phase 1: Renamed apps/gci $\rightarrow$ tools

  • Moved the directory
  • Updated app.yaml — service name gci $\rightarrow$ tools
  • Updated go.mod — module path to tools
  • Updated deploy.sh — description text

Phase 2–3: Email config + Firestore queue (root-cms)

  • plugin.ts — Added CMSEmailConfig interface and email?: CMSEmailConfig to CMSPluginOptions with options for enabled, sender, recipients (supports "ADMINS" sentinel), events, and webhook
  • client.ts — Added:
    • QueuedEmail, EmailStatus, QueueEmailOptions interfaces for the Projects/{id}/Emails Firestore collection
    • queueEmail() — writes a pending email doc to Firestore
    • listPendingEmails() — queries emails with status == 'pending'
    • updateEmailStatus() — updates status to sent / failed
    • resolveEmailRecipients() — resolves "ADMINS" to actual admin emails from ACL
    • queueEmailForAction() — auto-generates email subject/body from action data
    • fireEmailWebhook() — fire-and-forget HTTP POST with HMAC-SHA256 signature
    • Updated logAction() to auto-queue emails when email.enabled and the action matches a configured event

Phase 4: Email sending handler (tools)

  • main.go — Added /_/send_emails?projectId= handler that:
    • Queries Projects/{projectId}/Emails where status == "pending" via Firestore
    • Sends each email via App Engine Mail API (mail.Send)
    • Updates doc status to sent (with sentAt) or failed (with error)
    • Returns JSON with sent / failed counts

Usage example

cmsPlugin({
  firebaseConfig: { ... },
  email: {
    enabled: true,
    sender: 'noreply@example.com',
    recipients: ['ADMINS'],
    events: ['doc.publish', 'doc.scheduled_publish', 'doc.unpublish'],
    webhook: {
      url: 'https://tools-dot-my-project.appspot.com/_/send_emails?projectId=default',
      secret: 'my-shared-secret',
    },
  },
});

fixes #858

@stevenle stevenle requested a review from jeremydw April 12, 2026 23:14
@jeremydw
Copy link
Copy Markdown
Member

Sorry for taking a while to get back to review this. A few high-level thoughts:

  1. Treating the email subsystem as a separate GAE app (akin to the GCI image service) sgtm.
  2. I was hoping that the email subsystem would be exposed similar to GCI with a client, e.g. so other plugins could use it for their own purposes. Maybe we should have a predefined mechanism for user plugins to access GCI and the email system, e.g. cmsPlugin.getSystem('email') or something long those lines that users can access. Theoretically a site might also want to build a plugin that sends an email as part of the actual web interface itself (e.g. if we build a "Root Forms" plugin maybe we have an email sending capability).

Regarding the notifications, I was thinking that rather than configuring recipients and events in the root config, those ideally are configured in the CMS UI somewhere, e.g. so users can "manage notifications", with "email" being one notification channel. I'm not entirely sure where this would be configured, maybe a mix of the action logs page and the settings page (and ideally users have a way to control their own notifications, similar to an app like Asana provides).

@stevenle
Copy link
Copy Markdown
Member Author

re: (2) i think the "system" you're referring to may be related to this: #897. i can refactor so that users need to register an "email provider" and the email provider plugin has its own client utilities.

for the larger notification system maybe we need to come up with some ux mocks and flesh out the requirements some more.

@stevenle
Copy link
Copy Markdown
Member Author

prompt used:

I'd like to refactor the root-cms notfiication system to abstract the email system a little more. In general, root should have a concept of "services" that a plugin can register, such a "cache" service, a "email" service, and a "translations" service. These services are optional to the core of root and root-cms, if a service is registered, it would enable extra functionality.

For now let's just focus on the email service.

- Provide an interface for what the email service looks like
- Add a server-side api for sending emails, which checks if there's an email service registered and calls the appropriate function
- Update the existing code to use this new pattern
- Add a RootEmailService which uses the one from apps/tools

@stevenle
Copy link
Copy Markdown
Member Author

i'm still reviewing/iterating but here's the summary from claude:

Screenshot 2026-04-23 at 4 25 02 PM

@stevenle
Copy link
Copy Markdown
Member Author

FYI ignore this PR, I may abandon it soon and start a new session. I forgot that you recently added a "translations service" and I wanna make sure that all the different "services" we have in the system have a consistent interface and configuration style. I'm gonna start a new session that plans this out better and if there are any changes to the translations API I can automatically have it convert to the new format so that your usage doesn't break when you upgrade to the new version.

@stevenle stevenle changed the title feat: add email notification system [DO NOT MERGE] add email notification system Apr 24, 2026
@stevenle
Copy link
Copy Markdown
Member Author

stevenle commented May 6, 2026

closed in favor of #1085

@stevenle stevenle closed this May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants