Reminder Evaluation Service
Component Detail
Description
Encapsulates the business logic for determining whether an assignment is overdue for a reminder or escalation. Computes the difference between the current date and the assignment's last_contact_date and compares against the organisation's configured thresholds.
reminder-evaluation-service
Summaries
The Reminder Evaluation Service is the decision-making core of the programme's follow-up system. It determines, for every open assignment, whether action is needed — and what kind. By codifying the organisation's configurable thresholds into a reliable, testable business rule engine, it ensures that engagement gaps are caught consistently, regardless of coordinator availability or manual oversight. This directly reduces the risk of students receiving inadequate support due to human error or workload pressure.
The service also enables the platform to offer differentiated service tiers to organisations with varying compliance requirements, since threshold logic is organisation-aware and fully configurable.
A medium-complexity backend service with two dependencies: `assignment-contact-tracking-repository` and `reminder-config-repository`. Because this component encapsulates the core business logic for reminder and escalation decisions, it is the highest-priority unit to get right and the most important to unit test thoroughly. Delivery planning should allocate time for edge case coverage: assignments with no contact ever recorded, assignments at exactly the threshold boundary, and organisations with non-standard threshold configurations. This service should be developed and tested before the scheduler service, as the scheduler delegates evaluation decisions entirely to it.
Clear documentation of the `EvaluationResult` type contract is important for smooth integration with downstream consumers.
The service exposes a pure, side-effect-free `evaluate(assignment, orgSettings): EvaluationResult` entry point, making it straightforward to unit test. `daysSinceLastContact(lastContactDate)` computes the integer day difference between now and `last_contact_date`, handling the null/undefined case (no contact ever recorded) by returning a sentinel value or throwing a typed error — this edge case must be explicitly handled in the evaluation logic. `isReminderDue` and `isEscalationDue` are boolean predicates that can be tested in complete isolation. `isEscalationDue` additionally considers `lastReminderSentAt` to ensure escalation is only triggered after a reminder has already been dispatched.
The `EvaluationResult` discriminated union (`action: 'none' | 'remind' | 'escalate'`) provides a clean contract for the scheduler to switch on. Avoid embedding date arithmetic directly in the scheduler — all threshold logic must live here for testability and single-responsibility compliance.
Responsibilities
- Calculate days since last recorded contact for an assignment
- Compare elapsed days against org reminder threshold
- Compare elapsed days against org escalation threshold
- Return evaluation result with recommended action (none, remind, escalate)
- Handle edge cases such as no contact ever recorded
Interfaces
evaluate(assignment, orgSettings): EvaluationResult
daysSinceLastContact(lastContactDate): number
isReminderDue(daysSince, reminderThreshold): boolean
isEscalationDue(daysSince, escalationThreshold, lastReminderSentAt): boolean
EvaluationResult: {action: 'none'|'remind'|'escalate', daysSince: number}
Relationships
Dependencies (2)
Components this component depends on