Alerts
Onelo opens an incident when a feature's error rate spikes above its alert rule. Configure email recipients per app and tune thresholds per feature.
Auto-rule per feature
The first time the SDK reports an event for a new featureName, a row is created in monitor_alert_rules with a sensible default. You never have to provision rules manually.
| Field | Default | Notes |
|---|---|---|
| error_threshold | 0.10 | Fraction; 0.10 = 10% errors over the window. The auto-rule trigger sets 0.10 (the raw column default is 0.05). |
| window_mins | 15 | Sliding window in minutes. |
| enabled | true | Set to false to silence alerts for this feature without deleting the rule. |
Source: supabase/migrations/20260426000002_monitor_alert_rules_auto.sql.
Configure thresholds
Open the dashboard → Monitor → click a feature row → Configure alert. Edit error_threshold and window_mins, or flip enabled to false to disable alerts entirely for that feature. Changes apply on the next evaluation tick.
Email config (per app)
Recipients and templates live in the monitor_alert_config table — one row per app. Set them with PUT /api/monitor/alert-config: that endpoint is the only way to change them today. The dashboard shows the stored recipients beside the switches, but its switches only turn the alerts on and off. The PUT writes only the fields your request carries: anything you omit is left as it is, so the dashboard's on/off switches cannot overwrite the recipients or templates you configured here. The one exception is that turning an alert on while alertEmails is still empty stores the signed-in account's address, so the alert has somewhere to go.
| Field | Type | Description |
|---|---|---|
| alertEmails | string[] | List of recipient email addresses. |
| alertEnabled | bool | Master switch for outbound alert emails. |
| recoveryEnabled | bool | When true, send an “all clear” email once error rate drops back below threshold. |
| alertSubject | string | Templated subject — supports {{app_name}}, {{feature_name}}, {{error_rate}}, {{errors}}, {{total}}, {{window_mins}}, {{incident_number}}, {{last_error_block}}, {{affected_str}}, {{dashboard_url}}. |
| alertHtml | string | Templated HTML body — same variables as alertSubject. |
| recoverySubject | string | Templated subject for recovery email — supports {{app_name}}, {{feature_name}}, {{error_rate}}, {{incident_number}}, {{dashboard_url}}. |
| recoveryHtml | string | Templated HTML body for recovery email — same variables as recoverySubject. |
Include {{app_name}} in your subject and body — if you manage multiple Onelo apps, recipients need to know which one the alert is about. The dashboard surfaces a warning on the app's Notifications page if a custom template is missing this variable.
{
"appId": "b3c4d5e6-…",
"alertEmails": ["[email protected]", "[email protected]"],
"alertEnabled": true,
"recoveryEnabled": true,
"alertSubject": "[Onelo] {{app_name}} · {{feature_name}} error rate {{error_rate}}",
"alertHtml": "<p>{{app_name}} / {{feature_name}}<br/>Last error: {{last_error_block}}</p>"
}Incident lifecycle
When a rule fires, Onelo opens a row in monitor_incidents. Numbering is per-workspace — unique across all apps in your tenant — and assigned by the next_incident_number(p_app_id) RPC, so your workspace's first incident is INC-0001 (a second app continues the same sequence).
| Field | Description |
|---|---|
| peak_error_rate | Highest error rate observed during the incident. |
| last_error | Most recent error string sampled while the incident is open. |
| affected_users | Count of app sessions active in the alert window — an approximation of reach, not a distinct count of users who hit the error. |
| priority | low / medium / high. Defaults to high. Editable. |
| description | Free-form incident description, editable in the dashboard. |
| notes | Separate free-form operator notes, editable in the dashboard. |
| alert_sent | Boolean, informational. Set once the email send was attempted (or skipped by the daily cap). Duplicate emails are prevented by the one-open-incident-per-feature rule, not this flag. |
| status | open / resolved. |
backend/app/scheduler.py) closes an open incident once the error rate drops back below the threshold, and sends a recovery email when recovery_enabled is on. Auto-resolve needs success traffic in the window — silence alone never closes an incident, so an error-only feature stays open until you click Resolve. You can always resolve manually (PATCH /api/monitor/incidents/{id} with status='resolved').reopen_count increments, reopened_at is set, and it shows a ↻ badge. Resolving manually never blocks a future reopen.In-app notifications
The bell icon in the dashboard reads from monitor_notifications. Each new incident inserts a row; clicking the notification or marking it read clears the badge. Notifications are per-user and don't replace email — they're a quick visual cue while you're already in the dashboard.
Webhooks
For Slack / Discord / PagerDuty fan-out, the natural integration point is the Webhooks product.
incident.opened / incident.resolved / incident.reopened, emitted from scheduler.py). The outbound Webhooks product (Slack / Discord / PagerDuty fan-out) does not yet emit these — backend/app/webhooks.py ships auth, waitlist, feedback and payment events only. Until incident webhooks land, bridge incident emails into chat.