From missed flight to mission: building a 24-hour reminder service on AWS
Source: Dev.to
🛠️ Stack
- Data: DynamoDB table storing appointments (
Name,Date,Time). - Compute: AWS Lambda scans the table, determines which appointments need a reminder.
- Notify: Amazon SNS publishes email/SMS notifications.
Step‑by‑Step Walkthrough
1. Create the DynamoDB Table
| Property | Value |
|---|---|
| Table name | Appointment |
| Primary key | Partition key = Name (String) |
| Attributes | Name – e.g., “Dentist Visit” Date – ISO string, e.g., 2025-12-29 Time – optional, 24‑hour format (HH:mm) |
You can add additional attributes (e.g.,
UserEmail) if you want per‑user notifications.
2. Create the SNS Topic and Subscribe
- Open Amazon SNS → Topics → Create topic.
- Topic name:
AppointmentReminders(Standard). - Copy the Topic ARN – you’ll need it in the Lambda code.
- Add a subscription:
- Protocol: Email (or SMS).
- Endpoint: your email address (or phone number).
- Confirm the subscription via the link sent by AWS.
3. Create the Lambda Function (Node.js)
Configuration
- Runtime: Node.js 18.x
- Handler:
index.handler - Memory / Timeout: 128 MB, 30 seconds (adjust as needed)
index.js
// index.js
const { DynamoDBClient, ScanCommand } = require("@aws-sdk/client-dynamodb");
const { SNSClient, PublishCommand } = require("@aws-sdk/client-sns");
// Environment variables (set in Lambda console)
const TABLE_NAME = process.env.APPOINTMENT_TABLE;
const SNS_TOPIC_ARN = process.env.SNS_TOPIC_ARN;
const ddb = new DynamoDBClient({});
const sns = new SNSClient({});
exports.handler = async () => {
// 1️⃣ Scan the Appointment table
const scanParams = {
TableName: TABLE_NAME,
ProjectionExpression: "Name, #d, #t, Email",
ExpressionAttributeNames: {
"#d": "Date",
"#t": "Time"
}
};
const data = await ddb.send(new ScanCommand(scanParams));
// 2️⃣ Determine which items are within the next 24 h
const now = new Date();
const next24h = new Date(now.getTime() + 24 * 60 * 60 * 1000);
const reminders = data.Items.filter(item => {
const dateStr = item.Date.S; // e.g. "2025-12-29"
const timeStr = item.Time?.S || "00:00"; // optional, default midnight
const apptDate = new Date(`${dateStr}T${timeStr}:00Z`);
return apptDate > now && apptDate <= next24h;
});
// 3️⃣ Publish a reminder for each upcoming appointment
for (const appt of reminders) {
const message = `Reminder: ${appt.Name.S} on ${appt.Date.S} at ${appt.Time?.S || "00:00"}.`;
const publishParams = {
TopicArn: SNS_TOPIC_ARN,
Message: message,
Subject: "24‑hour Appointment Reminder",
MessageAttributes: {
"email": {
DataType: "String",
StringValue: appt.Email?.S || ""
}
}
};
await sns.send(new PublishCommand(publishParams));
}
return {
statusCode: 200,
body: `Sent ${reminders.length} reminder(s).`
};
};
Environment variables to set in the Lambda console
| Variable | Value |
|---|---|
APPOINTMENT_TABLE | Appointment |
SNS_TOPIC_ARN | ARN of the AppointmentReminders topic |
4. IAM Permissions for Lambda
Attach an inline policy (or a managed policy) to the Lambda execution role that allows:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:Scan",
"dynamodb:Query",
"dynamodb:GetItem"
],
"Resource": "arn:aws:dynamodb:*:*:table/Appointment"
},
{
"Effect": "Allow",
"Action": "sns:Publish",
"Resource": "arn:aws:sns:*:*:AppointmentReminders"
}
]
}
5. Add a Test Item in DynamoDB
| Name | Date | Time | |
|---|---|---|---|
| Dentist Visit | 2025-12-29 | 09:00 | your.email@example.com |
You can add the item via the DynamoDB console or the AWS CLI:
aws dynamodb put-item \
--table-name Appointment \
--item '{"Name":{"S":"Dentist Visit"},"Date":{"S":"2025-12-29"},"Time":{"S":"09:00"},"Email":{"S":"your.email@example.com"}}'
6. Test the Lambda
- In the Lambda console, click Test and create a simple event (the function doesn’t use the payload).
- Run the test.
- Check your email (or SMS) – you should receive a message like:
Subject: 24‑hour Appointment Reminder
Message: Reminder: Dentist Visit on 2025-12-29 at 09:00.
If you see the email, the end‑to‑end flow works.
🚀 What I learned
- Forgetting is easy; systems aren’t. A tiny serverless stack can reliably give you a heads‑up.
- 24‑hour timing provides enough buffer to prepare without being intrusive.
- You don’t need a massive platform—just a DynamoDB table, a Lambda function, an SNS topic, and a scheduled trigger (e.g., CloudWatch Events / EventBridge) to run the Lambda once a day.
- Building this project cemented core DevOps / Cloud Engineering skills: IAM least‑privilege policies, Lambda development, DynamoDB data modeling, and SNS notifications.
That’s the whole reminder service—simple, cheap, and effective. Happy building!