DEV Community

linou518
linou518

Posted on

Products Disappeared When We Connected ERP to EC — 4 Sequelize Debug Traps in a Row

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

The code was accessing properties directly on Sequelize model instances:

// Bad
const items = await Inventory.findAndCountAll({ where: { ... } });
const name = items.rows[0].name;  // undefined
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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 buildpm2 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)