Skip to content

ProCourt


This project was vibecoded with Claude Code. I set the problem, the design and the demo; we wrote the code together.

ProCourt started as an assignment for the course Advanced English for Communication Technologies at the University of Valladolid: pitch a product idea in English and defend it with a live demo. I picked an everyday problem, booking a sports court without phone calls, keys or waiting around, and took it through to a working application.

Booking is only the beginning: once they’ve paid, players open the court door from their phone with a simulated smart lock, and if they overrun their slot they’re charged an overtime fine automatically. The fine is counted in full minutes after a configurable grace period (by default 5 minutes) and charged off-session to the saved card:

fine=minutes overrun×hourly price×fine rate\text{fine} = \text{minutes overrun} \times \text{hourly price} \times \text{fine rate}

The default fine rate is 0.02. All state lives in a relational database with foreign keys, CHECK constraints, amounts stored in cents and a transaction around every write, and the admin panel and the phone stay in sync by polling the server state every few seconds.

What it offers

Players

  • A catalogue of 11 padel, tennis and 5-a-side football courts across 3 venues, with photos, surface, rating and hourly price.
  • An availability calendar and booking in 30-minute steps, from 30 minutes up to 4 hours.
  • Payment through Stripe Checkout (test mode) and a backup PIN for the door.
  • An open-door button that unlocks 10 minutes before the start, with a session timer and a warning 5 minutes before the end.
  • Automatic overtime fine, with a final breakdown of booking and fine.
  • Meet Up: publish an open match with a skill level, pay only your share, and join other players’ matches.
  • Refund if the lock fails.
  • English and Spanish interface, light and dark mode, installable as a PWA.

Managers

  • A panel with the live status of every court (free, booked, in use or overtime).
  • KPIs for revenue, fines collected, occupancy and today’s bookings.
  • Manual booking with a PIN for people without a smartphone, and remote opening of any door.
  • Live editing of prices, grace minutes and fine rate.

Demo

  • Hidden controls to time-travel (jump to the start, to 5 minutes before the end, or to the end of a booking), simulate a lock failure and reset the data, built for a roughly 60-second pitch from booking to open door.

Technical

A Next.js (App Router) app with React and TypeScript, styled with Tailwind v4 and shadcn/ui components and following the Figma design closely. Data is stored in Turso (libSQL) and payments go through Stripe; if either fails, the app falls back to local SQLite or a mock checkout so the demo never breaks on stage. It’s deployed to Cloudflare Workers through OpenNext. The design and the direction of the product are mine.

Este proyecto está vibecodeado con Claude Code. Yo planteé el problema, el diseño y la demo; el código lo escribimos juntos.

ProCourt nació como proyecto para presentar en inglés, una idea de producto y defenderla con una demo en directo. Elegí un problema cotidiano, reservar una pista deportiva sin llamadas, sin llaves y sin esperas, y lo llevé hasta una aplicación funcional.

La reserva es solo el principio: tras pagar, el jugador abre la puerta de la pista desde el móvil con una cerradura inteligente simulada, y si se pasa de su hora se le cobra automáticamente una multa proporcional al tiempo excedido. La multa se calcula en minutos completos pasada una tolerancia configurable (por defecto 5 minutos) y se carga fuera de sesión a la tarjeta guardada:

multa=minutos excedidos×precio por hora×tarifa\text{multa} = \text{minutos excedidos} \times \text{precio por hora} \times \text{tarifa}

La tarifa por defecto es 0,02. Todo el estado vive en una base de datos relacional con claves foráneas, restricciones CHECK, importes en céntimos y transacciones en cada escritura, y el panel y el móvil se mantienen sincronizados consultando el estado del servidor cada pocos segundos.

Qué ofrece

Jugadores

  • Catálogo de 11 pistas de pádel, tenis y fútbol 5 repartidas en 3 sedes, con fotos, superficie, valoración y precio por hora.
  • Calendario de disponibilidad y reserva en tramos de 30 minutos, de 30 minutos a 4 horas.
  • Pago con Stripe Checkout (modo prueba) y un PIN de respaldo para la puerta.
  • Botón de apertura que desbloquea 10 minutos antes del inicio, con temporizador de sesión y aviso a 5 minutos del final.
  • Cobro automático del tiempo excedido, con desglose final entre reserva y multa.
  • Meet Up: publicar un partido abierto con nivel, pagar solo tu parte y unirse a los de otros jugadores.
  • Reembolso si falla la cerradura.
  • Interfaz en inglés y español, modo claro y oscuro, instalable como PWA.

Gestores

  • Panel con el estado en directo de cada pista (libre, reservada, en uso o en exceso de tiempo).
  • Indicadores de ingresos, multas cobradas, ocupación y reservas del día.
  • Reserva manual con un PIN para quien no lleva smartphone, y apertura remota de cualquier puerta.
  • Ajuste en directo de precios, minutos de gracia y tarifa de multa.

Demo

  • Controles ocultos para viajar en el tiempo (saltar al inicio, a 5 minutos del final o al final de la reserva), simular un fallo de cerradura y reiniciar los datos, pensados para una presentación de unos 60 segundos desde la reserva hasta la puerta abierta.

Técnico

Aplicación Next.js (App Router) con React y TypeScript, estilos con Tailwind v4 y componentes de shadcn/ui, siguiendo fielmente el diseño de Figma. Los datos se guardan en Turso (libSQL) y los pagos pasan por Stripe; si alguno falla, la app recurre a SQLite local o a un checkout simulado para no caerse en plena demo. Está desplegada en Cloudflare Workers mediante OpenNext. El diseño y la dirección del producto son míos.