Skip to content
Alvaro Sarria
Menú
← Todo el trabajo

Wordsmith Retreat

Estantería personal de libros que fusiona el catálogo de solo lectura de Open Library con tus propios libros y marcadores en Supabase.

Problema

Las colecciones personales de libros son fáciles de perder de vista: qué tienes, qué has leído, qué merece una relectura. Quería un catálogo de verdad, no otra hoja de cálculo.

Enfoque

La app lee de dos fuentes a la vez y las fusiona en una única estantería: Open Library aporta los libros en tendencia semanal y la búsqueda por título en el catálogo público, pero es de solo lectura, mientras que Supabase guarda los libros que creas y los que marcas. Tus libros aparecen primero y después los resultados del catálogo. Si una de las dos fuentes está caída, la estantería sigue renderizando la otra y lo indica.

Arquitectura

  • Cliente: React 19 + Vite. Cada página de ruta gestiona su propia carga de datos y su estado; los componentes inferiores se rigen íntegramente por props
  • Capa de datos: una capa utils/ que habla con Supabase y Open Library y normaliza ambas en una única forma de libro, de modo que nada aguas abajo necesita saber de qué fuente vino
  • Base de datos: Postgres en Supabase con dos tablas — books para lo que creas y favorites para la estantería de marcadores — y políticas de row level security, sin las cuales cada inserción falla y la interfaz no hace nada sin avisar
  • Estilos: design tokens en styles/tokens.css; ningún color, espaciado ni tipografía escrito a mano fuera de ahí

Decisiones clave

  • favorites es una tabla aparte que fotografía el libro en lugar de ser un flag en books, así la página de marcadores se renderiza con una sola consulta en vez de una petición a Open Library por marcador. Una restricción CHECK obliga a que cada fila apunte exactamente a una fuente: una obra de Open Library o un libro local
  • Open Library limita a los clientes de navegador a aproximadamente una petición por segundo (el nivel superior exige un User-Agent propio, que los navegadores no permiten), así que las búsquedas se debouncean y las peticiones superadas se abortan
  • Las fichas de libro se obtienen en lugar de teclearse, de modo que añadir un libro del catálogo es una búsqueda, no un formulario

Resultados

Una estantería funcional con CRUD completo sobre tus propios libros, marcadores sobre ambas fuentes, un modal de detalle que carga la sinopsis completa bajo demanda, validación en línea y detección de duplicados al añadir un libro, temas claro y oscuro, y estados diferenciados de carga, vacío, error y caída parcial en toda la app.

Qué haría diferente

La app no tiene login: su clave publicable viaja en el bundle del navegador y las políticas de row level security le dan acceso total, lo cual está bien para una demo y mal para datos reales de usuario — añadir Supabase Auth y acotar las políticas a auth.uid() es la solución. También reconciliaría las fotografías de los marcadores, porque editar uno de tus libros deja el marcador existente mostrando la ficha antigua, y añadiría una suite de tests: ahora mismo npm run lint && npm run build es toda la definición de “no está roto”.