Skip to content
Case study · 03 / 15← All work

Kabina

A press-kit platform for DJs in Latin America: presskit, booking inbox, visit stats and a mascot called Kabi.

Role
Product, design implementation and full-stack development
Stack
SvelteKit (Svelte 5), TypeScript, Go (chi + Huma), Postgres + sqlc, River, Cloudflare Workers + D1, Clerk
Panel home
Panel homeThe design handoff is compiled, not retyped
(01) The problem

DJs send their press kit as a PDF or a Drive folder that goes out of date the week after. Promoters ask for the same bio, photos, rider and dates over WhatsApp. Kabina gives each DJ one live page, a place to receive booking offers and a way to see who looked. It had to run on free plans, with hard caps, until it has paying users.

My roleI built the product end to end, from the design handoff to the API, payments and the demo.
(02) ResultsCounted in the code
110API operations typed in the web client from OpenAPI
83API routes simulated so the demo runs without the backend
9presskit templates over the same content
(03) Architecture

Three decisions that shaped it.

  1. 01

    The design handoff is compiled, not retyped

    Why. The designs came as 16 HTML prototypes. A small porter (tools/dc2svelte) splits each one into Svelte components, driven by a spec per screen. The dynamic parts live in a view model next to them, so a design change is a regeneration, not a manual diff.

    Trade-off. Generated files can't be edited by hand. Fixes go into replace rules in the spec, which is slower for one-off tweaks. Complex new views, like the booking inbox, are written by hand outside the generated folders.

  2. 02

    One build, two backends

    Why. With DEMO=1 the same SvelteKit app compiles for Cloudflare Workers and answers API calls from local handlers with sample data. Each visitor gets a session in D1 that expires after three days. People can try the full panel at demo.kabina.online without an account and without touching production.

    Trade-off. Every new endpoint needs a demo handler too, or the demo returns an empty response. That is a second implementation to keep in step with the Go API.

  3. 03

    Free tiers with caps enforced in the database

    Why. Kabi's AI and the poster generator run on the free Workers AI quota. Each request reserves its cost first with one atomic upsert in Postgres. If the day's cap would be passed, no row comes back and the call never goes out.

    Trade-off. The cost is an estimate before the call and is corrected after. Users can hit a daily limit that a paid plan would not have.

(04) GalleryKeep scrolling →
Panel home
Panel home · The week at a glance: visits, plays, booking clicks and offers waiting for an answer. Sample data from the demo.
Templates
Templates · Nine templates over the same content. Switching keeps the bio, music, dates and photos.
Stats
Stats · Visits, plays, booking clicks and EPK downloads, with sources and who viewed the presskit. Visitors are never shown by email.
Public presskit on a phone
Public presskit on a phone · The page promoters open. Server-rendered, with SEO tags and a tracked booking button.
(05) What I'd do next
01Launch: move the stack to the VPS with Docker Compose and Caddy, and turn on the deploy workflow.
02Generate the demo handlers' types from the same OpenAPI file, so a missing or outdated handler fails the build.
03Build Escena: turn Discover into a network for the electronic scene, with city pages, follows and gig listings on top of the presskits.
Next project · 04 / 15
Paso →Ticketing platform with 98 screens checked against the design
Case study · 03 / 15

Kabina

A press-kit platform for DJs in Latin America: presskit, booking inbox, visit stats and a mascot called Kabi.

Role
Product, design implementation and full-stack development
Stack
SvelteKit (Svelte 5), TypeScript, Go (chi + Huma), Postgres + sqlc, River, Cloudflare Workers + D1, Clerk
Kabina
(01) The problem

DJs send their press kit as a PDF or a Drive folder that goes out of date the week after. Promoters ask for the same bio, photos, rider and dates over WhatsApp. Kabina gives each DJ one live page, a place to receive booking offers and a way to see who looked. It had to run on free plans, with hard caps, until it has paying users.

My roleI built the product end to end, from the design handoff to the API, payments and the demo.
(02) Results
110API operations typed in the web client from OpenAPI
83API routes simulated so the demo runs without the backend
9presskit templates over the same content
(03) Architecture

Three decisions that shaped it.

01

The design handoff is compiled, not retyped

Why. The designs came as 16 HTML prototypes. A small porter (tools/dc2svelte) splits each one into Svelte components, driven by a spec per screen. The dynamic parts live in a view model next to them, so a design change is a regeneration, not a manual diff.

Trade-off. Generated files can't be edited by hand. Fixes go into replace rules in the spec, which is slower for one-off tweaks. Complex new views, like the booking inbox, are written by hand outside the generated folders.

02

One build, two backends

Why. With DEMO=1 the same SvelteKit app compiles for Cloudflare Workers and answers API calls from local handlers with sample data. Each visitor gets a session in D1 that expires after three days. People can try the full panel at demo.kabina.online without an account and without touching production.

Trade-off. Every new endpoint needs a demo handler too, or the demo returns an empty response. That is a second implementation to keep in step with the Go API.

03

Free tiers with caps enforced in the database

Why. Kabi's AI and the poster generator run on the free Workers AI quota. Each request reserves its cost first with one atomic upsert in Postgres. If the day's cap would be passed, no row comes back and the call never goes out.

Trade-off. The cost is an estimate before the call and is corrected after. Users can hit a daily limit that a paid plan would not have.

(04) Gallery
Panel home
Panel home · The week at a glance: visits, plays, booking clicks and offers waiting for an answer. Sample data from the demo.
Templates
Templates · Nine templates over the same content. Switching keeps the bio, music, dates and photos.
Stats
Stats · Visits, plays, booking clicks and EPK downloads, with sources and who viewed the presskit. Visitors are never shown by email.
Public presskit on a phone
Public presskit on a phone · The page promoters open. Server-rendered, with SEO tags and a tracked booking button.
(05) What I'd do next
01Launch: move the stack to the VPS with Docker Compose and Caddy, and turn on the deploy workflow.
02Generate the demo handlers' types from the same OpenAPI file, so a missing or outdated handler fails the build.
03Build Escena: turn Discover into a network for the electronic scene, with city pages, follows and gig listings on top of the presskits.
Next projectPaso →
Nahuel SantillánEN