A modern, full-stack subscription management application built with Turborepo, Node.js/Express, Next.js, MongoDB, and Google Gemini AI.
Loopify is a sophisticated monorepo-based application that helps users manage their subscriptions efficiently. It features user authentication, subscription tracking, AI-powered responses, and automated email reminders.
- Turborepo ^2.6.1 - Monorepo management and task orchestration
- PNPM ^10.19.0 - Fast, disk-space-efficient package manager
- TypeScript 5.9+ - Full static type checking across the project
- Node.js β₯18 - JavaScript runtime
- Express ^5.1.0 - Web application framework
- MongoDB - NoSQL database
- Mongoose ^9.0.0 - MongoDB object modeling
- Next.js ^16.1.4 - React framework with SSR/SSG
- React ^19.2.0 - UI library
- Next.js Auth ^4.24.13 - Authentication solutions
- Google Gemini AI (@google/genai) - AI-powered responses
- Google Auth Library ^10.5.0 - OAuth2 authentication
- Nodemailer ^7.0.12 - Email sending service
- Tailwind CSS ^4.1.5 - Utility-first CSS framework
- Tailwind PostCSS ^4.1.5 - PostCSS plugin for Tailwind
- Custom Theme - Blue (#2a8af6), Purple (#a853ba), Red (#e92a67)
- Bcrypt ^6.0.0 - Password hashing
- JSON Web Tokens (JWT) ^9.0.2 - Secure token-based authentication
- Zod ^4.1.13 - TypeScript-first schema validation
- Nodemon ^3.1.11 - Auto-reload during development
- TSX ^4.21.0 - TypeScript execution for Node.js
- ESLint - Code linting
- Prettier - Code formatting
loopify/
βββ apps/
β βββ server/ # Express API backend
β β βββ src/
β β β βββ index.ts # Main entry point
β β β βββ database/
β β β β βββ connection.ts # MongoDB connection
β β β βββ controllers/
β β β β βββ login.controller.ts
β β β β βββ signup.controller.ts
β β β β βββ subscription.controller.ts
β β β β βββ response.controller.ts (AI)
β β β β βββ mailer/ # Email controllers
β β β βββ routes/
β β β β βββ login.routes.ts
β β β β βββ signup.routes.ts
β β β β βββ subscription.routes.ts
β β β β βββ response.routes.ts
β β β β βββ reminderMail.routes.ts
β β β β βββ authentication/
β β β βββ models/
β β β β βββ signupModel.ts # User schema
β β β β βββ subscription.model.ts
β β β βββ schema/
β β β β βββ signup.schema.ts
β β β β βββ subscription.schemas.ts
β β β βββ authentication/
β β β β βββ middleware.authentication.ts
β β β β βββ verify-otp.authentication.ts
β β β βββ integrations/
β β β β βββ geminiClient.ts # Google Gemini AI
β β β βββ interface/ # TypeScript interfaces
β β β βββ utils/
β β β β βββ services/
β β β β β βββ mailer.ts
β β β β β βββ reminderMailer.ts
β β β β βββ password/ # Bcrypt utilities
β β β β βββ token/ # JWT utilities
β β β β βββ signup/ # Signup logic
β β β β βββ login/ # Login logic
β β β β βββ otp/ # OTP generation
β β β β βββ zod/ # Validation schemas
β β β β βββ google/ # OAuth logic
β β β β βββ subscription/ # Subscription logic
β β β βββ types/ # TypeScript type definitions
β β β βββ middlewares/
β β βββ package.json
β β βββ tsconfig.json
β β
β βββ web/ # Next.js frontend
β βββ app/
β β βββ layout.tsx # Root layout (Geist font)
β β βββ page.tsx # Landing page
β β βββ [landing]/
β β β βββ [...]landingCards/
β β β βββ [...]landingPrice/
β β β βββ [...]landingSteps/
β β β βββ [...]landingSubscription/
β β βββ dashboard/ # User dashboard
β β βββ login/ # Login page
β β βββ signup/ # Signup page
β β βββ oauth2callback/ # OAuth callback
β β βββ api/ # API routes
β β β βββ get/
β β β βββ post/
β β β βββ put/
β β β βββ delete/
β β βββ globals.css # Global styles
β βββ public/
β βββ utils/
β βββ package.json
β βββ next.config.ts
β βββ tsconfig.json
β βββ tailwind.config.ts
β
βββ packages/ # Shared packages
β βββ eslint-config/
β β βββ base.js # Base ESLint config
β β βββ next.js # Next.js ESLint rules
β β βββ react-internal.js # React rules
β βββ tailwind-config/
β β βββ shared-styles.css # Custom theme colors
β β βββ postcss.config.js
β βββ typescript-config/
β β βββ base.json # Base TypeScript config
β β βββ nextjs.json # Next.js config
β β βββ react-library.json # React library config
β βββ ui/ # Shared React components
β βββ src/
β β βββ card.tsx
β β βββ gradient.tsx
β β βββ styles.css
β β βββ tailwindcss/
β
βββ pnpm-workspace.yaml # PNPM workspace config
βββ turbo.json # Turborepo config
βββ package.json # Root package.json
βββ README.md
β
User Registration - Email-based signup with password hashing (Bcrypt)
β
JWT Authentication - Secure token-based API access
β
OTP Verification - Email OTP for account verification
β
Google OAuth - Social login via Google
β
Middleware Protection - All protected routes require valid JWT token
β
Create Subscriptions - Track multiple subscriptions with detailed metadata
β
Categories - Organize by Productivity, Education, Entertainment, Utility, Other
β
Plan Types - Monthly, Yearly, Free, Trial options
β
Auto-Renewal - Track auto-renewal status
β
Payment Methods - Credit Card, Debit Card, PayPal, UPI support
β
Billing Reminders - Automatic reminders 1, 3, 7, 14, or 30 days before renewal
β
OTP Emails - Beautiful HTML formatted verification codes
β
Reminder Emails - Customizable billing reminders
β
Gmail SMTP - Secure email delivery via Gmail
β
Google Gemini 2.5 Flash - AI-powered prompt responses
β
Real-time Processing - Low-latency responses
β
Full TypeScript - Every file is type-safe
β
Zod Validation - Runtime schema validation
β
Interface Definitions - Comprehensive TypeScript interfaces
{
_id: ObjectId;
email: string;
password: string (hashed with Bcrypt);
otp: string | null;
createdAt?: Date;
updatedAt?: Date;
}{
_id: ObjectId;
userId: ObjectId (ref: Users);
appName: string;
category: "Productivity" | "Education" | "Entertainment" | "Utility" | "Other";
planType: "Monthly" | "Yearly" | "Free" | "Trial";
amount: number;
currency: string (e.g., "USD", "INR");
paymentMethod: "Credit Card" | "Debit Card" | "PayPal" | "Upi" | "Other";
autoRenew: boolean;
startDate: Date;
nextBillingDate: Date;
reminderDaysBefore: 1 | 3 | 7 | 14 | 30;
createdAt?: Date;
updatedAt?: Date;
}POST /google - Google OAuth login
POST /otp-verification/:id - Verify OTP
POST /create-user - Create new user
GET /get-user/:userId - Get user info (Protected)
DELETE /delete-user/:userId - Delete user (Protected)
POST /login-user - User login with email/password
POST /create-subscription - Create new subscription (Protected)
GET /get-subscription/:id - Get subscription details (Protected)
PUT /update-subscription - Update subscription (Protected)
DELETE /delete-subscription - Delete subscription (Protected)
POST /one-day-reminder/:id - Send 1-day reminder (Protected)
POST /three-day-reminder/:id - Send 3-day reminder (Protected)
POST /seven-day-reminder/:id - Send 7-day reminder (Protected)
POST /fourteen-day-reminder/:id - Send 14-day reminder (Protected)
POST /thirty-day-reminder/:id - Send 30-day reminder (Protected)
POST /create-prompt-response - Get AI response via Gemini
# Database
MONGODB_URI=mongodb+srv://user:password@cluster.mongodb.net/database
# Authentication
JWT_SECRET=your-secret-key-here
# Email Service
USER_EMAIL=your-gmail@gmail.com
USER_PASS=your-app-specific-password
# Google OAuth
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
# AI Integration
GEMINI_API_KEY=your-gemini-api-key
# Server Port
PORT=3000NEXT_PUBLIC_API_URL=http://localhost:3000/api/v1
NEXT_PUBLIC_GOOGLE_CLIENT_ID=your-google-client-id- Node.js β₯18
- PNPM β₯10.19.0
- MongoDB Atlas account
- Gmail account (for email service)
- Google Cloud project (for OAuth & Gemini API)
-
Clone the repository
git clone https://github.com/yourusername/loopify.git cd loopify -
Install dependencies
pnpm install
-
Configure environment variables
# Copy .env template to .env cp apps/server/.env.example apps/server/.env cp apps/web/.env.example apps/web/.env.local # Fill in your credentials
-
Start development servers
# Run all apps in parallel pnpm dev # Server: http://localhost:3000 # Web: http://localhost:3001
# Build all packages and apps
pnpm build
# Start production server
pnpm startpnpm dev # Start all apps in development mode
pnpm build # Build all packages and apps
pnpm lint # Run ESLint across all packages
pnpm check-types # Type check all TypeScript files
pnpm badiya # Format code with Prettierpnpm --filter server dev # Start Express server in dev mode
pnpm --filter server build # Build TypeScript to dist/
pnpm --filter server start # Run production buildpnpm --filter web dev # Start Next.js dev server
pnpm --filter web build # Build Next.js for production
pnpm --filter web start # Start production server- Version: 4.1.5
- PostCSS: Enabled with autoprefixer
- Custom Colors:
--color-blue-1000: #2a8af6 (Primary) --color-purple-1000: #a853ba (Secondary) --color-red-1000: #e92a67 (Accent)
- Global styles in
apps/web/app/globals.css - Shared theme in
packages/tailwind-config/shared-styles.css - Component styles with Tailwind utilities
- Custom CSS prefixes for UI components (
ui-prefix)
- Primary Font: Geist (Google Font)
- Fallback: System fonts (Segoe UI, Tahoma, Geneva, Verdana)
- User signs up β password hashed with Bcrypt
- JWT token generated with user ID
- Token sent to client
- Client includes token in Authorization header:
Bearer {token} - Middleware verifies token on protected routes
- User registration β OTP generated (4 digits)
- Email sent via Nodemailer β Beautiful HTML template
- User submits OTP β Server validates
- Account activated β OTP cleared from DB
- User initiates Google login
- Redirect to Google authentication
- Google returns authorization code
- Server exchanges code for tokens
- User info retrieved and stored/updated
- Service: Gmail SMTP
- Authentication: App-specific password (recommended)
- Templates: HTML + Plain text fallback
- OTP Verification - Account setup
- Billing Reminders - 1, 3, 7, 14, 30 days before renewal
- Custom Emails - Extensible design
- Responsive HTML design
- Gradient headers
- Mobile-friendly
- Brand colors and styling
- Model: Gemini 2.5 Flash
- Purpose: Generate AI-powered responses to user prompts
- Endpoint:
POST /api/v1/response/create-prompt-response
POST http://localhost:3000/api/v1/response/create-prompt-response
Content-Type: application/json
{
"prompt": "How can I manage my subscriptions better?"
}{
"success": true,
"prompt": "How can I manage my subscriptions better?",
"aiResponse": "Here are some strategies..."
}- Zod Schemas - Runtime type checking
- Email Validation - Format verification
- Password Requirements - Strength checking
- OTP Expiration - Time-based validation
pnpm check-types # Full TypeScript compilation checkpnpm lint # ESLint with strict rules
pnpm badiya # Prettier auto-formattingβ
Shared Dependencies - Single node_modules installation
β
Consistent TypeScript Configuration - Across all projects
β
Unified Linting & Formatting - ESLint, Prettier configs
β
Efficient Builds - Task orchestration & caching
β
Workspace Dependencies - Easy local package imports
@repo/eslint-config- ESLint configurations@repo/tailwind-config- Tailwind CSS theme@repo/typescript-config- TypeScript configurations@repo/ui- Shared React components
- Try-catch blocks in all controllers
- Consistent error response format
- Detailed console logging
- HTTP status codes (400, 401, 404, 500)
{
"success": false,
"message": "Descriptive error message",
"error": "Optional error details"
}- CORS - Cross-origin requests enabled
- JSON Parser - Express built-in (5MB limit)
- Dotenv - Environment variable loading
- JWT Authentication - Token verification for protected routes
# Build TypeScript
pnpm --filter server build
# Output: apps/server/dist/
# Start: node ./dist/index.js# Build Next.js
pnpm --filter web build
# Output: apps/web/.next/
# Start: next start- TypeScript compilation ready
- Environment variables configurable
- Both apps containerizable
- Express: Lightweight API framework
- Mongoose: Minimal DB overhead
- Zod: ~15KB validation library
- Bcrypt: Native binding for fast hashing
- JWT: Stateless authentication
- β Tree-shaking with native ES modules
- β TypeScript strict mode for safety
- β Minimal dependencies
- β Tailwind CSS production optimization
-
Create Route
// routes/feature.routes.ts router.route('/endpoint').post(controller);
-
Create Controller
// controllers/feature.controller.ts export const controller = async (req: Request, res: Response) => { // Implementation };
-
Add Validation Schema
// schema/feature.schema.ts export const featureSchema = z.object({ field: z.string() });
-
Create Model (if needed)
// models/feature.model.ts const Feature = mongoose.model('Features', schema);
- Turborepo: https://turbo.build/
- Express: https://expressjs.com/
- Next.js: https://nextjs.org/
- Mongoose: https://mongoosejs.com/
- Tailwind CSS: https://tailwindcss.com/
- Zod: https://zod.dev/
- Google Gemini: https://ai.google.dev/
- Nodemailer: https://nodemailer.com/
ISC
- Create a feature branch
- Make your changes
- Test with
pnpm check-typesandpnpm lint - Submit a pull request
For support, email support@loopify.app or open an issue on GitHub.
Built with β€οΈ using Turborepo, TypeScript, and modern web technologies