Skip to main content

Common Use Cases

Overview

This guide provides production-ready code examples for common Q01 Core API use cases. Each pattern includes complete implementation with error handling, performance optimization, and best practices.

Covered Use Cases:

  1. Product Catalog Management
  2. Order Processing Workflow
  3. Customer Data Management
  4. Inventory Synchronization
  5. Multi-Tenant Application
  6. Real-Time Dashboard
  7. Data Migration Project
  8. External System Integration

Use Case 1: Product Catalog Management

Scenario

E-commerce application managing product catalog with categories, prices, and inventory.

Implementation

class ProductCatalogService {
constructor(coreAPI) {
this.coreAPI = coreAPI;
this.cache = new Map();
}

// Get products by category with caching
async getProductsByCategory(categoryId, page = 1, limit = 20) {
const cacheKey = `category:${categoryId}:${page}:${limit}`;

// Check cache
if (this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
if (Date.now() - cached.timestamp < 300000) { // 5 minutes
return cached.data;
}
}

// Fetch from API
const response = await this.coreAPI.get('/api/v4/core/products', {
params: {
filters: `XPRD05:eq:${categoryId},TREC:eq:N,XPRD06:eq:Y`,
fields: 'PRD_ID,XPRD01,XPRD02,XPRD03,XPRD04,XPRD05',
order_by: 'XPRD01',
limit: limit,
offset: (page - 1) * limit
}
});

// Cache result
this.cache.set(cacheKey, {
data: response.data,
timestamp: Date.now()
});

return response.data;
}

// Create product with validation
async createProduct(productData) {
// Validate required fields
const required = ['XPRD01', 'XPRD02', 'XPRD05'];
for (const field of required) {
if (!productData[field]) {
throw new Error(`Missing required field: ${field}`);
}
}

// Set defaults
productData.XPRD06 = productData.XPRD06 || 'Y'; // Active by default
productData.TREC = 'N'; // New record

try {
const response = await this.coreAPI.post('/api/v4/core/products', productData);

// Invalidate category cache
this.invalidateCategoryCache(productData.XPRD05);

return response.data;
} catch (error) {
console.error('Failed to create product:', error);
throw error;
}
}

// Update product price
async updatePrice(productId, newPrice) {
const response = await this.coreAPI.patch(`/api/v4/core/products/${productId}`, {
XPRD02: newPrice
});

// Invalidate product cache
this.cache.delete(`product:${productId}`);

return response.data;
}

// Bulk price update
async bulkUpdatePrices(updates) {
const batchSize = 100;
const batches = this.chunk(updates, batchSize);

for (const batch of batches) {
await this.coreAPI.put('/api/v4/core/products/batch', {
records: batch
});
}

// Clear all caches
this.cache.clear();
}

// Search products
async searchProducts(query, filters = {}) {
const response = await this.coreAPI.get('/api/v4/core/products', {
params: {
search: query,
filters: this.buildFilters(filters),
fields: 'PRD_ID,XPRD01,XPRD02,XPRD03,XPRD04',
limit: 50
}
});

return response.data;
}

buildFilters(filters) {
const parts = ['TREC:eq:N'];

if (filters.category) parts.push(`XPRD05:eq:${filters.category}`);
if (filters.active !== undefined) parts.push(`XPRD06:eq:${filters.active ? 'Y' : 'N'}`);
if (filters.minPrice) parts.push(`XPRD02:gte:${filters.minPrice}`);
if (filters.maxPrice) parts.push(`XPRD02:lte:${filters.maxPrice}`);

return parts.join(',');
}

invalidateCategoryCache(categoryId) {
for (const [key, value] of this.cache.entries()) {
if (key.startsWith(`category:${categoryId}:`)) {
this.cache.delete(key);
}
}
}

chunk(array, size) {
const chunks = [];
for (let i = 0; i < array.length; i += size) {
chunks.push(array.slice(i, i + size));
}
return chunks;
}
}

// Usage
const catalogService = new ProductCatalogService(coreAPIClient);

// Get products by category
const products = await catalogService.getProductsByCategory(5, 1, 20);

// Create new product
const newProduct = await catalogService.createProduct({
XPRD01: 'Widget Pro 2024',
XPRD02: 49.99,
XPRD03: 'WGT-2024-001',
XPRD04: 'widget-pro-2024',
XPRD05: 5,
XPRD06: 'Y'
});

// Update price
await catalogService.updatePrice(123, 44.99);

// Bulk update
await catalogService.bulkUpdatePrices([
{PRD_ID: 123, XPRD02: 44.99},
{PRD_ID: 124, XPRD02: 54.99},
{PRD_ID: 125, XPRD02: 64.99}
]);

