Skip to main content

Overview

The Crypto Shop Backend uses MongoDB with Mongoose for data persistence. This page documents all database models, their schemas, relationships, and business logic.

User Model

Represents user accounts with authentication, wallet, and security features. Location: src/models/User.js

Schema

email
string
required
User’s email address (unique, lowercase)
username
string
required
Username (unique, minimum 3 characters)
password
string
required
Hashed password (minimum 8 characters, not selected by default)
role
string
default:"user"
User role: user or admin
wallet
object
TRON wallet information
phone
string
default:"null"
User’s phone number (optional)
country
string
default:"null"
User’s country (optional)
recoveryEmail
string
default:"null"
Recovery email address (optional)
twoFactorEnabled
boolean
default:"false"
Whether 2FA is enabled
twoFactorSecret
string
default:"null"
2FA secret key (encrypted)
isActive
boolean
default:"true"
Whether the user account is active
lastLogin
Date
Timestamp of last successful login
createdAt
Date
default:"Date.now"
Account creation timestamp
updatedAt
Date
default:"Date.now"
Last account update timestamp

Methods

matchPassword(enteredPassword)

Compares a plain-text password with the hashed password.
const isMatch = await user.matchPassword('password123');
Parameters:
  • enteredPassword (string) - Plain-text password to verify
Returns: Promise<boolean> - True if password matches

Hooks

Pre-save Hook

Automatically hashes the password before saving if it has been modified.
userSchema.pre('save', async function(next) {
  if (!this.isModified('password')) return next();
  
  const salt = await bcryptjs.genSalt(10);
  this.password = await bcryptjs.hash(this.password, salt);
  next();
});

Example Document

{
  "_id": "507f1f77bcf86cd799439011",
  "email": "[email protected]",
  "username": "johndoe",
  "password": "$2a$10$...",
  "role": "user",
  "wallet": {
    "address": "TYourWalletAddress123456789",
    "privateKey": "encrypted_private_key"
  },
  "phone": "+1234567890",
  "country": "US",
  "recoveryEmail": "[email protected]",
  "twoFactorEnabled": false,
  "twoFactorSecret": null,
  "isActive": true,
  "lastLogin": "2026-03-04T10:30:00.000Z",
  "createdAt": "2026-01-15T08:00:00.000Z",
  "updatedAt": "2026-03-04T10:30:00.000Z"
}

Order Model

Represents customer orders with products, pricing, and payment status. Location: src/models/Order.js

Schema

