All controllers must use connection-scoped models (forMaster/forTenant) instead of direct imports.
// productController.js
const Product = require("../models/productModels");
exports.createProduct = async (req, res) => {
const product = await Product.create(req.body); // ❌ Uses WRONG connection
res.json(product);
};// productController.js
const { getAutoModels } = require("../utils/SaaS/autoModelInitializer");
exports.createProduct = async (req, res) => {
const { Product } = getAutoModels(req); // ✅ Auto-detects correct connection
const product = await Product.create(req.body);
res.json(product);
};// Add at top of controller
const { getAutoModels } = require("../utils/SaaS/autoModelInitializer");// ❌ REMOVE these:
const Product = require("../models/productModels");
const Category = require("../models/categoryModels");
const Brand = require("../models/brandModels");
// etc.// ❌ OLD:
exports.getAllProducts = async (req, res) => {
const products = await Product.find();
};
// ✅ NEW:
exports.getAllProducts = async (req, res) => {
const { Product } = getAutoModels(req);
const products = await Product.find();
};// ✅ Can destructure multiple models
exports.createProduct = async (req, res) => {
const { Product, Category, Brand } = getAutoModels(req);
const category = await Category.findById(req.body.categoryId);
const brand = await Brand.findById(req.body.brandId);
const product = await Product.create({
name: req.body.name,
category: req.body.categoryId,
brand: req.body.brandId,
});
};- productController.js - Product CRUD
- categoryController.js - Category CRUD
- purchaseController.js - Purchase CRUD
- salesController.js - Sales CRUD
- CustomerInvoiceController.js - Invoice CRUD
- supplierModel.js - Supplier CRUD
- customerController.js - Customer CRUD (already working?)
- brandController.js - Brand CRUD
- posSaleController.js - POS Sales
- warehouseControllers.js
- stockController.js
- invoiceSettingsController.js
- creditNoteController.js
- debitNoteController.js
grep -n "const.*require.*models" productController.jsgrep -n "Product\.\|Category\.\|Brand\." productController.jsconst { Product, Category } = getAutoModels(req);
const product = await Product.create({
name: req.body.name,
category: req.body.categoryId,
...
});const { Product } = getAutoModels(req);
const product = await Product.findById(id);
const products = await Product.find({ status: "Active" });
const product = await Product.findOne({ name: "xyz" });const { Product } = getAutoModels(req);
const product = await Product.findByIdAndUpdate(
id,
{ name: req.body.name },
{ new: true }
);const { Product } = getAutoModels(req);
await Product.findByIdAndDelete(id);const { Product } = getAutoModels(req);
const results = await Product.aggregate([
{ $match: { status: "Active" } },
{ $group: { _id: "$category", count: { $sum: 1 } } },
]);# 1. Login as tenant user (get token)
curl -X POST http://localhost:5000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "tenant@company.com",
"password": "password"
}'
# 2. Create with token
curl -X POST http://localhost:5000/api/products \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"productName": "Test Product",
"category": "...",
"price": 100
}'
# 3. Verify data is in TENANT database only, not mastertry {
const { Product } = getAutoModels(req);
// Use Product...
} catch (error) {
console.error("Model resolution failed:", error.message);
return res.status(500).json({
error: "Database context not available",
message: error.message
});
}For rapid migration, run this in each controller:
-
Add import at line 1:
const { getAutoModels } = require("../utils/SaaS/autoModelInitializer");
-
Find each export function
-
Add this line as first line of function:
const { Product, Category, Brand, ... } = getAutoModels(req);
-
Delete old
const Product = require(...)imports
- getAutoModels imported in controller
- All model constants removed from top-level imports
- Each function gets models from getAutoModels(req)
- All Product/Category/Brand/.etc usage goes through Models
- No
mongoose.model()direct calls - Auth middleware provides req.db
- Test create, read, update, delete
- Verify data isolation (tenant only sees own data)
const Product = require("../models/productModels");
const Category = require("../models/ categoryModels");
exports.createProduct = async (req, res) => {
const product = await Product.create(req.body);
res.json(product);
};
exports.getAllProducts = async (req, res) => {
const products = await Product.find();
res.json(products);
};const { getAutoModels } = require("../utils/SaaS/autoModelInitializer");
exports.createProduct = async (req, res) => {
const { Product, Category } = getAutoModels(req);
const product = await Product.create(req.body);
res.json(product);
};
exports.getAllProducts = async (req, res) => {
const { Product } = getAutoModels(req);
const products = await Product.find();
res.json(products);
};- Phase 1 (Immediate): Update 5 critical controllers
- Phase 2 (1-2 hours): Update 4 high-priority controllers
- Phase 3 (Next session): Update remaining controllers
- Phase 4 (Final): Test all CRUD operations across all modules
If a controller fails after migration:
- Check if getAutoModels returns the model
- Verify auth middleware sets req.db
- Ensure model has forTenant/forMaster factories
- Check console for specific error messages