La Casa de Pickleball
La Casa de Pickleball is “la casa del pickleball en español” — a publication for the Spanish-speaking pickleball community, built to turn an Instagram following into an owned audience. The site is Spanish first and English second, on purpose and in the schema: a discounts directory with partner codes, articles, lessons, gear reviews, a video series archive, events, coaching, and, since September 2026, a paid training guide. The founders edit all of it themselves. It went from a seventeen-page brief to a live site in two days and to a publication in six weeks. I am a partner in the company, not its contractor.
- Role —
- A partner in La Casa de Pickleball. Carlos and David asked me to join the company to launch the site with their vision; I designed, built and operate it, end to end.
- Timeline —
- August 2026 — ongoing
- Stack —
- Next.js 16 (App Router), React, TypeScript, Sanity (Studio, private dataset), next-intl (localized routes), Stripe Checkout, Resend, Vercel Blob, Umami + Vercel Analytics, Tailwind CSS v4 + shadcn/ui, vitest + Playwright
The problem
Carlos Zambrano started La Casa on Instagram and built a real following among Spanish-speaking players, then partnered with David Rosales — the founder of Wakamole PBC, and already my client — to make content together. When they wanted a home for it, they did not hire me; they asked me to join the company as a partner and launch the site with their vision. The vision arrived as a seventeen-page brief, and it was explicit about what it was not: not a brochure. A living publication that converts social-media attention into an audience La Casa owns, that generates affiliate sales it can actually track, and that David and Carlos can update end to end without calling a developer. Spanish complete; English present without creating duplicate content. And one acceptance criterion stricter than the rest: every active discount reachable in two taps, with Copy Code and Shop Now working inside Instagram’s in-app browser, because that is where the audience already was.
What I built
The first two days were the discounts directory, on purpose. It was the brief’s own “critical conversion page” and its strictest requirement, so building it first proved the whole stack on the revenue path — brand tokens with contrast rules encoded as tests, a Logo component that cannot pair the wrong lockup with the wrong background, localized routes so /es/descuentos and /en/discounts are separately indexable, a Sanity schema where Spanish is required and English optional, a tracked redirect for every Shop Now, a Copy Code button with a fallback for Instagram’s webview, and Playwright asserting the two-tap rule. It went to production on August 7, 2026, the day after the first commit.
The next two weeks built the publication around it: an editorial design system — a newspaper masthead with a live count of active offers, type-led offer pages where the discount numeral is the image, generated brand tiles that a photograph can later drop into — then the engines, one a day: articles, lessons, gear reviews with seven rating axes, a video series archive, events, coaching and contact with an inquiry pipeline, About, Partners and Community. Search across all of it came on August 26. The whole time, a public content-gaps list and a thirty-one-question document to the founders kept launch blocked on La Casa filling fields, never on code; the affiliate roster itself was seeded from Wakamole’s partners page and then corrected against what David sent back.
From September the work turned to operating it and selling from it. A password-protected panel gives David and Carlos the five numbers that matter, the inquiry queue they can answer in place, and QA scripts with recorded verdicts. An hourly health cron checks the specific ways this site has broken silently. Legal policies were drafted from what the code actually does and published at the founders’ request. Then the first product: Cómo entrenar para llegar a ser un 5.0, a training guide sold through Stripe with the price decided server-side, a launch-price window Carlos controls from the Studio and the panel shows on an Eastern-time clock, the PDF in private storage, and a tokenized download only the buyer can open. It went on sale on September 18. The site is instrumented for the numbers; this early, the case study quotes none.
Decisions worth explaining
The engineering, for anyone who wants it.
Prose 404s; utility falls back
The brief asked for two things that pull against each other — separately indexable URLs per language, and one discount record reused everywhere — and for English never to create duplicate content. The resolving rule is about publishing lifecycle, not about whether something is prose: if a content type needs to be published in one language before the other, it is localized at the document level; if it is a single real-world fact, at the field level. Articles, lessons and reviews are documents, because Spanish ships first and English lags, routinely. A discount is fields, because there is one code and one expiry and two copies would drift. Then the asymmetric fallback: an English article route exists only where a reviewed English document exists — otherwise it is absent from the sitemap and 404s, never Spanish body copy under /en/. But a Spanish “why we recommend it” does show on the English discounts page, because hiding an active code from an English visitor would break the two-tap rule. Functional parity beats translation purity on the path where money moves.
Shop Now is never a plain link
Every affiliate button goes to /r/[slug], which injects the tracking parameters on the server and redirects. Three reasons, none of them cosmetic. Server-side tracking survives ad blockers and JavaScript failure — a client-side click event on a raw outbound link fails the “Shop Now is tracked” criterion the moment a blocker is active, which on a discounts site is a meaningful share of visitors. The affiliate URLs stay out of the page source. And the founders can change a destination in the Studio with no deploy. Copy Code has its own fallback, because the clipboard API is unreliable inside Instagram’s in-app browser, and the brief named that browser as the primary source of traffic.
A green button always carries dark text
The brand manual gives three colours: Manzana green, Militar charcoal, Crema off-white. Measured, not estimated: white on Manzana is 2.31:1 and Crema on Manzana is 2.05:1, both failing WCAG badly, while Militar on Manzana is 6.61:1. The instinct on a green primary button is white text, and every call to action in the brief is a green button. So the button component offers only the passing pairings, and a unit test asserts the palette is closed. The same move for the logo: the asset named “Principal” is the dark-background lockup and is invisible on white, so a Logo component takes a variant and picks the file, and no call site can get it wrong.
An empty page is a silent failure, so it fails the build instead
The Sanity dataset is private. An unauthenticated query against it does not return 403; it returns 200 with an empty result. A deploy missing its read token would therefore render a discounts page with zero offers and no error in any log — the revenue page, blank, quietly. The client refuses to boot without the token whenever it is running on Vercel, so a misconfigured deploy fails the build rather than shipping nothing. The same instinct built the health cron: after /studio answered 500 in production for an unknown number of days while every page worked and every test passed, an hourly job now actively checks the specific things this site can break silently — the active-offer count, the Studio, the Instagram feed — because a route nobody visits produces no error logs.
Launch blocked on content, never on code
The brief listed substantial assets still to come: photography, biographies, real discount percentages, legal text. Every engine was built to run on structured Spanish placeholders and to render honestly without the missing piece — a generated brand tile where a product photo will drop in at identical dimensions, name-only partner rows where a dark-background logo does not exist yet, “Exclusive discount” where a percentage is unconfirmed, because we will not invent one. The legal pages shipped empty on purpose: the engine exists, the route 404s until counsel writes the body, and we do not draft legal language. Two documents in the repository — content-gaps.md and a thirty-one-question list for the founders — say exactly what is waiting on whom. Client communication itself lives in the repo as scripts that create and update Trello cards, so what was asked, when, and what shipped is in git.
No cookie banner, asserted rather than assumed
Analytics run on Umami and Vercel Web Analytics, both cookieless, so the site sets exactly one cookie — the locale preference, which is functional and needs no consent — and therefore needs no consent banner. That is a legal position resting on a technical claim, and “we did not add a tracking cookie” is precisely the kind of claim that quietly stops being true when someone adds a tag. So a Playwright test walks the site and fails if any cookie other than the allowed one appears. Both collectors receive every event: Vercel’s because it has the data back to launch, Umami’s because it is the one David and Carlos can open.
The price is decided at the till, not on the page
The guide has a regular price and a launch price with an end date, both set by Carlos in the Studio. The page shows one; the checkout route computes the same one, from the same function, at the moment of payment — because a price rendered into a page can be stale by the time someone clicks, and the first version had exactly that gap. Every ambiguous state resolves to the regular price: a half-configured early bird is someone mid-edit, not an offer. Fulfilment is one payment, one email, idempotent under Stripe’s retries; the PDF lives in private storage and the download link carries a token only the buyer holds. Times in the panel are Eastern by name, not by offset, so the November clock change does not move a launch window an hour.