back to index

orchestrating five systems without middleware

The integration challenge: Connect Medusa (commerce), Odoo (ERP), a custom Product Configurator, Strapi (PIM), and a Data Management Portal. Maintain data consistency. Avoid complex middleware.

Traditional approach: Complex middleware. Sync failure handling. Data inconsistency debugging. Brittle connections.

Our approach: Event-driven architecture using Medusa's workflow engine. No middleware. No unnecessary data duplication.

System Responsibilities

Medusa:

Odoo (ERP):

Product Configurator:

Data Management Portal:

Strapi (PIM):

Each system owns its domain. Medusa coordinates without trying to own everything.

The Integration Pattern

Two-way sync with Odoo:

Orders flow bidirectionally. Web orders go from Medusa → Odoo. Sales rep orders go Odoo → Medusa. This ensures consistency regardless of order source.

External IDs for linking:

Every entity (customer, order, product) has both a Medusa ID and an Odoo ID. We store the mapping, so systems stay loosely coupled.

// Simplified example of how we link entities
interface Customer {
  id: string;              // Medusa ID
  externalId: string;      // Odoo ID
  organizationId: string;  // Links multiple buyers
}

Caching for performance:

Customer shipping data caches in Medusa, updated only when Odoo sends change webhooks. This makes checkout fast. No waiting on ERP queries.

Workflows for data flow:

Medusa workflows handle order placement:

  1. Validate cart against configurator pricing
  2. Calculate shipping from Odoo data
  3. Create order in Medusa
  4. Send webhook to Odoo
  5. Listen for fulfillment updates

Built-in rollback if any step fails. No orphaned data.

Custom Pricing Integration

This was the complex part. Pricing depends on:

How it works:

  1. Customer configures product in storefront
  2. Configurator calculates base price using DMP rules
  3. DMP applies org-specific discounts
  4. Price validation happens at checkout
  5. Final price stores in Medusa order
  6. Order data syncs to Odoo with price locked

No price stored until validated. No chance of stale pricing at checkout.

Organization Accounts

Extended Medusa's customer model:

// Simplified schema
customer {
  id: string;
  email: string;
  organizationId: string;  // New field
  externalId: string;      // Links to Odoo
}

Result:

Single field extension. Significant B2B experience impact.

What Worked

Event-driven beats request-response. Webhooks mean systems don't wait on each other. Order placement doesn't block on Odoo. Fulfillment updates arrive asynchronously.

Cache what changes slowly. Shipping rules don't change every second. Cache them in Medusa, update only when Odoo signals changes.

Validate at boundaries. Pricing calculations happen in the configurator, but Medusa validates before order creation. Catch inconsistencies early.

External IDs for loose coupling. Systems reference each other through IDs, not tight integration. Replacing one system doesn't cascade everywhere.

Technical Lessons

Middleware indicates unclear responsibilities. Complex middleware suggests architecture problems.

Workflows prevent bug classes. Structured patterns for multi-step operations with rollbacks eliminate failure modes.

Caching strategy equals architecture importance. Distinguish frequent changes (cart data) from rare changes (shipping rules). Cache accordingly.

ERP integration doesn't mean ERP ownership. Commerce platforms handle commerce better. Sync only what ERP requires.

Read about this integration pattern in Medusa's ERP guide.


Technical implementation by the rb2 team. I worked on the architecture and integration patterns.