// Search
const results = await catalogService.searchProducts('widget', {
category: 5,
minPrice: 20,
maxPrice: 100
});

Use Case 2: Order Processing Workflow

Scenario

Handle complete order lifecycle from creation to fulfillment.

Implementation

class OrderProcessingService {
constructor(coreAPI, eventBus) {
this.coreAPI = coreAPI;
this.eventBus = eventBus;
}

// Create order with line items
async createOrder(orderData) {
try {
// 1. Create order header
const order = await this.coreAPI.post('/api/v4/core/orders', {
XORD_CUSTOMER_ID: orderData.customerId,
XORD_DATE: new Date().toISOString(),
XORD_STATUS: 'PENDING',
XORD_TOTAL: orderData.total,
TREC: 'N'
});

// 2. Create order lines
for (const item of orderData.items) {
await this.coreAPI.post('/api/v4/core/order_lines', {
XORDLN_ORDER_ID: order.ORD_ID,
XORDLN_PRODUCT_ID: item.productId,
XORDLN_QUANTITY: item.quantity,
XORDLN_PRICE: item.price,
XORDLN_TOTAL: item.quantity * item.price,
TREC: 'N'
});
}

// 3. Reserve inventory
await this.reserveInventory(orderData.items);

// 4. Emit event
this.eventBus.emit('order.created', {
orderId: order.ORD_ID,
customerId: orderData.customerId,
total: orderData.total
});

return order;
} catch (error) {
console.error('Failed to create order:', error);
throw error;
}
}

// Update order status
async updateOrderStatus(orderId, newStatus) {
const order = await this.coreAPI.patch(`/api/v4/core/orders/${orderId}`, {
XORD_STATUS: newStatus,
XORD_UPDATED_AT: new Date().toISOString()
});

// Emit status change event
this.eventBus.emit('order.status_changed', {
orderId: orderId,
oldStatus: order.XORD_STATUS,
newStatus: newStatus
});

// Handle status-specific actions
switch (newStatus) {
case 'CONFIRMED':
await this.processPayment(orderId);
break;
case 'SHIPPED':
await this.sendShippingNotification(orderId);
break;
case 'DELIVERED':
await this.completeOrder(orderId);
break;
case 'CANCELLED':
await this.releaseInventory(orderId);
break;
}

return order;
}

// Get order with details
async getOrderDetails(orderId) {
// Get order header
const order = await this.coreAPI.get(`/api/v4/core/orders/${orderId}`, {
params: {
expand: 'XORD_CUSTOMER_ID'
}
});

// Get order lines
const lines = await this.coreAPI.get('/api/v4/core/order_lines', {
params: {
filters: `XORDLN_ORDER_ID:eq:${orderId}`,
expand: 'XORDLN_PRODUCT_ID'
}
});

return {
...order.data,
lines: lines.data
};
}

// Reserve inventory
async reserveInventory(items) {
for (const item of items) {
await this.coreAPI.patch(`/api/v4/core/inventory/${item.productId}`, {
XINV_RESERVED: {$inc: item.quantity}
});
}
}

// Release inventory
async releaseInventory(orderId) {
const lines = await this.coreAPI.get('/api/v4/core/order_lines', {
params: {
filters: `XORDLN_ORDER_ID:eq:${orderId}`
}
});

for (const line of lines.data) {
await this.coreAPI.patch(`/api/v4/core/inventory/${line.XORDLN_PRODUCT_ID}`, {
XINV_RESERVED: {$inc: -line.XORDLN_QUANTITY}
});
}
}

async processPayment(orderId) {
// Payment processing logic
console.log(`Processing payment for order ${orderId}`);
}

async sendShippingNotification(orderId) {
// Shipping notification logic
console.log(`Sending shipping notification for order ${orderId}`);
}

async completeOrder(orderId) {
// Order completion logic
console.log(`Completing order ${orderId}`);
}
}

// Usage
const orderService = new OrderProcessingService(coreAPIClient, eventBus);

// Create order
const order = await orderService.createOrder({
customerId: 456,
items: [
{productId: 123, quantity: 2, price: 29.99},
{productId: 124, quantity: 1, price: 49.99}
],
total: 109.97
});

// Update status
await orderService.updateOrderStatus(order.ORD_ID, 'CONFIRMED');
await orderService.updateOrderStatus(order.ORD_ID, 'SHIPPED');
await orderService.updateOrderStatus(order.ORD_ID, 'DELIVERED');

// Get details
const details = await orderService.getOrderDetails(order.ORD_ID);

Use Case 3: Multi-Tenant Application

