Adding a New Alert Type
Quick steps to add a new alert type. For full pipeline details — how each channel works, the content dict contract, recipient resolution, all edge cases — see Alert Processor Reference.
Files to create / modify
| File | Action |
|---|---|
app/services/alerts/constants/alert_types.py | Add string constant |
app/services/alerts/alerts_content/my_alert_content.py | Create content builder class |
app/services/alerts/alerts_processor.py | Add elif branch in get_content() |
app/templates/alert/my_alert.html | (Optional) Custom email HTML template |
Step 1 — Add the alert type constant
File: app/services/alerts/constants/alert_types.py
MY_ALERT = 'my_alert'
This string is what the caller passes as alertType in the POST body.
Step 2 — Create the content builder class
File: app/services/alerts/alerts_content/my_alert_content.py
class MyAlertContent:
def __init__(self, data, unit_name, industry_name, timezone):
self.data = data
self.unit_name = unit_name
self.industry_name = industry_name
self.timezone = timezone
def build(self):
value = self.data.get('meta', {}).get('currentValue')
threshold = self.data.get('meta', {}).get('threshold')
return {
'subject': f'My Alert — {self.unit_name}',
'body': f'{self.unit_name} reported {value}, threshold {threshold}.',
'industry_name': self.industry_name,
'unit_name': self.unit_name,
'value': value,
'threshold': threshold,
'alert_type': 'my_alert',
}
subject and body are required. All other keys are available as Jinja2 variables in the email template. Do not call the database or dispatch channels here — content classes only build data.
Step 3 — Register in AlertsProcessor.get_content()
File: app/services/alerts/alerts_processor.py
from app.services.alerts.alerts_content.my_alert_content import MyAlertContent
from app.services.alerts.constants.alert_types import MY_ALERT
# Inside AlertsProcessor.get_content():
elif self.request.alert == MY_ALERT:
return MyAlertContent(
data = self.request.data,
unit_name = self.unit_name,
industry_name = self.request.industry_name,
timezone = self.request.timezone,
).build()
If this branch is not reached (unknown type), get_content() returns None → processor returns "Alert type not implemented" and stops.
Step 4 — (Optional) Add an email HTML template
File: app/templates/alert/my_alert.html
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; font-size: 13px; }
.box { border-left: 4px solid #e53e3e; padding: 12px; background: #fff5f5; }
</style>
</head>
<body>
<h2>{{ subject }}</h2>
<div class="box">
<p>{{ industry_name }} — {{ unit_name }}</p>
<p>Value: {{ value }} / Threshold: {{ threshold }}</p>
<p>{{ body }}</p>
</div>
</body>
</html>
If no custom template exists, the email channel falls back to alert/default.html.
Step 5 — Test
POST /api/user/alerts
Authorization: Bearer <access_token>
Content-Type: application/json
{
"type": "threshold",
"unitId": "U001",
"createdOn": "2025-07-23T10:30:00Z",
"meta": {
"alertType": "my_alert",
"currentValue": 1600,
"threshold": 1500
},
"recipients": [{ "userId": "user-abc" }]
}
- Correct
alertType→ channels fire,successlist non-empty - Unknown
alertType→"Alert type not implemented", no channels fire - Missing
recipients→200,success: [],failed: [] - Email received with correct subject and template rendering