A subscription management system built with Node.js, Express, and MongoDB. Track your subscriptions, get renewal reminders, and manage your recurring payments efficiently.
- User Authentication: Secure JWT-based authentication with bcrypt password hashing
- Subscription Management: Create, read, update, and delete subscriptions
- Automated Reminders: Smart email notifications for upcoming renewals (7, 5, 2, 1 days before)
- Workflow Automation: Upstash Workflow integration for reliable reminder scheduling
- Security: Arcjet middleware for rate limiting and security protection
- Email Notifications: Nodemailer integration with customizable email templates
- Data Validation: Comprehensive input validation and error handling
- Multi-Currency Support: USD, EUR, GBP, INR currency options
- Flexible Billing: Daily, weekly, monthly, and yearly subscription frequencies
- Backend: Node.js, Express.js
- Database: MongoDB with Mongoose ODM
- Authentication: JWT (JSON Web Tokens)
- Security: Arcjet, bcryptjs
- Email: Nodemailer
- Workflow: Upstash Workflow
- Date Handling: Day.js
- Development: Nodemon, ESLint
- Node.js (v14 or higher)
- MongoDB database
- Email service credentials (Gmail/SMTP)
- Upstash account for workflow management
- Arcjet account for security features
git clone <repository-url>
cd subscription-trackernpm installCreate .env.development.local file in the root directory:
# Server Configuration
PORT=5500
SERVER_URL="http://localhost:5500"
NODE_ENV='development'
# Database
DB_URI="your_mongodb_connection_string"
# JWT Authentication
JWT_SECRET="your_jwt_secret_key"
JWT_EXPIRES_IN="1d"
# Arcjet Security
ARCJET_KEY="your_arcjet_key"
ARCJET_ENV="development"
# Upstash Workflow
QSTASH_URL="your_qstash_url"
QSTASH_TOKEN="your_qstash_token"
# Email Configuration
EMAIL_PASSWORD="your_email_app_password"# Development mode
npm run dev
# Production mode
npm startThe API will be available at http://localhost:5500
http://localhost:5500/api/v1
POST /api/v1/auth/sign-up
Content-Type: application/json
{
"name": "John Doe",
"email": "john@example.com",
"password": "password123"
}Response (201):
{
"success": true,
"message": "User created successfully",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"_id": "507f1f77bcf86cd799439011",
"name": "John Doe",
"email": "john@example.com"
}
}
}POST /api/v1/auth/sign-in
Content-Type: application/json
{
"email": "john@example.com",
"password": "password123"
}Response (200):
{
"success": true,
"message": "User signed in successfully",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"_id": "507f1f77bcf86cd799439011",
"name": "John Doe",
"email": "john@example.com"
}
}
}GET /api/v1/usersResponse (200):
{
"success": true,
"data": [
{
"_id": "507f1f77bcf86cd799439011",
"name": "John Doe",
"email": "john@example.com"
}
]
}GET /api/v1/users/:id
Authorization: Bearer <token>Response (200):
{
"success": true,
"data": {
"_id": "507f1f77bcf86cd799439011",
"name": "John Doe",
"email": "john@example.com"
}
}POST /api/v1/subscriptions
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "Netflix",
"price": 15.99,
"currency": "USD",
"frequency": "monthly",
"category": "entertainment",
"paymentMethod": "Credit Card",
"startDate": "2024-01-01"
}Response (201):
{
"success": true,
"data": {
"_id": "507f1f77bcf86cd799439012",
"name": "Netflix",
"price": 15.99,
"currency": "USD",
"frequency": "monthly",
"category": "entertainment",
"paymentMethod": "Credit Card",
"status": "active",
"startDate": "2024-01-01T00:00:00.000Z",
"renewalDate": "2024-01-31T00:00:00.000Z",
"user": "507f1f77bcf86cd799439011"
},
"workflowRunId": "wfr_1234567890"
}GET /api/v1/subscriptions/user/:userId
Authorization: Bearer <token>Response (200):
{
"success": true,
"data": [
{
"_id": "507f1f77bcf86cd799439012",
"name": "Netflix",
"price": 15.99,
"currency": "USD",
"frequency": "monthly",
"category": "entertainment",
"paymentMethod": "Credit Card",
"status": "active",
"startDate": "2024-01-01T00:00:00.000Z",
"renewalDate": "2024-01-31T00:00:00.000Z",
"user": "507f1f77bcf86cd799439011"
}
]
}POST /api/v1/workflows/subscription/reminder
Content-Type: application/json
{
"subscriptionId": "507f1f77bcf86cd799439012"
}{
"success": false,
"message": "Validation failed",
"errors": [
{
"field": "email",
"message": "Please fill a valid email address"
}
]
}{
"success": false,
"message": "Unauthorized"
}{
"success": false,
"message": "User not found"
}{
"success": false,
"message": "User already exists"
}For protected routes, include the JWT token:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
USD- US DollarEUR- EuroGBP- British PoundINR- Indian Rupee
daily- Daily billingweekly- Weekly billingmonthly- Monthly billingyearly- Yearly billing
sports- Sports subscriptionsnews- News subscriptionsentertainment- Entertainment subscriptionslifestyle- Lifestyle subscriptionstechnology- Technology subscriptionsfinance- Finance subscriptionspolitics- Politics subscriptionsother- Other categories
active- Active subscriptioncancelled- Cancelled subscriptionexpired- Expired subscription
subscription-tracker/
βββ config/
β βββ arcjet.js # Arcjet security configuration
β βββ env.js # Environment variables
β βββ nodemailer.js # Email service configuration
β βββ upstash.js # Upstash workflow client
βββ controllers/
β βββ auth.controller.js # Authentication logic
β βββ subscription.controller.js # Subscription CRUD operations
β βββ user.controller.js # User management
β βββ workflow.controller.js # Workflow automation
βββ database/
β βββ mongodb.js # Database connection
βββ middlewares/
β βββ arcjet.middleware.js # Security middleware
β βββ auth.middleware.js # JWT authentication
β βββ error.middleware.js # Error handling
βββ models/
β βββ subscription.model.js # Subscription schema
β βββ user.model.js # User schema
βββ routes/
β βββ auth.routes.js # Authentication routes
β βββ subscription.routes.js # Subscription routes
β βββ user.routes.js # User routes
β βββ workflow.routes.js # Workflow routes
βββ utils/
β βββ email-template.js # Email templates
β βββ send-emaill.js # Email sending utility
βββ app.js # Application entry point
βββ package.json # Dependencies and scripts
name: String (required, 2-50 characters)email: String (required, unique, validated)password: String (required, min 6 characters, hashed)
name: String (required, 2-100 characters)price: Number (required, min 0)currency: Enum ['USD', 'EUR', 'GBP', 'INR']frequency: Enum ['daily', 'weekly', 'monthly', 'yearly']category: Enum ['sports', 'news', 'entertainment', 'lifestyle', 'technology', 'finance', 'politics', 'other']paymentMethod: String (required)status: Enum ['active', 'cancelled', 'expired']startDate: Date (required, must be in past)renewalDate: Date (auto-calculated based on frequency)user: ObjectId (reference to User)
The application automatically sends email reminders at:
- 7 days before renewal
- 5 days before renewal
- 2 days before renewal
- 1 day before renewal
- JWT Authentication: Secure token-based authentication
- Password Hashing: bcrypt with salt rounds
- Input Validation: Mongoose schema validation
- Rate Limiting: Arcjet middleware protection
- CORS: Cross-origin resource sharing configuration
- Error Handling: Centralized error management
This application is deployed on AWS EC2 using PM2 for process management.
# Install PM2 globally
npm install -g pm2
# Start application with PM2 (using npm start)
pm2 start npm --name subdub -- start
# Save PM2 configuration
pm2 save
# Setup PM2 to start on system boot
pm2 startup
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ec2-user --hp /home/ec2-user
# Monitor application
pm2 status
pm2 logs subdub# Restart application
pm2 restart subdub
# Stop application
pm2 stop subdub
# View logs
pm2 logs subdub --lines 100
# Monitor resources
pm2 monit
# Kill processes on port (if needed)
pkill node
lsof -i :5500Create .env.production.local file:
NODE_ENV='production'
PORT=5500
SERVER_URL="http://localhost:5500"
DB_URI="your_mongodb_production_uri"
JWT_SECRET="your_strong_production_secret"
JWT_EXPIRES_IN="1d"
ARCJET_KEY="your_arcjet_production_key"
ARCJET_ENV="production"
QSTASH_URL="your_qstash_url"
QSTASH_TOKEN="your_qstash_token"
EMAIL_PASSWORD="your_email_password"- Ensure
NODE_ENV=productionis set in package.json start script - Use
openssl rand -hex 64to generate secure JWT secrets - Configure Arcjet for production IP handling
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Built with Node.js and a production-grade backend stack