Database migration and Notifications::EmailEvent model creation
Database migration/table creation for Notifications::EmailEvent
Problem
We currently track email notifications through various timestamp fields scattered across different models (e.g., Order#increased_billing_rate_notified_at, Order#seat_overage_notified_at, Order#auto_renew_error_notified_at). This approach lacks consistency, makes it difficult to track all sent notifications in one place, and complicates preventing duplicate emails when jobs are retried.
Proposal
Create a new Notifications::EmailEvent model and corresponding database table to centralize tracking of all email notifications sent by our system.
The table structure will include:
| Field | Type | Description | Example |
|---|---|---|---|
| id | bigint | Primary key | 1 |
| notification_type | string | The type of notification sent | "upcoming_renewal_30_days" |
| sent_at | datetime | When the notification was sent | 2024-01-01 12:00:00 |
| recipient | string | Email address of recipient | test@example.com |
| source_type | string | Object type that triggered notification | "Order" |
| source_id | bigint | ID of the object that triggered notification | 123 |
| metadata | jsonb | Additional context data (flexible) | {"plan_name": "Premium", "amount": 1000} |
Indexing Strategy: Based on the current UpcomingNotificationCronJob implementation and the future need to support multiple notification periods (90/60/45/30/1 day cadence), we need the following indexes:
# Composite index for efficiently finding notifications for a specific order and notification type
add_index :email_events, [:source_type, :source_id, :notification_type],
name: 'index_email_events_on_source_and_notification_type'
# Index for time-based queries (to replace the NOTIFICATION_PERIOD.ago check)
add_index :email_events, :sent_at
# Index for filtering by notification type (useful when implementing multiple periods)
add_index :email_events, :notification_type
The primary composite index will support queries that check if a specific notification has already been sent for an order, which will replace the current pattern of using the upcoming_auto_renewal_notified_at timestamp field. This will be particularly important when we implement multiple notification periods, as we'll need to track each period separately.
Result
- A centralized system for tracking all email notifications
- Ability to prevent duplicate emails by checking if a notification has already been sent
- Support for multiple notification periods (90/60/45/30/1 day cadence) in the future
- Improved auditing capabilities to see what notifications were sent, when, and to whom
- Foundation for future analytics on email notification patterns
- Efficient querying through properly indexed fields
Next steps (if any)
- After this implementation, update existing notification services to use this new model
- Consider adding a cleanup job to prevent unbounded table growth (low priority)
How will we measure success?
- All new email notifications are properly recorded in the
EmailEventtable - We can successfully prevent duplicate emails when jobs are retried
- We can query the table to get accurate counts of different notification types
- Query performance remains efficient as the table grows
- The table design supports the future implementation of multiple notification periods