Skip to content
advanced Phase 104 · Commerce Design Advanced

Integration Architecture Design

45m
1 problems
Topic Progress 0%

Integration Architecture Overview

Integration Types

ERP Integration:
├── Product catalog sync
├── Inventory sync
├── Order export
├── Customer sync
└── Financial data

CRM Integration:
├── Customer data sync
├── Order history
├── Support tickets
└── Marketing data

Third-party:
├── Shipping carriers
├── Payment gateways
├── Tax services
└── Analytics

Integration Patterns

1. Point-to-Point:
   System A ↔ System B
   Simple, but doesn't scale

2. Hub-and-Spoke:
   System A ↔ Hub ↔ System B
   Centralized, easier management

3. Event-Driven:
   System A → Event Bus → System B
   Loose coupling, scalable

4. API Gateway:
   Client → Gateway → Multiple Systems
   Single entry point, rate limiting

Data Flow

Magento 2 Integration:
├── Outbound (Magento → External)
│   ├── Product updates
│   ├── Order exports
│   ├── Customer sync
│   └── Inventory updates
├── Inbound (External → Magento)
│   ├── Product imports
│   ├── Price updates
│   ├── Inventory updates
│   └── Customer imports
└── Bidirectional
    ├── Real-time sync
    ├── Batch sync
    └── Event-based sync

ERP Integration Patterns

Product Sync

// ERP product import
class ErpProductImport
{
    public function importProducts($products)
    {
        foreach ($products as $erpProduct) {
            // Map ERP data to Magento
            $productData = $this->mapProductData($erpProduct);
            
            // Check if product exists
            $existing = $this->productRepository->get(
                $productData['sku'],
                false
            );
            
            if ($existing) {
                // Update existing product
                $existing->addData($productData);
                $this->productRepository->save($existing);
            } else {
                // Create new product
                $product = $this->productFactory->create();
                $product->addData($productData);
                $this->productRepository->save($product);
            }
            
            // Sync inventory
            $this->inventoryService->updateStock(
                $productData['sku'],
                $erpProduct['stock']
            );
        }
    }
    
    private function mapProductData($erpProduct)
    {
        return [
            'sku' => $erpProduct['item_code'],
            'name' => $erpProduct['description'],
            'price' => $erpProduct['unit_price'],
            'qty' => $erpProduct['quantity_on_hand'],
            'status' => $erpProduct['is_active'] ? 1 : 0,
            'weight' => $erpProduct['weight'],
            'description' => $erpProduct['long_description']
        ];
    }
}

Order Export

// Export order to ERP
class OrderExportService
{
    public function exportOrder($order)
    {
        $erpOrder = $this->mapOrderData($order);
        
        // Send to ERP
        $response = $this->erpClient->createOrder($erpOrder);
        
        if ($response->isSuccess()) {
            // Update order with ERP reference
            $order->setData('erp_order_id', $response->getOrderId());
            $order->addStatusHistoryComment(
                'Exported to ERP: ' . $response->getOrderId()
            );
            $order->save();
        } else {
            throw new \Exception('ERP export failed: ' . $response->getMessage());
        }
    }
    
    private function mapOrderData($order)
    {
        return [
            'customer_id' => $order->getCustomerErpId(),
            'po_number' => $order->getPoNumber(),
            'items' => array_map(function($item) {
                return [
                    'sku' => $item->getSku(),
                    'qty' => $item->getQtyOrdered(),
                    'price' => $item->getPrice()
                ];
            }, $order->getItems()),
            'shipping_address' => $this->mapAddress($order->getShippingAddress()),
            'totals' => [
                'subtotal' => $order->getSubtotal(),
                'tax' => $order->getTaxAmount(),
                'shipping' => $order->getShippingAmount(),
                'total' => $order->getGrandTotal()
            ]
        ];
    }
}

Inventory Sync

// Real-time inventory sync
class InventorySyncService
{
    public function syncInventory($sku, $qty, $sourceCode)
    {
        // Update Magento inventory
        $this->inventoryService->updateStock($sku, $sourceCode, $qty);
        
        // Send to ERP
        $this->erpClient->updateInventory([
            'sku' => $sku,
            'warehouse' => $sourceCode,
            'quantity' => $qty
        ]);
        
        // Update search index
        $this->searchService->updateStock($sku, $qty);
    }
    
    // Batch sync
    public function batchSync($inventoryData)
    {
        foreach ($inventoryData as $item) {
            $this->syncInventory(
                $item['sku'],
                $item['qty'],
                $item['source']
            );
        }
    }
}

Message Queue Design

Queue Architecture

Message Queue System:
├── Producers
│   ├── Order creation
│   ├── Product update
│   └── Inventory change
├── Queues
│   ├── order.export
│   ├── product.sync
│   ├── inventory.update
│   └── notification.send
├── Consumers
│   ├── ERP sync worker
│   ├── Search indexer
│   ├── Email sender
│   └── Analytics processor
└── Dead Letter Queue
    └── Failed messages

Queue Implementation

