Blogpost

Van rommelige dataset naar werkend systeem

2026-04-12 · 4 min leestijd

pandaweb engineeringsystem design

Het laatste vak dat ik bij mijn studie AI had gekozen was een Computer Science-vak: web engineering. Vooral de deployment-kant van AI vond ik interessant, en daar had ik nog niet heel veel mee gedaan. Tijdens dat vak leer je hoe webapplicaties gestructureerd worden, maar ik wilde die ideeën liever toepassen op iets rommeligers dan een nette Kaggle-dataset.

Een vriend van mij heeft een hobby waarbij hij spullen bestelt uit China. Geen oordeel. De logistiek eromheen is alleen een beetje organisch geregeld. Shops zijn in het Chinees, productfoto’s zijn inconsistent, bestelbronnen komen van allerlei verschillende platforms en de rest van de informatie leeft verspreid over screenshots, willekeurige linkjes en losse notities.

De meest voor de hand liggende aanpak was een platte lijst van items geweest. Simpel, snel, klaar. Maar dan heb je ook direct een lijst met problemen. Wat als een item meerdere afbeeldingen heeft? Wat als je het meerdere keren bestelt? Wat als je een wishlist wil bijhouden?

Dus in plaats van een platte lijst heb ik een rijker domeinmodel gemaakt: losse entiteiten voor items, afbeeldingen, bestellingen en wishlist-entries, met relaties ertussen. Wat me daarna ook opviel: als je dat model serieus neemt, dwingt het je om je data netjes te houden. Een canonieke source URL per item bijvoorbeeld, zodat er geen duplicaten insluipen. Dat soort beslissingen lijken klein, maar hebben veel impact. Als het datamodel slap is, is de rest van het systeem dat vroeg of laat ook.

Toen het project groeide, werd ook duidelijk waarom die hele “lagen”-discussie bestaat. Frontend voor interactie, backend voor logica en workflows, database als bron van waarheid. Klinkt als tekstboekstof, maar zodra je meerdere flows hebt — items aanmaken, admin-acties, generatiejobs, wishlist-gedrag — merk je hoe snel het anders uit elkaar valt.

Iets vergelijkbaars gebeurde met API’s. In het begin voelt een endpoint als “haal deze data op”, maar eigenlijk leg je er gedrag mee vast. Bijvoorbeeld: voordat een item wordt aangemaakt, checkt de backend of het al bestaat. Dat soort logica hoort niet in de frontend. Dat is waar je systeem bepaalt wat wel en niet mag.

De productfoto’s in de dataset zijn vaak rommelig. Niet heel gek voor spullen uit Chinese webshops. Ik wilde nettere, catalog-achtige afbeeldingen genereren. Dat leek aanvankelijk het leukste onderdeel van het project: AI, beelden, fancy. Maar wat ik al snel merkte: het genereren zelf is het makkelijke gedeelte. Wat je systeem eromheen nodig heeft, is het interessante.

Ik heb het als een jobsysteem opgezet. Iedere generatieopdracht is een aparte job met een eigen status. Dat maakt het trackable en herhaalbaar. Als er iets misgaat, weet je waar, en je kunt het opnieuw proberen zonder de rest van de applicatie te raken. Dat soort infrastructuur kost meer tijd dan de feature zelf, maar het is wel het verschil tussen een demo en iets wat je daadwerkelijk blijft gebruiken.

Later heb ik daar een assistant bovenop gebouwd voor het toevoegen van items via Yupoo-links. Aan de buitenkant voelt dat een beetje als een chatbot, maar eronder zit een strakke flow. Iedere stap is expliciet en de backend geeft gestructureerde responses terug: wat er is gevonden, wat de volgende stap is, welke afbeeldingen je kunt kiezen. Flexibel van buiten, maar vrij deterministisch van binnen.

Daar liep ik ook tegen een praktisch probleem aan: afbeeldingen die prima in de browser werken, falen in productie door hotlinking en referer-restricties. Oftewel: zichtbaar betekent niet bruikbaar. De oplossing was een image proxy in de backend, zodat externe afbeeldingen eerst gecontroleerd binnenkomen. Kleine ingreep, groot verschil in betrouwbaarheid.

Ik had aanvankelijk originele afbeeldingen direct naar de client gestuurd. Die waren soms megabytes groot per stuk, omdat de bronfoto’s onbewerkt zijn. Dat werkt, maar het is traag en duur. Uiteindelijk heb ik een conversie toegevoegd: originelen voor interne verwerking, kleinere WebP-versies voor weergave. Dat scheelde enorm.

Verder heb ik op een paar plekken lichte client-side caching ingebouwd voor de catalogus- en profielweergave. Niet ingewikkeld: data tijdelijk opslaan zodat je bij navigatie niet alles opnieuw hoeft op te halen. De backend blijft de source of truth, maar de UI voelt een stuk sneller.

Kortom: Panda begon als een dataset van een vriend en groeide uit tot iets wat meer op een echt systeem lijkt. Items, wishlist-intentie, bestellingen, afbeeldingsgeneratie en een assistent erbovenop. Wat eerst losse concepten waren — data modelleren, lagen scheiden, API’s ontwerpen en omgaan met falende systemen — werden tijdens het bouwen ineens heel concreet.