Solo para el mantenedor · Camilo

Manual de mantenimiento

Cómo funcionan las versiones, cómo publicar cada semana, qué mostrar en la demo y qué pedirle a quien está de turno.

Cómo llegar aquí: directo en programas-tierra-linda.pages.dev/mantenimiento.html, o desde la aplicación abierta con ?publicar, botón ⚙️ Mantenimiento. Los autores no ven ese botón, así que esta página no les aparece por ningún lado. Conviene tener las dos direcciones en favoritos.

0. Cómo funciona, en una página

Tres piezas, y cada una responde una pregunta distinta.

PiezaQué esQué resuelve
La página
index.html
Un solo archivo con todo: el diseño, la edición y la impresión. Cloudflare la sirve como un archivo cualquiera. Que cualquiera edite sin instalar nada ni crear cuenta.
El API
functions/api/
Un archivo de JavaScript que corre en el servidor de Cloudflare solo cuando alguien llama /api/…. Guardar y leer programas compartidos. Es la única pieza con llave.
La base
D1 programas-tl
Una base SQLite en mi cuenta de Cloudflare. Una fila por fecha + tipo de programa, más la tabla de autores (ahí también vive la marca de quién puede administrar). Que el programa publicado exista en un solo lugar y no en fotos de WhatsApp.

Qué pasa cuando un autor toca ☁️ Publicar: la página manda su programa y su código al API; el API comprueba el código contra la tabla de autores, deriva la fecha del texto ("Sábado 5 de septiembre de 2026" → 2026-09-05) y guarda esa fila. Desde ese momento, cualquiera que abra la página sin copia propia ve ese programa.

