Products Disappeared When We Connected ERP to EC — 4 Sequelize Debug Traps in a Row
What Happened
While refactoring product management for TechsFree Platform, I hit this situation:
- ERP backoffice: 16 products registered
- EC admin panel (tf-admin): 2 products showing
- EC storefront (shop-pc): 0 products
After receiving a report that "data isn't consistent," I started debugging. About 90 minutes and 4 consecutive traps later, I had my answer.
System Architecture (Background)
ERP backend (old, port 8520)
└─ inventory table (product master, owned by ERP)
tf-backend (new, port 3210, Node.js + Sequelize + TypeScript)
└─ tf_products table (old copy, stale design)
└─ can also connect to inventory table
The root cause was simple: the EC side was reading from tf_products (an old copy table) that had drifted out of sync with the ERP's inventory table. The fix was equally simple — point the products API at inventory instead.
Getting there was not.
Trap 1: Heredoc × TypeScript Template Literals
I tried to edit files on the infra server via SSH heredoc:
ssh user@server << 'EOF'
cat > /path/to/products.ts << INNER
// TypeScript code
const query = `SELECT * FROM inventory WHERE id = ${id}`;
INNER
EOF
The backticks and ${} were interpreted by the shell before reaching the file. The TypeScript came out mangled.
Lesson: When writing TypeScript template literals inside heredocs, even quoting the inner delimiter ('INNER') doesn't fully prevent outer heredoc expansion from interfering. Either scp the file directly, or generate it with a tool that bypasses the shell entirely. I ended up using a write tool to create the file in-place.
Trap 2: Forgot the dist Directory
Modified the TypeScript source, fired a request — same old behavior. No change.
Why: Node.js runs the compiled JS in dist/. Editing src/ does nothing until you run npm run build. PM2 doesn't watch for file changes, so there's no automatic reload.
# On the infra server
cd /mnt/shared/projects/techsfree-platform/tf-backend
npm run build
pm2 restart tf-backend
Skip either step and your changes are invisible. In TypeScript projects, the edit-build-restart cycle is one atomic unit. When you're jumping between servers, it's easy to forget.
Trap 3: Sequelize Type Error (Op.ne with undefined)
The unit_price field on the Inventory model was typed as number | undefined.
where: {
unit_price: { [Op.ne]: null } // Type error: undefined not assignable here
}
TypeScript strict mode rejects Op.ne: null comparisons on fields that include undefined in their type. The fix was either to cast explicitly where unit_price was used as number, or restructure the where clause. Either way: compile errors, fix them one by one.
Trap 4: findAndCountAll Returns Fields as null
This was the worst one.
Build passed, API responded with product data. But every field was null (or undefined):
{
"id": 1,
"name": null,
"unit_price": null,
"stock": null
}
The code was accessing properties directly on Sequelize model instances:
// Bad
const items = await Inventory.findAndCountAll({ where: { ... } });
const name = items.rows[0].name; // undefined
Sequelize stores actual data in dataValues internally. Whether .property access works depends on how the model is defined and whether associations are loaded. It's not always reliable.
Fix: add raw: true:
const items = await Inventory.findAndCountAll({
where: { ... },
raw: true // Returns plain JS objects instead of model instances
});
const name = items.rows[0].name; // Works
Alternatively, use .get('name') on the model instance. raw: true is simpler to read, but you lose access to model methods — keep that in mind.
Final Result
Before: reading from tf_products (2 items, stale)
After: reading from inventory directly (13 items, matches ERP)
13 products returned correctly: F-00001 through F-00006 (produce), PROD001 through PROD005 (electronics), V-00001 through V-00002 (vegetables).
Summary: 4 Traps Hit Today
| # | Problem | Cause | Fix |
|---|---|---|---|
| 1 | TypeScript written incorrectly | Heredoc × template literal interference | Generate file directly |
| 2 | Changes not taking effect |
dist/ still had old compiled output |
edit → npm run build → pm2 restart
|
| 3 | TypeScript compile errors |
undefined-typed field with Op.ne
|
Fix type definitions, add cast |
| 4 | All fields returning null
|
Direct property access on Sequelize instances | Add raw: true
|
Every one of these is a "5-second fix if you know it" problem. Hit all four in sequence and it costs you 90 minutes.
That's why you write the debug log.
Tags: #TypeScript #Sequelize #NodeJS #Debugging #ERP #Ecommerce #Backend #RealWorld
Top comments (0)