Part 1Marc de Batlle
0%
Part 1Marc de Batlle
All work06 / 11
Seven

The affiliate marketplaceFive retail partnerships, a curated catalogue with CLIP vectors, and a recommendation engine that knows how much it knows about you.

Chapter concepts
  1. 1WRDB's revenue model is affiliate commerce: recommend a product that fills a gap in someone's wardrobe and earn a commission when they buy it. I ran the affiliate side end to end, from the network applications and the programme partnerships to the feed pipeline, the catalogue and the scoring engine that blends discovery with personal taste by a continuous richness score.
  2. 2Role: Co-founder: the affiliate side, end to end. Status: Live.
  3. 3Stack: Awin, Supabase, pgvector, CLIP, gpt-4o-mini, Python, Swift.
  4. 4Key figure: 298 products live, from five Awin programmes.
06
PeriodJan 2026 to present
RoleCo-founder: the affiliate side, end to end
StatusLive

Recommend, do not sell

A wardrobe app knows something a shop never does: what the user already owns. WRDB's business model turns that into affiliate commerce. The app recommends a product that fills a real gap in the wardrobe, the user taps through to the merchant on a tracked link, and the network pays a commission on the sale. Nothing is stocked, nothing is shipped, and the recommendation is only worth showing if it is good. I owned that side of the company end to end: the applications to the networks, the programme partnerships, the product feed pipeline, the catalogue and the recommendation engine's design and SQL.

The partnerships came first. In January 2026 I applied to the affiliate networks with a publisher profile describing the app, its audience and the integration, and the pitch deck attached. CJ Affiliate blocked the application because a promotional property needs a live App Store link. Awin España accepted it on a refundable one-euro deposit. Inside Awin every merchant runs its own programme, so I applied programme by programme: thejewellershop.com ES joined on 29 January 2026 and activated its product feed the same day; Bonheur Jewelry, Dooers and Zapatos OBI were accepted after it; Palomo Spain is applied for. On the network's own figures the jeweller converts 16.15 percent of clicks, approves 93 percent of sales and pays 1.58 EUR per click, fifty-four days after the sale.

5
Awin programmes joined or accepted
14,274
products in the first merchant feed
298
products live after curation
16%
conversion rate on the jeweller's programme, network figure
1.58 EUR
earned per click on that programme, network figure
512
dimensions per product vector, the same as the wardrobe's
7
steps in the scoring query
0 EUR
paid for the catalogue: the feeds come with the programmes
1 EUR
the deposit, refundable
Exhibit 7-3
The partnerships
ProgrammeNetworkStatusTerms and notes
thejewellershop.com ESAwin EspañaJoined 29 Jan 2026Feed 101788, 14,274 products; 16.15% conversion, 93% approval, 1.58 EUR per click, 54-day payment
Bonheur JewelryAwin EspañaAccepted10% commission; feed to be activated
DooersAwin EspañaAcceptedFeed ingested with its own script
Zapatos OBIAwin EspañaAcceptedFeed ingested; images cropped for the flatlay
Palomo SpainAwin EspañaApplied10% commission, 30-day cookie
SHEINCJ AffiliateBlockedA promotional property needs a live App Store link
*Programme terms as shown by the networks at application time; conversion and earnings per click are the network's figures for the programme, not WRDB's results.

From feed to catalogue

A joined programme unlocks two things: a product feed and a tracked deep link per product. The jeweller's feed is a gzipped CSV of 14,274 rows that Awin refreshes every four hours. A fetch script downloads, decompresses and parses it; a price filter from 2 to 150 EUR keeps 6,111 rows; a curation script applies category and brand exclusions, de-duplicates variants on the model number, since the same design comes in gold, silver and several sizes, and scores what is left. The first cut was 100 products, then 200 split evenly between women and men, and the catalogue stands at 298 across the programmes today.

The feed carries a name, a price, a brand, a hierarchical category and up to five images, and nothing about colour, material or occasion. The pipeline fills the gap. Each product is inserted with its deep link, its image with the background removed and its bounding box measured so it can sit in a flatlay next to the user's own garments, tags from gpt-4o-mini for colour, style, pattern, material, season and occasion, a gender derived from the merchant category, and a 512-dimensional CLIP vector stored in a pgvector column. That last step matters most: the user's garments carry the same embedding, so visual similarity between a product and a wardrobe is one cosine distance.

Exhibit 7-5
One product, feed to feed
  1. 1.Programme joined; feed and deep links unlocked
  2. 2.fetch-awin-feed: gzip CSV, 14,274 rows
  3. 3.Price filter 2 to 150 EUR: 6,111
  4. 4.filter-feed: exclusions, dedup on model number, quality score
  5. 5.Ingest: background removal, bounding box, gpt-4o-mini tags, gender
  6. 6.CLIP vector, 512-d, pgvector
  7. 7.get_marketplace_feed scores and ranks for the user
  8. 8.Tap: deep link out; purchase webhook posts to Slack

