Sitio web estático de agenda cultural de Aldea Pucela, generado automáticamente a partir de la categoría de eventos del foro Discourse.
- Publicar una agenda cultural clara, rápida y accesible.
- Evitar dependencia en tiempo real del foro durante la navegación.
- Facilitar despliegue continuo y mantenimiento sencillo.
- Node.js (scripts de sincronización y build)
- Nunjucks (plantillas HTML)
- Tailwind CSS + PostCSS (estilos)
- GitHub Actions + GitHub Pages (CI/CD y hosting)
- Node.js 20 o superior
- npm
npm installnpm run sync # Sincroniza eventos desde Discourse a cache local
npm run build # Genera el sitio estático en dist/
npm run rebuild # Reconstrucción completa (re-sincroniza y regenera)
npm run dev # Flujo de desarrollo local
npm run clean # Elimina dist/Hay un script auxiliar en scripts/generate_events_poster.py para componer un poster de Instagram a partir de una base visual y los proximos eventos publicados.
Lee por defecto https://eventos.aldeapucela.org/site-data.json, filtra los proximos 3 dias en horario de Madrid, elige hasta 6 eventos y coloca sus carteles sobre la imagen base.
Tiene dos modos de seleccion:
next-days: reparte hasta6eventos entre los proximos dias para evitar que salgan todos del mismo dia.next-weekend: busca hasta6eventos variados del siguiente fin de semana, tomando como ventana desde el viernes a las15:00hasta el domingo a las23:59en horario de Madrid.
Bases por defecto segun el modo:
next-days:src/assets/social-base-story.jpgysrc/assets/social-base-post.jpgnext-weekend:src/assets/social-base-finde-story.jpgysrc/assets/social-base-finde-post.jpg
Salidas por defecto segun el modo:
next-days:scratch/posters/proximos-story.pngyscratch/posters/proximos-post.pngnext-weekend:scratch/posters/proximos-weekend-story.pngyscratch/posters/proximos-weekend-post.png
Las imagenes generadas deben escribirse en scratch/posters/. La cache temporal de carteles descargados se guarda por defecto en .cache/poster-images/.
Ejemplo generando story y post en una sola ejecucion:
python3 scripts/generate_events_poster.pyEjemplo para el siguiente fin de semana:
python3 scripts/generate_events_poster.py --mode next-weekendOpciones utiles:
--days 4para ampliar la ventana de eventos.--limit 6para ajustar el numero maximo de carteles.--mode next-dayso--mode next-weekendpara cambiar la logica de seleccion.--story-output ...o--post-output ...si quieres sobrescribir solo un destino.--keep-cachesi alguna vez quieres conservar la cache temporal de imagenes descargadas.--endpoint ...para usar otro JSON compatible.
El repositorio incluye dos workflows manuales para publicar posters en GitHub Pages:
generate-posters-next-days.ymlgenerate-posters-next-weekend.yml
Cada workflow:
- genera los PNG en
scratch/posters/ - actualiza los posters versionados en
src/posters/ - escribe un JSON minimo de metadata para automatizaciones externas
- hace commit automatico al repositorio para que el deploy normal de Pages los publique
Metadata publica disponible:
https://eventos.aldeapucela.org/posters/proximos.jsonhttps://eventos.aldeapucela.org/posters/proximos-weekend.json
Formato esperado:
{
"mode": "next-days",
"generatedAt": "2026-05-17T18:31:12Z",
"success": true,
"hasEvents": true,
"eventCount": 4,
"storyUrl": "https://eventos.aldeapucela.org/posters/proximos-story.png",
"postUrl": "https://eventos.aldeapucela.org/posters/proximos-post.png"
}La idea es que n8n consulte ese JSON y valide que la generacion es reciente antes de reutilizar la imagen.
Si hasEvents es false, el workflow solo actualiza la metadata y conserva los ultimos PNG versionados.
El proyecto sigue una arquitectura estática:
scripts/sync.mjsconsulta Discourse y normaliza eventos.- Los datos se guardan en
cache/para reutilización y resiliencia. scripts/build.mjsrenderiza plantillas Nunjucks y assets.- El resultado final se publica en
dist/. - GitHub Pages sirve el contenido generado.
Ventajas:
- rendimiento alto;
- SEO sólido con URLs únicas por evento;
- menor riesgo ante caídas o latencia de Discourse;
- despliegue reproducible.
La caché no es un detalle de implementación prescindible: es la pieza que permite que los cron de GitHub Pages sean ligeros. En un deploy normal no se vuelven a descargar los detalles de todos los temas.
El flujo de .github/workflows/deploy-pages.yml es:
- Restaura
cache/y el estado de.ci-state/. scripts/check-events-signature.mjsconsulta una sola vez el listado de Discourse, guarda una instantánea para que el build la reutilice y compara con el digest anterior únicamente los eventos vigentes o futuros. Además, detecta ediciones del primer post medianteupdated_aty firmas de contenido. Para no cargar el foro, solo sondea una tanda rotatoria de eventos vigentes o futuros (por defecto, 20 por intervalo).- Si encuentra cambios, publica sus IDs en
refresh_ids. scripts/build.mjsreutiliza la instantánea del detector y llama al sincronizador conrebuild: false. Este conserva los registros cuyotopicSignatureno ha cambiado y solo vuelve a leer los temas nuevos, editados o forzados medianteEVENT_REFRESH_IDS.- Guarda la caché actualizada y publica
dist/en GitHub Pages.
El título mostrado procede del tema de Discourse; el nombre del bloque
[event] solo se usa como respaldo. El detector incluye el título en su
digest y el sincronizador compara el título del listado con el registro
cacheado: si difieren, relee solo ese tema, incluso si su slug y fechas no
cambian. Esto también corrige los títulos antiguos sin invalidar toda la caché.
Esto significa que si alguien edita manualmente el primer post de un evento
vigente o futuro, un deploy posterior reconstruye únicamente ese evento. Si se
necesita forzar un tema concreto, se puede pasar su ID mediante
workflow_dispatch/EVENT_REFRESH_IDS. No se utiliza un webhook: la
detección sucede durante el propio deploy leyendo Discourse por HTTP.
Los temas pasados permanecen en la caché y en el archivo público, pero ya no
participan en el digest ni en las sondas de edición del cron.
En el bloque [event] de Discourse, location contiene únicamente el nombre
del recinto o lugar y address únicamente la calle y número (si se conoce).
La web usa location para agrupar eventos por espacio y compone
displayLocation como location · address para mostrar ambos datos juntos,
en mapas, calendarios, RSS y datos estructurados. Los registros históricos que
todavía tengan ambos valores mezclados se interpretan con el parser
determinista como compatibilidad, pero los nuevos eventos y reintentos deben
escribirlos separados desde n8n.
Reglas importantes para mantenimiento:
- No usar
--rebuilden el deploy normal. La reconstrucción integral está reservada al workflow manualresync-pages.yml. - No eliminar la restauración/guardado de
cache/,EVENT_REFRESH_IDS, el detector de firmas nipostUpdatedAtdel índice. - No sustituir el camino normal por
loadCachedEvents: impediría recoger ediciones del foro. - No añadir una descarga completa de detalles al cron de 15 minutos.
cache/,dist/y.ci-state/son artefactos generados y no se versionan.
La especificación ampliada para agentes de programación está en
AGENTS.md.
.
├─ src/
│ ├─ templates/ # Vistas Nunjucks (home, detalle, guardados, layout)
│ ├─ styles/ # CSS base y páginas
│ ├─ scripts/ # JS cliente
│ ├─ data/ # lógica de acceso/formato de datos
│ └─ assets/ # imágenes e iconos
├─ scripts/ # scripts de sync/build/dev
├─ cache/ # cache local de eventos sincronizados
├─ dist/ # salida estática lista para publicar
└─ .github/workflows/ # automatización CI/CD y despliegue
Flujo recomendado:
- Instalar dependencias:
npm install - Sincronizar datos:
npm run sync - Generar sitio:
npm run build - Iterar con flujo local:
npm run dev
Si detectas datos desactualizados o inconsistencias de cache, ejecuta npm run rebuild.
El repositorio incluye workflow para:
- ejecución en cada
pushamain; - ejecución programada por
cron(actualmente cada 15 minutos, UTC); - ejecución manual desde GitHub Actions.
Flujo del workflow:
- instala dependencias;
- sincroniza y reconstruye;
- publica
dist/en GitHub Pages.
- Asegura que la rama principal sea
main. - Ve a
Settings > Pagesen GitHub. - En
Build and deployment, seleccionaGitHub Actions. - Verifica permisos de Actions para publicar Pages.
- Frecuencia de actualización: configurable en
crondel workflow. - Cache local:
cache/reduce llamadas innecesarias y acelera builds; el deploy normal solo refresca los temas nuevos o modificados. - Reconstrucción forzada:
npm run rebuildpara refresco integral. - Artefactos generados (
dist/,cache/) no necesitan versionarse.
- Error por versión de Node:
- confirma
node -vy usa Node.js 20+.
- confirma
- Build sin eventos o datos viejos:
- revisa primero la salida de
check-events-signature.mjsy la caché restaurada; - ejecuta
npm run rebuildsolo si necesitas una resincronización integral.
- revisa primero la salida de
- Diferencias entre local y producción:
- revisa la última ejecución del workflow en GitHub Actions.
- Fallo de publicación en Pages:
- comprueba permisos y configuración en
Settings > Pages.
- comprueba permisos y configuración en
Este repositorio se distribuye bajo GNU Affero General Public License v3.0 (AGPL-3.0-only). Consulta el archivo LICENSE.
El contenido editorial/publicado de la agenda se muestra bajo Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0).
- Web comunidad: https://aldeapucela.org
- Repositorio código: https://github.com/aldeapucela/eventos