Skip to main content

Rule Engine

What the rules are for​

By default, every appointmentAppointmentA task scheduled to a resource for a specific period - the scheduled instance you see on the planning board. assigned to a resourceResourceAn entity that can carry out work - a person, vehicle, tool, or room - that you schedule on the planning board. with the Exchange integration enabled ends up in that person's Outlook calendar. That is usually too much. A placeholder the planner parked on the board, an appointment that is still "to be confirmed", or an absence that has not been approved yet adds nothing to a calendar and may even mislead the person reading it.

The rule engine is the filter that sits between the planning boardPlanning boardThe main graphical scheduling surface where dispatchers drag tasks onto resources across a timeline. and Exchange. Each rule is a test on the appointment: its subject, its categoryCategoryA visual indicator (a color) applied to appointments to classify or label them., its time markerTime markerA visual indicator on an appointment, separate from its category, used to flag a status or condition at a point in time., the taskTaskA unit of work that belongs to a job. It appears in the open task list until it is scheduled to a resource. behind it, the jobJobA high-level container, comparable to a project, that bundles related tasks together with common information such as customer, billing, and address. behind that task. When an appointment is about to be synchronized, every rule runs against it. An appointment that passes all of them is sent to Exchange; an appointment that fails even one is held back, and the Error message you wrote for that rule is what identifies which test it failed. That is why it pays to keep rules small and well named: one rule per concern makes it obvious why a given appointment never showed up in Outlook.

Rules are stored in Dime.Scheduler and managed on the Rules page at https://app.dimescheduler.com/exchangerules. The page is only available with an Exchange license. A change takes effect as soon as it is saved; nothing needs to be restarted.

Example​

The simplified example below shows how this works. Two conditions must both pass before an appointment is sent to Exchange:

  • The category name (the background of the appointment in the planning board) must be "SERVICE" and a free boolean fieldFree fieldOne of the unmapped fields on jobs, tasks and appointments that a back office can fill with its own data, each with a localizable caption. on the task must be true.
  • The time marker name (the line below the subject of the appointment in the planning board) must be "IN PROCESS" and that same free boolean field must be true.

Suppose the planner schedules the four appointments below. Edit any of them - change the category, the time marker, or the sync flag - and watch which ones the rules let through to Outlook:

Sync rule - both conditions must pass
Category = SERVICE and sync flag onTime marker = IN PROCESS and sync flag on
Appointment #1Synced
Category
Time marker
category ruletime marker rule
Appointment #2Blocked
Category
Time marker
category ruletime marker rule
Appointment #3Blocked
Category
Time marker
category ruletime marker rule
Appointment #4Blocked
Category
Time marker
category ruletime marker rule
Outlook calendar
Appointment #1
1 of 4 reach Outlook

Out of the box, only appointment #1 is sent to Exchange, because it is the only one that meets both requirements: the category name is "SERVICE", the time marker name is "IN PROCESS", and the free boolean field is true.

The Rules page​

The page has two parts. The sidebar on the left lists the rule sets you have saved; the area on the right is where you build the one that is selected.

Managing rule sets​

The sidebar sorts rule sets by name. The arrow button flips the order between A-Z and Z-A. The plus button starts a new, unsaved draft: it appears in italics at the bottom of the list and can be thrown away with its Cancel cross before it is ever saved. Only one draft can exist at a time, so the plus button is disabled while a draft is open.

Clicking a rule set opens it on the right. Hovering a row reveals a Delete icon for that single rule set. To remove several at once, hold Shift and click a row: the list switches to selection mode with a checkbox in front of every row, a header checkbox that selects or deselects all of them, a counter, a Delete button for the whole selection and a Cancel cross to leave selection mode. Every delete, single or bulk, asks Are you sure? before anything is removed.

Building a rule set​

The toolbar above the builder holds the rule set's Name, a Save button (Ctrl+S does the same), and a toggle between Builder and JSON Output. As soon as you change anything, an Unsaved changes marker appears next to the buttons and stays until you save or switch to another rule set.

