Telegram Bot

The NIVAA Telegram bot (@NIVAAMainBot) provides real-time session management, daily reminders, check-in/out, and coordinator tools. It connects to the same D1 database as the web platform via webhook.

Bot Architecture

The bot runs as a webhook handler inside the Cloudflare Worker. Telegram sends updates to /telegram/webhook, and the Worker processes commands and callback queries synchronously.

Account Linking

Telegram accounts are linked to NIVAA users via deep links. Each user gets a unique link that associates their Telegram chat ID with their NIVAA user ID and role.

How Deep Links Work

The deep link format is:

Deep Link Format
https://t.me/NIVAAMainBot?start=link_ROLE_ID

Examples:
https://t.me/NIVAAMainBot?start=link_TUTOR_1052
https://t.me/NIVAAMainBot?start=link_ADMIN_20

When a user clicks this link, Telegram opens a chat with the bot and sends /start link_ROLE_ID. The bot then:

  1. 1 Parses the role and user ID from the deep link payload.
  2. 2 Verifies the user exists in the users table.
  3. 3 Creates or updates a record in telegram_links, mapping the Telegram chat ID to the NIVAA user.
  4. 4 Responds with a confirmation message including the user's display name and role.

Auto-generated Links

When coordinators add new users via /admin/people, the system automatically generates the Telegram deep link. This link is displayed on the user profile and can be shared directly.

Tutor Commands

Tutors have access to the following commands after linking their account:

CommandDescriptionDetail
/sessionsToday's sessionsShows all sessions for today with check-in/out status, student names, addresses (with Google Maps links), and inline buttons for check-in, check-out, and session changes.
/upcomingNext 7 daysLists all scheduled sessions for the next week, grouped by date.
/checkinCheck inChecks into the next unchecked session today. Respects the 30-minute-before-start time window. Also available as an inline button on <code>/sessions</code>.
/checkoutCheck outChecks out of the currently active session. Available from 30 minutes before scheduled end until 24 hours after. Transitions status to <code>Awaiting_Approval_Parent</code> and prompts for session notes.
/todosDaily to-do listShows pending items: sessions to attend, notes to upload, admin tasks.
/mystudentsActive matchesLists all students the tutor is currently matched with, including subjects and areas.
/postingsBrowse postingsShows open postings the tutor can apply to, with subject, location, and schedule details.
/notesSubmit session notesAllows the tutor to send text, photos, documents, or voice messages as session notes. Files are downloaded from Telegram and stored in R2 (max 10MB per file).
/mypayBilling summaryShows the current month's session count, hours worked, and sessions pending parent approval.
/helpCommand listDisplays all available commands for the user's role.

Coordinator Commands

Coordinators (Admin role) have an expanded command set:

CommandDescriptionDetail
/dashboardSystem KPIsPlatform-wide metrics: students, educators, today's sessions, open postings, open tickets, disputes.
/sessionsAll sessions todayLists all sessions across all tutors for the current day, showing tutor names, student names, and check-in status. Limited to 20 results.
/alertsOpen ticketsLists open support tickets (status Open or In_Progress), showing category and subject.
/pendingSessions awaiting approvalLists all sessions in <code>Awaiting_Approval_Parent</code> status that need parent confirmation.
/postingsqueuePosting pipelineSummary of the posting funnel: open postings, applications received, pending coordinator review.
/student <name|id>Student lookupFuzzy search by name or exact lookup by ID. Returns child profile, parent info, and active matches.
/tutor <name|id>Tutor lookupFuzzy search by name or exact lookup by ID. Returns tutor profile, active matches, and session stats.
/lowpackagesLow balance parentsLists parents whose session packages are below 20% remaining.
/newappsRecent applicationsShows the most recent posting applications that need coordinator review.
/impersonateView as tutorWithout arguments: shows a list of tutors with inline buttons. With ID: <code>/impersonate 42</code> sets impersonation. While impersonating, tutor commands (<code>/sessions</code>, <code>/todos</code>, <code>/upcoming</code>) show that tutor's data.
/stopimpersonateReturn to coordinator viewClears the impersonation flag and returns to the coordinator's own view.

