Automated Compliance Expiry Alerts & Tenancy Notifications
Automated Compliance Expiry Alerts & Tenancy Notifications
As of v0.3.13, the platform automatically monitors compliance certificate expiry dates and upcoming tenancy end dates, delivering proactive alerts to agents via in-app notifications and email — with no manual configuration required.
Compliance Expiry Alerts
How It Works
A daily scheduled job (compliance-expiry-scan) runs at 6 AM UTC and checks every property in the system for certificates that are expiring or have already expired.
Certificates Monitored
| Certificate | Sources Checked |
|---|---|
| Gas Safety Certificate | properties.gas_safety_expiry and compliance_documents table |
| Energy Performance Certificate (EPC) | properties.epc_expiry and compliance_documents table |
| Electrical Installation Condition Report (EICR) | properties.eicr_expiry and compliance_documents table |
For documents in the compliance_documents table, the scan uses the latest version of each document type per property.
Alert Windows
Three alert types are generated depending on how far a certificate is from its expiry date:
| Alert Type | Condition | Email Style |
|---|---|---|
| 30-Day Warning | Expires within 30 days | Amber |
| Expired | Expired today (±1 day) | Red |
| Post-Expired / Overdue | Expired more than 1 day ago | Red |
Who Gets Notified
Alerts are targeted based on property assignment:
- Assigned properties: Notification is sent to the agent set as
managed_by_user_idon the property. - Unassigned properties: Notification is sent to all members of the organisation.
Notification Channels
Each alert is delivered through two channels:
- In-app notification — Appears in the shell notification panel (bell icon).
- Email alert — Styled with urgency-appropriate colours (amber for warnings, red for expired/overdue).
Email alerts include:
- Document type and property address
- Expiry date
- Days remaining (warning) or days overdue (post-expired)
- Direct link to the Portfolio Dashboard
Deduplication
A compliance_expiry_alerts database table ensures each unique combination of organisation, source record, and alert type is only sent once. Subsequent daily runs skip alerts that have already been dispatched.
Tenancy Expiry → Renewals Pipeline
How It Works
A separate daily job (tenancy-expiry-alert-scan) runs at 6 AM UTC and scans for tenancies approaching their end date.
Alert Windows
| Window | Action |
|---|---|
| 90 days before expiry | Creates a renewal record with decision_required status |
| 7 days before expiry | Creates an urgent renewal record with decision_required status |
Where to See These
Renewal records created by this scan appear in the Renewals Pipeline > Decision Required queue. Agents are prompted to decide on renewals well in advance of tenancy end dates.
Portfolio Dashboard
The Portfolio Dashboard's Expired Compliance tab is dynamically visible — it only appears when there are properties with expired compliance certificates. The daily scan drives awareness by surfacing these records, prompting agents to open the tab and take action.
Technical Reference
Inngest Functions
| Function ID | Type | Schedule | Concurrency |
|---|---|---|---|
compliance-expiry-scan | Cron | Daily 6 AM UTC | limit: 1 (fn scope) |
compliance-expiry-notify | Event-triggered (fan-out) | On demand | key: orgId |
tenancy-expiry-alert-scan | Cron | Daily 6 AM UTC | limit: 1 (fn scope) |
Database Table: compliance_expiry_alerts
| Column | Type | Description |
|---|---|---|
id | text (UUID) | Primary key |
org_id | text | Organisation ID |
source | text | Source type: compliance_document, property_gas_safety, property_epc, property_eicr |
source_id | text | ID of the source record |
property_id | text | Property ID |
alert_type | text | 30_day, expired, or post_expired |
document_type | text | Human-readable certificate type |
property_address | text | Property address for display |
expiry_date | timestamp | Certificate expiry date |
in_app_sent | boolean | Whether in-app notification was sent |
email_sent | boolean | Whether email was sent |
error_message | text | Error details if delivery failed |
created_at | timestamp | Record creation time |
A unique index on (org_id, source, source_id, alert_type) enforces deduplication at the database level.