Frequently Asked Questions
You can schedule SMS messages by building a Next.js application that integrates with AWS EventBridge Scheduler. The frontend collects user input (phone number, message, time) and sends it to a Next.js API route. This route then interacts with AWS services to schedule and send the SMS at the specified time.
AWS EventBridge Scheduler is a serverless service that handles the scheduling logic. It triggers AWS Simple Notification Service (SNS) to send the SMS message at the designated date and time, offloading this responsibility from the Next.js application.
DynamoDB, a NoSQL database, stores metadata about scheduled messages, such as the phone number, message content, and scheduled time. While optional, it's recommended for tracking, management, and potential future features. DynamoDB's Time-to-Live (TTL) feature helps automatically delete old records.
AWS credentials (access key ID and secret access key) should be configured during project setup. Store these securely in a `.env.local` file for local development and use more secure mechanisms like IAM roles for production environments. Do not hardcode these values directly into your Next.js code.
Yes, Zod is recommended for validating user input on the server-side within your Next.js API routes. This ensures that data conforms to the expected format (E.164 phone numbers, valid date format) before being processed and sent to AWS services.
NextAuth.js handles user authentication for your Next.js application. It provides an easy way to protect the scheduling functionality by requiring users to sign in before accessing the form. This prevents unauthorized scheduling of messages.
AWS Identity and Access Management (IAM) controls access to AWS services. You need to configure specific IAM permissions for both your Next.js backend and the EventBridge Scheduler's execution role. These permissions define which actions each entity is authorized to perform, ensuring security and preventing unintended access.
You will need Node.js, an AWS account, AWS CLI, and basic knowledge of React and Next.js. Familiarity with TypeScript, though not strictly necessary, is beneficial. A verified phone number might also be necessary depending on your SNS configuration (sandbox environment).
The `createEventBridgeSchedule` function in the API route handles the interaction with the AWS SDK. It creates a one-time schedule using the input data, assigns a unique name using a UUID, sets the scheduled time, and specifies the execution role with necessary permissions.
The key AWS services involved are EventBridge Scheduler, which triggers the message sending; SNS, which sends the actual SMS messages; DynamoDB for metadata storage (optional); and IAM, which manages access control and permissions.
You can use a regular expression (regex) and a validation library like Zod in your Next.js API route to ensure phone numbers conform to the E.164 format. This provides reliable validation on the server-side, even if client-side checks are bypassed.
Use try-catch blocks to handle both Zod validation errors and errors from the AWS SDK or other issues. Return appropriate HTTP status codes (e.g., 400 for invalid input, 500 for server errors) with helpful error messages while also logging details server-side for debugging.
Zod, a TypeScript-first schema validation library, is used in the `src/lib/validations.ts` file. You define schemas to enforce data types, constraints (like regex for phone numbers, minimum/maximum string lengths), and custom checks (ensuring the scheduled time is in the future).
Figure 1: System Architecture Diagram
This diagram illustrates the flow: A user interacts with the Next.js frontend, authenticating via NextAuth.js. Upon submitting a schedule request, the Next.js API route validates the data, stores metadata in DynamoDB, and creates a one-time schedule in EventBridge Scheduler using the AWS SDK. The API route requires specific IAM permissions to interact with AWS services. At the scheduled time, EventBridge Scheduler assumes its execution role (which needs
sns:Publish
permission) and triggers SNS to send the SMS message to the user's phone number.Project Overview and Goals
This guide details how to build a production-ready application using Next.js that enables users to schedule SMS reminders for future dates and times.
Problem Solved:
Technologies Used:
Final Outcome & Prerequisites:
By the end of this guide, you will have a Next.js application where authenticated users can:
Prerequisites:
1. Setting up the Project
Let's initialize the Next.js project and install necessary dependencies.
Step 1: Create Next.js App
This command scaffolds a new Next.js project using TypeScript, Tailwind CSS, ESLint, the App Router (
--app
), asrc/
directory, and@/*
import alias.Step 2: Install Dependencies
next-auth
: Handles authentication.@aws-sdk/client-scheduler
: AWS SDK v3 client for EventBridge Scheduler.@aws-sdk/client-sns
: AWS SDK v3 client for SNS.@aws-sdk/client-dynamodb
,@aws-sdk/lib-dynamodb
: AWS SDK v3 clients for DynamoDB.zod
: For input validation.react-datepicker
,@types/react-datepicker
: UI component for selecting dates/times.date-fns
: Utility library for date manipulation.date-fns-tz
: Extension fordate-fns
to handle timezones correctly.uuid
,@types/uuid
: For generating unique schedule names.Step 3: Configure Environment Variables
Create a file named
.env.local
in the project root. Never commit this file to version control. Fill in your actual AWS details where indicated.openssl
command provided.Step 4: Project Structure and Architecture Decisions
We are using the Next.js App Router (
src/app/
)./src/app/api/schedule/route.ts
: Backend API endpoint to handle scheduling requests./src/app/page.tsx
: Main page with the scheduling form UI./src/app/layout.tsx
: Root layout, potentially including authentication providers./src/components/
: Reusable React components (e.g., SchedulerForm, DatePickerWrapper)./src/lib/
: Utility functions, AWS SDK client initialization, validation schemas./src/app/api/auth/[...nextauth]/route.ts
: NextAuth.js API route for authentication handling.This structure separates concerns: frontend UI, backend API logic, authentication, shared utilities, and components. Using the App Router allows server components for efficiency and colocated API routes.
2. Implementing Core Functionality (Frontend UI)
Let's build the form for users to input scheduling details.
Step 1: Create the Scheduler Form Component
Create
src/components/SchedulerForm.tsx
:Explanation:
'use client';
: Marks this as a Client Component, necessary for using hooks (useState
) and event handlers.phoneNumber
,message
,scheduledAt
), loading state (isLoading
), and status feedback (statusMessage
,isError
).DatePicker
component provides the UI for selecting date and time.minDate
prevents selecting past dates.handleSubmit
:scheduledAt
date to ISO 8601 UTC string usingdate-fns/formatISO
. This is crucial for consistency when sending to the backend and interacting with AWS services.POST
request to/api/schedule
with the form data in the body.+12223334444
) is requested for the phone number.Step 2: Add Form to the Main Page
Update
src/app/page.tsx
:Explanation:
getServerSession
checks if the user is authenticated on the server.SchedulerForm
.3. Building a Complete API Layer
Now, let's create the Next.js API route that handles the scheduling logic.
Step 1: Define Validation Schema
Create
src/lib/validations.ts
:Explanation:
phoneNumber
: Must be a string matching the E.164 format.message
: Must be a non-empty string, with a max length (adjust as needed).scheduledAt
: Must be a valid ISO 8601 datetime string and represent a future time.Step 2: Implement the API Route
Create
src/app/api/schedule/route.ts
:Explanation:
getServerSession
. If no valid session exists, it returns a 401 Unauthorized error. The user's email is extracted as an identifier.scheduleSchema
using Zod. If validation fails, it returns a 400 Bad Request error with details. It also double-checks if the parsed date string results in a validDate
object.createEventBridgeSchedule
(defined in the next section) to interact with the AWS SDK and create the one-time schedule in EventBridge. A unique name is generated using a sanitized prefix from the user email and a UUID (uuidv4
) to ensure uniqueness and avoid collisions. The name is truncated to 64 characters to comply with EventBridge limits.saveScheduleMetadata
(defined later) to save details about the schedule (like the EventBridge ARN, user, phone number, etc.) to DynamoDB. This step is wrapped in atry...catch
to handle potential database errors without necessarily failing the entire request if the schedule itself was created successfully. You might add logic here to clean up the EventBridge schedule if the DB write is critical and fails.try...catch
blocks to handle Zod errors specifically and generic errors (AWS SDK errors, network issues), logging them server-side and returning appropriate HTTP status codes (400 for validation, 500 for server errors).4. Integrating with AWS Services
Now, let's implement the logic to interact with EventBridge Scheduler, SNS (implicitly via Scheduler), IAM, and DynamoDB.
Step 1: Configure AWS SDK Clients
Create
src/lib/aws/clients.ts
:Explanation:
DynamoDBDocumentClient
) and EventBridge Scheduler..env.local
.AWS_ACCESS_KEY_ID
andAWS_SECRET_ACCESS_KEY
environment variables directly in your application code. Use IAM roles associated with your compute environment (like Vercel's Environment Variables, EC2 Instance Profiles, Lambda Execution Roles, ECS Task Roles) for better security. The SDK will automatically pick up credentials from these sources if the environment variables are not explicitly set.getEnvVariable
to safely access required environment variables, ensuring they are present.Step 2: Create IAM Roles and Policies
This is a critical step requiring configuration in the AWS Console or via AWS CLI/IaC. Remember to replace placeholders like
YOUR_REGION
,YOUR_AWS_ACCOUNT_ID
,YourSchedulerExecutionRoleName
, andSmsSchedulesTableName
with your actual values.A. IAM Permissions for the Next.js API Route (Backend Function)
The IAM user/role whose credentials (
AWS_ACCESS_KEY_ID
,AWS_SECRET_ACCESS_KEY
) are used by the Next.js backend (or the role assumed by the compute environment like Vercel/Lambda) needs the following permissions:Explanation:
scheduler:CreateSchedule
: Allows creating new schedules. Resource ARN should ideally be scoped to a specific group or naming pattern (e.g.,arn:aws:scheduler:YOUR_REGION:YOUR_AWS_ACCOUNT_ID:schedule/default/sms-*
).iam:PassRole
: Crucial. Allows the Next.js backend to specify (pass
) theEVENTBRIDGE_SCHEDULER_ROLE_ARN
when creating the schedule. TheCondition
ensures this role can only be passed to the EventBridge Scheduler service. ReplaceYourSchedulerExecutionRoleName
with the actual name of the role created in the next step.dynamodb:PutItem
: Allows writing metadata to the DynamoDB table. ReplaceSmsSchedulesTableName
with your actual table name.B. IAM Execution Role for EventBridge Scheduler
EventBridge Scheduler needs its own role to assume when it executes the task (publishing to SNS).
AmazonSNSFullAccess
policy (for simplicity) OR create a more restrictive custom policy (Recommended):YourSchedulerExecutionRoleName
(or similar - this name must match the ARN used in.env.local
and theiam:PassRole
resource)..env.local
file forEVENTBRIDGE_SCHEDULER_ROLE_ARN
, ensuring the Account ID and Role Name are correct.Step 3: Implement