Scenario

SaaS application serving multiple tenants with data isolation.

Implementation

class TenantService {
constructor(coreAPI) {
this.coreAPI = coreAPI;
}

// Set tenant context for all requests
setTenantContext(tenantId, userId, peso = 3) {
this.context = {
source: tenantId,
peso: peso,
ambiente: 'P',
centro_dett: 'HQ',
modulo: 'app',
lingua: 'IT'
};

// Add interceptor to include context in all requests
this.coreAPI.interceptors.request.use(config => {
config.headers['X-Source'] = this.context.source;
config.headers['X-Peso'] = this.context.peso;
config.headers['X-Ambiente'] = this.context.ambiente;
config.headers['X-Centro-Dett'] = this.context.centro_dett;
return config;
});
}

// Get tenant-specific data
async getTenantData(dimension, filters = {}) {
// Context automatically applied via interceptor
const response = await this.coreAPI.get(`/api/v4/core/${dimension}`, {
params: {
filters: this.buildFilters(filters),
limit: 100
}
});

return response.data;
}

// Create tenant-specific record
async createTenantRecord(dimension, data) {
// source automatically set from context
const response = await this.coreAPI.post(`/api/v4/core/${dimension}`, {
...data,
TREC: 'N'
});

return response.data;
}

// Tenant analytics
async getTenantMetrics() {
const [products, orders, customers] = await Promise.all([
this.getTenantData('products', {active: true}),
this.getTenantData('orders', {status: 'CONFIRMED'}),
this.getTenantData('customers', {active: true})
]);

return {
totalProducts: products.total,
totalOrders: orders.total,
totalCustomers: customers.total,
activeProducts: products.data.filter(p => p.XPRD06 === 'Y').length
};
}

buildFilters(filters) {
const parts = ['TREC:eq:N'];

if (filters.active !== undefined) {
// Dimension-specific active field
parts.push(`XPRD06:eq:${filters.active ? 'Y' : 'N'}`);
}

if (filters.status) {
parts.push(`XORD_STATUS:eq:${filters.status}`);
}

return parts.join(',');
}
}

// Usage per tenant
const tenantService = new TenantService(coreAPIClient);

// Tenant A session
tenantService.setTenantContext('tenant_a', 'user_1', 3);
const tenantAProducts = await tenantService.getTenantData('products');
// Only sees tenant_a products

// Tenant B session
tenantService.setTenantContext('tenant_b', 'user_2', 3);
const tenantBProducts = await tenantService.getTenantData('products');
// Only sees tenant_b products (complete isolation)

// Analytics
const metrics = await tenantService.getTenantMetrics();
console.log(metrics);

Use Case 4: Real-Time Dashboard

Scenario

Admin dashboard with real-time metrics and updates.

Implementation

class DashboardService {
constructor(coreAPI, websocket) {
this.coreAPI = coreAPI;
this.websocket = websocket;
this.metrics = new Map();
this.subscribers = new Set();
}

// Initialize dashboard
async initialize() {
// Load initial metrics
await this.refreshMetrics();

// Subscribe to real-time updates (OUTBOX events)
this.websocket.on('ProductCreated', () => this.refreshMetrics());
this.websocket.on('OrderCreated', () => this.refreshMetrics());
this.websocket.on('CustomerCreated', () => this.refreshMetrics());

// Periodic refresh (every 30 seconds)
setInterval(() => this.refreshMetrics(), 30000);
}

async refreshMetrics() {
try {
const [products, orders, revenue, customers] = await Promise.all([
this.getProductMetrics(),
this.getOrderMetrics(),
this.getRevenueMetrics(),
this.getCustomerMetrics()
]);

const metrics = {
products,
orders,
revenue,
customers,
timestamp: Date.now()
};

this.metrics.set('dashboard', metrics);

// Notify subscribers
this.notifySubscribers(metrics);

return metrics;
} catch (error) {
console.error('Failed to refresh metrics:', error);
throw error;
}
}

async getProductMetrics() {
const response = await this.coreAPI.get('/api/v4/core/products', {
params: {
filters: 'TREC:eq:N',
aggregate: 'count',
group_by: 'XPRD05'
}
});

return {
total: response.total,
active: response.data.filter(p => p.XPRD06 === 'Y').length,
byCategory: response.data
};
}

async getOrderMetrics() {
const response = await this.coreAPI.get('/api/v4/core/orders', {
params: {
filters: 'TREC:eq:N',
aggregate: 'count,sum:XORD_TOTAL',
group_by: 'XORD_STATUS'
}
});

return {
total: response.total,
byStatus: response.data
};
}

async getRevenueMetrics() {
const today = new Date().toISOString().split('T')[0];

const response = await this.coreAPI.get('/api/v4/core/orders', {
params: {
filters: `TREC:eq:N,XORD_STATUS:eq:CONFIRMED,XORD_DATE:gte:${today}`,
aggregate: 'sum:XORD_TOTAL'
}
});

return {
today: response.aggregates.sum_XORD_TOTAL || 0
};
}

async getCustomerMetrics() {
const response = await this.coreAPI.get('/api/v4/core/customers', {
params: {
filters: 'TREC:eq:N',
aggregate: 'count'
}
});

return {
total: response.total
};
}

// Subscribe to metric updates
subscribe(callback) {
this.subscribers.add(callback);

// Return unsubscribe function
return () => this.subscribers.delete(callback);
}

notifySubscribers(metrics) {
for (const callback of this.subscribers) {
try {
callback(metrics);
} catch (error) {
console.error('Subscriber error:', error);
}
}
}
}

