Frequently Asked Questions
Use NestJS's @nestjs/schedule
module along with the Vonage Messages API. Create a scheduled task (cron job) that queries your database for upcoming appointments and sends SMS reminders via the Vonage API at the designated time before the appointment. This guide provides a complete walkthrough using PostgreSQL, Prisma, and other key technologies.
NestJS provides a structured, scalable backend framework. It facilitates API endpoint creation for scheduling, database integration with PostgreSQL via Prisma, and scheduled task management for sending SMS reminders through the Vonage Messages API. Its modular architecture and dependency injection simplify development and maintenance.
The Vonage Messages API allows you to programmatically send SMS messages. This is ideal for appointment reminders as it enables automation and ensures timely notifications to reduce no-shows and improve communication with users.
This guide uses PostgreSQL, a robust and open-source relational database, combined with Prisma, a modern database toolkit and ORM. Prisma simplifies database interactions and data modeling within the NestJS application.
These packages are crucial for request data validation. class-validator
provides decorators for defining validation rules (e.g., required fields, data types, string length). class-transformer
facilitates transforming request payloads into data transfer objects (DTOs), enforcing data integrity and security.
Obtain your API Key and API Secret from your Vonage API Dashboard. Store these securely in a .env
file (never commit this to version control) and access them within your NestJS application using @nestjs/config
for secure configuration management.
Use the Vonage CLI to create a new application with the Messages capability. The command vonage apps:create "My SMS Scheduler App" --capabilities=messages --messages_version=v1 --keyfile=private.key
sets up an application and generates a private key file (ensure this key is stored securely).
A Vonage virtual number is required to send SMS messages via the Vonage API. After purchasing and linking a Vonage number to your application, add it to your .env
file (VONAGE_SMS_FROM_NUMBER) as the sender ID for your reminders. Ensure the number is in E.164 format (+12015550123).
Never commit the private.key
file to version control. Instead, manage it through a secure method such as environment variables, a dedicated secrets manager, or mounting it as a volume in containerized environments (e.g. Kubernetes secrets).
Prisma is a modern database toolkit that includes an ORM (Object-Relational Mapper). It simplifies database interactions, schema management, and data modeling in your Node.js and TypeScript applications, making it easier to work with PostgreSQL or other supported databases.
The @nestjs/schedule
module allows you to define cron jobs (scheduled tasks). A cron job runs every minute (using CronExpression.EVERY_MINUTE) to check the database for appointments whose reminder time has passed but haven't had a reminder sent. If found, the app sends an SMS using the Vonage Messages API.
The @nestjs/config
module provides a way to manage environment variables and application configuration securely. It helps access sensitive data like database credentials and API keys from a .env
file without exposing them directly in the codebase. Create a .env.example
file to track these environment variables.
This guide provides a complete walkthrough for building a robust SMS appointment scheduling and reminder system using NestJS, Node.js, PostgreSQL, Prisma, and the Vonage Messages API. You will learn how to create an API endpoint to schedule appointments, store them in a database, and automatically send SMS reminders at a specified time before the appointment.
We aim to build a reliable backend service capable of handling appointment creation and triggering timely SMS notifications. This solves the common business need for reducing no-shows and keeping users informed about their upcoming appointments.
Key Technologies:
@nestjs/schedule
: For running scheduled tasks (cron jobs) within NestJS to trigger reminders.@nestjs/config
: For managing environment variables securely.class-validator
&class-transformer
: For robust request data validation.System Architecture:
Final Outcome & Prerequisites:
By the end of this guide, you will have a functional NestJS application with:
POST /appointments
) to schedule new appointments.Prerequisites:
npm install -g @vonage/cli
).ngrok
installed (optional, for testing inbound webhooks if needed later).1. Setting up the Project
Let's initialize our NestJS project and install the necessary dependencies.
1.1 Install NestJS CLI:
If you don't have it installed globally, run:
1.2 Create New NestJS Project:
Choose your preferred package manager (npm or yarn) when prompted.
1.3 Install Dependencies:
We need several packages for configuration, scheduling, database interaction, validation, and the Vonage SDK.
@nestjs/config
: For environment variable management.@nestjs/schedule
: For scheduling reminder jobs (usesnode-cron
internally).@vonage/server-sdk
: The official Vonage Node.js library.class-validator
,class-transformer
: For input validation using DTOs.@prisma/client
,prisma
: Prisma client and CLI for database interactions.@nestjs/terminus
,@nestjs/axios
: For implementing health check endpoints.1.4 Set up Prisma:
Initialize Prisma in your project:
This creates:
prisma
directory with aschema.prisma
file..env
file at the project root (if it doesn't exist).1.5 Configure Environment Variables (
.env
):Open the
.env
file created by Prisma and add your database connection string and Vonage API credentials. Never commit this file to version control. Create a.env.example
file to track necessary variables..env
:.env.example
(Commit this file):Note: Ensure your
VONAGE_SMS_FROM_NUMBER
is a number purchased from Vonage and linked to your application (see Section 4). It should be in E.164 format (e.g.,14155552671
).1.6 Project Structure (Conceptual):
NestJS encourages a modular structure. We'll create modules for different concerns:
We will create these modules and files in the subsequent steps.
2. Implementing Core Functionality (Appointments & Scheduling)
Now, let's build the core logic for creating appointments and scheduling reminders.
2.1 Create Prisma Module:
This module provides the Prisma service for database interactions throughout the application.
src/database/prisma.service.ts
:src/database/prisma.module.ts
:Register
PrismaModule
inAppModule
:src/app.module.ts
:2.2 Create Vonage Module:
Encapsulate Vonage SDK interaction within its own module and service.
src/vonage/vonage.service.ts
:src/vonage/vonage.module.ts
:Register
VonageModule
inAppModule
:src/app.module.ts
:2.3 Create Appointments Module:
This module handles the creation and management of appointments.
Define Data Transfer Object (DTO) for Validation:
src/appointments/dto/create-appointment.dto.ts
:Implement Appointments Service:
src/appointments/appointments.service.ts
:Implement Appointments Controller:
src/appointments/appointments.controller.ts
:Configure Appointments Module:
src/appointments/appointments.module.ts
:Register
AppointmentsModule
inAppModule
:src/app.module.ts
:2.4 Create Scheduler Module for Reminders:
This module will contain the scheduled task (cron job) that checks for due reminders and triggers SMS sending.
src/scheduler/reminder.task.service.ts
:src/scheduler/scheduler.module.ts
:Register
AppSchedulerModule
inAppModule
:src/app.module.ts
:2.5 Enable Validation Pipe Globally:
To ensure all incoming requests are validated against DTOs, enable the
ValidationPipe
globally.src/main.ts
:3. Building the API Layer
The primary API endpoint is
POST /appointments
, which we created in the previous section.Endpoint Definition:
POST
/appointments
CreateAppointmentDto
(JSON)201 Created
with the createdAppointment
object (JSON).400 Bad Request
: If validation fails (e.g., invalid phone number, missing fields).500 Internal Server Error
: If database operation or other internal process fails.Request Example (JSON):
Response Example (JSON - Success 201 Created):
Testing with
curl
:Replace placeholders with your actual data and running application URL (e.g.,
http://localhost:3000
).4. Integrating with Vonage
This involves setting up your Vonage account, application, and number correctly.
4.1 Vonage Account & Credentials:
.env
file (VONAGE_API_KEY
,VONAGE_API_SECRET
).4.2 Create a Vonage Application:
An application acts as a container for your configurations and links your virtual number. You can create this via the Dashboard or the CLI. Using the CLI is often faster for developers.
Authenticate CLI (if first time):
Create Application: We only need the Messages capability for sending SMS. Webhooks aren't strictly required for this guide's core functionality (sending reminders), but you might enable them if you plan to handle inbound messages later.
4.3 Purchase and Link a Vonage Number:
You need a Vonage virtual number to send SMS messages from.
.env
: Add the purchased number (in E.164 format, e.g.,12015550123
) toVONAGE_SMS_FROM_NUMBER
in your.env
file.4.4 Configure Private Key:
vonage apps:create
command generated aprivate.key
file.VONAGE_PRIVATE_KEY_PATH
in your.env
file correctly points to the location of this file relative to your project root (e.g.,./private.key
).private.key
to your.gitignore
file. In production, manage this key securely (e.g., environment variable content, secrets manager, mounted volume) rather than committing it or copying it directly into container images.Your Vonage integration setup is now complete. The
VonageService
uses these credentials and the private key to authenticate with the Vonage API for sending SMS messages.