// Producer
class MessageProducer
{
    public function send($queue, $message, $options = [])
    {
        $this->queue->sendMessage($queue, json_encode($message), $options);
    }
}

// Consumer
class ErpSyncConsumer
{
    public function process(MessageInterface $message)
    {
        $data = json_decode($message->getBody(), true);
        
        try {
            switch ($data['type']) {
                case 'order':
                    $this->orderExportService->exportOrder($data['order_id']);
                    break;
                case 'product':
                    $this->productSyncService->syncProduct($data['product_id']);
                    break;
                case 'inventory':
                    $this->inventorySyncService->syncInventory(
                        $data['sku'],
                        $data['qty']
                    );
                    break;
            }
            
            // Acknowledge message
            $this->queue->acknowledge($message);
            
        } catch (\Exception $e) {
            $this->logger->error('Queue processing failed', [
                'error' => $e->getMessage(),
                'message' => $message->getBody()
            ]);
            
            // Retry or dead letter
            if ($message->getRedeliveryCount() >= 3) {
                $this->queue->deadLetter($message);
            } else {
                $this->queue->retry($message);
            }
        }
    }
}

Queue Configuration

<!-- queue_consumer.xml -->
<config>
    <queue name="order.export">
        <consumer name="erp.order.export"
                  queue="order.export"
                  handler="Vendor\Module\Consumer\ErpOrderExport::process"
                  maxMessages="100"/>
    </queue>
    
    <queue name="product.sync">
        <consumer name="erp.product.sync"
                  queue="product.sync"
                  handler="Vendor\Module\Consumer\ErpProductSync::process"/>
    </queue>
</config>

Webhook Design

Webhook System

// Webhook manager
class WebhookManager
{
    public function register($event, $url, $secret)
    {
        $webhook = $this->webhookFactory->create();
        $webhook->setEvent($event);
        $webhook->setUrl($url);
        $webhook->setSecret($secret);
        $webhook->setIsActive(true);
        
        $this->webhookRepository->save($webhook);
    }
    
    public function dispatch($event, $data)
    {
        $webhooks = $this->webhookRepository->getByEvent($event);
        
        foreach ($webhooks as $webhook) {
            $this->sendWebhook($webhook, $data);
        }
    }
    
    private function sendWebhook($webhook, $data)
    {
        $payload = json_encode([
            'event' => $webhook->getEvent(),
            'data' => $data,
            'timestamp' => time()
        ]);
        
        // Generate signature
        $signature = hash_hmac('sha256', $payload, $webhook->getSecret());
        
        // Send request
        $response = $this->httpClient->post($webhook->getUrl(), [
            'headers' => [
                'Content-Type' => 'application/json',
                'X-Webhook-Signature' => $signature,
                'X-Webhook-Event' => $webhook->getEvent()
            ],
            'body' => $payload
        ]);
        
        // Log result
        $this->logWebhook($webhook, $response);
    }
}

Webhook Security

// Verify webhook signature
public function verifySignature($payload, $signature, $secret)
{
    $expected = hash_hmac('sha256', $payload, $secret);
    return hash_equals($expected, $signature);
}

// Rate limiting
public function checkRateLimit($webhookId)
{
    $key = 'webhook_' . $webhookId . '_rate';
    $count = $this->cache->increment($key);
    
    if ($count > 100) { // 100 requests per hour
        throw new \Exception('Rate limit exceeded');
    }
    
    if ($count === 1) {
        $this->cache->save('1', $key, [], 3600);
    }
}

Practice Problems

0 / 1 solved
ERP Integration Design

Design ERP integration for real-time inventory sync and batch order export.

Solution
// System:
// 1. Inventory: Real-time sync via queue
// 2. Orders: Batch export every 5 min
// 3. Products: Nightly full sync
// 4. Errors: Retry + dead letter
// 5. Monitoring: Queue depth, failure rate
// 6. Fallback: Manual sync option

Quiz

1. What is the benefit of event-driven integration?

Question 1 options

2. What is the purpose of message queues?

Question 2 options

3. What is a dead letter queue?

Question 3 options

4. How should webhook signatures be verified?

Question 4 options

Flashcards

Question

Event-driven integration benefit?

Answer

Loose coupling between systems

Question

Message queue purpose?

Answer

Async processing and load leveling

Question

Dead letter queue?

Answer

Failed messages that can't be processed

Question

Webhook signature verification?

Answer

HMAC signature with shared secret

Question

ERP integration patterns?

Answer

Product sync, order export, inventory sync

Revision Notes

Key Takeaways

  • 1. Event-driven: Loose coupling, scalable
  • 2. Message queues: Async processing, load leveling
  • 3. Dead letter queue: Failed message handling
  • 4. Webhooks: HMAC signature verification
  • 5. ERP: Product, order, inventory sync

Interview Tips

  • Compare integration patterns
  • Explain message queue benefits
  • Discuss webhook security
  • Know ERP integration requirements

Cheat Sheet

Integration Design

  • Event-driven: Loose coupling
  • Queues: Async, load leveling
  • Dead letter: Failed messages
  • Webhooks: HMAC verification
  • ERP: Product, order, inventory sync