Dit Petje
Over het platform
Dit Petje is een multi-channel productontdekkingsplatform waarmee bezoekers per categorie producten doorzoeken, vergelijken en doorklikken naar aanbieders. Onder de motorkap draait MFP (Multi Feed Processing): één Symfony-codebase die drie consumentenmerken bedient — ditpetje.nl (petten en hoeden), dithorloge.nl (horloges) en ditparfum.nl (parfum) — en architectonisch is opgezet om N kanalen aan te kunnen via dynamic discovery (geen hardcoded limiet).
Samenwerking tussen merk en bouwer
Concept, marketing en innovatieplannen komen vanuit ten Bruggencate Marketing; ontwikkeling, doorontwikkeling en beheer nemen wij voor onze rekening. De rolverdeling zorgt ervoor dat marktinzicht en techniek hand-in-hand evolueren zonder dat één discipline de ander blokkeert.
Architectuur in één zin
Feed-bronnen → MFP Dashboard → kanaal-sites → gekoppelde socials. Producten worden centraal ingelezen, per kanaal gefilterd en gescoord, en pas getoond als ze door de display-gates komen.
Vijf feed-bronnen, één pijplijn
- Awin (6 uur), Bol.com (12 uur), Amazon (24 uur), TradeTracker (12 uur) en Zalando (12 uur) — elke bron heeft zijn eigen schedule, validators en feed-status (active / blocked / paused).
- Een global-sync orchestrator (
feed:sync:global) downloadt elke bron één keer en routeert producten naar alle relevante kanalen — voorkomt dubbele downloads bij groei naar meer kanalen. - Per-bron parsing via een gedeelde
FeedServiceTraitmet centrale relevantie-detectie (Nederlandse compound-keywords als sportpet, winterpet worden expliciet ondersteund) — geen knip-en-plak per bron. - Geblokkeerde feeds markeren bestaande producten automatisch als niet-beschikbaar; gepauzeerde feeds skippen sync zonder data te verliezen.
Strikte kanaalscheiding
- EAN-lookups inclusief channelId — voorkomt cross-channel matching wanneer hetzelfde product op meerdere kanalen verschijnt.
- Per-channel config in
channel.{id}.yaml— eigen prijs-floor/ceiling, keyword-allowlists, display-thresholds en validatieregels. - Per-channel Matomo site-IDs — analytics blijft schoon en aggregatie per merk klopt.
- Display-gates per kanaal —
min_display_scoreenrequire_image_for_displaybepalen of een product zichtbaar wordt; admin-views zien alles, frontend alleen het kwaliteitsfilter. - Composite scoring combineert prijs, beschikbaarheid, beeld en feed-betrouwbaarheid tot één rankingscore per product per kanaal.
Drie merken, drie design-systemen
Elk merk heeft zijn eigen brand-design-system (kleur, typografie, tone) — geserveerd vanuit dezelfde Symfony-applicatie via een ChannelService die templates, routes en configuratie scopt. Brand-namen, domein-namen en channel-defaults worden nooit hardcoded; alles loopt via een channel-context. Dat maakt het toevoegen van een vierde merk een config-actie, geen rewrite.
Redactie en SEO/GEO/WCAG
- Redactionele guides per merk met kanaalspecifieke auteur-defaults — beheerd in een eigen admin-omgeving.
- Product structured data met
offers,price,priceCurrencyenavailability; producten zonder afbeelding krijgen géén schema (Google-vereiste). - CLS-bewuste typografie — Inter met
display=optional, icoonfont met expliciete dimensies tegen layout-shift. - Mobile-first ontwerp- en build-discipline op consumer-pages; SEO, GEO en WCAG worden tijdens ontwikkeling toegepast, niet achteraf.
- Pinterest-export-feed en social-koppelingen per kanaal — content stroomt vanaf de site naar de connected socials.
Operationele weerbaarheid
- Auto-maintenance — kanalen met nul beschikbare producten gaan automatisch in 503-modus (60s gecached); voorkomt lege productpagina's tijdens import-gaps.
- /health endpoint dat altijd 200 JSON teruggeeft, gebruikt voor Docker-healthchecks (skipt maintenance- en rate-limit-subscribers).
- Redis voor sessies én voor de live activity-feed in het dashboard — graceful degradation als Redis tijdelijk wegvalt.
- Async messenger (twee transports:
feed_sync+enrichment) houdt feed-imports en AI-verrijking buiten de request-cycle. - HTTP-smoke-tests per kanaal-domein als verplicht onderdeel van de release-flow — PHPUnit alleen dekt geen Traefik/Apache-config-issues.
Techniek en kwaliteit
- Symfony 7.4 op PHP 8.3, Doctrine ORM, Twig 3.23 en Bootstrap 4.6 — productieversie v3.15.0.
- 1693 tests / 4159 assertions via PHPUnit 11; PHPStan level 6 met 0-error-baseline over 439 bestanden; PHP-CS-Fixer (PER-CS2) en phplint per release.
- Bitbucket Pipelines draait phplint, CS-Fixer, PHPStan en PHPUnit op elke master-merge en deployt vervolgens via SSH.
- Docker + Traefik dev- en productiestack; MySQL met custom config; OPcache afgesteld op de codebase (14k+ files,
max_accelerated_files=20000) tegen silent recompilation.
Resultaat
Drie merken, één onderhoudbare codebase, een gestage release-cadans (huidige major al op v3.x) en directe lijnen tussen marketingstrategie en technische uitvoering. Dit Petje fungeert ook als proeftuin voor patronen die terugkeren in opdrachtwerk — zoals de multi-brand-aanpak bij Stenenwinkeltje en in de Shopware Plugin Suite.