Reminders & Cron

The NIVAA Telegram bot sends automated reminders to educators via Cloudflare Cron Triggers. There are two reminder types: a daily morning digest and pre-session alerts.

Daily 7am SGT Digest

Every morning at 7:00 AM Singapore Time (SGT, UTC+8), each linked educator receives a personalized digest message.

Message Contents

  • Personalized greeting with the tutor's display name
  • Today's session count
  • For each session: time range, student name, and address with a Google Maps link
  • Count of session notes pending upload (sessions where the tutor has checked out but not yet submitted notes)
  • If no sessions are scheduled, the message says so
Example Daily Digest
Good morning, Alex!

2 sessions today:
  - 09:00-10:00 - Emily Chen
    Open in Maps
  - 14:00-15:00 - James Tan
    Open in Maps

1 session note pending upload.
Have a great day!

Implementation Details

  • Only tutors with linked Telegram accounts receive the digest
  • The SGT date is computed as Date.now() + 8 * 3600000 (UTC offset)
  • Sessions with status Disputed or Cancelled_By_Tutor are excluded
  • Address is parsed from the child profile's address_data JSON field

Pre-session 1-hour Reminders

Approximately 1 hour before each session, the assigned tutor receives a targeted reminder.

Message Contents

  • Session date and time
  • Student name
  • Address and Google Maps link
  • "Check In Now" inline button (if the 30-minute check-in window is already open)
  • Note about when check-in opens (30 mins before start)
Example Pre-session Reminder
Session in ~1 hour!

2026-03-27 at 14:00-15:00
James Tan
123 Orchard Road, Singapore 238888
Open in Google Maps

Check-in opens 30 mins before start.

[Check In Now]

Timing Logic

The cron job runs every 15 minutes. To avoid missing sessions, it looks for sessions starting in the 45-75 minute window from the current time. This ensures each session is caught exactly once within the 15-minute cron interval.

Pre-session Reminder Window
> 75 min before
Skipped (too early, next cron will catch it)
45-75 min before
Reminder sent
< 45 min before
Skipped (already sent or too late)

Deduplication

Both reminder types use the telegram_reminder_log table to prevent duplicate sends. This is essential because cron jobs may overlap or retry.

Reminder TypeDedup KeyLookback Window
daily_7amchat_id + reminder_type20 hours (ensures one per day even with timezone edge cases)
pre_session_1hrchat_id + reminder_type + appointment_idNo lookback window (exact match, one per appointment)

The daily digest uses INSERT OR IGNORE and checks for existing records within the past 20 hours. Pre-session reminders check for any existing record with the same chat_id and appointment_id, regardless of timing.

Error Handling

If sending a message fails (e.g., the user has blocked the bot or Telegram is unavailable), the error is logged to the console but does not prevent other reminders from being sent. Each reminder is sent independently in a loop.

Cron Schedule

TriggerScheduleFunction
Daily digest0 23 * * * (23:00 UTC = 07:00 SGT)sendDailyReminders(env)
Pre-session*/15 * * * * (every 15 minutes)sendPreSessionReminders(env)