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

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.

2010 - 2016
~6 years
Software Engineer then Senior Software Engineer
European Sourcing Group
PHP 5.xSymfony 2/3MySQLElasticsearchAngularJSDoctrine ORMZend FrameworkMemcacheRabbitMQApacheProxmox VE

Lines of Code

~9.2M

PHP, JS, Twig, CSS, HTML

Database Tables

97

MySQL (master-slave)

Sub-Applications

15+

Microservices ecosystem

Languages Supported

7

FR, EN, DE, ES, IT, NL, PT

Dedicated Servers

9

OVH Proxmox VE

Supplier Connectors

26+

Automated data import

Versioning Entries

1,234

836 Git + 398 SVN

Reseller Websites

~160

MyEasyWeb hosted CMS

Presentation & Project Definition

Fifteen interconnected sub-applications, four search-engine generations, 8 years of development

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.

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).

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

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)
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.

Stakes

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.

Identified Risks

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.

The Steps - What I Did

From SQLI monolith to distributed microservices architecture

Phase 1
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
Phase 2
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
Phase 3
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
Project Timeline
European Sourcing - 2008-2017
Supplier Data Import Flow

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:

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).

Contribution Distribution (Git + SVN)
External stakeholders I interacted with

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)
Microservices Ecosystem
Technology Distribution
Codebase Scale
7,514PHP files
4,505JS files
909Controllers
2,222Views / templates
87Cron jobs
1,506i18n files
611Test files

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.

Technical Architecture

Architectural Évolution - Monolith to Microservices

Related journey

Professional experience linked to this achievement

Skills applied

Technical and soft skills applied

Hard Skills

Architecture & Design5/5

Software & System Architecture

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)

Software Development5/5

Fullstack Development

Built 15+ interconnected sub-applications spanning PHP MVC custom, Symfony 2/3, AngularJS SPA, jQuery Mobile and PhoneGap/Cordova apps over 8 years

DevOps & Cloud4/5

DevOps, Cloud & Production Industrialization

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 & AI4/5

Data, AI & Machine Learning

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

Architecture & Design4/5

Reverse Engineering & Algorithms

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)

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