Doplax.Dev
← Volver a proyectos
Sport Moto Team

Capacidades

  • Tandas en directo desde TrackLap
  • Back office
  • Imágenes en CDN
  • Email transaccional

Frontend

Next.jsNext.js
TypeScriptTypeScript
TailwindTailwind

Backend

PostgreSQLPostgreSQL
NeonNeon
CloudinaryCloudinary
NodemailerNodemailer
DockerDocker

Sport Moto Team

En desarrollo

Sport Moto Team es la Yamaha Official Riding School: más de quince años organizando tandas de moto en circuito por toda España. Su web vivía en una plataforma antigua y la rehice como un proyecto Next.js 14 con App Router y componentes de servidor: home con la próxima tanda y cuenta atrás, calendario mensual y anual, alquiler, seguro anual, libro de visitas, media y contacto. Las tandas no se escriben a mano: se leen de la API pública de TrackLap, donde el club ya las gestiona. Detrás hay un panel desde el que el equipo edita textos, banners, patrocinadores, fotos y opiniones, sobre PostgreSQL y con las imágenes en Cloudinary.

El reto

El club ya gestiona sus tandas en TrackLap, así que la web no podía convertirse en un segundo sitio donde mantener las mismas fechas, plazas y precios: tenía que leerlas de allí y estar siempre al día sin que nadie tocara nada. Todo lo demás —textos, fotos, patrocinadores, opiniones— lo cambia el propio club, muchas veces desde el móvil a pie de circuito, así que el panel tenía que ser cómodo en pantalla táctil y no depender de un desarrollador para cada cambio. Y la misma base de código tenía que desplegarse igual en Vercel que en un VPS propio.

Capturas

Arquitectura

Diagrama de arquitectura de Sport Moto Team

Implementación

  • Tandas en directo desde TrackLap

    La home, el calendario y la cuenta atrás de la próxima tanda se alimentan de la API pública de TrackLap con componentes de servidor y revalidación cada cinco minutos; el botón de reservar lleva a la inscripción en TrackLap. Un test de contrato compara la respuesta real de producción con el tipado local para que un cambio en el backend salte antes de llegar a la web.

  • El contenido manda desde la base de datos

    Cada texto de la web es un bloque en content_blocks: el literal del código es solo el fallback si la fila no existe. El club edita por secciones con vista previa o directamente pinchando el texto en la propia web con el modo edición, en las ocho páginas.

  • Panel multiusuario con sesión firmada

    Usuarios con rol owner y editor, contraseñas con scrypt y sesión en cookie HttpOnly firmada con HMAC-SHA256. El middleware corre en Edge y solo valida firma y caducidad; la comprobación autoritativa la hace cada ruta de API en Node, y cambiar una contraseña o desactivar a alguien caduca sus sesiones al instante subiendo su token_version.

  • Freno a la fuerza bruta y arranque en frío

    Cinco fallos por IP y usuario bloquean el login quince minutos. Si la tabla de usuarios está vacía, la primera entrada con la contraseña de entorno crea al owner; a partir de ahí manda la base de datos y esa variable deja de usarse.

  • Libro de visitas moderado con quince años de histórico

    Las opiniones nacen ocultas y se publican desde el panel, con posición fija opcional, y las 660 opiniones de la web antigua (2011–2026) se importan de forma idempotente por su número original.

  • Imágenes a medida desde Cloudinary

    El panel sube fotos, banners y logos de patrocinadores a Cloudinary; las URLs se reescriben con f_auto, q_auto y el ancho justo para cada sitio, y la portada pasó de unos 9 MB a menos de 1 MB de imágenes.

  • Formularios que nunca se pierden

    Seguro anual y libro de visitas guardan primero en la base de datos y después avisan al club por correo con Nodemailer: si el correo falla, la solicitud sigue ahí y se ve desde el panel.

  • Un código, dos despliegues

    El cliente de base de datos elige driver según DATABASE_URL: el HTTP serverless de Neon en Vercel, o pg con pool contra un Postgres normal en el VPS con EasyPanel, empaquetado con Dockerfile. Los tests sustituyen la base de datos por un Postgres de mentira en memoria: ninguno toca una real.

  • Panel pensado para el móvil

    Se usa a pie de circuito: nada esencial detrás de un hover, 44 px de área táctil, confirmaciones en dos pasos en lugar de window.confirm y una barra de guardar fija con el número de cambios pendientes.

Frontend