---
title: "European B2B Search Engine for Promotional Products (European Sourcing)"
description: "B2B search engine acting as an online tradeshow for European promotional products resellers - a precursor to today's marketplaces."
locale: "en"
canonical: "https://portfolio.josedacosta.net/en/achievements/moteur-de-recherche-europeen-b2b-objets-publicitaires"
source: "https://portfolio.josedacosta.net/en/achievements/moteur-de-recherche-europeen-b2b-objets-publicitaires.md"
html_source: "https://portfolio.josedacosta.net/en/achievements/moteur-de-recherche-europeen-b2b-objets-publicitaires"
author: "José DA COSTA"
date: "2010"
type: "achievement"
slug: "moteur-de-recherche-europeen-b2b-objets-publicitaires"
tags: ["PHP 5.x", "Symfony 2/3", "MySQL", "Elasticsearch", "AngularJS", "Propel/Doctrine ORM", "Memcache", "RabbitMQ", "Apache", "Proxmox VE", "AWS SES", "PhoneGap/Cordova"]
generated_at: "2026-06-02T15:37:49.462Z"
---

# European B2B Search Engine for Promotional Products (European Sourcing)

B2B search engine acting as an online tradeshow for European promotional products resellers - a precursor to today's marketplaces.

**Date:** 2010 - 2016  
**Duration:** ~6 years  
**Role:** Software Engineer then Senior Software Engineer  
**Technologies:** PHP 5.x, Symfony 2/3, MySQL, Elasticsearch, AngularJS, Propel/Doctrine ORM, Memcache, RabbitMQ, Apache, Proxmox VE, AWS SES, PhoneGap/Cordova

### Key Metrics

- Lines of Code: **-** - PHP, JS, Twig, CSS, HTML
- Database Tables: **-** - MySQL (master-slave)
- Sub-Applications: **-** - Microservices ecosystem
- Languages Supported: **-** - FR, EN, DE, ES, IT, NL, PT
- Dedicated Servers: **-** - OVH Proxmox VE
- Supplier Connectors: **-** - Automated data import
- Versioning Entries: **-** - 836 Git + 398 SVN
- Reseller Websites: **-** - MyEasyWeb hosted CMS

## Presentation & Project Definition

_Fifteen interconnected sub-applications, four search-engine generations, 8 years of development_

### Business Domain

B2B communication through promotional objects - connecting European suppliers, resellers, and agencies in the promotional products industry.

### Target Users

