A production-ready backend API that helps users manage subscriptions and avoid unexpected renewals by sending automated email reminders before renewal dates, powered by serverless background workflows.
Built with Node.js, Express, MongoDB, and modern cloud-native services, following real-world backend engineering best practices.
Subscriptions are everywhere streaming platforms, SaaS tools, utilities but users often forget renewal dates and get charged unexpectedly.
This project solves that problem by:
- Automatically tracking subscription renewal dates
- Proactively notifying users before renewals happen
- Running reminders reliably in the background
- Remaining stable even if the API server restarts
The goal is predictability, transparency, and user trust.
- Authenticates users securely using JWT
- Allows users to create and manage subscriptions
- Automatically calculates renewal dates
- Triggers background workflows on subscription creation
- Sends multiple email reminders before renewal
- Protects APIs against bots and abuse
- Scales cleanly using stateless APIs and serverless workflows
Client (Postman / Frontend)
β
βΌ
Express REST API
β
βββ JWT Authentication
βββ Arcjet Security Layer
βββ Controllers
β βββ Auth
β βββ User
β βββ Subscription
β βββ Workflow
β
βββ MongoDB (Mongoose)
β
βββ Upstash Workflow (QStash)
β βββ Automated Email Reminders
- Stateless API design
- Separation of concerns
- Fail-open third-party integrations
- Asynchronous background processing
- Environment-based configuration
- User sign-up and sign-in using JWT
- Password hashing with bcrypt
- Authorization middleware for protected routes
- Token-based access control (Bearer tokens)
Example Authorization Header Authorization: Bearer <JWT_TOKEN>
When a user creates a subscription:
- Input is validated
- Renewal date is automatically calculated
- Subscription status is determined (
active/expired) - Subscription is saved to the database
- A background workflow is triggered
- Active β Renewal date is in the future
- Expired β Renewal date has passed
- A subscription is created
- The system calculates the renewal date
- A serverless workflow is triggered via Upstash
- The workflow schedules reminders at:
- 7 days before renewal
- 5 days before renewal
- 2 days before renewal
- 1 day before renewal
- On each reminder date:
- The workflow wakes up
- An email notification is sent
- Users can renew or cancel in advance
Traditional approaches like setTimeout or cron jobs:
- Fail on server restarts
- Donβt scale reliably
- Are hard to retry safely
Upstash Workflows solve this by:
- Persisting workflow state
- Sleeping in the cloud
- Resuming execution reliably
- Retrying failed steps automatically
- Receive subscription ID payload
- Fetch subscription data safely
- Validate subscription state
- Calculate reminder dates
- Sleep until scheduled times
- Trigger email delivery logic
- Run independently of API uptime
POST /api/v1/auth/sign-up POST /api/v1/auth/sign-in
GET /api/v1/user/me GET /api/v1/user/:id
POST /api/v1/subscription GET /api/v1/subscription/:userId
POST /api/v1/workflows/subscription/reminder
Workflow endpoints are not intended for public use and are invoked internally by Upstash.
subscriptionManagementSystem/
β
βββ app.js # Application entry point
β
βββ config/
β βββ env.js # Environment configuration
β βββ upstash.js # Upstash workflow client
β
βββ controllers/
β βββ auth.controller.js
β βββ user.controller.js
β βββ subscription.controller.js
β βββ workflow.controller.js
β
βββ routes/
β βββ auth.routes.js
β βββ user.routes.js
β βββ subscription.routes.js
β βββ workflow.routes.js
β
βββ middlewares/
β βββ auth.middleware.js
β βββ arcjet.middleware.js
β βββ error.middleware.js
β
βββ models/
β βββ user.model.js
β βββ subscription.model.js
β
βββ database/
β βββ mongodb.js # MongoDB connection
β
βββ package.json
- Passwords are never stored in plain text
- JWT secrets are environment-scoped
- Bot protection and rate limiting enabled
- Sensitive fields excluded from responses
- Background workflows isolated from API logic
- Node.js
- Express
- MongoDB
- Mongoose
- JWT
- bcrypt
- Arcjet
- Upstash Workflow
- QStash
- dotenv
- dayjs
- cookie-parser
- nodemon
Example .env.development.local:
PORT=5500
NODE_ENV=development
DB_URI=mongodb://localhost:27017/subscriptions
JWT_SECRET=your_secret_key
JWT_EXPIRES_IN=7d
ARCJET_KEY=your_arcjet_key
ARCJET_ENV=development
QSTASH_TOKEN=your_qstash_token
QSTASH_URL=https://qstash.upstash.io
SERVER_URL=http://localhost:5500npm install
npm run devThis project does not:
- Process payments
- Handle billing or invoices
- Integrate payment gateways
- Replace full CRM systems
The system focuses on subscription tracking and reminders, not financial transactions.
- Email provider integration (SES / SendGrid / Resend)
- User notification preferences
- Admin roles & dashboards
- Subscription analytics
- Swagger / OpenAPI documentation
- Unit & integration tests