// Usage
const dashboardService = new DashboardService(coreAPIClient, websocket);

// Initialize
await dashboardService.initialize();

// Subscribe to updates
const unsubscribe = dashboardService.subscribe((metrics) => {
console.log('Dashboard updated:', metrics);
updateUI(metrics);
});

// Get current metrics
const metrics = dashboardService.metrics.get('dashboard');

Use Case 5: Data Migration

Scenario

Migrate data from legacy system to Q01 Core APIs.

Implementation

class DataMigrationService {
constructor(coreAPI, legacyDB) {
this.coreAPI = coreAPI;
this.legacyDB = legacyDB;
this.batchSize = 100;
}

async migrateProducts() {
const stats = {
total: 0,
migrated: 0,
failed: 0,
errors: []
};

try {
// 1. Get total count
const countResult = await this.legacyDB.query(
'SELECT COUNT(*) as total FROM products'
);
stats.total = countResult[0].total;

console.log(`Migrating ${stats.total} products...`);

// 2. Process in batches
let offset = 0;
while (offset < stats.total) {
const batch = await this.fetchLegacyBatch(offset);
const transformed = this.transformProducts(batch);

try {
await this.coreAPI.post('/api/v4/core/products/batch', {
records: transformed
});

stats.migrated += batch.length;
console.log(`Progress: ${stats.migrated}/${stats.total}`);
} catch (error) {
stats.failed += batch.length;
stats.errors.push({
offset: offset,
count: batch.length,
error: error.message
});
}

offset += this.batchSize;
}

return stats;
} catch (error) {
console.error('Migration failed:', error);
throw error;
}
}

async fetchLegacyBatch(offset) {
return this.legacyDB.query(
`SELECT * FROM products LIMIT ${this.batchSize} OFFSET ${offset}`
);
}

transformProducts(legacyProducts) {
return legacyProducts.map(legacy => ({
XPRD01: legacy.name,
XPRD02: legacy.price,
XPRD03: legacy.code,
XPRD04: this.slugify(legacy.name),
XPRD05: legacy.category_id,
XPRD06: legacy.active ? 'Y' : 'N',
TREC: 'N'
}));
}

slugify(text) {
return text
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-|-$/g, '');
}

// Validation
async validateMigration() {
const [legacyCount, coreCount] = await Promise.all([
this.legacyDB.query('SELECT COUNT(*) as total FROM products'),
this.coreAPI.get('/api/v4/core/products', {params: {limit: 0}})
]);

return {
legacy: legacyCount[0].total,
core: coreCount.total,
match: legacyCount[0].total === coreCount.total
};
}
}

// Usage
const migrationService = new DataMigrationService(coreAPIClient, legacyDB);

// Run migration
const stats = await migrationService.migrateProducts();
console.log(`Migrated: ${stats.migrated}/${stats.total}`);
console.log(`Failed: ${stats.failed}`);

// Validate
const validation = await migrationService.validateMigration();
console.log(`Validation: ${validation.match ? 'PASS' : 'FAIL'}`);

Summary

  • ✅ Product catalog: Caching, bulk updates, search
  • ✅ Order processing: Complete lifecycle management
  • ✅ Multi-tenancy: Data isolation per tenant
  • ✅ Real-time dashboard: Live metrics with WebSocket
  • ✅ Data migration: Batch processing with validation

Key Takeaways:

  1. Use caching for frequently accessed data
  2. Implement proper error handling and retry logic
  3. Leverage batch operations for performance
  4. Apply context correctly for multi-tenancy
  5. Subscribe to OUTBOX events for real-time updates
  6. Transform legacy data carefully during migration
  7. Validate data after migration