A MERN stack backend for a virtual auction house where users can bid on items using simulated money. Built as a learning project to master complex backend patterns.
Auction House is a virtual auction platform where users receive simulated money upon signup. They can:
- π Create auctions to sell items
- πΈ Bid on other users' auctions
- π Transfer money between users
- π Win auctions and receive payment
Purpose: Learn complex backend patterns including escrow systems, scheduled jobs, transaction handling, and service architecture.
backend/
βββ src/
β βββ auth/ # Better-Auth configuration
β βββ controllers/ # Request handlers
β βββ db/ # Database connection
β βββ middleware/ # Auth & error handling
β βββ models/ # Mongoose schemas
β βββ routes/ # Express routes
β βββ services/ # Business logic (service layer)
β βββ types/ # TypeScript definitions
β βββ utils/ # Utilities & schedulers
| Pattern | Description |
|---|---|
| Service Layer Architecture | Separation of business logic from controllers |
| Repository Pattern | Models handle data access |
| Error Handling Middleware | Centralized error management |
| Transaction Support | Atomic operations for money transfers |
| Feature | Description |
|---|---|
| User Authentication | Email/password + Google OAuth via Better-Auth |
| Virtual Balance | Users get $1,000β$10,000 on signup |
| Create Auction | List items with title, description, starting price, category, images |
| Place Bid | Bid on auctions with amount validation |
| Bid Locking | Escrow system β funds locked when bidding |
| Auto-Expire | Cron job ends auctions after 24 hours |
| Money Transfer | P2P transfers with transaction support |
| Pagination | All list endpoints support pagination |
| Service Layer | Clean separation of concerns |
| Search | Search auctions by title or description |
| Sort Options | Sort by price (asc/desc), endDate, newest |
| Categories | 9 categories (electronics, jewelry, fashion, etc.) |
| Image Upload | Array of image URLs per auction |
| Auto-Extend | +5 minutes if bid placed in last 5 minutes |
The core learning feature β a complete escrow system for auctions.
User A has $1,000 balance
β
User A bids $500 on Item #1
β
Balance: $500 | Locked: $500 | Available: $500
β
User B bids $600 on Item #1
β
User A refunded β Balance: $1,000 | Locked: $0
User B locked β Balance: $400 | Locked: $600
β
Auction ends
β
Seller receives $600
User B's locked $600 released
- Bid amount is locked (deducted from available balance)
- Only one active bid per auction per user
- Cannot bid on your own auctions
- Cannot bid on already-expired auctions
- Must bid higher than the current price
| Technology | Purpose |
|---|---|
| Express | Web framework |
| TypeScript | Type safety |
| MongoDB | Database |
| Mongoose | ODM |
| Better-Auth | Authentication |
| node-cron | Scheduled jobs |
| Zod | Validation |
| mongoose-paginate-v2 | Pagination |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/auth/sign-up |
Register user |
POST |
/api/v1/auth/sign-in |
Login user |
POST |
/api/v1/auth/sign-out |
Logout |
GET |
/api/v1/auth/get-session |
Get current session |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/auction/create |
Create new auction |
GET |
/api/v1/auction/list |
List active auctions (with search, sort, category filters) |
GET |
/api/v1/auction/:id |
Get auction by ID |
GET |
/api/v1/auction/my |
Get user's auctions |
POST |
/api/v1/auction/:id/end |
Manually end auction |
| Parameter | Example | Description |
|---|---|---|
page |
?page=1 |
Page number (default: 1) |
limit |
?limit=10 |
Items per page (default: 10) |
search |
?search=iphone |
Search title/description |
sort |
?sort=price_asc |
Sort: price_asc, price_desc, endDate_asc, newest |
categorie |
?categorie=electronics |
Filter by category |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/bid/place |
Place a bid |
GET |
/api/v1/bid/:auctionId |
Get all bids on auction |
GET |
/api/v1/bid/my |
Get user's active bids |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/account/balance |
Get user balance |
POST |
/api/v1/account/transfer |
Transfer money to user |
id ObjectId
name String
email String
image String
username String
createdAt Date
userId ObjectId (ref: user)
balance Number (default: 0)
lockedAmount Number (default: 0)
createdAt Date
updatedAt Date
title String (5β100 chars)
description String (10β500 chars)
status "active" | "ended"
categorie String (electronics, jewelry, properties, toys, vehicles, household, fashion, sports, other)
image String[] (array of image URLs)
sellerId ObjectId (ref: user)
winnerId ObjectId (ref: user, nullable)
isTransactionDone Boolean (default: false)
sellingPrice Number (minimum: 5)
finalPrice Number (nullable)
endDate Date (24 hours from creation, extends +5min on late bids)
createdAt Date
auctionId ObjectId (ref: auction)
bidderId ObjectId (ref: user)
amount Number
isLocked Boolean (default: false)
isActive Boolean (default: false)
lockedAt Date
createdAt Date
- Frequency: Every 5 minutes
- Tasks:
- Mark expired auctions as
"ended" - Transfer locked funds to the seller
- Release locked amounts for losing bidders
- Mark the winning bid as inactive
- Mark auction as
isTransactionDone: true
- Mark expired auctions as
- Node.js 18+
- MongoDB (local or Atlas)
- pnpm (or npm/yarn)
# Clone the repository and navigate into the backend
cd backend
# Install dependencies
pnpm install
# Copy environment variables
cp .env.example .envFill in your .env file (see below), then start the dev server:
pnpm devPORT=3000
MONGODB_URI=mongodb://localhost:27017/auction-house
BETTER_AUTH_URL=http://localhost:3000
FRONTEND_URL=http://localhost:5173
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secretManual testing with Postman or Thunder Client:
# 1. Register a user
POST /api/v1/auth/sign-up
{
"email": "user1@example.com",
"password": "password123"
}
# 2. Check balance (should be ~$1,000β$10,000)
GET /api/v1/account/balance
# 3. Create an auction with category and images
POST /api/v1/auction/create
{
"title": "iPhone 15 Pro",
"description": "Like new condition, with box",
"sellingPrice": 500,
"categorie": "electronics",
"image": ["https://example.com/iphone1.jpg"]
}
# 4. List auctions with filters
GET /api/v1/auction/list?categorie=electronics&sort=price_asc
GET /api/v1/auction/list?search=iphone&sort=newest
GET /api/v1/auction/list?sort=endDate_asc
# 5. Place a bid (from another user account)
POST /api/v1/bid/place
{
"auctionId": "<auction_id>",
"amount": 105
}This project demonstrates:
- Authentication β OAuth, session management, JWT
- Authorization β Middleware, role-based access
- Database Design β Schemas, relationships, indexes
- Transaction Handling β ACID operations, rollback
- Escrow Systems β Lock/unlock funds, atomic updates
- Scheduled Jobs β Cron jobs, background processing
- Service Architecture β Controllers, services, separation of concerns
- Error Handling β Custom error classes, middleware
- Validation β Zod schemas, input sanitization
- Pagination β Offset-based pagination
- Search β Regex-based search, text indexes
- Filtering β Dynamic query building
- Auto-Extend Logic β Time-based event handling
This is a learning project. MIT License.
Vivek β Built as a MERN backend learning exercise.
π¦ Twitter: @vivek_z9