Service Layer medium complexity backend
3
Dependencies
1
Dependents
2
Entities
0
Integrations

Description

Core service that coordinates the end-to-end certificate expiry notification flow. It receives expiry data from the scheduled edge function, determines which notification thresholds have been reached (60, 30, 7 days), and dispatches push notifications to the peer mentor and their coordinator via the shared FCM sender.

Feature: Certificate Expiry Notifications

expiry-notification-orchestrator

Summaries

The Certificate Expiry Notification Orchestrator is the core engine that ensures both peer mentors and their coordinators are proactively informed before a certification lapse occurs, rather than discovering the problem reactively after it has already disrupted program operations. By automating structured notifications at 60, 30, and 7-day thresholds, the organization dramatically reduces unplanned certification lapses and the scheduling disruptions they cause. Early multi-stage warnings give mentors sufficient runway to complete renewal without conflicts, maintaining roster availability and reducing the administrative burden on coordinators who would otherwise need to manually track expiry dates across their entire roster. This directly improves program continuity, reduces operational risk, and frees coordinator time for higher-value activities.

This medium-complexity backend service is central to the certificate expiry feature and must be delivered before the in-app notification banner and detail view can be fully tested end-to-end with real data. It depends on three services — certification-expiry-repository, notification-record-repository, and fcm-push-notification-sender — all of which must be available or properly mocked for integration testing. The duplicate-notification prevention logic (`hasNotificationBeenSent()` and `markThresholdNotified()`) carries high delivery risk: notification spam is a visible failure mode with direct negative user impact and must be covered by dedicated integration tests. Coordinate with the infrastructure team to confirm the scheduled edge function trigger is stable and reliable before end-to-end testing begins, as the orchestrator is invoked by that trigger and cannot be tested in isolation from it.

Core orchestration service invoked by the scheduled edge function, with `processUpcomingExpirations(expirations: List)` as its primary entry point. For each expiry record, `evaluateThreshold(expiryDate: DateTime) -> NotificationThreshold?` determines which of the 60/30/7-day thresholds applies, returning null when no threshold is reached. `hasNotificationBeenSent(mentorId, threshold) -> bool` queries notification-record-repository to guard against duplicate dispatches for the same mentor-threshold pair before any outbound action is taken. `dispatchExpiryNotification()` coordinates a dual write: a push notification via fcm-push-notification-sender and a persistent in-app notification record via notification-record-repository for banner display.

`markThresholdNotified()` writes the sent state atomically after successful dispatch. Depends on certification-expiry-repository for expiry data and peer_mentor_profile for coordinator ID resolution. Threshold evaluation and deduplication logic carry the highest unit test surface area. Backend execution context only.

Responsibilities

  • Evaluate upcoming expiration dates against 60/30/7 day thresholds
  • Dispatch push notifications to peer mentor and coordinator
  • Create in-app notification records for persistent banner display
  • Prevent duplicate notifications for the same threshold

Interfaces

processUpcomingExpirations(expirations: List<ExpiryRecord>)
evaluateThreshold(expiryDate: DateTime) -> NotificationThreshold?
dispatchExpiryNotification(mentorId: String, coordinatorId: String, threshold: NotificationThreshold)
hasNotificationBeenSent(mentorId: String, threshold: NotificationThreshold) -> bool
markThresholdNotified(mentorId: String, threshold: NotificationThreshold)

Related Data Entities (2)

Data entities managed by this component

API Contract

View full contract →
REST /api/v1/expiry-orchestration 5 endpoints
GET /api/v1/expiry-orchestration
GET /api/v1/expiry-orchestration/:run_id
POST /api/v1/expiry-orchestration
PUT /api/v1/expiry-orchestration/:run_id
DELETE /api/v1/expiry-orchestration/:run_id