A few weeks ago, I had the idea of creating a service that would send daily reminders to motivate people to work on their goals. To start, the service would send an SMS message with an inspirational quote at a selected time, for example just before a training session.
There are many motivation apps on the market that offer a similar service – displaying motivational quotes at random or scheduled times – but I haven’t found any that don’t require installing an app and use SMS instead. So I decided to give it a try and build one myself, as a side project to my current job.
The motivation for this project is twofold: working on system design and learning about marketing and growth.
Final result: https://www.uppush.me/
StacK: Next.js, Material UI, AWS EventBridge Scheduler, AWS SNS, AWS Lambda, DynamoDB, Terraform.
There are 4 key components to make this work:
- A form for users to sign up
- A database to store user schedules and other metadata.
- A scheduler to activate the sending of an SMS at the time selected by the user.
- An SMS broker: a service that provides an API to send SMS messages to a given phone number in exchange for a small fee.
The criteria that I took into account to design the architecture were:
Simplicity: Keep the design as simple as possible and avoid unnecessary complexities. This will facilitate maintenance and minimize problems.
Low cost: Choose free or low-cost options, but without compromising quality.
Speed: Use platforms and tools you are familiar with to reduce friction and move forward as quickly as possible.
The landing page and registration form
The landing page must be able to show the value of the service to visitors, in a simple and concise way. Once familiar with the service, users should be able to decide whether to register or not.
To build the UI, I used Next.js and the Material UI library. Next.js allows you to quickly develop client-side and backend APIs, and comes with many optimizations out of the box, as well as providing excellent documentation.
Hosting is done at Vercel, the company that created Next.js, and which offers a generous free tier with enough quota for a project of this size. It also integrates with GitHub and offers CI/CD out of the box.
By design, the application does not depend on large reads or writes to the database and does not store relational data. I chose AWS DynamoDB because it is a perfect fit: It is serverless (no provisioning and maintenance overhead), has a low and predictable provisioning cost, and is non-SQL.
A very interesting and fun part to design and implement.
Once enrolled, users expect to receive an SMS at certain times of the day and certain days of the week, for example, every other day at 6:00. There are many options for scheduling a task.
There are many options for a task scheduler (e.g. Airflow, Celery), but getting back to design requirements, the simplest and fastest solution is Amazon EventBridge Scheduler – it’s serverless, easy to set up, and has a generous free tier. .
An EventBridge schedule (equivalent to a cron task) is created for each quadrant of the hour (at minute 00, minute 15, minute 30, and minute 45), for each hour of the day, and for each day of the week. The result is 4 quadrants x 24 hours x 7 days = 672 hours.
Each user is assigned times that correspond to the times selected during registration (converted to UTC).
It has been very interesting to take into account users’ time zones during registration. In most cases, we can safely assume that the time zone configured in the user’s locale (system settings) is where the user lives, but that is not always accurate, because users may be traveling, or because the locale simply cannot be accessed or read from the browser. Therefore, the registration form has a drop-down list of all commonly known time zones that users can select. The form defaults to the time zone read (or guessed) in the locale.
Once a time zone is selected, the user’s time is converted from the local time zone to UTC using the UTC offset list in the IANA database.
To programmatically send an SMS to a given phone number, AWS SNS is an option that fits well with our design requirements. It’s affordable (although not always the cheapest), and integrates well with other AWS services.
For UpPush.me, each schedule triggers a call to a Lambda function that obtains a quote and formats the SMS message which is then sent to subscribers via SNS.
However, I ran into a few roadblocks that required some back-and-forth with the AWS support team (who were very responsive and helpful, even on my personal “entry-level” account):
- Increase the default spending quota of $1/month.
- Exit the SMS sandbox so you can send messages to phone numbers that are not restricted to a preset list of allowed destinations.
- Trying to get a Sender ID, which is a requirement in some countries like India, which represents an incredible market for UpPush.me, given the large population. I have not received the Sender ID yet, but fortunately almost all countries do not have it as a requirement.
Once I had an MVP, I started sharing UpPush.me on builder forums like indiehackers.com and subreddits like r/smallbusiness and r/EntrepreneurRideAlong. The result was that I received feedback from other builders and had my first subscribers 🎉!
What other builders found great was the clarity of the landing page message, and how it conveys the idea and in a simple and clear way.
Another common feedback about the service was that the UI (landing page) needed improvement, and I received many recommendations to use a no-code tool to build the landing page instead of using a React library. Although it is important to have a visually appealing user interface, it is not the most critical part of UpPush.me. Therefore, at this stage, I prefer to keep and improve the current UI, and focus on building the service, rather than investing in rebuilding with a no-code tool.
Users also commented that they would like to add features such as sending quotes and rating quotes sent to them by message or author.
Perfection is the enemy of good
As engineers and developers, we can easily get distracted from the goal of building a product that is useful and desirable to users and focus on the minutiae of building the perfect product. Perfection is the enemy of good, and it is important to define what the desired outcome of any project is (what good is), and establish safeguards that prevent us from devoting too much time and energy to mere construction.
In my opinion, the most powerful safeguard against perfectionism is deadlines, because with them the most precious resource is time, and they allow you to change the perspective of “it would be nice to have this” to “how can I build and ship this function and move on to the next one.”
Continuously seek and integrate feedback
Building a service without knowing what users really want has the double negative effect of wasting resources (time, energy) and creating momentum that takes us away from delivering a product. It’s important to regularly seek feedback and integrate it into product development, whether to create new features, edit current ones, or fix bugs.
Doing is the best way to learn
If you want to become a better systems designer, architect, developer or marketer, working on your own large-scale projects is the best way because you have the freedom to do your own research for the best implementation, and the best tools and technologies to use. . Furthermore, the resources you have at your disposal are finite (time, energy, budget) and that leads you to be diligent in using each of them.
After 4 weeks since its launch, UpPush.me is already happily serving 32 subscribers (and counting!)
Today’s ecosystem for tech entrepreneurs is booming with solutions for building and delivering software – from no-code tools to low-cost hosting solutions – and I’m excited to see how big the communities of “small business” builders are and how many products and interesting services are being developed