All posts

From SnowTeach to a Generic Marketplace: RocRoi, KayakGrandTour, NaturaAdventour

Published Aug 8, 20253 min read
  • Product
  • Marketplace
  • Engineering
From SnowTeach to a Generic Marketplace: RocRoi, KayakGrandTour, NaturaAdventour

Key takeaways

  • It took roughly two and a half years, and running RocRoi and then KayakGrandTour, before SnowTeach's original open question got validated enough to invest in generalizing it.
  • One Go backend with Ent, one Directus CMS, one Next.js storefront and backoffice now power RocRoi, KayakGrandTour and NaturaAdventour through environment variables, not three forked codebases.
  • Unlike Lueira's multi-tenancy, these three brands share the same booking/inventory logic while needing genuinely distinct branding, SEO and content because they can compete for the same customer.
  • The shared core is now growing a Mastra-based AI service for SEO/translations, plus a catalog MCP server exposing interactive widgets.

In December 2022 I wrote about SnowTeach, our first two-sided marketplace, and ended that post with a question I genuinely didn't know the answer to: if it works, is there a more general version of this platform underneath it — not a marketplace for snow-sports classes specifically, but for other outdoor activities running into the same two-sided problem? I said at the time that not knowing was the whole point of writing it down. It took about two and a half years, and two more brands running on the same code, to actually find out.

1. What changed since SnowTeach

SnowTeach worked well enough, and taught us enough about running a marketplace, that the next natural test wasn't "should we build another one" but "can the same platform carry a different brand." RocRoi was that test: adventure activities in Spain, rafting and kayak among them, a different sport and a different customer than ski and snowboard schools, but recognizably the same two-sided shape underneath.

Then came KayakGrandTour, and that one stretched the model harder than RocRoi did. It isn't a single-region marketplace the way SnowTeach and RocRoi started out; it's a nationwide, multi-destination catalog spanning Cantabria, León, Menorca, Valencia, Zaragoza, Lleida, Málaga and more, across kayak, rafting, canyoning, canoes, SUP, via ferrata, triathlon, hiking and multi-adventure packages. Getting a catalog that varied to behave consistently is what actually forced the question SnowTeach had only raised. By the time NaturaAdventour came along as a third brand, the pattern was undeniable: we weren't building marketplaces one at a time anymore, we were building the same marketplace three times with different clothes on.

2. One codebase, three brands

What we generalized is one Go backend with Ent as the ORM, Directus as the CMS, and a Next.js storefront and backoffice — a single codebase that now powers RocRoi, KayakGrandTour and NaturaAdventour through environment variables rather than three forks. One deployment pipeline, one booking and inventory engine, one catalog model. What changes per brand is configuration: branding, domain, storefront copy and presentation, not the logic underneath.

This is the boring, unglamorous payoff of generalizing late instead of early. If we'd tried to design a "generic outdoor marketplace" from SnowTeach's first commit, we'd have been guessing at requirements RocRoi and KayakGrandTour hadn't taught us yet.

3. A different kind of "one core, many faces" than Lueira

I've written before about why Lueira, our booking platform for sports schools, was designed multi-tenant from day one. That's the same instinct at work here — one core serving many — but the axis of variation is genuinely different.

Lueira's tenants are different businesses: a ski school in the Pyrenees and a dive center in the Canaries, sharing infrastructure and a back office, but never seeing each other's data and never competing for the same customer. Isolation is the whole point.

RocRoi, KayakGrandTour and NaturaAdventour aren't separate businesses in that sense — they're one business wearing three different storefronts, and those storefronts can genuinely compete for the same person. Someone searching for a kayak trip in Spain could land on RocRoi or on KayakGrandTour. That means branding, SEO and content per brand can't be a cosmetic reskin — each brand needs its own voice, its own positioning, its own search footprint, or it cannibalizes itself instead of adding reach. The hard part isn't sharing the booking and inventory logic; the hard part is making three brands that share a spine look and read like they don't.

4. What's next: an AI layer in the shared core

The core repo that all three brands run on has started growing a layer none of them had at the SnowTeach stage: a Mastra-based AI service that generates SEO and product descriptions and handles translations, mixing Claude Sonnet, Claude Haiku and GPT-5-mini depending on the task. Alongside it sits a catalog MCP server exposing interactive "MCP App" widgets — product cards, an availability calendar — built to render inside an MCP-compatible client like Claude or ChatGPT. I've written elsewhere about why we build MCP servers for almost everything at Maladeta, so I won't repeat that case here.

None of this was the plan when SnowTeach shipped. The question I asked at the end of that post sat unanswered for two and a half years, and it didn't get answered by sitting down to design a generic platform — it got answered by running a second brand, then a third, and noticing how much of the code didn't need to change to do it.