Skip to content

GSM / SMS Integration

DailyDesk utilizes a custom GSM Gateway (Skyline) to send SMS notifications for marketing campaigns, appointment reminders, and reviews. This integration handles high-volume messaging by interfacing directly with a hardware or virtual GSM gateway via HTTP.

Network Configuration

The GSM Gateway is an on-premise hardware appliance. To expose it to the internet securely without opening inbound ports, a CloudFlare Tunnel is used via a cloudflared daemon running on the internal network.

There are two distinct endpoints exposed:

1. Administration Dashboard

2. Backend API

  • Public URL: https://gsm.dailydesk.com/
  • Internal IP: 192.168.7.250
  • Usage: Used by the backend services to send SMS via HTTP requests.

Environment Variables & SSM Parameters

Secrets are managed in SSM Parameter Store and injected into the ECS containers.

SSM Path Pattern: /dailydesk/{stage}/{parameter}

Variable SSM Parameter Path ARN (us-east-1) Value
SMS_BASE_URL /gsm/base-url arn:aws:ssm:us-east-1:858695866949:parameter/dailydesk/{stage}/gsm/base-url https://gsm.dailydesk.com
SMS_USERNAME /gsm/username arn:aws:ssm:us-east-1:858695866949:parameter/dailydesk/{stage}/gsm/username root
SMS_PASSWORD /gsm/password arn:aws:ssm:us-east-1:858695866949:parameter/dailydesk/{stage}/gsm/password (Secret)
SMS_ENABLED /gsm/is-enabled arn:aws:ssm:us-east-1:858695866949:parameter/dailydesk/{stage}/gsm/is-enabled true

Replace {stage} with dev or production.

Infrastructure (CDK)

The CdkBackendStack manages the scheduling of SMS tasks using EventBridge Rules:

  • Review SMS: Triggers every 1 minute.
  • Confirmation SMS: Triggers every 30 minutes.
  • Campaign SMS: Triggers every 15 minutes.

These rules target the backend API endpoints (e.g., /crons/send-campaign) using an ApiDestination secured with an API Key.

Backend Implementation

Core Module: SmsGatewayModule

  • SmsGatewayService: The core service that abstracts the HTTP communication with the provider.
  • Method: sendSMS(params, body)
  • Payload: Constructs a payload containing the task list (phone numbers + message content) and a sr_url (Status Report URL) where the gateway should send delivery receipts.
  • Events: Emits ServerEvents.Logs upon success or failure for auditing.

  • SmsGatewayController: Exposes endpoints for the gateway to call back:

  • POST /sms-gateway/handle-serverless: The webhook endpoint that receives delivery status reports from the GSM gateway.

Application Logic

The SMS system is currently primarily triggered by Online Booking events and Cron Jobs. Manual actions performed by receptionists via the Scheduling Tab do not trigger SMS notifications in the current implementation.

For a business-process view of these flows (including the desired future state), please see SMS User Flows.

1. Current State Analysis

Event Online Booking Trigger Manual Trigger (Receptionist) SMS Sent? Note
Scheduled OnlineBookingService.createAppointment TicketsService.create YES (Online only) Manual bookings are silent.
Rescheduled OnlineBookingService.updateAppointment TicketsService.updateTicket YES (Online only) Manual changes are silent.
Canceled OnlineBookingService (Not Implemented) TicketsService.cancelTicket NO No SMS is sent for cancellations from any source.
Confirmed N/A N/A YES (Cron) "Reminders" are sent via Cron job 1-3 days prior.

2. Detailed Service Logic

A. Scheduled (New Appointment)

  • Technical Implementation: AppointmentNotificationService.sendSMSScheduledToCustomer exists but is only called by OnlineBookingService.

B. Rescheduled (Change Time/Date)

  • Technical Implementation: AppointmentNotificationService.sendSMSRescheduledToCustomer exists but is only called by OnlineBookingService.

C. Canceled

  • Technical Implementation: No method exists for cancellation SMS.

D. Reminders / Confirmations (Cron)

  • Trigger: Cron Job (cronSendSMSConfirmationToCustomer) running every 30 minutes.
  • Logic:
  • Finds appointments N days in the future (configurable per salon).
  • Checks if confirmationStatus is pending.
  • Sends SMS: "Please confirm your appointment at [Salon] on [Date]..."
  • Updates status to SENDING / SENT.

Maintenance

Remote Access via NordVPN

To access the Raspberry Pi remotely without being on the local network, you can use NordVPN's Meshnet feature. The account owner must first invite you to the Pi's Meshnet and ensure your access is restricted to the Pi only:

  1. Request an Invite: Ask the NordVPN account owner to send an invitation to join the Meshnet via your email address.
    • Account Owner Instructions: SSH into the Raspberry Pi locally and run nordvpn meshnet invite send <email@example.com> to send the invitation. Do not send this from the Windows App.
  2. Restrict Local Access (Account Owner Only): To ensure the invited user cannot access the 192.168.x.x home network, the account owner must explicitly disable their local network permissions.
    • Find the peer's Nord Name: nordvpn meshnet peer list
    • Deny local access: nordvpn meshnet peer local deny <their-nord-name>
  3. Accept and Connect: Ensure NordVPN is running, Meshnet is enabled, and accept the invitation in your app.
  4. SSH into the Raspberry Pi using its static Meshnet IP:
    ssh pi@100.65.38.185
    
  5. Enter the Raspberry Pi password to connect.

Updating Cloudflared on Raspberry Pi

To update the cloudflared daemon tunneling the GSM gateway:

  1. Connect to the Raspberry Pi either via the local network or remotely using NordVPN.
  2. SSH into the Raspberry Pi:
    • Local Network: ssh pi@192.168.7.250
    • Remote (NordVPN): ssh pi@100.65.38.185
  3. Enter the Raspberry Pi password to connect.
  4. Run the update command:
    sudo apt-get update && sudo apt-get install --only-upgrade cloudflared
    
  5. Restart the service:
    sudo systemctl restart cloudflared.service
    

Troubleshooting

Verification Steps

  1. Check Feature Flag: Ensure SMS_ENABLED is set to true in the environment's SSM parameters.
  2. Check Logs: The backend logs sendSMS events. Search CloudWatch for #error: sendCampaign or smsSending.
  3. Gateway Status: Use the getStatus method (exposed via API) to verify the backend can reach the GSM gateway.