B2B professionals across Europe - communication agencies, distributors and examples of integrated European suppliers (Midocean, PF Concept, BIC, Paul Stricker, SOL'S, TopTex, Topico, Inspirion, Makito, Xindao, Clipper, Cybernecard, Pixika, Delta, Passot, Lm, Boomerang, Axpol, Goya, GetImpressed, Giving, Lensen Toppoint, Cottel, Eljte, Frezal, Imbretex).

European Sourcing is a **B2B search engine for promotional products** acting as a permanent online tradeshow at European scale - a **precursor to what we call marketplaces today**, aimed at all European promotional products resellers. The project constitutes a **complete application ecosystem** composed of fifteen interconnected sub-applications, developed over more than 6 years (2010-2017).

The platform connects three types of actors in the promotional products market:
- **Suppliers** (manufacturers/wholesalers) who list their product catalogs → **B2B**
- **Resellers/Distributors** (communication agencies) who search products for their clients → **B2B**
- **Visitors** who browse the online catalog on reseller sites (end clients) → **B2C**

The system functions as a **permanent professional online tradeshow**, offering suppliers a multi-channel showcase (online catalog, newsletters, advertising banners, annual guidebook, Google Ads) and resellers a multilingual product search engine covering 7 European languages.

### Functional Scope

### Multilingual Product Catalog (7 languages)

### Full-Text Search (Elasticsearch)

### Supplier/Reseller Back-Office

### Automated Supplier Data Import (26+ connectors)

### REST API with WSSE Authentication

### Centralized Translation System

### Online Payment (Sogenactif)

### Reseller Mini-Sites CMS (MyEasyWeb)

### Mobile Applications (PhoneGap/Cordova)

### Consultation Statistics (views, searches, clicks)

### Data Export (CSV + product images)

### SEO / Marketing Back-Office

## Objectives, Context, Stakes & Risks

_Digitalizing the European promotional products market_

### Context

The initial project (v1/v2) was developed by **SQLI**, a French IT services company, with a custom PHP framework and Smarty templates. The legacy code contained 398 SVN revisions covering 2010-2013.

When I joined SQLI, **5 full-time PHP developers** were dedicated to the project. Over time, I took on a growing share of the technical scope, eventually handling **the entire perimeter on my own** - a role that naturally evolved with my expertise and the autonomy that came with the PME environment. After covering the full perimeter solo for a while, I asked for reinforcement and obtained the hiring of a second developer.

From 2014-2016, **our new Medialeads team** undertook a **complete rewrite** of the platform, progressively migrating from the custom framework to **Symfony 2/3** while maintaining the public site on a lighter custom MVC framework.

The platform was **multilingual** (7 languages), **multi-country**, with high product data volumes, and the need to maintain compatibility with existing supplier data feeds - **all hosted on fully self-managed OVH dedicated servers: we handled absolutely everything ourselves, from system configuration to deployments**.

### Business Model

Revenue from supplier subscriptions (240-288 EUR/year) and advertising services (banners, newsletters, guidebook, Google Ads, media planning).

### Strategic Position

European Sourcing positioned itself as the go-to reference for online promotional product sourcing in Europe - a precursor to today's B2B marketplaces, replacing traditional paper catalogs and physical tradeshows.

### Brand Ecosystem

The company also operated TendanceObjet.com, Kadobjet.fr, FranceObjet.com, Omyague.com, GourmetOnline.pro, Recherche-Publicitaire.com, GraphicSourcing.com, CPrint-Sourcing.com, WineSpiritSourcing.com, Tradexpo-Online.fr - each targeting a specific market segment.

### Technical Debt

Progressive migration from a custom framework to Symfony, coexistence of two architectures (SVN legacy + Git modern), MD5 password hashing with a single iteration and no salt - consistent with the state of the art of PHP security practices during the 2008-2014 decade, before bcrypt became the default standard.

### Integration Complexity

Supplier data feeds were heterogeneous (CSV, XML, API), requiring a specific adapter per supplier maintained in flux.europeansourcing.com.

### Infrastructure Dependency

9 dedicated OVH servers with Proxmox virtualization, MySQL master/slave replication, manual deployments via svn up - reflecting the technical constraints of the era, before the democratization of Docker and modern CI/CD pipelines.

### Bus Factor

Only 3 main developers for the entire ecosystem of 38 sub-projects and 9 servers.

### Objectives

- Position the platform as **the European reference** for online B2B promotional products sourcing, replacing paper catalogs and physical tradeshows
- Build a **multilingual product catalog** aggregating **several million products and variants** from dozens of suppliers
- Provide resellers with an **advanced search engine** with filters by category, brand, price, attributes, marking
- Automate the **import of supplier data feeds** (prices, stocks, docs, descriptions) from 26+ suppliers
- Offer resellers a **turnkey mini-site e-commerce solution** (MyEasyWeb) with their own branded storefront connected to the central catalog
- Generate **detailed consultation statistics** for suppliers (product views, searches, clicks)

### Stakes

### Identified Risks

## The Steps - What I Did

_From SQLI monolith to distributed microservices architecture_

### SQLI Development & SVN Legacy (2008-2013) (2008 - 2013)

- I managed the legacy codebase inherited from SQLI - a PHP monolith with Smarty templates, under SVN versioning (398 revisions)
- On the supplier and reseller extranet, I took on both maintenance and functional extensions (product CRUD, image management, pricing, attributes, markings)
- In parallel, I drove the deployment operations on dedicated servers and coordinated the work with SQLI documentation (47+ specification documents)
- To fix data quality issues (missing parent categories, incorrect colors, broken docs), I wrote dedicated correction scripts

### Internal Takeover & Microservices (2014-2016) (Jan 2016 - Dec 2016)

- I led the migration from SVN to GitHub - 13 repositories created in January 2016, organization medialeads with 8 members and 20+ private repos
- On the extranet side, I carried out the full rewrite (177 commits) on a custom PHP MVC framework with direct MySQL database access
- On the backend, I developed the REST API (api.europeansourcing.com) on Symfony 2.4 with Propel ORM and WSSE authentication
- To automate supplier data imports on flux.europeansourcing.com, I built dedicated connectors for Pixika, Makito, Midocean, BIC, Paul Stricker, TopTex and Cybernecard
- For full-text search, I implemented Elasticsearch with dedicated multilingual indexes
- In parallel, I created the centralized translation system (translate.europeansourcing.com) on Symfony 3.0

### Architectural Modernization (2016-2017) (Mar 2016 - Nov 2016)

- I initiated the architectural rewrite around shared Symfony bundles (ESCoreBundle: 143 commits, ESSourcingBundle: 15 commits)
- On the modeling side, I designed the Doctrine behaviors: Sluggable, Sortable, Timestampable, Translatable, Blameable, Toggleable, Visible, Overloadable, Tree
- To absorb load spikes, I implemented asynchronous processing with RabbitMQ for data import and visibility computations
- On the infrastructure side, I set up the provisioning with Chef for the extranet_rebirth project

### Phase 1

### Phase 2

### Phase 3

## The Actors - Interactions

_How I collaborated within a small but highly productive team_

### Development Team

Depending on the period, I worked with 3 to 5 active developers, with clearly divided responsibilities:

### External stakeholders I interacted with

### Development Workflow

I worked inside the medialeads GitHub organization (Bordeaux), on branches named after each developer (jose, fancyweb, wamania), with internal documentation on DokuWiki. No formal Pull Request process existed at the time: we relied on direct branch merges, with each developer owning specific areas of the codebase - I carried my perimeters end-to-end.

- José DA COSTA - My role - Lead Developer. I produced 35.3% of the total versioning (225 Git + 116 SVN), with a dominant footprint on extranet (177 commits), flux (15), and SVN legacy management.
- Thomas C. - Senior Developer I worked with daily - 36.9% (355 Git + 1 SVN). Dominant on ESCoreBundle (113), translate (88), supplierbo (19).
- wamania - Developer with whom I shared the platform codebase - 24.2% (226 Git + 8 SVN). Dominant on europeansourcing.com (166 commits), extranet (49).
- IronXtreme - Developer I crossed paths with on ESCoreBundle - 3.0% (29 Git commits on that perimeter).

- SQLI - I took over and leveraged the deliverables of this IT services company that developed v1/v2/v3 (specifications, initial development)
- Dolead - On the paid acquisition side, I collaborated with this agency for Google AdWords management
- Universem - For SEO, I relied on this agency for the TendanceObjet and Kadobjet audits
- OVH - For hosting, I drove their 9 dedicated servers day in, day out

## The Results

_Measurable impact for the business and for my career_

### For Me

- **Massive data management & SQL optimization**: I sharpened my mastery of **SQL normal forms** (1NF, 2NF, 3NF, BCNF), every **join type** (INNER/LEFT/RIGHT/CROSS/SELF) and **advanced indexing** (B-tree, composite, covering indexes), with constant **`EXPLAIN ANALYZE`** plan analysis, relying on **MySQL master-slave replication** and **Memcache caching**. I kept **nightly batches of several hours** running to recompute stock levels, prices and promotions across the whole catalog - at that scale a missing index could turn a 50 ms query into a 30-second timeout, so every millisecond saved per query compounded over millions of executions.
- **Search engines & indexing**: I went hands-on across **four generations** of search engines - (1) **MySQL LIKE / FULLTEXT** (MyISAM/InnoDB), (2) **PostgreSQL full-text search** with `tsvector`/`tsquery`, **GIN indexes** and `to_tsvector`/`ts_rank` functions, (3) **Apache Solr**, where I indexed hundreds of thousands of products with advanced faceting (categories, colors, prices, suppliers), spell-checking and custom relevance scoring, (4) **Elasticsearch** with inverted indexes, multilingual analyzers (stemming, tokenization, normalization), TF-IDF scoring, aggregations and facets. This journey let me grasp in depth the differences between a relational engine and a dedicated search engine.
- **Complex algorithms & business rules**: I designed and implemented **numerous complex algorithms** and **intricate business rules** - for example computing every possible combination of price, product variants and availability (**Cartesian product / combinatorial explosion** generating thousands of combinations per product across sizes, colors, quantities, marking types, marking zones and finishes). Dynamic pricing rule modeling and business decision engines are now part of my toolbox.
- I consolidated my mastery of the **Symfony 2/3 ecosystem** at production scale (Propel, Doctrine, bundles, services, security, WSSE).
- On **legacy code migration**, I built strong skills by driving the transition from the SVN monolith to Git-based microservices without downtime.
- On the business side, I gained deep domain knowledge of the **B2B promotional products** market, data feed automation and multi-country e-commerce.
- Finally, this project changed my way of working: I learned to coordinate inside a small team where each developer owns significant portions of the codebase, and to carry perimeters end-to-end.

### For the Company

- Functional Coverage - **Complete B2B sourcing lifecycle** handled within a single ecosystem - from supplier catalog upload to reseller storefront, with no manual handover between services
- Catalog Volume - Indexed the **largest European database of promotional products** - several million products and variants aggregated from **26+ supplier feeds**, stored across **97 MySQL tables** with master-slave replication
- Multilingual Reach - **7 European languages** with dedicated Elasticsearch indexes and centralized translation management
- Geographic Coverage - Localized sub-domains covering key European markets: **UK**, **Iberia**, **Italy**, **Germany**, plus a dedicated Textile vertical
- Automation Scale - **26+ automated supplier connectors** handling heterogeneous formats (CSV, XML, API) from major European brands
- Reseller Network - **~160 hosted reseller mini-sites** on the MyEasyWeb CMS platform
- Brand Ecosystem - **11+ domain brands** operated: europeansourcing.com, tendanceobjet.com, kadobjet.fr, franceobjet.com, omyague.com, gourmetonline.pro, recherche-publicitaire.com, graphicsourcing.com, cprint-sourcing.com, winespiritsourcing.com, tradexpo-online.fr

**Key features delivered:**
- Multilingual product catalog with dedicated Elasticsearch indexes and custom relevance scoring
- REST API with WSSE stateless authentication (nonce + timestamp + digest)
- Automated supplier data import connectors handling heterogeneous CSV / XML / API feeds
- Supplier/reseller back-office with complete product management
- SPA supplier dashboard (AngularJS 1.2 + CoffeeScript + Grunt + Bower)
- Reseller mini-sites CMS (MyEasyWeb) with branded storefronts connected to the central catalog
- Online payment integration (Sogenactif, Société Générale)
- SEO / marketing back-office (Zend Framework + ExtJS + web crawler)
- Hybrid mobile applications (jQuery Mobile + PhoneGap/Cordova)

## The Aftermath

_What happened after I left the project_

**I left the project in November 2016**, handing over a platform in full running order. The team continued operating and evolving European Sourcing - **the project was not interrupted**, it simply continued without me. The final consolidation phase around shared Symfony bundles, which I had started, was carried on by the team.

With hindsight, the architectural choices made in Phase 2 proved **sound and modern for their era**: the service-oriented approach with dedicated subdomains, the WSSE stateless inter-service authentication, the search engine architecture and the automated supplier connector infrastructure remained technically impressive long after I had moved on.

## My Critical Perspective

_How I judge this project, with the hindsight of 8 years of development_

### Strengths

- Well-designed microservices architecture - With hindsight, I consider that the way we broke down the SQLI monolith into **specialized services** (API, search, flux, translation, export, statistics) reflects a **solid architectural vision**. Each service we carved out has a clear responsibility and well-defined functional perimeter.
- Rare end-to-end product scope - At the time, very few competitors offered the **entire B2B sourcing lifecycle within a single ecosystem**. I remain convinced that this level of integration - which we pushed far - is what positioned European Sourcing as a leader on the European market.
- Native internationalization - I stand behind the choice of **per-language Elasticsearch indexes** and a **centralized translation system**: we engineered European ambition from day one rather than retrofitting it.
- Supplier import automation - With time, I measure the value of the connectors I built to handle heterogeneous formats (CSV, XML, API) - a **considerable technical investment** and **core business value** that formed a real moat against competitors.

### Areas for Improvement

- Pre-CI/CD deployment - I only deployed manually via svn up, with no continuous integration pipeline and no automated testing. It was consistent with PHP ecosystem practices of the 2008-2014 decade (GitHub Actions did not exist yet, Jenkins and Travis CI were still early), but I clearly identify it today as a limitation.
- Pre-SemVer versioning - I never tagged any of the 13 repositories in Git - reflecting the era, before SemVer was broadly adopted in the PHP ecosystem and GitHub Releases became a standard practice. With hindsight, I regret it.
- Multi-framework ecosystem - I had to juggle the coexistence of multiple frameworks (custom PHP, Symfony 2.4, 2.8, 3.0, 3.1, Zend Framework 1) and 2 ORMs (Propel, Doctrine) - a consequence of the progressive migration spread over several years, consistent with PHP ecosystem evolution between 2010 and 2016, but heavy to maintain.

### What I Would Do Differently

With today's standards and hindsight, here are the choices I would now make differently - each decision made sense within the constraints of its era:
- **Adopting a single framework** from the start rather than maintaining a custom PHP framework alongside Symfony, though historical context justified coexistence during migration.
- **Setting up CI/CD** from the GitHub migration (January 2016) - Jenkins, Travis CI or GitLab CI were available even if GitHub Actions did not exist yet.
- **Using Docker** for dev and deploy environments, though Proxmox was the mature virtualization standard for PHP PME at the time.
- **Centralizing data access** via a single API rather than direct MySQL from each service - a pattern that only became widespread after 2017.

### Lasting lessons this project brought me

- Legacy migration is a marathon - The transition from the SQLI monolith to microservices architecture took me 3+ years and remained in progress when I left the project. I walk away convinced that planning realistic milestones and accepting temporary compromises is essential.
- Data import automation is critical - I measure how much the supplier connectors I built represent considerable business value but also permanent maintenance debt - any supplier can change their format at any time, and each breakage turns into a production incident.
- Internationalization must be planned from day one - I experienced first-hand how much the centralized translation system is an excellent pattern. Retrofitting multilingual support would have cost me exponentially more than designing it upfront.
- SSII documentation is precious - Years after the end of the engagement, I could still lean on SQLI's specifications to understand the architecture. I take away that investing in technical documentation has a long-term ROI.

## Skills applied

_Technical and soft skills applied_

- **[Problem Solving & Adaptability](https://portfolio.josedacosta.net/en/skills/problem-solving-adaptability.md)** - Solved complex data integration challenges - heterogeneous supplier formats, multilingual search across 7 languages, massive catalog optimization where any poorly designed query was fatal for performance, Evolved from PHP custom + SVN monolith to Symfony microservices + Git + Elasticsearch + AngularJS SPA - continuously learned new stacks, frameworks and search technologies across 3 architectural phases
- **[Software & System Architecture](https://portfolio.josedacosta.net/en/skills/system-architecture-design.md)** - Decomposed the SQLI monolith into a microservices ecosystem (API, search, flux, translate, export, stats, supplierbo) with shared Symfony bundles (ESCoreBundle, ESSourcingBundle) and WSSE stateless inter-service authentication - Built a REST JSON API on Symfony 2.4 + Propel with WSSE stateless authentication (nonce + timestamp + digest), JMS Serializer, CORS, and multi-database connections (europeansourcing + tendanceobjet) - Applied microservices, MVC, SPA (AngularJS), Strategy pattern for 26+ heterogeneous supplier connectors (CSV/XML/API), and Doctrine behaviors (Sluggable, Sortable, Timestampable, Translatable, Blameable)
- **[Fullstack Development](https://portfolio.josedacosta.net/en/skills/fullstack-development.md)** - Built 15+ interconnected sub-applications spanning PHP MVC custom, Symfony 2/3, AngularJS SPA, jQuery Mobile and PhoneGap/Cordova apps over 8 years
- **[DevOps, Cloud & Production Industrialization](https://portfolio.josedacosta.net/en/skills/devops-cloud-production.md)** - Led the migration from SVN (398 revisions) to GitHub (13 repositories, 836 commits) - organization setup, per-developer branch strategy, 20+ private repos under the medialeads organization
- **[Data, AI & Machine Learning](https://portfolio.josedacosta.net/en/skills/data-ai-machine-learning.md)** - Designed and optimized a 97-table MySQL schema with master-slave replication - SQL normal forms (1NF/2NF/3NF/BCNF), advanced indexing (B-tree, composite, covering), constant EXPLAIN plan analysis and progression to PostgreSQL full-text (tsvector/GIN) then Elasticsearch
- **[Reverse Engineering & Algorithms](https://portfolio.josedacosta.net/en/skills/reverse-engineering-algorithms.md)** - Implemented combinatorial pricing algorithms (Cartesian product generating thousands of combinations per product: sizes × colors × quantities × marking types × marking zones × finishes) and search-engine indexing theory (inverted index, analyzers, TF-IDF scoring)

## Related journey

_Professional experience linked to this achievement_

- **Software Engineer · PHP Zend Framework Developer**

## Image gallery

_Project screenshots and visuals_

## Need a multilingual B2B portal designed?

I delivered the European Sourcing portal end-to-end: multilingual product modeling, sourcing catalog and buyer workflows. Let's talk about your context.

**Contact me**
