Saltar al contenido
Miguel Llobell

Studio38

Web de una academia de danza con un mini-CMS propio: la propietaria edita fotos, textos y horarios sin tocar código ni redesplegar.

2026 En producción Rol: Diseño, desarrollo y despliegue Astro 7 · Tailwind CSS 4 · TypeScript · Zod · sharp · Node.js SSR · Docker
Portada de la web de Studio38, con el rótulo y los botones de contacto

Contexto

Studio38 es una academia de danza de Elche (Alicante). Necesitaba una web que presentara sus clases, horarios y galería, y poder mantenerla sin depender de un programador cada vez que cambia una foto o un horario.

La respuesta fue construir la web y, junto a ella, un panel de contenido a medida. Es el mismo enfoque que uso en este portfolio: el contenido se gestiona desde un panel y el código no se toca.

Mi contribución

Planteé el proyecto de principio a fin: diseño de la web, panel de contenido, modelo de datos, seguridad y despliegue en servidor propio con Cloudflare Tunnel.

Problema

Una academia de danza cambia fotos, horarios y clases cada curso. Depender de un programador para cada cambio es lento y caro.

Solución

Una web SSR con un panel privado de un solo usuario: edita el contenido, lo previsualiza como borrador y lo publica. El contenido vive en el servidor, no en el código.

Funcionalidades

  • Panel privado con login de un único usuario y sesión firmada
  • Edición de fotos, textos, horarios, clases, profesores y SEO desde el navegador
  • Borrador con previsualización antes de publicar, e historial con versiones restaurables
  • Pipeline de imágenes: el original se guarda en privado y se sirven derivados WebP responsive
  • Horarios y clases como datos estructurados, no como texto suelto

Retos técnicos

  • Pipeline de imágenes content-addressed e inmutable: los archivos nunca cambian de nombre, así que se cachean para siempre
  • Seguridad propia del panel: contraseña con scrypt, CSRF de doble envío, rate-limit de login y CSP en todas las respuestas
  • SSR detrás de Cloudflare Tunnel: protección de origen hecha en middleware porque el adapter de Node no lee X-Forwarded-Proto
  • Despliegue repetible con Docker Compose, datos en volúmenes y un script idempotente