This is the backend API for JouleAI, an AI-powered e-commerce store builder platform. The backend is built with Node.js, Express, and MongoDB (Mongoose).
Purpose: Manages user authentication and account information.
Schema Structure:
{
name: String, // Required, max 50 chars
email: String, // Required, unique, validated email format
passwordHash: String, // Required, auto-hashed with bcrypt (salt rounds: 12)
timestamps: true // createdAt, updatedAt
}Key Features:
- Password hashing with bcrypt (pre-save hook)
- Email validation with regex
- Password comparison method:
comparePassword(candidatePassword) - Automatic removal of
passwordHashfrom JSON responses
Indexes:
email: unique index
Purpose: Represents an e-commerce store created by a user.
Schema Structure:
{
ownerId: ObjectId, // Required, ref: 'User'
storeName: String, // Required, max 100 chars
domain: String, // Required, unique, lowercase, validated format
description: String, // Optional, max 500 chars
isActive: Boolean, // Default: true
theme: Object, // Store theme configuration
layout: Object, // Store layout structure
currency: String, // Default: 'USD'
locale: String, // Default: 'en-US'
// AI-generated layout
jsonLayout: Object, // JSON structure for publishing
// Publishing & Deployment
publishedUrl: String, // Vercel deployment URL
vercelDeploymentId: String, // Vercel deployment ID
vercelProjectName: String, // Vercel project name
vercelAlias: String, // Custom domain alias
lastPublished: Date, // Last publish timestamp
// Approval & Theme
approved: Boolean, // Default: false
chosenThemeId: String, // Selected theme ID
timestamps: true // createdAt, updatedAt
}Key Features:
- Domain format validation (lowercase, alphanumeric with hyphens/dots)
- Theme and layout stored as flexible objects
- Vercel integration for deployment tracking
- Support for both
layoutandjsonLayout(for backward compatibility)
Indexes:
ownerId: indexed for fast user queriesdomain: unique, indexed for lookups
Purpose: Represents products within a store.
Schema Structure:
{
storeId: ObjectId, // Required, ref: 'Store'
name: String, // Required, max 150 chars
description: String, // Optional
price: Number, // Required, min: 0
stock: Number, // Required, min: 0, default: 0
// Images (supports old and new formats)
images: Mixed[], // Array of strings OR objects {url, publicId}
// Publishing status
status: String, // Enum: ['draft', 'published'], default: 'draft'
publishedAt: Date, // Timestamp when published
timestamps: true // createdAt, updatedAt
}Key Features:
- Flexible image storage (backward compatible)
- Old format: Array of URL strings
- New format: Array of objects
{url, publicId, ...}
- Product status lifecycle (draft → published)
- Custom validator for images array
Indexes:
storeId: indexed for store queriesname: indexed for search
Purpose: Manages team/organization structures for collaboration.
Schema Structure:
{
name: String, // Required, max 100 chars
slug: String, // Required, unique, lowercase, hyphenated
ownerId: ObjectId, // Required, ref: 'User'
settings: Object, // Team configuration settings
timestamps: true // createdAt, updatedAt
}Key Features:
- URL-friendly slug validation (lowercase, hyphens only)
- Flexible settings object for team preferences
- Team ownership tracked via
ownerId
Indexes:
slug: unique indexownerId: indexed for owner queries
Purpose: Links users to teams with specific roles.
Schema Structure:
{
teamId: ObjectId, // Required, ref: 'Team'
userId: ObjectId, // Required, ref: 'User'
role: String, // Enum: ['owner', 'admin', 'member'], default: 'member'
mfaEnabled: Boolean, // Default: false
invitedBy: ObjectId, // Optional, ref: 'User'
timestamps: true // createdAt, updatedAt
}Key Features:
- Role-based access control (owner > admin > member)
- MFA setting per membership
- Tracks who invited the member
Indexes:
{teamId, userId}: compound unique index (prevents duplicate memberships){teamId, role}: compound index for role-based queries
Purpose: Manages pending team invitations.
Schema Structure:
{
teamId: ObjectId, // Required, ref: 'Team'
email: String, // Required, lowercase, validated
role: String, // Enum: ['admin', 'member'], default: 'member'
token: String, // Required, unique, random hex (48 chars)
invitedBy: ObjectId, // Required, ref: 'User'
expiresAt: Date, // Default: 7 days from creation
acceptedAt: Date, // Null until accepted
timestamps: true // createdAt, updatedAt
}Key Features:
- Secure token generation:
generateToken()static method - Automatic expiration (7 days)
- TTL index for auto-cleanup of expired invites
- Tracks acceptance status
Indexes:
{teamId, email}: compound index for invite lookupstoken: unique indexexpiresAt: TTL index with partial filter (only unaccepted invites)
Static Methods:
TeamInvite.generateToken(): Generates a secure random token
Base Path: /api/auth
| Method | Endpoint | Access | Description |
|---|---|---|---|
| POST | /register |
Public | Register a new user |
| POST | /login |
Public | Login and receive JWT token |
| GET | /me |
Private | Get current user info |
Request/Response Examples:
POST /api/auth/register
// Request
{
"name": "John Doe",
"email": "john@example.com",
"password": "securepass123"
}
// Response (201)
{
"success": true,
"message": "User registered successfully",
"data": {
"user": { "_id": "...", "name": "John Doe", "email": "john@example.com" },
"token": "jwt_token_here"
}
}POST /api/auth/login
// Request
{
"email": "john@example.com",
"password": "securepass123"
}
// Response (200)
{
"success": true,
"message": "Login successful",
"data": {
"user": { "_id": "...", "name": "John Doe", "email": "john@example.com" },
"token": "jwt_token_here"
}
}GET /api/auth/me
// Headers: Authorization: Bearer <token>
// Response (200)
{
"success": true,
"data": {
"user": { "_id": "...", "name": "John Doe", "email": "john@example.com" }
}
}Base Path: /api/store
| Method | Endpoint | Access | Description |
|---|---|---|---|
| POST | / |
Private | Create a new store |
| GET | / |
Private | Get all stores for authenticated user |
| GET | /:id |
Public | Get store by ID |
| PUT | /:id |
Private (Owner) | Update store details |
| DELETE | /:id |
Private (Owner) | Delete store |
Models Used: Store
Key Features:
- Domain uniqueness validation
- Owner-only modification/deletion
- Population of owner information
Base Path: /api/product
| Method | Endpoint | Access | Description |
|---|---|---|---|
| POST | / |
Private (Owner) | Create a new product |
| GET | /:storeId |
Public | Get products for a store (with pagination, search, filters) |
| GET | /item/:id |
Public | Get single product by ID |
| PUT | /:id |
Private (Owner) | Update product |
| DELETE | /:id |
Private (Owner) | Delete product (with image cleanup) |
| POST | /bulk |
Private (Owner) | Bulk actions (delete, publish, unpublish) |
Models Used: Product, Store
Key Features:
- Advanced querying: pagination, search, sorting, status filtering
- Automatic Cloudinary image cleanup on deletion
- Bulk operations for efficiency
- Owner validation via
ownerCheckMiddleware
Query Parameters for GET /:storeId:
page: Page number (default: 1)limit: Items per page (default: 12, max: 100)search: Search term (name, description)sortBy: Field to sort by (name, price, stock, createdAt, updatedAt)sortDir: Sort direction (asc, desc)status: Filter by status (draft, published)
Base Path: /api/store
| Method | Endpoint | Access | Description |
|---|---|---|---|
| GET | /test-ai |
Public | Test AI service availability |
| POST | /:storeId/ai-prompt |
Private (Owner) | Generate store design with AI |
| POST | /:storeId/generate-component |
Private (Owner) | Generate individual React component |
| GET | /:storeId/react-website |
Private (Owner) | Get React website data |
| GET | /:storeId/preview |
Private (Owner) | Generate HTML preview of store |
Models Used: Store
Key Features:
- OpenAI integration for AI-powered store generation
- Industry-specific design templates (ecommerce, SaaS, portfolio, restaurant, etc.)
- React component generation with fallback templates
- Dynamic content generation based on user prompts
- Live HTML preview generation
- Support for multiple design archetypes and style presets
AI Prompt Example:
// POST /:storeId/ai-prompt
{
"prompt": "Create a modern coffee shop website with warm colors",
"mode": "create",
"industry": "ecommerce"
}
// Response includes generated React components, theme, and layoutBase Path: /api/store
| Method | Endpoint | Access | Description |
|---|---|---|---|
| PUT | /:storeId/approve |
Private (Owner) | Approve store for publishing |
| GET | /:storeId/editor |
Private (Owner) | Get editor data (layout, products) |
| POST | /:storeId/editor-update |
Private (Owner) | Update store from editor |
| POST | /themes/choose |
Private | Choose a theme for store |
Models Used: Store, Product
Key Features:
- Editor data payload includes full layout and products
- Batch product operations (create, update, delete)
- Theme selection management
- Syncs both
layoutandjsonLayoutfields
Base Path: /api/store
| Method | Endpoint | Access | Description |
|---|---|---|---|
| POST | /:storeId/publish |
Private (Owner) | Publish store to Vercel |
| GET | /:storeId/publish/status |
Private (Owner) | Get publishing status |
| PUT | /:storeId/layout |
Private (Owner) | Update store layout |
| DELETE | /:storeId/unpublish |
Private (Owner) | Unpublish store |
| GET | /:storeId/debug-layout |
Private (Owner) | Debug layout data |
Models Used: Store
Key Features:
- Vite + React project generation
- Vercel deployment integration
- Automatic build directory cleanup
- Project name and alias management
- Deployment status tracking
Base Path: /api/teams
| Method | Endpoint | Access | Description |
|---|---|---|---|
| POST | / |
Private | Create a new team |
| GET | /my |
Private | Get all teams for user |
| GET | /:teamId |
Private (Member) | Get team by ID |
| PUT | /:teamId |
Private (Owner/Admin) | Update team details |
| GET | /:teamId/members |
Private (Member) | List team members |
| POST | /:teamId/invites |
Private (Owner/Admin) | Invite member to team |
| POST | /invites/accept |
Private | Accept team invitation |
| PUT | /:teamId/members/:userId |
Private (Owner/Admin) | Update member role/MFA |
| DELETE | /:teamId/members/:userId |
Private (Owner/Admin or Self) | Remove member or leave team |
Models Used: Team, TeamMembership, TeamInvite, User
Key Features:
- Automatic slug generation from team name
- Role-based access control (owner, admin, member)
- Invite system with token generation
- Email-based invitations
- MFA settings per membership
- Protection against removing last owner
- Self-service leaving teams
Base Path: /api/upload
| Method | Endpoint | Access | Description |
|---|---|---|---|
| POST | /images |
Private | Upload multiple images (max 10) |
| POST | /single-image |
Private | Upload single image |
| DELETE | /images |
Private | Delete images from Cloudinary |
| GET | /health |
Public | Check upload service health |
Key Features:
- Cloudinary integration for image storage
- File size limit: 10MB per file
- Supported formats: jpg, jpeg, png, webp, gif
- Automatic public ID tracking
- Bulk delete support
- Health check endpoint
Purpose: Validates JWT tokens and attaches user to request.
Usage:
router.get('/protected', authMiddleware, (req, res) => {
// req.user contains authenticated user
});Purpose: Validates that the authenticated user owns a resource (store, product, etc.).
Usage:
router.put('/:storeId', authMiddleware,
ownerCheckMiddleware((req) => req.params.storeId),
async (req, res) => {
// req.store contains the validated store
}
);Features:
- Flexible resource ID extraction via function parameter
- Automatic store lookup and validation
- Attaches
req.storefor use in route handler
User (1) ──────────> (N) Store
│
└──> (N) Product
User (1) ──────────> (N) Team (as owner)
│ │
│ └──> (N) TeamMembership
│
└──────────> (N) TeamMembership (as member)
Team (1) ──────────> (N) TeamInvite
│
└──────────> (N) TeamMembership
User (1) ──────────> (N) TeamInvite (as inviter)
- User → Store: One user can own multiple stores (
ownerId) - Store → Product: One store can have multiple products (
storeId) - Team → User: Many-to-many via
TeamMembership - Team → TeamInvite: One team can have multiple pending invites
- User → TeamInvite: One user can send multiple invites
1. User registers/logs in → receives JWT
2. User creates Store → store.ownerId = user._id
3. User adds Products → product.storeId = store._id
4. User generates AI design → store.layout, store.jsonLayout updated
5. User approves store → store.approved = true
6. User publishes store → Vercel deployment
→ store.publishedUrl, store.vercelDeploymentId updated
1. User creates Team → team.ownerId = user._id
2. TeamMembership auto-created → role: 'owner'
3. Owner invites member → TeamInvite created with token
4. Invitee accepts → TeamMembership created, invite.acceptedAt updated
5. Owner/admin can manage roles → Update TeamMembership.role
Required environment variables:
# MongoDB
MONGODB_URI=mongodb://localhost:27017/JouleAI
# JWT
JWT_SECRET=your_jwt_secret_here
# OpenAI (for AI features)
OPENAI_API_KEY=sk-...
OPENAI_PROJECT_ID=optional
OPENAI_ORG_ID=optional
OPENAI_MODEL=gpt-4o-mini
# Cloudinary (for image uploads)
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
# Vercel (for deployment)
VERCEL_TOKEN=your_vercel_token
# Server
PORT=5000
NODE_ENV=developmentAll API responses follow a consistent format:
Success Response:
{
"success": true,
"message": "Operation successful",
"data": {
// Response data here
}
}Error Response:
{
"success": false,
"message": "Error message here",
"error": "Detailed error (dev mode only)"
}200: Success201: Created400: Bad Request (validation errors)401: Unauthorized (missing/invalid token)403: Forbidden (insufficient permissions)404: Not Found500: Server Error503: Service Unavailable (external service issues)
Mongoose validation errors are caught and formatted:
{
"success": false,
"message": "Email is required" // First validation error
}- Password Hashing: Bcrypt with 12 salt rounds
- JWT Authentication: 7-day token expiration
- Owner Validation: Middleware ensures resource ownership
- Email Validation: Regex validation on email fields
- Input Sanitization: Trim and lowercase where appropriate
- Rate Limiting: (Recommended to implement)
- CORS: Configure for production
- Environment Variables: Sensitive data in .env
- Register User:
curl -X POST http://localhost:5000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"name":"Test User","email":"test@example.com","password":"password123"}'- Create Store:
curl -X POST http://localhost:5000/api/store \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"storeName":"My Store","domain":"mystore"}'- Add Product:
curl -X POST http://localhost:5000/api/product \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"storeId":"STORE_ID","name":"Product 1","price":99.99,"stock":10}'- Add rate limiting for public endpoints
- Implement caching (Redis) for frequently accessed data
- Add search indexing (Elasticsearch/Algolia) for products
- Webhook system for Vercel deployment notifications
- Email service integration for team invites
- Admin dashboard endpoints
- Analytics endpoints for store owners
- Payment integration (Stripe/PayPal)
- Order management system
- Customer management and CRM features
For questions or issues, please refer to the main project README or contact the development team.
Last Updated: October 2025