- Project Overview
- Tech Stack
- Project Structure
- Architecture
- Database Design
- API Routes
- Authentication & Authorization
- Key Features
- Configuration
- Development Guide
iLearning Backend is a subscription-based learning platform backend application built with Express.js, PostgreSQL, and Prisma ORM. The system manages student subscriptions, billing plans, and payment processing through Stripe integration.
It also uses the Genkit API to generate AI-powered quiz questions for the learning module.
- Student registration and authentication
- Subscription plan management
- Payment processing and webhook handling
- Role-based access control
- Premium content access management
- AI quiz question generation using Genkit
| Category | Technology | Version |
|---|---|---|
| Runtime | Node.js | - |
| Framework | Express.js | ^5.2.1 |
| Language | TypeScript | - |
| Database | PostgreSQL | - |
| ORM | Prisma | ^7.3.0 |
| Authentication | Better Auth | ^1.4.18 |
| Payment Gateway | Stripe | ^20.3.1 |
| AI Quiz Generation | Genkit | ^1.31.0 |
| Validation | Zod | ^4.3.6 |
| JWT | jsonwebtoken | ^9.0.3 |
| CORS | cors | ^2.8.6 |
| Environment | dotenv | ^17.2.3 |
ilearning-backend/
├── prisma/
│ ├── migrations/ # Database migrations
│ │ ├── migration_lock.toml
│ │
│ └── schema/ # Prisma schema files (modular)
│ ├── auth.prisma # Auth-related models
│ ├── enum.prisma # Enums (Role, Status types)
│ ├── payment.prisma # Payment model
│ ├── plan.prisma # Billing plan model
│ ├── schema.prisma # Main schema configuration
│ └── subscription.prisma # Subscription model
│
├── src/
│ ├── app.ts # Express app initialization
│ ├── server.ts # Server entry point
│ │
│ ├── app/
│ │ ├── config/ # Configuration files
│ │ │ ├── env.ts # Environment variables validation
│ │ │ └── stripe.config.ts # Stripe API configuration
│ │ │
│ │ ├── errorHelpers/ # Error handling utilities
│ │ │ ├── AppError.ts # Custom error class
│ │ │ ├── handlePrismaErrors.ts
│ │ │ └── handleZodError.ts
│ │ │
│ │ ├── interfaces/ # TypeScript interfaces & types
│ │ │ ├── error.interface.ts
│ │ │ ├── index.d.ts
│ │ │ └── requestUser.interface.ts
│ │ │
│ │ ├── lib/ # Core libraries
│ │ │ ├── auth.ts # Better Auth configuration
│ │ │ └── prisma.ts # Prisma client instance
│ │ │
│ │ ├── middleware/ # Express middleware
│ │ │ ├── checkAuth.ts # Authentication middleware
│ │ │ ├── checkPremiumAccess.ts # Premium access verification
│ │ │ ├── globalErrorHandler.ts # Global error handling
│ │ │ ├── notFound.ts # 404 handler
│ │ │ └── validateRequest.ts # Request validation (Zod)
│ │ │
│ │ ├── modules/ # Feature modules (MVC pattern)
│ │ │ ├── auth/ # Authentication module
│ │ │ │ ├── auth.controller.ts
│ │ │ │ ├── auth.route.ts
│ │ │ │ └── auth.service.ts
│ │ │ │
│ │ │ ├── payment/ # Payment processing module
│ │ │ │ ├── payment.controller.ts
│ │ │ │ ├── payment.interface.ts
│ │ │ │ ├── payment.route.ts
│ │ │ │ ├── payment.service.ts
│ │ │ │ └── payment.validation.ts
│ │ │ │
│ │ │ ├── plans/ # Subscription plans module
│ │ │ │ ├── plan.controller.ts
│ │ │ │ ├── plan.route.ts
│ │ │ │ ├── plan.service.ts
│ │ │ │ └── plan.validation.ts
│ │ │ │
│ │ │ └── subscriptions/ # Subscription management module
│ │ │ ├── subscription.controller.ts
│ │ │ ├── subscription.interface.ts
│ │ │ ├── subscription.route.ts
│ │ │ ├── subscription.service.ts
│ │ │ └── subscription.validation.ts
│ │ │
│ │ ├── routes/
│ │ │ └── index.ts # Main API route aggregator
│ │ │
│ │ ├── shared/ # Shared utilities
│ │ │ ├── catchAsync.ts # Async error catcher wrapper
│ │ │ └── sendResponse.ts # Standardized response formatter
│ │ │
│ │ └── utils/ # Helper utilities
│ │ ├── cookie.ts # Cookie management
│ │ ├── jwt.ts # JWT token utilities
│ │ ├── seed.ts # Database seeding
│ │ └── token.ts # Token generation utilities
│ │
│ └── generated/ # Auto-generated Prisma files
│ └── prisma/
│ ├── browser.ts
│ ├── client.ts
│ ├── commonInputTypes.ts
│ ├── enums.ts
│ ├── models.ts
│ └── models/ # Individual model files
│
├── package.json # Project dependencies & scripts
├── pnpm-lock.yaml # Dependency lock file
├── prisma.config.ts # Prisma configuration
├── tsconfig.json # TypeScript configuration
└── PROJECT_DOCUMENTATION.md # This file
The application follows a layered architecture with modular feature-based organization:
┌─────────────────────────────────────────────────┐
│ Express Application (app.ts) │
├─────────────────────────────────────────────────┤
│ Middleware Layer │
│ ├─ CORS, JSON Parser, Cookie Parser │
│ ├─ Authentication (checkAuth) │
│ ├─ Request Validation (validateRequest) │
│ ├─ Global Error Handler │
│ └─ 404 Handler │
├─────────────────────────────────────────────────┤
│ Route Layer (routes/index.ts) │
│ ├─ /api/v1/auth │
│ ├─ /api/v1/plans │
│ ├─ /api/v1/subscriptions │
│ └─ /webhook (Stripe webhook handler) │
├─────────────────────────────────────────────────┤
│ Feature Modules (modules/*) │
│ ├─ Controllers (Handle requests) │
│ ├─ Services (Business logic) │
│ ├─ Validation (Zod schemas) │
│ └─ Routes (Endpoint definitions) │
├─────────────────────────────────────────────────┤
│ Data Access Layer │
│ ├─ Prisma ORM │
│ ├─ Database Models │
│ └─ Query Builders │
├─────────────────────────────────────────────────┤
│ Database (PostgreSQL) │
└─────────────────────────────────────────────────┘
-
MVC (Model-View-Controller)
- Controllers handle HTTP requests
- Services implement business logic
- Models defined via Prisma schemas
-
Middleware Pattern
- Authentication verification
- Request validation
- Error handling
- CORS and security
-
Error Handling Strategy
- Custom
AppErrorclass for controlled errors - Global error handler middleware
- Prisma error handling
- Zod validation error handling
- Custom
-
Response Standardization
- Unified response format via
sendResponseutility - Consistent error responses via global handler
- Unified response format via
┌─────────────┐ ┌─────────────┐
│ User │◄──────│ Subscription│
│ │ │ │
│ id (UUID) │ │ id (UUID) │
│ email │ │ name │
│ role │ │ email │
│ status │ │ profilePhoto│
│ isDeleted │ │ contactNum │
│ │ │ address │
└─────────────┘ │ isDeleted │
└─────────────┘
▲ │
│ │
┌──────┴──────┐ │
│ │ │
┌─────────────┐ ┌──────────┐
│ Plan │ │ Payment │
│ │ │ │
│ id (CUID) │ │ id (UUID)│
│ name │ │ amount │
│ price │ │ status │
│ interval │ │ stripeId │
│ isActive │ │invoiceUrl│
└─────────────┘ └──────────┘
- Managed by Better Auth
- Roles: SUPER_ADMIN, ADMIN, INSTRUCTOR, STUDENT
- Status: ACTIVE, BLOCKED, DELETED
- Additional fields: role, status, needPasswordChange, isDeleted
- One-to-one relation with User
- Stores student profile information
- Multiple subscriptions relationship
- Soft delete support (isDeleted, deletedAt)
- Billing plan configuration
- Pricing and interval (DAILY, MONTHLY, YEARLY, LIFETIME)
- BillingInterval enum for flexible billing periods
- Multiple subscriptions relationship
- Links Student to Plan
- Statuses: PENDING, ACTIVE, CANCELLED, EXPIRED, PAST_DUE, TRIAL
- Payment tracking (PaymentStatus: PAID, UNPAID)
- Temporal tracking (startDate, endDate)
- Stripe integration support (externalRef, paymentProvider)
- Transaction tracking for Stripe
- One-to-one relation with Subscription
- Stores invoice URL and payment gateway data
- Status tracking (PAID, UNPAID)
http://localhost:5000/api/v1
Base Path: /auth
| Method | Endpoint | Protection | Description |
|---|---|---|---|
POST |
/register |
Public | Register new student account |
POST |
/login |
Public | Login user (email & password) |
GET |
/me |
Protected* | Get current user profile |
*Protected: Requires valid session token for ADMIN, SUPER_ADMIN, or STUDENT roles
Register Student
POST /api/v1/auth/register
Content-Type: application/json
{
"email": "student@example.com",
"password": "securePassword123",
"name": "John Doe"
}Login
POST /api/v1/auth/login
Content-Type: application/json
{
"email": "student@example.com",
"password": "securePassword123"
}Get Current User
GET /api/v1/auth/me
Authorization: Bearer <session_token>
Cookie: better-auth.session_token=<token>Base Path: /plans
| Method | Endpoint | Protection | Description |
|---|---|---|---|
GET |
/ |
Public | Get all active plans |
POST |
/ |
Protected** | Create new subscription plan |
Protected: Requires ADMIN role
Get All Plans
GET /api/v1/plansCreate Plan (Admin Only)
POST /api/v1/plans
Authorization: Bearer <session_token>
Content-Type: application/json
{
"name": "Pro Plan",
"slug": "pro-plan",
"description": "Advanced learning features",
"price": 99.99,
"currency": "USD",
"interval": "MONTHLY",
"isActive": true
}Base Path: /subscriptions
| Method | Endpoint | Protection | Description |
|---|---|---|---|
GET |
/ |
Admin Protected | Get all subscriptions (admin view) |
GET |
/my-subscription |
Student Protected | Get current user's subscription |
GET |
/my-premium-access |
Premium Verified | Check premium access status |
POST |
/ |
Student Protected | Create new subscription |
POST |
/initiate-payment/:id |
Student Protected | Initiate Stripe payment for subscription |
POST |
/book-subscription-with-pay-later |
Student Protected | Create subscription with deferred payment |
POST |
/cancel-unpaid |
Admin Protected | Cancel all unpaid subscriptions |
PATCH |
/:id/status |
Admin Protected | Update subscription status |
Get My Subscription
GET /api/v1/subscriptions/my-subscription
Authorization: Bearer <session_token>
Cookie: better-auth.session_token=<token>Create Subscription
POST /api/v1/subscriptions
Authorization: Bearer <session_token>
Cookie: better-auth.session_token=<token>
Content-Type: application/json
{
"planId": "plan_12345",
"studentId": "student_uuid"
}Initiate Payment
POST /api/v1/subscriptions/initiate-payment/subscription_12345
Authorization: Bearer <session_token>
Cookie: better-auth.session_token=<token>Check Premium Access
GET /api/v1/subscriptions/my-premium-access
Authorization: Bearer <session_token>
Cookie: better-auth.session_token=<token>Update Subscription Status
PATCH /api/v1/subscriptions/subscription_12345/status
Authorization: Bearer <session_token>
Content-Type: application/json
{
"status": "ACTIVE"
}| Method | Endpoint | Protection | Description |
|---|---|---|---|
POST |
/webhook |
Stripe Header Verification | Handle Stripe webhook events |
POST /webhook
Content-Type: application/json
stripe-signature: <signature>
{
"type": "payment_intent.succeeded",
"data": {...}
}The webhook endpoint is handled directly in app.ts and uses Stripe's signature verification for security.
-
User Registration/Login
- Uses Better Auth (Open-source authentication framework)
- Email and password-based authentication
- Optional email verification
-
Session Management
- Cookie-based sessions (better-auth.session_token)
- Server-side session validation via database
- Configurable session expiration
-
Token Refresh
- Sessions tracked in database with expiration
- Auto-refresh headers when session nearing expiration
- X-Session-Refresh header indicates refresh needed
Role-Based Access Control (RBAC)
enum Role {
ADMIN // System administration
STUDENT // Access learning content
}Protection Middleware Examples
// Public route
router.post("/register", AuthController.registerStudent)
// Single role required
router.get("/me", checkAuth(Role.STUDENT), AuthController.getMe)
// Multiple roles allowed
router.get("/",
checkAuth(Role.ADMIN, Role.ADMIN),
SubscriptionController.getAllSubscriptions
)- CORS Configuration: Restricted to authenticated frontend origins
- Cookie Security: HttpOnly, Secure flags
- HTTPS Enforced: For production
- Environment Variables: Sensitive data externalized
- Stripe Signature Verification: Webhook validation
- Session Expiration: Automatic cleanup of expired sessions
- Create and manage subscription plans
- Track subscription lifecycle (PENDING → ACTIVE → EXPIRED/CANCELLED)
- Support multiple billing intervals (DAILY, MONTHLY, YEARLY, LIFETIME)
- Status management with full audit trail
- Stripe integration for secure payment handling
- Multiple payment statuses (PAID, UNPAID)
- Pay-later functionality with deferred billing
- Webhook handling for payment confirmations
- Invoice URL storage and tracking
- Middleware-based premium verification
- Student premium access checking
- Status-based access control
- Automatic expiration handling
- Admin-only subscription viewing
- Bulk subscription status updates
- Unpaid subscription management
- Plan creation and management
| Variable | Type | Description | Required |
|---|---|---|---|
NODE_ENV |
string | Environment (development/production) | ✓ |
PORT |
number | Server port | ✓ |
DATABASE_URL |
string | PostgreSQL connection string | ✓ |
BETTER_AUTH_SECRET |
string | Better Auth secret key | ✓ |
BETTER_AUTH_URL |
string | Better Auth service URL | ✓ |
STRIPE_SECRET_KEY |
string | Stripe API secret key | ✓ |
STRIPE_WEBHOOK_SECRET |
string | Stripe webhook secret | ✓ |
FRONTEND_URL |
string | Frontend application URL | ✓ |
SUPER_ADMIN_EMAIL |
string | Super admin email | ✓ |
SUPER_ADMIN_PASSWORD |
string | Super admin password | ✓ |
ACCESS_TOKEN_SECRET |
string | JWT access token secret | ○ |
REFRESH_TOKEN_SECRET |
string | JWT refresh token secret | ○ |
ACCESS_TOKEN_EXPIRES_IN |
string | Access token expiration (e.g., 1h) | ○ |
REFRESH_TOKEN_EXPIRES_IN |
string | Refresh token expiration (e.g., 7d) | ○ |
BETTER_AUTH_SESSION_TOKEN_EXPIRES_IN |
string | Session token expiration | ○ |
BETTER_AUTH_SESSION_TOKEN_UPDATE_AGE |
string | Session refresh age threshold | ○ |
✓ = Required | ○ = Optional
Allowed Origins
[
process.env.FRONTEND_URL,
process.env.BETTER_AUTH_URL,
"http://localhost:3000",
"http://localhost:5000"
]Allowed Methods: GET, POST, PUT, DELETE, PATCH Credentials: Enabled (for cookie-based auth)
# Install dependencies
pnpm install
# Set up environment variables
cp .env.example .env# Run migrations
pnpm run migrate
# Generate Prisma client
pnpm run generate
# Reset database (⚠️ Destroys data)
pnpm run prisma:reset
# Seed database
pnpm run seed# Start development server with hot reload
pnpm run dev
# Build for production
pnpm run build
# Start production server
pnpm run start
# Run linting
pnpm run lint
# Open Prisma Studio (Database GUI)
pnpm run studio# Listen to Stripe webhooks locally
pnpm run stripe:webhook-
Modular Organization
- Each feature has its own folder (auth, plans, subscriptions, etc.)
- Within each module: controller, service, route, validation
-
Separation of Concerns
- Controllers: HTTP request/response handling
- Services: Business logic implementation
- Routes: Endpoint definitions
- Validation: Schema definitions (Zod)
-
Error Handling
- Use
catchAsyncwrapper for async controller functions - Throw
AppErrorfor controlled errors - Global handler catches and formats errors
- Use
-
Database Queries
- Use Prisma client from lib/prisma.ts
- Leverage Prisma's type safety
- Use relations as needed for eager loading
-
Validation
- Define Zod schemas in validation files
- Use validateRequest middleware for input validation
- Type-safe request bodies in controllers
// route.ts
router.post("/", validateRequest(createSchema), Controller.create);
// controller.ts
static create = catchAsync(async (req: Request, res: Response) => {
const result = await Service.create(req.body);
sendResponse(res, { statusCode: 201, data: result });
});
// service.ts
static async create(data: CreateDTO) {
return await prisma.model.create({ data });
}
// validation.ts
export const createSchema = z.object({
// validation rules
});The iLearning Backend is a well-architected Node.js application that implements:
- ✅ Clean layered architecture with modular feature organization
- ✅ Type-safe development with TypeScript and Zod
- ✅ Secure authentication with Better Auth and role-based authorization
- ✅ Reliable payment processing with Stripe integration
- ✅ Database design supporting subscription and billing workflows
- ✅ Comprehensive error handling and validation
- ✅ RESTful API with clear endpoint organization
- ✅ Production-ready code structure and patterns
Last Updated: March 25, 2026 Version: 1.0.0