An engine with no cold start

Most recommenders have a phase one for new users and a phase two for known ones, with a threshold between them. This one has neither. Every user carries a richness score between 0 and about 1 that says how much the system knows: a weighted sum of saturating functions of how many garments, vectors, outfits, interactions and feedback events they have, plus a few profile flags. A new account scores near zero and sees a discovery feed built from global popularity, product quality, recency and click-through with a little exploration noise. A power user scores high and sees a personal feed built from CLIP similarity to their own garments, their past interactions, the categories missing from their wardrobe, their style, colours and price range. Everyone in between sees a blend, and the blend moves as they use the app.

The marketplace has three tabs. For You is the standard blend. Missing in Wardrobe raises the effective richness to at least 0.5 and puts 60 percent of the personal score on wardrobe gaps, so it answers one question: what do you not own. Discover forces richness to zero and shows the same feed to everyone. One SQL function computes all of it in seven steps, from the user's dismissals and saves through CLIP scores and the context row to a diversified page that caps any brand at three products and any category at five, and returns each product with a reason code: a CLIP match, a wardrobe gap, trending, new, exploration, a style match or popular.

Three rules keep it honest. Penalties are soft, never exclusions: the opposite gender costs 0.6, a product dismissed in the last thirty days 0.9, one already saved 0.1. Every impression, view, click, save and dismissal is kept raw for training and rolled up by triggers into per-product and per-user statistics, with five cron jobs computing click-through, rolling windows, engagement scores and daily aggregates and archiving events older than ninety days. And the user's context row is recomputed by triggers whenever a garment, an outfit, an interaction, a rejection or a profile field changes, so the feed never scores against stale data.

Review of
Formulas

1.score = (1 − r) × discovery + r × personal + penalties
(7-1)
r
is the user's richness: 0.25 closet + 0.20 vectors + 0.20 interactions + 0.15 outfits + 0.10 behaviour + 0.10 profile, each a saturating 1 − 1 / (1 + n / k)
discovery
is 0.35 popularity + 0.25 quality + 0.20 recency + 0.10 click-through + 0.10 exploration noise
personal
is 0.30 CLIP similarity + 0.25 interactions + 0.15 wardrobe gap + 0.10 style + 0.10 taste + 0.05 colour + 0.05 price

Missing in Wardrobe uses max(r, 0.5) and moves the gap weight to 0.60; Discover sets r to 0. The half-way points k are 10 garments, 8 vectors, 20 interactions, 8 outfits and 15 feedback events.

The loop, per user

  1. 1Context: garments, vectors, outfits, interactions and profile feed one richness score
  2. 2Score: one SQL function blends discovery and personal signals by that score
  3. 3Diversify: brand cap three, category cap five, a reason code per product
  4. 4Show: For You, Missing in Wardrobe or Discover
  5. 5Log: every impression, view, click, save and dismissal, raw
  6. 6Roll up: triggers and cron jobs update product and user statistics
  7. 7Recompute: any change to the wardrobe or the profile rewrites the context row

What the numbers say

The engine is built and the catalogue is live, and the funnel it feeds is waiting on distribution. On the production pull of 15 September 2026, 45 of 145 accounts had consented to affiliate tracking, 15 accounts had engagement rows, and the interaction log held no affiliate clicks and no purchases. The app is still on TestFlight, so the marketplace has been seen by beta users and by nobody else. The honest reading is that the merchant terms are real, the catalogue is real, and the conversion rate is not yet WRDB's to claim.

That is also why it was built this way. The richness score means the first thousand users get a sensible feed on day one without a training set, the raw log means the first real clicks are already training data, and the purchase webhook means the first sale will land in Slack before anyone looks at a dashboard.

At a glance
RolePartnerships, feed pipeline, catalogue, recommendation design and migrations; the Swift marketplace screens with Alex Matos
NetworksAwin España, accepted; CJ Affiliate, blocked pending an App Store link
Programmesthejewellershop.com ES joined 29 Jan 2026; Bonheur Jewelry, Dooers, Zapatos OBI accepted; Palomo Spain applied
Catalogue298 products, 2 to 150 EUR, jewellery, shoes and accessories; Thomas Sabo, Leonardo and Fossil lead the first feed
Data modelaffiliate_products with clip_vector(512), user_context, product and user statistics, raw interaction log with 90-day archive
Engineget_marketplace_feed, seven CTEs, three feed modes, seven reason codes; five triggers recompute user context
BuiltJan to Feb 2026, phases 70 to 71 and 141 to 143 of the app; Awin purchase webhook to Slack
DataRepository documentation and the production pull of 15 Sep 2026
Continue
Previous chapterThe marketing machine
Next chapterWRDB