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 role
  • user:{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):

  1. Creates a Task at each interval
  2. Task is linked to source record via the What polymorphic field
  3. When task is marked complete → sends notification and logs activity

Direct Mode (when only notification block exists):

  1. Sends notification directly at each interval
  2. 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:

  1. Queries all schemas with field trigger configurations
  2. For each trigger, finds records where the date field falls within an interval window
  3. Evaluates conditions against each record
  4. Creates tasks or sends notifications as configured
  5. 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

  1. Use appropriate intervals — Space intervals logically (e.g., [90d, 60d, 30d, 7d])
  2. Always include a condition — Filter to active/relevant records only
  3. Use task mode for action items — Create tasks when follow-up action is required
  4. Use direct mode for reminders — Send notifications for informational alerts
  5. Include merge tags in subjects — Use {Name}, {Number} for context
  6. Assign to roles, not users — Prefer role:RoleName over hardcoded assignments
  7. Set up notification templates — Ensure Messy templates exist before configuring
  8. Test with short intervals first — Use [24h] during development

Experience the Platform

See how P9 and the Tuli platform work together

Ready to Build with P9?

Get hands-on with the platform. See how P9 accelerates your development workflow and integrates seamlessly with your existing systems.