OLaNouKay: lo que una guía local de las Antillas francesas exige al código
TL;DR
OLaNouKay responde a tres preguntas en Guadalupe y Martinica: dónde comer un bokit, qué playa, qué río. El sitio reúne fichas de lugares, un mapa, clasificaciones por municipio y un panel para comerciantes.
Los pedidos y el pago no están abiertos. Este texto describe lo que el producto exigió al código.
Qué hace el producto
El producto se divide en dos superficies: una aplicación web para descubrir lugares y un panel para los comerciantes. En la parte de descubrimiento hay:
- Las fichas: fotos, descripción, horarios y menú del día cuando el comerciante publica uno.
- Las clasificaciones: listas por municipio y categoría, como
/gp/baie-mahault/bokit, ordenadas por número de vistas y después por nombre. - El mapa: marcadores coloreados por categoría, con filtros.
- Lokal Now: la página
/lokal-nowlista los lugares abiertos en ese instante, del más cercano al cierre al más lejano.
El panel cubre el menú del día, el stock, las promociones, los eventos y las estadísticas.
En junio de 2026 quité el mapa de la barra de navegación. La pestaña Bokit lo sustituyó: el producto se lanza con este único plato, y el mapa sigue accesible desde la portada.
Datos de lugares que no se deben inventar
Una guía local vale lo que valen sus fichas, y las mías pasan por herramientas distintas según el dato que falte.
El script de importación toma una lista de nombres y municipios, y consulta Google Places para obtener coordenadas, dirección, horarios, teléfono y fotos. Trabaja en dos tiempos:
planlee sin poder escribir y clasifica cada línea: por importar, ya presente, no encontrada, cerrada, fuera del archipiélago o fuera del catálogo.applycrea las fichas del plan revisado y omite las que ya existen. Relanzar el script tras una interrupción no crea duplicados.
La clasificación no se fía solo de los tipos de Google, que no conocen ni el bokit ni el food truck. La etiqueta de mi lista manda cuando es más precisa. No se copia ninguna descripción: las fichas importadas llegan con el texto vacío.
La geocodificación de Mapbox pide otra protección. Sin una zona impuesta, una calle «La Savane» podía resolverse cerca de Bayona, en la Francia continental. Cada petición lleva por eso la caja geográfica del territorio, y el script solo rellena las coordenadas que faltan.
El peor defecto venía de la visualización. Una ficha sin horarios mostraba «11h · 22h», y una ficha sin equipamientos declarados anunciaba terraza, entrega a domicilio, pago con tarjeta y wifi. Playas y ríos incluidos. Ahora, los horarios ausentes aparecen como «Non renseignés» (sin datos) en francés y el bloque de equipamientos desaparece.
Un mapa que solo carga en el navegador
El mapa se apoya en mapbox-gl, una biblioteca que necesita el navegador. El componente se carga por eso sin renderizado en servidor, y su código importa mapbox-gl al inicializarse. Las fichas, en cambio, se renderizan en el servidor y figuran en el mapa del sitio.
Los marcadores son elementos HTML construidos a mano. Un bug me impuso una regla de estructura: Mapbox escribe su propia transformación en el elemento exterior para situar el marcador. Un zoom al pasar el cursor, colocado en el mismo sitio, la sobrescribía y mandaba los marcadores a la esquina superior izquierda del mapa. El zoom vive ahora en un elemento interior.
La hora local de «abierto ahora»
Todo cálculo de apertura pasa por un desfase fijo de cuatro horas, porque Guadalupe se mantiene en UTC-4 todo el año. El cálculo resta ese desfase del instante actual y luego lee la hora en UTC:
const d = new Date(epochMs - GUADELOUPE_UTC_OFFSET_MS)
return d.getUTCHours() * 60 + d.getUTCMinutes()
La primera versión de la función programada updateIsOpen leía getHours(). El servidor funciona en UTC, y el parámetro timeZone de la programación solo regula el disparo. Una ficha abierta de 11:00 a 22:00 lo habría estado de 07:00 a 18:00 en el lugar. Ninguna ficha tenía aún horarios: corregí el defecto en octubre de 2026 antes de que produjera efecto.
La segunda trampa viene de los servicios nocturnos. Una entrada 18:00 → 02:00 abre un día y cierra al siguiente, así que openStateAt comprueba dos cosas: el servicio del día y el final del de la víspera. Antes de este cambio, la función programada marcaba como cerrado de forma permanente un servicio 18:00 → 00:00. Once casos de prueba cubren este cálculo.
De ahí salen otras dos decisiones:
- Dos lecturas:
updateIsOpenescribe el campoisOpencada 15 minutos, mientras que/lokal-nowrecalcula el estado en cada petición, sin caché estática. - Una copia asumida: las Cloud Functions no resuelven el paquete compartido en ejecución. El cálculo existe allí por duplicado, con un comentario que exige mantener alineadas las dos versiones.
La función recorre todas las fichas activas sin filtro de territorio: el mismo desfase se aplica a los lugares de Martinica.
Dos idiomas de interfaz y una canónica por versión
La interfaz existe en francés e inglés con next-intl, sin versión en español. El francés se queda en la raíz y el inglés vive bajo /en, lo que conservó las direcciones francesas existentes.
Esta estructura produjo un bug de SEO. Las páginas fijaban en el código su canónica hacia la ruta francesa: la versión inglesa se declaraba copia de la otra, sin etiqueta de idioma. Resultado observado: /en/gp/bokit salía en búsquedas francesas. La función alternatesFor da ahora a cada versión su propia canónica y anuncia la otra con hreflang.
Lo que no está abierto
El repositorio contiene más código del que el sitio pone en servicio, y conviene dejar escrita la diferencia:
- Pedidos y pago: las funciones de Stripe y la pantalla de pago existen, pero el pago con tarjeta nunca se ha probado de principio a fin. Nada se presenta como entregado hasta superar esa prueba.
- Votos: el código de las campañas existe, las campañas no se han lanzado. Un script aún puede votar en bucle con direcciones inventadas, y eso hay que impedirlo antes.
- Martinica: los datos de referencia cubren sus 34 municipios y el catálogo inicial contiene 11 bokits, pero las páginas por municipio solo existen bajo
/gp, y la importación de Google filtra por la zona de Guadalupe.
A 1 de noviembre de 2026, el repositorio está en la versión 0.3.8.