╔══════════════════════════════════════════════════════════════════════╗
║ ████████╗███████╗███████╗████████╗ ║
║ ╚══██╔══╝██╔════╝██╔════╝╚══██╔══╝ ║
║ ██║ █████╗ ███████╗ ██║ ║
║ ██║ ██╔══╝ ╚════██║ ██║ ║
║ ██║ ███████╗███████║ ██║ ║
║ ╚═╝ ╚══════╝╚══════╝ ╚═╝ ║
║ E N D - T O - E N D F L O W V E R I F I C A T I E ║
║ Connector → APLT → Medusa → Tenant ║
║ Inclusief stock updates & data-integriteit ║
╚══════════════════════════════════════════════════════════════════════╝
┌─────────────┐ ┌──────────────┐ ┌─────────────┐ ┌──────────────┐
│ Supplier │────▶│ APLT │────▶│ Medusa │────▶│ Tenant │
│ Connectors │ │ Tabellen │ │ Sync │ │ Database │
└─────────────┘ └──────────────┘ └─────────────┘ └──────────────┘
Spranz (01) aplt_products Product upsert magic_b2b_*
XD Connect (04) aplt_techniques Variant mapping Sales channels
PF Concept (05) aplt_stock Tiered pricing Stock levels
Mid Ocean (06) aplt_tech_pricing Image handling
Toppoint (07) aplt_categories Metadata sync
Verifieer dat de PIM-update connectors correct data doorstromen naar de APLT-tabellen.
Overzicht van alle connectors ophalen
Controleer de huidige sync status van alle connectors via de PIM admin API:
GET /admin/connectors/sync
Of direct via de database:
SELECT connector_id, last_sync_at
ORDER BY last_sync_at DESC ;
Per connector de laatste sync tijd verifiëren
Connector Verwachte frequentie Check spranz_stock2x per dag (06:00, 18:00) last_sync_at < 12 uur geledenxdconnect_productsDagelijks last_sync_at < 24 uur geledenxdconnect_stockElk 15 minuten last_sync_at < 30 min geledenpfconcept_productsDagelijks last_sync_at < 24 uur geledenpfconcept_stock2x per dag last_sync_at < 12 uur geledenmidocean_productsDagelijks last_sync_at < 24 uur geledenmidocean_stockElk uur last_sync_at < 2 uur geledentoppoint_productsDagelijks (04:15) last_sync_at < 24 uur geledentoppoint_stockElk uur last_sync_at < 2 uur geleden
Handmatige sync triggeren voor elke connector
# Trigger sync per connector
POST /admin/connectors/sync?connector=spranz_stock
POST /admin/connectors/sync?connector=xdconnect_products
POST /admin/connectors/sync?connector=pfconcept_products
POST /admin/connectors/sync?connector=midocean_products
POST /admin/connectors/sync?connector=toppoint_products
Gebruik ?force=true om cache te bypassen en ?limit=50 voor een test-batch.
Product telling per supplier
SELECT supplier_code, COUNT ( * ) as product_count,
COUNT ( DISTINCT CASE WHEN name_nl IS NOT NULL THEN sku END ) as with_nl_name,
COUNT ( DISTINCT CASE WHEN name_en IS NOT NULL THEN sku END ) as with_en_name,
MIN (updated_at) as oldest_update,
MAX (updated_at) as newest_update
Ontbrekende verplichte velden detecteren
SELECT supplier_code, sku, variant_code
WHERE name_nl IS NULL OR name_nl = ''
-- Producten zonder prijs
SELECT supplier_code, sku, variant_code
WHERE retail_price_100 IS NULL OR retail_price_100 = 0
-- Producten zonder afbeelding
SELECT supplier_code, sku, COUNT ( * )
WHERE image_1 IS NULL OR image_1 = ''
GROUP BY supplier_code, sku
Printtechnieken controleren
-- Technieken per supplier
SELECT p . supplier_code , COUNT ( DISTINCT t . technique_code ) as technique_count,
COUNT ( DISTINCT t . product_sku ) as products_with_techniques
JOIN aplt_products p ON t . product_sku = p . variant_code
GROUP BY p . supplier_code ;
-- Technieken zonder pricing
SELECT t . technique_code , t . technique_name , t . product_sku
LEFT JOIN aplt_technique_pricing tp ON t . technique_code = tp . technique_code
WHERE tp . technique_code IS NULL
SELECT technique_code, technique_name, product_sku
WHERE position IS NULL OR position = ''
Data-anomalieën opsporen
SELECT sku, supplier_code, retail_price_100
WHERE retail_price_100 < 0 ;
-- Extreem hoge prijzen (>1000 EUR)
SELECT sku, supplier_code, retail_price_100
WHERE retail_price_100 > 100000
-- Dubbele SKU's binnen zelfde supplier
SELECT supplier_code, variant_code, COUNT ( * ) as cnt
GROUP BY supplier_code, variant_code
Let op: Supplier-specifieke SKU logica
Elke supplier heeft een eigen logica voor base SKU vs variant grouping:
Spranz (01): 101-05.001 → base=101-05, variant=101-05.001 (split op punt)
XD Connect (04): P110.023 → base=P110, variant=P110.023 (split op punt)
PF Concept (05): 10016500 → base=10016 (laatste 3 cijfers verwijderen)
Mid Ocean (06): AR1804-03 → base=AR1804 (split op koppelteken)
Toppoint (07): LT26203-N0001 → base=LT26203 (split op koppelteken)
Voor alle distributeurs behalve Langenberg (03) en Spranz (01) moeten volledige vertalingen worden toegevoegd (DE → NL + EN).
Distributeur Code Vertalingen XD Connect 04 Alle vertalingen (NL + EN) PF Concept 05 Alle vertalingen (NL + EN) Mid Ocean 06 Alle vertalingen (NL + EN) Toppoint 07 Alle vertalingen (NL + EN) NewWave 09 Alle vertalingen (NL + EN) Langenberg 03 Uitgesloten Spranz 01 Uitgesloten
Productnamen en beschrijvingen
name_nl, name_en (bron: name_de of Bezeichnung)
description_nl, description_en (bron: description_de)
Materiaal en kleur
color_nl, color_en (bron: color_de)
material_nl, material_en (bron: material_de)
Printtechniek posities
Standaard vertalingen:
Duits (bron) Nederlands Engels seitlich zijkant lateral vorne voorzijde front Ruckseite achterzijde back oben bovenzijde top unten onderzijde bottom
Techniek namen
Duits (bron) Nederlands Engels Tampon-Druck Tampondruk Pad printing Siebdruck Zeefdruk Screen printing Lasergravur Lasergravure Laser engraving Digitaldruck Digitale druk Digital printing Stickerei Borduurwerk Embroidery
Verificatie na vertaling
-- Controleer ontbrekende vertalingen per supplier
COUNT ( CASE WHEN name_nl IS NULL OR name_nl = '' THEN 1 END ) as missing_nl,
COUNT ( CASE WHEN name_en IS NULL OR name_en = '' THEN 1 END ) as missing_en
WHERE supplier_code NOT IN ( ' 01 ' , ' 03 ' )
-- Positie-vertalingen controleren
SELECT DISTINCT position, position_nl
JOIN aplt_products p ON t . product_sku = p . variant_code
WHERE p . supplier_code NOT IN ( ' 01 ' , ' 03 ' )
AND (position_nl IS NULL OR position_nl = '' );
Langenberg & Spranz uitgesloten
Langenberg (03) en Spranz (01) worden overgeslagen voor vertalingen. Deze suppliers hebben ofwel al vertalingen of worden apart afgehandeld.
Verifieer dat APLT-data correct gesynchroniseerd wordt naar Medusa.
Sync starten per supplier
# Start sync voor een specifieke supplier (bv. PF Concept)
POST /admin/connectors/medusa-sync?supplier= 05 & limit = 50
Sync status monitoren
GET /admin/connectors/medusa-sync
# Response: { status, processed, inserted, updated, errors }
Verifieer product-aanmaak in Medusa
Na sync, controleer of producten correct zijn aangemaakt:
-- In magic_pim database (Medusa)
SELECT p . id , p . title , p . handle , p . metadata - >> ' aplt_sku ' as aplt_sku,
p . metadata - >> ' supplier_code ' as supplier,
p . metadata - >> ' synced_at ' as synced_at
WHERE p . metadata - >> ' supplier_code ' IS NOT NULL
ORDER BY p . metadata - >> ' synced_at ' DESC
Varianten per product controleren
SELECT p . title , p . metadata - >> ' aplt_sku ' as base_sku,
COUNT ( pv . id ) as variant_count,
p . metadata - >> ' variant_count ' as expected_variants
JOIN product_variant pv ON pv . product_id = p . id
WHERE p . metadata - >> ' supplier_code ' IS NOT NULL
GROUP BY p . id , p . title , p . metadata - >> ' aplt_sku ' , p . metadata - >> ' variant_count '
HAVING COUNT ( pv . id ) != CAST ( p . metadata - >> ' variant_count ' AS int )
Prijzen verifiëren (tiered pricing)
Medusa slaat tiered pricing op als:
Tier min_quantity max_quantity price_100 1 199 price_200 200 299 price_300 300 499 price_500 500 999 price_1000 1000 NULL
-- Controleer of alle tiers aanwezig zijn
SELECT pv . sku , COUNT ( pp . id ) as price_tiers
JOIN product_variant_price_set pvps ON pvps . variant_id = pv . id
JOIN price_set ps ON ps . id = pvps . price_set_id
JOIN price pp ON pp . price_set_id = ps . id
WHERE pp . currency_code = ' eur '
Technieken in metadata controleren
-- Producten met technieken in metadata
SELECT p . title , p . metadata - >> ' aplt_sku ' as sku,
jsonb_array_length( p . metadata - > ' available_techniques ' ) as technique_count
WHERE p . metadata - > ' available_techniques ' IS NOT NULL
ORDER BY jsonb_array_length( p . metadata - > ' available_techniques ' ) DESC
-- Producten ZONDER technieken die ze wel zouden moeten hebben
SELECT p . metadata - >> ' aplt_sku ' as sku, p . metadata - >> ' supplier_code ' as supplier
WHERE p . metadata - >> ' supplier_code ' IS NOT NULL
AND ( p . metadata - > ' available_techniques ' IS NULL
OR jsonb_array_length( p . metadata - > ' available_techniques ' ) = 0 )
Afbeeldingen verifiëren
SELECT p . title , p . thumbnail ,
( SELECT COUNT ( * ) FROM image i
JOIN product_image pi ON pi . image_id = i . id
WHERE pi . product_id = p . id ) as image_count
WHERE p . metadata - >> ' supplier_code ' IS NOT NULL
Verifieer de volledige tenant update flow — wijzigingen in PIM/APLT moeten correct doorstromen naar de juiste tenant.
Tenant Database Opmerkingen magic_brinxx magic_b2b_brinxx Primaire test-tenant magic_brandbutler magic_b2b_brandbutler magic_demo magic_b2b_demo Demo omgeving magic_jodasign magic_b2b_jodasign magic_logohorloge magic_b2b_logohorloge magic_bovisales magic_b2b_bovisales magic_desluis magic_b2b_desluis magic_default magic_b2b_default Default template
Sales channels ophalen voor de tenant
-- In tenant database (bv. magic_b2b_brinxx)
SELECT id, name , description
WHERE deleted_at IS NULL ;
Tenant update triggeren
POST /admin/tenant-update
"tenant" : " magic_brinxx " ,
"salesChannel" : " <sales_channel_id> " ,
"suppliers" : [ " 01 " , " 04 " , " 05 " , " 06 " , " 07 " ]
Sync volgorde verifiëren
De tenant update moet in de juiste volgorde uitvoeren:
Colors (FK dependency)
Products (gefilterd op supplier codes)
Techniques (gelinkt via variant_code)
Technique pricing
Images (met rank ordering)
Category linking (via product_category_product)
Data in tenant database controleren
-- Producten per supplier
SELECT supplier_code, COUNT ( * ) as count
SELECT COUNT ( * ) FROM aplt_techniques;
SELECT COUNT ( * ) FROM aplt_technique_pricing;
-- Controleer product-sales channel koppeling
SELECT sc . name , COUNT ( psc . product_id ) as product_count
LEFT JOIN product_sales_channel psc ON psc . sales_channel_id = sc . id
Vergelijk bron en doel
-- Tel producten in PIM vs tenant (per supplier)
SELECT supplier_code, COUNT ( * ) FROM aplt_products
WHERE supplier_code IN ( ' 01 ' , ' 04 ' , ' 05 ' , ' 06 ' , ' 07 ' )
-- Tenant (magic_b2b_brinxx):
SELECT supplier_code, COUNT ( * ) FROM aplt_products
WHERE supplier_code IN ( ' 01 ' , ' 04 ' , ' 05 ' , ' 06 ' , ' 07 ' )
-- Aantallen moeten overeenkomen!
Categorie sync apart triggeren
POST /admin/tenant-update?action=categories
Controleer categorie-koppeling
SELECT pc . name , COUNT ( pcp . product_id ) as linked_products
LEFT JOIN product_category_product pcp ON pcp . product_category_id = pc . id
ORDER BY linked_products DESC ;
Verifieer dat voorraadmutaties vanuit connectors correct verwerkt worden in APLT en doorstromen naar tenants.
Stock records per supplier
COUNT ( * ) as total_records,
COUNT ( CASE WHEN quantity_available > 0 THEN 1 END ) as in_stock,
COUNT ( CASE WHEN quantity_available = 0 THEN 1 END ) as out_of_stock,
MIN (last_updated) as oldest_update,
MAX (last_updated) as newest_update,
AVG (quantity_available) as avg_stock
Verouderde stock records identificeren
-- Records die langer dan 24 uur niet bijgewerkt zijn
SELECT supplier_code, product_sku, quantity_available,
NOW () - last_updated as age
WHERE last_updated < NOW () - INTERVAL ' 24 hours '
ORDER BY last_updated ASC
Stock sync triggeren per connector
POST /admin/connectors/sync?connector=spranz_stock & force = true
POST /admin/connectors/sync?connector=xdconnect_stock & force = true
POST /admin/connectors/sync?connector=pfconcept_stock & force = true
POST /admin/connectors/sync?connector=midocean_stock & force = true
POST /admin/connectors/sync?connector=toppoint_stock & force = true
Verifieer upsert werking
-- Controleer dat ON CONFLICT correct werkt
-- Neem een bekend product en vergelijk voor/na sync
SELECT product_sku, quantity_available, quantity_reserved,
expected_delivery_date, expected_quantity, status , last_updated
WHERE supplier_code = ' 05 ' -- PF Concept
ORDER BY last_updated DESC
Vergelijk stock in PIM vs Tenant
SELECT supplier_code, product_sku, quantity_available, last_updated
WHERE supplier_code = ' 05 '
-- Tenant (magic_b2b_brinxx) - zelfde query
SELECT supplier_code, product_sku, quantity_available, last_updated
WHERE supplier_code = ' 05 '
Afwijkingen detecteren
Als de tenant een aplt_stock tabel heeft, vergelijk de aantallen:
SELECT supplier_code, COUNT ( * ) as pim_count,
SUM (quantity_available) as pim_total_stock
FROM aplt_stock GROUP BY supplier_code;
SELECT supplier_code, COUNT ( * ) as tenant_count,
SUM (quantity_available) as tenant_total_stock
FROM aplt_stock GROUP BY supplier_code;
Controleer Medusa inventory levels
-- Medusa inventory tracking (in tenant db)
SELECT il . id , ii . sku , il . stocked_quantity , il . reserved_quantity ,
JOIN inventory_item ii ON ii . id = il . inventory_item_id
ORDER BY il . stocked_quantity DESC
Fase 1: Connectors → APLT
Fase 2: APLT → Medusa
Fase 3: Tenant Update
Fase 4: Stock Update
Doel Pad Connector Index /mnt/data/magic_pim/backend/src/modules/connectors/index.tsDatabase Operations /mnt/data/magic_pim/backend/src/modules/connectors/database.tsConnector API /mnt/data/magic_pim/backend/src/api/admin/connectors/sync/route.tsMedusa Sync API /mnt/data/magic_pim/backend/src/api/admin/connectors/medusa-sync/route.tsTenant Update API /mnt/data/magic_pim/backend/src/api/admin/tenant-update/route.tsAPLT Products API /mnt/data/magic_pim/backend/src/api/admin/aplt/products/route.tsSync State /mnt/data/magic_pim/backend/src/modules/connectors/sync-state.tsMaster Sync Script /mnt/data/magic_pim/sync-master.js
Het gehele proces van Connector → APLT → Medusa → Tenant moet end-to-end werken zonder handmatige tussenkomst. Na het doorlopen van alle vier fasen moet elk acceptatiecriterium afgevinkt zijn. Eventuele fouten worden gedocumenteerd met de specifieke query-resultaten en foutmeldingen voor verdere analyse.