Qué ve cada persona al abrir la página, en este orden y con la primera que aplique:

  1. El programa que venga en el enlace que le compartieron (#…).
  2. Su propia copia, si estaba editando en ese equipo. Por eso lo publicado nunca le pisa el trabajo a nadie, y por eso yo veo mi borrador mientras los demás ven lo publicado.
  3. El vigente de la base: el sábado más próximo que aún no pasa. Puedo dejar el 5, el 12 y el 19 publicados y cada uno se estrena solo a medianoche del anterior. Si esa fecha tiene varios programas (culto y Sociedad de Jóvenes), abre el principal.
  4. El respaldo del repositorio y, en último caso, el ejemplo interno: la página nunca abre vacía.

Dos hojas, un solo programa. El botón 📣 Anuncios pasa a la hoja que el anciano de turno lee en voz alta. No es otro archivo ni otra dirección: los anuncios son un campo más del modelo, así que se guardan, se comparten y se publican con el programa. Lo que cambia es qué hoja se ve, y el botón de imprimir siempre saca la hoja que se está viendo.

Nadie instala nada. Nadie inicia sesión. El código de autor es la única llave.

1. Las tres versiones que existen

Casi todos los enredos que puedan pasar salen de confundir estas tres cosas. Son distintas y viven en lugares distintos.

VersiónDónde viveQuién la veSe actualiza
La copia de cada persona En el teléfono o computador de quien edita Solo esa persona, en ese equipo Sola, con cada tecla
El enlace (editable o de solo lectura) Dentro de la dirección, comprimido Quien reciba el enlace Nunca. Es una foto del momento en que se copió
El programa publicado La base de datos (D1 programas-tl), una fila por fecha Todos los que entren a la página sin enlace y sin copia propia Cuando un autor toca ☁️ Publicar
El enlace es una foto. Lo publicado es el original.

Consecuencia práctica: si Andrés comparte su enlace y después sigue corrigiendo, su enlace no cambia. Lo que sí cambia al instante es lo publicado: corrige y vuelve a publicar.

Los JSON de programas/ en el repositorio ya no son la fuente: son el respaldo y lo que ve la página si la base llegara a fallar. Vale la pena refrescarlos de vez en cuando (paso a paso abajo).

2. El flujo de una semana

1

Jueves o viernes: el de turno arma el programaautor

Abre programas-tierra-linda.pages.dev. Le sale el programa vigente, edita fecha, etiquetas del encabezado y espacios. Puede usar 🗂️ Programas para partir de otro sábado parecido.

2

Publica él mismoautor

Botón ☁️ Publicar. La página le pide confirmación, le pregunta qué programa del día es (el principal, o uno con nombre propio como la Sociedad de Jóvenes) y desde ese momento es lo que ve todo el que entre. Su código de autor ya está guardado en su aparato (lo recibió una vez como enlace ?a=…). Yo no estoy en el camino.

3

Se reparteautor

Manda al grupo el 👁️ Enlace de solo lectura o el PDF. El programa queda cerrado y nadie lo cambia sin querer.

Mi papel ahora es otro: ya no publico cada semana; administro los códigos de autor (👥 Autores), reviso de vez en cuando que lo publicado esté bien, y mantengo el respaldo en Git. Si un autor no puede publicar (código perdido, sin internet en el computador de la iglesia), el plan B de siempre sigue funcionando: me manda el enlace editable y publico yo.

3. Mi parte: autores, respaldo y base

Quién puede administrar (y por qué ya no depende de recordar una clave)

Administrar autores se abre de dos maneras, y por dentro son la misma: el servidor hashea lo que llega en Authorization y lo compara contra una fila.

Para cambiar la clave desde el panel, entrando con mi código, hay que escribir también la actual. Es a propósito: la clave es el único camino de vuelta si pierdo todos los dispositivos, y un enlace ?a=… filtrado (viaja en una URL, queda en el historial) no puede rotarla y dejarme afuera. La excepción es la primera vez, mientras la clave sigue siendo la que trae el código: ahí nadie la conoce y exigirla sería un candado sin llave.

La lista contesta quién es quién; la ficha de cada persona contiene las acciones. El panel abre con un renglón por persona, agrupados en Administran, Solo publican y Desactivados (estos últimos plegados), y cada rótulo lleva su cuenta: cuántos administran se responde sin abrir nada. Tocar un nombre abre su ficha, que ocupa el panel entero, y ‹ Todos los autores vuelve a la lista. Desde ocho autores aparece arriba un buscador por nombre, que ignora las tildes y que también encuentra a los desactivados aunque estén plegados.

Dentro de la ficha, los dos permisos son interruptores y no botones: un botón dice la acción («Dar permiso de administrar») y para saber el estado hay que leer la acción al revés; el interruptor dice el estado y debajo qué pasa si se toca. El vencimiento tiene su propio renglón, y abajo quedan Generar código y Desactivar. Cambiar un permiso deja abierta la misma ficha: los dos se reparten juntos.

El permiso se da y se quita en el mismo panel, con el interruptor Puede administrar de su ficha. El servidor no deja quitarle el permiso al último que administra si entré con un código; entrando con la clave sí, porque ahí no hay forma de quedar por fuera.

Cada persona tiene dos llaves y no abren lo mismo. El enlace ?a=… son 144 bits aleatorios que guarda el navegador: nadie lo teclea. El código de 6 dígitos existe para poder dictarse por WhatsApp, y eso mismo lo hace adivinable: un millón de combinaciones repartidas entre los códigos vivos. Por eso, por omisión, el código de 6 dígitos publica pero no administra, incluso si esa persona administra con su enlace. A quien de verdad lo necesite se le habilita uno por uno, con el interruptor Su código de 6 dígitos también administra, que en la ficha solo aparece en quien ya tiene el permiso de administrar. Quitarle a alguien el permiso de administrar apaga también este, para que no quede dormido y se despierte solo el día que alguien reponga el rol.

Cuándo se usó cada código, y hasta cuándo sirve. Cada renglón de la lista dice, debajo del nombre, cuándo se usó ese código por última vez («usado hace tres meses», «sin uso registrado») y, si tiene fecha de vencimiento, cuál es. El primer dato responde la pregunta que antes solo se podía adivinar: cuáles de los códigos vivos ya no los usa nadie. «Sin uso registrado» no quiere decir que nadie lo haya usado; quiere decir que no hay dato, porque el código es anterior a que esto existiera.

En la ficha, Vencimiento pone una fecha después de la cual ese código deja de servir, sin que nadie tenga que acordarse de desactivarlo. Es para quien participa una sola vez: un invitado que dirige un programa especial. Se escribe como 2026-12-31, y se deja en blanco para que no venza. Una fecha ya pasada no se acepta: si hay que cortar el acceso ahora, eso es Desactivar.

Resumiendo quién puede qué: yo tengo administración y firma; un anciano normal tiene solo firma; y quien administra puede cambiárselo a cualquiera desde este panel. La única puerta que no depende de nadie más es la clave, que sigue pidiendo la actual para cambiarse.

Pasar mi permiso a otro dispositivo: botón 📱 Mi enlace del panel. Muestra mi enlace y su QR; el celular lo escanea y queda con el mismo permiso. Ese enlace es mi llave: no se reenvía. Cambiar la clave de emergencia: botón 🔑 Cambiar la clave, mínimo 10 caracteres, sin terminal y sin calcular hashes a mano.

Crear o revocar un código de autor

  1. Abrir programas-tierra-linda.pages.dev/?publicar → botón 👥 Autores. Ese botón me aparece en la página normal, sin escribir ?publicar, porque mi código administra; a los demás no les sale. ?publicar sigue siendo para lo otro: descargar copia, JSON y mantenimiento.
  2. Crear: nombre y botón Crear. Salen el enlace ?a=… y un código de 6 dígitos, los dos una sola vez: copiar el que sirva y mandárselo al autor por WhatsApp. Con el enlace, él lo abre una vez y listo; con el código, lo escribe en el aviso «¿Quién eres?» o en ☁️ Publicar. Es la misma llave de las dos formas: el código es más fácil de mandar por texto (no se corta al copiarlo, y no importa si termina en el celular equivocado), pero es más débil que el enlace, así que si el autor ya tiene el enlace guardado no hace falta darle también el código.
  3. Generar código en la ficha de un autor que ya existe (creado antes de que el código existiera, o a quien se le perdió el que tenía): sale un código nuevo, una sola vez. El anterior deja de servir en el acto — no hay forma de recuperarlo, solo de reemplazarlo.
  4. Revocar: botón Desactivar en la ficha del autor. Corta el acceso al instante, con cualquiera de los dos (el enlace o el código) — por ejemplo, un enlace reenviado a quien no era.

Refrescar el respaldo en Git (una vez al mes, o tras un sábado importante)

# desde ~/Documents/Iglesia/projects/programas-tierra-linda
# bajar el vigente publicado: botón "⬇️ Descargar JSON" en ?publicar, y luego
mv ~/Downloads/2026-09-05.json programas/
node tools/indexar.js
git add -A
git commit -m "Respaldo del programa del 5 de septiembre"
git push

Nunca editar programas/index.json a mano. Lo genera indexar.js leyendo la carpeta.

Dos programas el mismo día

La llave de guardado es fecha + tipo: al publicar, el autor elige si es el programa principal del día o uno con nombre propio (Sociedad de Jóvenes, culto del miércoles…). Cada combinación es una fila y ninguna pisa a la otra. Para borrar una:

npx wrangler d1 execute programas-tl --remote \
  --command "DELETE FROM publicacion WHERE clave = '2026-09-05-sociedad-de-jovenes'"

Quitar y recuperar un programa publicado

Cualquiera con código de autor puede quitar uno con la ✕ del panel 🗂️ Programas: la página pregunta, avisa si es el vigente y no deja quitar el último que quede. No se destruye: la fila pasa a la tabla papelera con quién la quitó y cuándo. Para devolverla:

npx wrangler d1 execute programas-tl --remote --command "INSERT INTO publicacion \
  (clave, fecha, tipo, titulo, json, espacios, publicado_por, actualizado_en) \
  SELECT clave, fecha, tipo, titulo, json, espacios, publicado_por, actualizado_en \
  FROM papelera WHERE clave = '2026-09-12' ORDER BY borrado_en DESC LIMIT 1"

Republicar encima también deja la versión anterior en la papelera, con borrado_por = quien la reemplazó y la nota «(al republicar)». Antes el upsert la sobreescribía sin guardar nada, mientras la página prometía que se podía recuperar.

Para ver qué hay en la papelera, sin terminal: /api/papelera con la clave o con un código de mantenedor. Con comando: SELECT clave, borrado_por, borrado_en FROM papelera ORDER BY borrado_en DESC.

Si la base se daña o no responde

La página no se cae: vuelve sola al respaldo del repositorio (por eso vale mantenerlo al día). Diagnóstico en 10 segundos: abrir /api/vigente — un 404 dice "no hay nada publicado", un 503 dice "el binding DB del proyecto está desconfigurado" (revisar wrangler.toml). Las tablas se crean solas la primera vez que el API corre contra una base vacía, así que recrear la base es: crearla (npx wrangler d1 create), poner el id nuevo en wrangler.toml y hacer push. El esquema está documentado en migrations/0001_inicial.sql.

Si me quedo por fuera de la administración

Pasa si perdí todos los dispositivos con mi enlace y no recuerdo la clave. La salida es darle el permiso a un código desde la base, con wrangler (que ya está autenticado en el Mac):

# ver quién hay y quién administra
npx wrangler d1 execute programas-tl --remote   --command "SELECT id, nombre, activo, mantenedor FROM autor ORDER BY id"
# darle el permiso a uno (y con ese enlace ya se entra sin clave)
npx wrangler d1 execute programas-tl --remote   --command "UPDATE autor SET mantenedor = 1 WHERE id = 3"

La clave de texto también se puede reponer a mano, pero desde que existe el botón 🔑 Cambiar la clave casi nunca hace falta: UPDATE config SET valor='<sha256 de la clave nueva>' WHERE clave='clave_mantenedor_hash'.

4. Casos especiales

Si se pierde la base

Tener respaldo y poder restaurar no son el mismo hecho. El respaldo son los archivos de programas/ en el repositorio, que baja tools/respaldar.sh. La vuelta es tools/restaurar.js, y este es el procedimiento, en orden:

  1. En el panel de Cloudflare, crear una base D1 nueva y poner su database_id en wrangler.toml, con el mismo binding DB. Este paso no se ha ensayado: es el único que toca la consola de Cloudflare y no hay forma de probarlo sin romper la base buena.
  2. Desplegar. La aplicación crea sus tablas sola la primera vez que alguien la toca; no hay que correr nada a mano. Que los archivos de migrations/ armen exactamente ese mismo esquema lo comprueba tests/esquema.js en cada npm test.
  3. Crear un autor. La base nueva no tiene ninguno, así que va con la clave de mantenedor, desde el panel de autores.
  4. Republicar todo lo del repositorio: SITIO=<el sitio> TOKEN=<el código del autor nuevo> node tools/restaurar.js --de-verdad. Solo publica: no borra, no toca autores y no toca el calendario.
  5. Comprobar con sh tools/verificar-produccion.sh.

Lo que el ensayo del 17 de septiembre de 2026 sí ejecutó, en local: borrar la base, dejar que la aplicación la volviera a crear, crear un autor con la clave y republicar los cuatro programas del repositorio. Quedaron los cuatro, con el vigente correcto. Lo que no se recupera y hay que rehacer a mano: los autores con sus enlaces y códigos, y el calendario de turnos. Los programas publicados sí, hasta donde llegue el último respaldo, que la revisión de los jueves refresca.

Corregir algo después de publicar

Editar y volver a tocar ☁️ Publicar con la misma fecha: la fila se sobreescribe. Cualquier autor activo puede corregir; la base guarda quién publicó de último y cuándo.

Publicar con anticipación

Se pueden dejar publicados varios sábados futuros: el vigente es el de la fecha más próxima que aún no pasa (día de Colombia), y cada programa se estrena solo a la medianoche del sábado anterior. Publicar hoy el del 19 no tapa el del 5. Si no hay ninguno por venir, la página muestra el más reciente que exista.

Revertir una publicación mala

Si el programa está mal, se corrige y se republica (caso de arriba). Si la fecha entera sobra (se publicó un sábado que no existe y quedó como vigente), se borra la fila directamente:

npx wrangler d1 execute programas-tl --remote \
  --command "DELETE FROM publicacion WHERE clave = '2026-09-05'"

El vigente vuelve a ser la fecha anterior. El respaldo del repositorio no se toca.

Dos personas editando el mismo sábado

No hay edición simultánea y no la va a haber sin servidor. La regla: una sola persona arma el programa, el de turno. Si alguien más tiene cambios, se los manda por texto y el de turno los mete. El que publica define la versión oficial.

Alguien perdió lo que estaba haciendo

Primero ↶ Deshacer, que guarda 40 pasos. Si ya cerró la página y entró desde otro equipo, no hay recuperación: su copia vive en el equipo donde editaba. Por eso el mensaje del manual insiste en mandarse el enlace a sí mismo cuando va a medias.

«Desapareció la lista de anuncios del programa»

El espacio del programa que trae los anuncios no está marcado en ninguna parte: se reconoce porque su nombre contiene la palabra «anuncio» (sin importar tildes ni mayúsculas, y vale cualquier fila que la contenga: «Bienvenida y anuncios», «Saludo oficial y anuncios»). Es el mismo criterio con el que el prellenado del calendario encuentra la fila de «Predicación», y por eso no hay un campo más que mantener.

Así que si alguien renombra ese espacio y le quita la palabra, se van a la vez las tres cosas: la lista en el programa, el botón del altavoz y el renglón de hora y minutos de la hoja de anuncios. La otra causa posible es que lo hayan apagado con el botón del altavoz de esa fila: ahí el nombre sigue bien y el botón se ve tachado. Esa preferencia se guarda en la fila (sinAnuncios), solo cuando está apagada.

Cambiar el logo

Reemplazar logo-tl.png o logo-sda.png en el repositorio y hacer push. El botón de reemplazar logo dentro de la página es solo para la copia de esa persona, no cambia el logo de todos.

5. Guion de la demo, 6 minutos

Orden pensado para que se entienda el valor antes de la mecánica. Abrir con el programa del sábado ya cargado, no con la página vacía.

MinutoQué muestroQué digo
0:00La página abierta con el programa del sábado "Esto es el programa del sábado, en el mismo formato que ya usamos. No hay que instalar nada ni crear cuenta."
0:45Clic sobre un nombre y lo cambio "Se escribe encima, así de simple. Aquí no hay campos ni formularios."
1:15Cambio una hora y señalo los minutos "Los minutos se calculan solos. Nadie tiene que sumar."
1:45Pongo el programa media hora más temprano y toco ⤓ ajustar siguientes "Y si algo se mueve, todo el horario se corrige de una: cada espacio arranca donde termina el anterior y sigue durando lo mismo."
2:30Muevo un espacio con ↑ y lo devuelvo con Deshacer "Se puede reordenar, y si uno se equivoca, se deshace."
3:00Imprimir / Guardar PDF "Y de aquí sale el PDF de siempre, en una hoja, para el grupo."
3:45☁️ Publicar y la confirmación con la fecha "Cuando está listo, un botón: se elige qué programa del día es y desde ahí es lo que ve todo el que entre a la página. No hay que mandármelo a mí."
4:10📣 Anuncios y su propio PDF "Y aquí van los anuncios del sábado, con letra grande para leerlos de pie. Se imprimen aparte: se imprime la hoja que uno esté viendo."
4:40El enlace de solo lectura "Y para el grupo, este enlace de solo lectura: se ve e imprime, pero nadie lo cambia sin querer."
5:10El teléfono, en vista de tarjetas "Y se puede hacer desde el celular, con letra grande."
5:40El manual "Todo esto está explicado en el manual, con el enlace en la misma página."
Lo que no muestro en la demo: el panel de autores, el JSON, la base de datos, el repositorio, ni la palabra Git. Eso es mío. Lo del código de autor se dice en una frase: "te mando un enlace una vez, lo abres y ya puedes publicar desde tu equipo".

Antes de la demo, dos minutos de alistamiento: entrar en una ventana privada para que cargue el programa publicado y no mi copia de pruebas, tener el celular con la página abierta, y tener listo el enlace de solo lectura para pegarlo en el grupo en vivo.

6. Dar de alta a un anciano nuevo

Cada anciano que vaya a armar programas necesita su código de autor. Es una vez en la vida, no una vez por sábado:

  1. Creo su código en ?publicar → 👥 Autores, con su nombre, y copio lo que sale (se muestra una sola vez): el enlace ?a=… y un código de 6 dígitos.
  2. Le mando lo que le sirva por WhatsApp. Si va a armar el programa siempre desde el mismo equipo, el enlace: "ábrelo una vez en el computador o celular donde armas el programa y ya puedes publicar desde ahí". Si prefiere escribirlo (o el enlace se corta al copiarlo por el chat), el código de 6 dígitos: lo escribe en el aviso "¿Quién eres?" o al tocar ☁️ Publicar. Nada más; no es una clave que tenga que recordar ni escribir cada vez, en ninguno de los dos casos.
  3. Le paso el manual (📖 en la barra) y le digo las tres cosas que sí importan: escribe encima, ⤓ corrige el horario completo, ☁️ Publicar lo deja como el que todos ven.
  4. Le pido una sola cosa de vuelta: que me diga qué le estorbó la primera vez. Eso es lo que mejora la herramienta; el resto lo sostengo yo.

Si el enlace o el código se le pierden, no hay recuperación (no se guardan en una forma que se pueda leer de vuelta): en la fila del autor, «Generar código» le da uno nuevo sin tocar el resto — sigue siendo el mismo autor, con el mismo historial de turnos, solo con una llave nueva. Crear un autor nuevo y desactivar el viejo ya no hace falta para esto: se reserva para cuando de verdad cambia la persona. Y si un enlace o un código se reenvía a quien no era, desactivar al autor corta el acceso al instante, con cualquiera de los dos.

7. Rutina semanal en una tarjeta

CuándoQué
JuevesRecordarle al de turno que arme el programa y lo publique él mismo (☁️ Publicar). Si es autor nuevo, mandarle antes su enlace de autor desde 👥 Autores.
Viernes a.m.Abrir la página en ventana privada y confirmar que el vigente es el del sábado que viene.
Viernes p.m.Que el de turno reparta el enlace de solo lectura o el PDF.
Una vez al mesRefrescar el respaldo en Git (Descargar JSON → indexar.js → commit), revisar la lista de autores activos y confirmar que sigue habiendo alguien con permiso de administrar (la fila con ✦ administra), y que nadie tenga ✦ con el código sin necesitarlo.
Cada tantoCorrer las pruebas antes de tocar el código: npm test, desde la raíz del repositorio. Son 19 tandas y tardan unos seis minutos. El comando levanta solo lo que cada una necesita (el servidor de la página, el del API, la base) y lo apaga al terminar; no hay que abrir terminales aparte ni acordarse del orden. Si falla alguna, al final dice cuál y cómo repetir solo esa. El detalle, en el README.

← Ir a la aplicación en modo publicación  ·  Manual de los autores