orderId
string
required
Auto-generated order ID (format: #TRX-{number})
userId
ObjectId
required
Reference to User model
products
array
required
Array of products in the order
subtotal
number
required
Order subtotal before fees and discounts
networkFee
number
default:"-0.01"
TRON network transaction fee
discount
number
default:"0"
Discount amount applied
total
number
required
Final total amount (subtotal + networkFee - discount)
status
string
default:"pending"
Order status: pending, completed, refunded, failed, cancelled
paymentMethod
string
default:"TRC-20"
Payment method used
transactionHash
string
default:"null"
TRON blockchain transaction hash
walletAddress
string
required
Customer’s wallet address
merchantAddress
string
required
Merchant’s wallet address (payment destination)
createdAt
Date
default:"Date.now"
Order creation timestamp
updatedAt
Date
default:"Date.now"
Last order update timestamp

Hooks

Pre-save Hook

Auto-generates sequential order IDs.
orderSchema.pre('save', async function(next) {
  if (!this.isNew) return next();
  
  const lastOrder = await mongoose.model('Order').findOne().sort({ createdAt: -1 });
  const lastNumber = lastOrder ? parseInt(lastOrder.orderId.replace('#TRX-', '')) : 0;
  this.orderId = `#TRX-${lastNumber + 1}`;
  next();
});

Example Document

{
  "_id": "507f1f77bcf86cd799439012",
  "orderId": "#TRX-1001",
  "userId": "507f1f77bcf86cd799439011",
  "products": [
    {
      "productId": "507f1f77bcf86cd799439013",
      "name": "Crypto Hardware Wallet",
      "price": 99.99,
      "quantity": 1,
      "color": "Black"
    }
  ],
  "subtotal": 99.99,
  "networkFee": -0.01,
  "discount": 0,
  "total": 99.98,
  "status": "completed",
  "paymentMethod": "TRC-20",
  "transactionHash": "abc123def456...",
  "walletAddress": "TCustomerWalletAddress",
  "merchantAddress": "TMerchantWalletAddress",
  "createdAt": "2026-03-04T09:00:00.000Z",
  "updatedAt": "2026-03-04T09:15:00.000Z"
}

Product Model

Represents products available for purchase. Location: src/models/Product.js

Schema

name
string
required
Product name (trimmed)
description
string
required
Product description
price
number
required
Product price in TRX (minimum 0)
stock
number
default:"0"
Available stock quantity (minimum 0)
category
string
required
Product category: digital, physical, or service
image
string
default:"null"
Product image URL
createdBy
ObjectId
required
Reference to User (admin) who created the product
isActive
boolean
default:"true"
Whether the product is active and available
createdAt
Date
default:"Date.now"
Product creation timestamp
updatedAt
Date
default:"Date.now"
Last product update timestamp

Example Document

{
  "_id": "507f1f77bcf86cd799439013",
  "name": "Crypto Hardware Wallet",
  "description": "Secure cold storage wallet for cryptocurrency",
  "price": 99.99,
  "stock": 50,
  "category": "physical",
  "image": "https://example.com/images/wallet.jpg",
  "createdBy": "507f1f77bcf86cd799439010",
  "isActive": true,
  "createdAt": "2026-02-01T10:00:00.000Z",
  "updatedAt": "2026-03-01T14:30:00.000Z"
}

Transaction Model

Represents blockchain transactions for payments and refunds. Location: src/models/Transaction.js

Schema

userId
ObjectId
required
Reference to User model
orderId
ObjectId
default:"null"
Reference to Order model (null for non-purchase transactions)
type
string
required
Transaction type: purchase, refund, deposit, or withdrawal
amount
number
required
Transaction amount in TRX
currency
string
default:"TRX"
Currency code
network
string
default:"TRC-20"
Blockchain network
transactionHash
string
default:"null"
Blockchain transaction hash
fromAddress
string
required
Sender wallet address
toAddress
string
required
Recipient wallet address
status
string
default:"pending"
Transaction status: pending, confirmed, or failed
confirmations
number
default:"0"
Number of blockchain confirmations
createdAt
Date
default:"Date.now"
Transaction creation timestamp
updatedAt
Date
default:"Date.now"
Last transaction update timestamp

Example Document

{
  "_id": "507f1f77bcf86cd799439014",
  "userId": "507f1f77bcf86cd799439011",
  "orderId": "507f1f77bcf86cd799439012",
  "type": "purchase",
  "amount": 99.98,
  "currency": "TRX",
  "network": "TRC-20",
  "transactionHash": "abc123def456...",
  "fromAddress": "TCustomerWalletAddress",
  "toAddress": "TMerchantWalletAddress",
  "status": "confirmed",
  "confirmations": 19,
  "createdAt": "2026-03-04T09:10:00.000Z",
  "updatedAt": "2026-03-04T09:15:00.000Z"
}

Session Model

Tracks user sessions for security and auditing. Location: src/models/Session.js

Schema

userId
ObjectId
required
Reference to User model
device
string
Device identifier
ipAddress
string
Client IP address
userAgent
string
Browser/client user agent string
lastActive
Date
default:"Date.now"
Last activity timestamp
isActive
boolean
default:"true"
Whether the session is currently active
createdAt
Date
default:"Date.now"
Session creation timestamp

Example Document

{
  "_id": "507f1f77bcf86cd799439015",
  "userId": "507f1f77bcf86cd799439011",
  "device": "Desktop",
  "ipAddress": "192.168.1.100",
  "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
  "lastActive": "2026-03-04T10:30:00.000Z",
  "isActive": true,
  "createdAt": "2026-03-04T08:00:00.000Z"
}

Model Relationships


Indexing Recommendations

For optimal performance, create these indexes:
// User indexes
db.users.createIndex({ email: 1 }, { unique: true })
db.users.createIndex({ username: 1 }, { unique: true })
db.users.createIndex({ 'wallet.address': 1 })

// Order indexes
db.orders.createIndex({ orderId: 1 }, { unique: true })
db.orders.createIndex({ userId: 1, status: 1 })
db.orders.createIndex({ status: 1, createdAt: -1 })
db.orders.createIndex({ transactionHash: 1 })

// Transaction indexes
db.transactions.createIndex({ userId: 1, createdAt: -1 })
db.transactions.createIndex({ orderId: 1 })
db.transactions.createIndex({ transactionHash: 1 })
db.transactions.createIndex({ status: 1 })

// Product indexes
db.products.createIndex({ category: 1, isActive: 1 })
db.products.createIndex({ name: 'text', description: 'text' })

// Session indexes
db.sessions.createIndex({ userId: 1, isActive: 1 })
db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 2592000 }) // 30 days

Build docs developers (and LLMs) love