Field Triggers
Expiry monitoring, notifications, task creation, and automated actions based on date fields.
Field Triggers
Field triggers enable declarative expiry notifications based on date fields. When a date field approaches a configured threshold, the system can create tasks for follow-up or send notifications directly.
Basic Syntax
Field triggers are defined within model files:
trigger FieldName {
intervals: [90d, 60d, 30d, 7d]
condition: [Status == "Active"]
task {
assign-to: "role:RoleName"
subject: "Review {Name} expiry"
}
notification {
channel: email
template: "template-name"
to: "{ContactEmail}"
cc: "{Manager.Email}"
}
}
Trigger Attributes
| Attribute | Description | Example |
|---|---|---|
intervals |
Array of time periods before date | [90d, 60d, 30d, 7d] |
condition |
Optional filter expression | [Status == "Active"] |
Interval Syntax:
Nd— N days before (e.g.,90d,30d,7d)Nh— N hours before (e.g.,24h,48h)
Task Block
When a task block is present, the system creates a Task record at each interval instead of sending notifications directly. Notifications are sent when the task is marked complete.
task {
assign-to: "role:ComplianceOfficer"
subject: "TRN Expiry Review: {Name} ({Number})"
}
| Attribute | Description | Example |
|---|---|---|
assign-to |
Role or user to assign | "role:ComplianceOfficer" |
subject |
Task title with merge tags | "Review: {Name}" |
Assignment Patterns:
role:RoleName— Assign to users with the specified roleuser:{FieldPath}— Assign to user from a field (e.g.,user:{Supervisor.Key})
Notification Block
Defines how notifications are sent:
notification {
channel: email
template: "trn-expiry-reminder"
to: "{ContactEmail}"
cc: "{Supervisor.Email}"
}
| Attribute | Description | Example |
|---|---|---|
channel |
Delivery channel | email, sms, push |
template |
Messy template name | "trn-expiry-reminder" |
to |
Primary recipient(s) | "{Email}" |
cc |
CC recipients (optional) | "{Manager.Email}" |
Behavior Modes
Task Mode (when task block exists):
- Creates a Task at each interval
- Task is linked to source record via the
Whatpolymorphic field - When task is marked complete → sends notification and logs activity
Direct Mode (when only notification block exists):
- Sends notification directly at each interval
- Logs activity for each notification sent
Condition Syntax
The condition attribute supports filter expressions:
| Operator | Example |
|---|---|
| Comparison | [Amount > 1000], [Status == "Active"] |
| AND/OR | [Status == "Active" AND Amount > 0] |
| IN/NOT IN | [Status IN ("Active", "Pending")] |
| IS NULL | [ExpiryDate IS NOT NULL] |
| Nested | [(Status == "Active" OR Priority == "High") AND Amount > 0] |
Complete Examples
Example 1: TRN Expiry with Task Creation
@object Supplier
@application Procurement
field TRNExpiryDate type:Date label:"TRN Expiry Date" optional:true
trigger TRNExpiryDate {
intervals: [90d, 60d, 30d, 7d]
condition: [Status == "Active"]
task {
assign-to: "role:ComplianceOfficer"
subject: "TRN Expiry Review: {Name} ({Number})"
}
notification {
channel: email
template: "trn-expiry-reminder"
to: "{ContactEmail}"
cc: "{Supervisor.Email}"
}
}
Example 2: Contract Expiry with Direct Notification
@object Contract
@application Leasing
field AgreementEndDate type:Date label:"Agreement End Date"
trigger AgreementEndDate {
intervals: [90d, 60d, 30d]
condition: [Status == "Active" AND ContractType IN ("Residential", "Commercial")]
notification {
channel: email
template: "contract-renewal-reminder"
to: "{Tenant.Email}"
}
}
Example 3: Insurance Expiry
@object Contract
@application Leasing
field InsuranceExpiryDate type:Date label:"Insurance Expiry"
trigger InsuranceExpiryDate {
intervals: [30d, 7d]
condition: [Status == "Active" AND InsuranceRequired == true]
notification {
channel: email
template: "insurance-expiry-notice"
to: "{Tenant.Email}"
cc: "{PropertyManager.Email}"
}
}
Example 4: License Expiry with Complex Condition
@object Employee
@application HR
field DrivingLicenseExpiry type:Date label:"Driving License Expiry" optional:true
trigger DrivingLicenseExpiry {
intervals: [60d, 30d, 7d]
condition: [Status == "Active" AND (Department == "Operations" OR JobTitle == "Driver")]
task {
assign-to: "role:HRManager"
subject: "License Renewal Required: {Name}"
}
notification {
channel: email
template: "license-expiry-reminder"
to: "{Email}"
}
}
Example 5: Passport Expiry with Multiple Notifications
@object Employee
@application HR
field PassportExpiry type:Date label:"Passport Expiry" optional:true
trigger PassportExpiry {
intervals: [180d, 90d, 60d, 30d, 7d]
condition: [Status == "Active"]
task {
assign-to: "role:HRAdmin"
subject: "Passport Renewal: {Name} - Expiring {PassportExpiry}"
}
notification {
channel: email
template: "passport-expiry-reminder"
to: "{Email}"
cc: "{Manager.Email}"
}
}
Merge Tags
Use merge tags in task subjects and notification templates:
| Tag | Description |
|---|---|
{FieldName} |
Value of any field on the record |
{Lookup.FieldName} |
Value from a related record |
{Name} |
Record name |
{Number} |
Record number |
{Key} |
Record key |
Background Processing
Field triggers are processed by a background job that runs hourly:
- Queries all schemas with field trigger configurations
- For each trigger, finds records where the date field falls within an interval window
- Evaluates conditions against each record
- Creates tasks or sends notifications as configured
- Tracks processed triggers to prevent duplicates
Deduplication
Each (ObjectName, FieldName, RecordId, IntervalKey) combination is tracked to prevent duplicate notifications for the same interval.
Best Practices
- Use appropriate intervals — Space intervals logically (e.g.,
[90d, 60d, 30d, 7d]) - Always include a condition — Filter to active/relevant records only
- Use task mode for action items — Create tasks when follow-up action is required
- Use direct mode for reminders — Send notifications for informational alerts
- Include merge tags in subjects — Use
{Name},{Number}for context - Assign to roles, not users — Prefer
role:RoleNameover hardcoded assignments - Set up notification templates — Ensure Messy templates exist before configuring
- Test with short intervals first — Use
[24h]during development