A rule set contains one or more rules, each shown as a card. A rule has a Name, an Error message and a list of conditions. Add rule appends an empty card; the trash icon on a card removes it. The code icon on a card, View expression, shows the expression the conditions compile to, which is handy when you want to check that the builder understood you.

Each condition is one line: a property, an operator and a value. Add filter adds a line. The first line reads Where; every following line starts with AND or OR, which is how conditions are chained. The property picker opens a searchable tree grouped under Appointment, Task and Job; type a few letters to filter it. The panel on the right of the builder shows the same tree with a type badge per property, and a property can be dragged from that panel straight onto a rule card to add a condition for it.

The operators on offer depend on the type of the property you picked:

  • Every type: equal, not equal, is null, is not null
  • Text: contains, begins with, ends with
  • Numbers and dates: greater, less, greater or equal, less or equal

The value field follows the type as well: a true/false choice for booleans, a number field, a date picker, or plain text. Picking is null or is not null hides the value field. Navigation properties such as Category, Time Marker, Task or Job can be selected on their own, in which case the only meaningful tests are is null and is not null: "the appointment has no task", for instance.

Missing data​

Appointments do not always have a time marker, a category or a linked task. The builder takes care of that for you. A condition on appointment.Task.Job.JobNo is compiled with the guards appointment.Task != null AND appointment.Task.Job != null in front of it, so a missing task fails the condition cleanly instead of erroring. is null on a nested property matches when any step along the path is missing, and is not null requires every step to be present.

Validation​

Save refuses the rule set and marks the offending fields in red when:

  • the rule set has no Name;
  • the rule set has no rules at all (the page says Add at least one rule before saving.);
  • a rule has no Name or no conditions;
  • a condition has no property or, unless it is a null check, no value.

The server checks the same things again and, in addition, caps a rule set at 100 rules, a rule at 50 conditions, names at 200 characters, error messages at 500 and values at 1,000.

JSON Output​

The JSON Output view shows what is actually stored: the rule set's Name and a Rules array where each rule carries its Name, ErrorMessage, the compiled Expression and the structured Conditions that produced it. Copy puts it on the clipboard. This is read-only; the server rebuilds the Expression from the Conditions on every save, so the conditions are the source of truth and the expression can never be edited into something the builder did not produce.

Expressions​

The expression a rule compiles to reads like the body of a filter function. appointment is the root of the graph; from there you reach the appointment's own properties and, through appointment.Task and appointment.Task.Job, the task and job data behind it. A few representative properties:

  • appointment.Subject, appointment.Body, appointment.StartDate, appointment.EndDate
  • appointment.Category.Name, appointment.TimeMarker.Name
  • appointment.Task.TaskNo, appointment.Task.Status, appointment.Task.FreeText1, appointment.Task.FreeBit1
  • appointment.Task.Job.JobNo

Comparisons use ==, !=, <, <=, >, >=; the string tests become .Contains("..."), .StartsWith("...") and .EndsWith("..."); conditions are joined with AND and OR; missing values are compared with null. A few rule sets written out in that form:

  • Do not sync appointments marked "TO BE CONFIRMED", while appointments without a time marker still go through: appointment.TimeMarker == null OR appointment.TimeMarker.Name != "TO BE CONFIRMED"
  • Only sync appointments linked to a task: appointment.Task != null
  • Sync everything except absences that are not confirmed yet: appointment.Task == null OR (appointment.Task.Job != null AND appointment.Task.Job.JobNo == "ABSENCES" AND (appointment.TimeMarker == null OR appointment.TimeMarker.Name != "TO BE CONFIRMED"))

The builder produces the first two directly. The third mixes AND and OR with parentheses, which the builder's flat list of conditions cannot express; split it into separate rules instead, one per concern, which is also easier to read back when an appointment is held.