Session Change / Cancel Flow

Tutors can cancel or reschedule sessions directly from Telegram. The flow includes a mandatory parent acknowledgement step and automatic coordinator notification.

Cancel Flow

Cancel Flow
Tutor taps "Change" on a session
Yes
Tutor taps "Cancel" and confirms
Yes
Has the parent acknowledged?

Reschedule Flow

Reschedule Flow
Tutor taps "Reschedule"
Yes
Tutor selects reason (Schedule conflict / Student unavailable / Other)
Yes
Has the parent acknowledged?

Callback Data Encoding

Telegram inline buttons use callback data strings to encode the action and context. The encoding scheme:

Callback Data
Check in to appointment
Check out of appointment
Open change menu for session
Initiate cancellation
Confirm cancellation
Parent acknowledged cancel
Parent NOT acknowledged cancel
Open reschedule reason picker
Select reschedule reason N
Parent acknowledged reschedule (reason N)
Parent NOT acknowledged reschedule
Set impersonation to tutor
chg_ID → cnl_ID
chg_ID → rsc_ID
cnl_ID → cnl_c_ID
cnl_c_ID → cnl_y_ID
cnl_c_ID → cnl_n_ID
rsc_ID → rsc_rN_ID
rsc_rN_ID → rsc_yN_ID
rsc_rN_ID → rsc_nN_ID

Cron Reminders

Daily 7am SGT Digest

Every morning at 7:00 AM SGT, each linked tutor receives a digest message containing:

  • Greeting with display name
  • Today's session count and schedule (times, student names, addresses with Google Maps links)
  • Count of pending session notes that need uploading

Pre-session 1-hour Reminders

Approximately 1 hour before each session, the tutor receives a reminder with:

  • Session time and student name
  • Address with Google Maps link
  • "Check In Now" inline button (if the 30-minute check-in window is already open)

The cron runs every 15 minutes and catches sessions starting in the 45-75 minute window to account for the cron interval.

Deduplication

Both reminder types are deduplicated via the telegram_reminder_log table. The daily digest deduplicates based on chat_id + reminder_type='daily_7am' with a 20-hour lookback. Pre-session reminders deduplicate on chat_id + reminder_type='pre_session_1hr' + appointment_id.

Database Tables

telegram_links

ColumnTypeDescription
idINTEGER PKAuto-increment ID
user_idINTEGERFK to users.id
chat_idTEXT UNIQUETelegram chat ID (unique constraint prevents duplicate links)
roleTEXTTutor | Admin
impersonating_tutor_idINTEGER NULLIf set, coordinator is viewing bot as this tutor (migration 0022)
linked_atDATETIMEWhen the link was created/updated

telegram_reminder_log

ColumnTypeDescription
idINTEGER PKAuto-increment ID
chat_idTEXTTelegram chat ID of recipient
reminder_typeTEXTdaily_7am | pre_session_1hr
appointment_idINTEGER NULLNULL for daily digest, set for pre-session reminders
sent_atDATETIMEWhen the reminder was sent (used for dedup lookback)

cancellation_requests

ColumnTypeDescription
idINTEGER PKAuto-increment ID
appointment_idINTEGERFK to appointments.id
tutor_user_idINTEGERFK to users.id
parent_acknowledgedBOOLEANWhether parent was informed before cancellation
coordinator_notifiedBOOLEANWhether coordinators were notified

reschedule_requests

ColumnTypeDescription
idINTEGER PKAuto-increment ID
appointment_idINTEGERFK to appointments.id
proposed_byTEXTTutor | Parent | Admin
proposed_by_user_idINTEGERFK to users.id
new_dateTEXTProposed new date (initially same as original, updated by coordinator)
new_start_timeTEXTProposed new start time
new_end_timeTEXTProposed new end time
statusTEXTProposed | Accepted | Rejected
reasonTEXTSchedule conflict / Student unavailable / Other
source_channelTEXTtelegram | web
parent_acknowledgedBOOLEANWhether parent was informed

Sub-pages