Tasks

Auto-resolve

← Back to Tasks

Auto-resolve is how most tasks complete themselves. A task with an auto-complete checklist item carries a scheduled fire time and a list of conditions; at fire time, the cron evaluates the conditions and — if all are met — runs the task's action and marks it done. If any condition is not met, the operator can optionally be notified.

Task card expanded — auto-resolve controls

The data model

An auto-resolve task has at least one checklist item like this:

{
  "label": "[Auto-complete] Complete at 19:00 (when 1 condition met)",
  "automaticType": "scheduled_time",
  "automaticConfig": {
    "time": "19:00",
    "conditions": [
      {
        "property": "messageThread.hasUnansweredGuestMessage",
        "operator": "equals",
        "value": "false",
        "notifyOnNotMet": true
      }
    ]
  }
}
  • time — the wall-clock time the cron evaluates this item (in the tenant's local timezone).
  • conditions — boolean checks against the reservation + guest + message state.
  • notifyOnNotMet — if true, when fire time arrives and the condition fails, the operator gets a WhatsApp ping.

How the cron evaluates

Two cron jobs in cronJobs.ts:

  • morningCron (06:00 CET)
  • afternoonCron (15:00 CET)

…both call dailyTaskSeeder, which:

  1. Iterates every reservation in the ±1 day window from today.
  2. For each task template that fires on check-in / check-out / after_checkout, re-evaluates whether a task should exist for that reservation.
  3. If yes and no live task exists yet → seed one.
  4. For existing auto-resolve tasks whose scheduled time falls in the window → evaluate conditions, fire or skip.

The ±1 day window is documented in server/services/reservationEventFiring.ts.

Common conditions

  • reservation.nukiAccessCode is_not_null — Send Check-in precondition (PIN exists).
  • messageThread.hasUnansweredGuestMessage equals false — pre-checkout reminder precondition (guest's last message was answered).
  • task.dependencies.allDone equals true — fire only after dependent tasks complete.
  • reservation.guestMood notIn ['angry', 'disputed'] — thank-you message precondition.
  • reservation.checkoutTime is_not_null — for time-relative tasks.

The full property catalogue lives in platformCapabilities.ts and is autodiscovered into the task template editor condition picker.

Why a task gets blocked

When fire time arrives and a condition is false, the cron:

  1. Logs the failure to app_errors.
  2. If notifyOnNotMet: true, sends the operator a WhatsApp message naming the task, reservation, and failing condition.
  3. Leaves the task in scheduled status (next morning cron will re-evaluate).

Example operator-facing message:

Task 216874 (Castle&River Luxe-Vydrica) Auto-resolve was BLOCKED because the condition is not met: reservation.nukiAccessCode is_not_null. Please resolve this task manually.

What to do — see Send Check-in for the classic case.

Skipped actions are never silent

When an action internally bails out (e.g. WhatsApp sendReply skipped because the guest opted out):

  • Auto-resolve runs the action.
  • If the action returns skipped: true with a reason, the task moves to failed with that reason.
  • The reason appears in the Activity Log and on the task card.

The same applies to assign_cleaner — a skip because the cleaner was unassigned is visible, never silent.


What an operator should know

  • Every auto-resolve task has a schedule (when it'll fire) and conditions (what must be true for it to fire).
  • You can see both on the task card.
  • If a condition is currently failing, you have until the fire time to fix it — usually by replying to the guest or generating the missing PIN.
  • If you miss the window, the operator-notification will arrive at fire time and you'll have to manually trigger.
Source: the luxury.host operator manual.