Hecho con Chinaski

Changelog

Cada versión etiquetada, de la más reciente a la más antigua. Las notas se publican por versión bajo su propio contenido; consulta los enlaces de Full-changelog para ver los diffs subyacentes.

v1.11.0

2026-09-25

Minor release: Chinaski ahora puede funcionar por completo en un teléfono Android y publicar a Cloudflare R2, además de un nuevo bloque schedule para horarios recurrentes y excepciones con fecha.

Novedades

  • #255 (#7365): nueva vía de instalación basada en Termux (install.sh --termux) que corre el admin completo (build, base de datos, todo) en un teléfono Android sin root ni systemd, más un launcher de arranque/widget idempotente (termux-start.sh) para que sobreviva al cierre y se reinicie solo tras un reinicio del teléfono. Ver Publicación desde un teléfono.
  • #255: nuevo interruptor maestro deploy_auto_enabled en Settings → Deploy que pone tanto el deploy rsync como el deploy S3 detrás de un solo toggle "Deploy automatically after a successful build", de modo que uno o ambos destinos pueden conectarse sin cambiar silenciosamente el comportamiento existente. Ver Despliegue SSH / rsync.
  • #255: nuevo tipo de bloque schedule. Un horario semanal recurrente (horarios de misa, horarios de apertura) más una lista de excepciones con fecha próximas (cierres, eventos únicos, cancelaciones), con datos estructurados schema.org Event automáticos. Ver Horario.
  • #255: el banner de estado de build/deploy del admin ahora avanza de "Building your update…" a "Publishing your update…" y de ahí a "Your update is live.", y sigue siendo preciso durante todo el tiempo que una sincronización siga corriendo de verdad, incluida una subida lenta por una conexión de teléfono.

Notas de actualización

No se requieren pasos manuales. Si el deploy por SSH/rsync o S3 ya estaba configurado y funcionando, el nuevo interruptor maestro deploy_auto_enabled se rellena automáticamente como activado durante la actualización, así que los deploys existentes siguen disparándose sin ninguna acción necesaria.

v1.10.4

2026-09-23

Patch release: una auditoría mobile-responsive del theme por defecto en los 32 tipos de bloque, más varios bugs de larga data que salieron a la luz por el camino.

Corregido

  • #253: pasada mobile-responsive completa sobre el theme por defecto. Los tipos de bloque text y grid no tenían CSS en absoluto; grid usaba un grid-template-columns inline que una media query móvil no podía sobrescribir y ahora usa propiedades personalizadas de CSS. Se corrigió una discrepancia de nombres de clase entre template y CSS que dejaba sin estilo los encabezados de los bloques columns y grid. El <pre> de code_block no tenía manejo de overflow, así que una línea larga ensanchaba toda la página en móvil en lugar de hacer scroll dentro del bloque. Se añadió el estilo faltante para los heroes de dos botones y la variante secundaria del button-group. Se corrigió un overflow real del header alrededor de 1024px de ancho de viewport (entre el breakpoint móvil y la fila de navegación de escritorio que se asume ancha) que dispara una navegación realista. El bloque testimonial ahora se apila por debajo de 480px en lugar de apretar el avatar y la cita en una fila de ancho fijo. El padding de los botones se aumentó en todo el site para que los tap targets superen la pauta de accesibilidad de ~44px.
  • #254: el manifest de build firmado de build.pl (private/build-manifest.json) se resolvía desde el propio directorio de instalación del script en lugar de seguir CHINASKI_OUTPUT, así que redirigir el output del build a otro lugar (p. ej. un build de prueba o en sandbox) escribía silenciosamente el manifest en el directorio private/ de la instancia en vivo. Ahora sigue la ubicación del directorio de output: un no-op para todo deployment normal.
  • #254: btn_submissions y otros 30 strings del panel de admin eran referenciados por los templates pero nunca definidos en ningún idioma, así que los admins veían el texto crudo de la clave (p. ej. "hdr_status") en lugar de etiquetas reales. Encontrado mediante un barrido completo de cada llamada t('...') contra las claves realmente definidas. Añadidos a los 4 idiomas.
  • #254: la variante de ancho block-form__field--w-half / newsletter-form__field--w-half, ofrecida en el editor de campos de formulario, no tenía CSS en absoluto: "half width" no hacía nada. Ahora los campos se ubican de a dos por fila en escritorio, apilándose por debajo de 640px.
  • #254: builder/site_templates/_landing_block_styles.tt (usado por el template independiente landing.tt) solo daba estilo a 15 de los 32 tipos de bloque. Los otros 17 se renderizaban completamente sin estilo en las landing pages; portados desde la corrección del theme descrita arriba.

Notas de actualización

No se requieren migraciones de base de datos para este release.

v1.10.3

2026-09-21

Patch release: corrección de i18n en el breadcrumb y en el encabezado de page_list.

Corregido

  • #7290: el crumb raíz del breadcrumb estaba fijado al string literal en inglés "Home" sin importar el idioma real de la página. Ahora usa el título real por idioma de la página de inicio del site, y recurre a "Home" solo cuando no existe ninguno para ese idioma.
  • #7291: el encabezado "Also in X" generado automáticamente por el bloque page_list estaba fijado en inglés. Ahora usa una tabla de prefijos por idioma (en/es/pt/fr).

Ambos ya estaban corregidos y verificados en vivo en este site antes de que este release formalizara la corrección en el código con cobertura de pruebas.

Notas de actualización

No se requieren migraciones de base de datos ni cambios de configuración para este release.

v1.10.2

2026-09-21

Patch release: correcciones del escapado de shortcodes y del chequeo de enlaces rotos, más dos nuevos settings expuestos en el admin.

Corregido

  • #7212: los expansores de shortcodes ([form:slug​], {{block:name​}}, {{stack:name​}}, {{document:slug​}}) ya no se expanden dentro de <pre>/<code>. Una página de docs que muestra la sintaxis como ejemplo literal ya no dispara un error de render ni bloquea la promoción.
  • #7215: _detect_broken_links ya no antepone dos veces el directorio de idioma a los hrefs que ya llevan un prefijo del idioma activo bajo lang_url_mode=path, lo que había estado dando falsos positivos en todo enlace interno correctamente escrito de un site multilingüe en modo path.

Novedades

  • #7214: campo org_email añadido a Settings > Organization, junto a org_phone. La plomería de JSON-LD del lado del builder ya existía pero no tenía campo de UI en el admin para definirlo.
  • #6018: build_jobs (workers de build en paralelo) expuesto en Settings > General, antes solo configurable mediante SQL directo o la variable de entorno CHINASKI_JOBS. En blanco conserva el comportamiento existente de autodetectar la cantidad de CPUs.

Notas de actualización

No se requieren migraciones de base de datos ni cambios de configuración para este release.

v1.10.1

2026-09-17

Patch release: correcciones de las unidades systemd de deploy/, sin cambios de app ni de base de datos.

Corregido

  • #247: StartLimitIntervalSec/StartLimitBurst estaban colocados bajo [Service] en las plantillas systemd por instancia (chinaski@.service, chinaski-mcp@.service), donde systemd los ignora silenciosamente. Movidos a [Unit], donde realmente se respetan. Sin esta corrección, una instancia que falla de forma persistente (p. ej. una cuyo directorio de trabajo fue borrado) se reinicia para siempre en lugar de rendirse tras 5 fallos en 60s y quedar en failed.
  • #248: chinaski-backup@.timer tenía un comentario inline al final de Persistent=true (Persistent=true # catch up...), que el parser de unidades de systemd no puede manejar; falló al interpretar el valor y lo descartó silenciosamente, así que un backup diario perdido mientras el host estaba apagado nunca se recuperaba al arrancar. Comentario movido a su propia línea.

Notas de actualización

Instalaciones existentes: vuelve a copiar los tres archivos de deploy/ (chinaski@.service, chinaski-mcp@.service, chinaski-backup@.timer) a /etc/systemd/system/ y ejecuta systemctl daemon-reload. No hay migraciones de base de datos en este release.

v1.10.0

2026-09-16

Minor release. Cuatro correcciones de bugs desde v1.9.0.

Correcciones

  • Forms: los campos de tipo date nunca se validaban del lado del servidor: un POST directo que evitara el selector de fechas del navegador dejaba pasar sin filtrar entradas malformadas, o incluso markup/enlaces de spam, a un campo de fecha. Ahora se validan como YYYY-MM-DD.
  • Settings: la regeneración del favicon fallaba silenciosamente al actualizar favicon.svg en una nueva subida si el archivo tenía la propiedad equivocada (p. ej. por un deploy que no volvió a hacer chown), mientras las variantes PNG/ICO se actualizaban bien y la UI reportaba éxito. Ahora favicon.svg se desvincula antes de reescribirse, igual que el manejo existente de PNG.
  • Builder: el sitemap nunca emitía la raíz simple del site cuando home_redirect apuntaba a una página normal en lugar del blog; y las URLs relativas de og:image/twitter:image (inválidas según la especificación OG) ahora se vuelven absolutas en páginas, posts y el índice del blog.
  • Breadcrumbs: el crumb del blog estaba fijado a la palabra literal "Blog" en lugar de usar el blog_index_title configurado del site; las instancias con una etiqueta de blog o prefijo de permalink personalizado (p. ej. "Notes" en /notes/) obtenían un trail de breadcrumb que no coincidía con la nomenclatura de su propia navegación/URL.

Suite completa: 122 archivos, 9,687 pruebas, todas pasando.

Full Changelog: https://github.com/bigjohncobb/chinaski/compare/v1.9.0…v1.10.0

v1.9.0

2026-08-31

Minor release: un importador de archivos Markdown te permite crear posts/páginas en borrador directamente desde archivos .md (con YAML front matter), más un lote de 8 bugs reportados en vivo corregidos en el admin de Posts/Pages, la construcción de permalinks/enlaces y el manejo de favicons.

✨ Funciones y UX

Importador de archivos Markdown para Posts y Pages (PR #242) - La nueva ruta /admin/import-markdown, enlazada desde las listas de Posts y Pages, acepta un solo archivo o un lote de hasta 100 archivos .md (40 MiB en total) y crea posts/páginas en borrador a partir de ellos, reemplazando el workaround anterior de escribir HTML a mano directamente en la base de datos. - El YAML front matter opcional (title, slug, language, meta_title, meta_description, category, tags, date) rellena los campos; los valores faltantes recurren al primer encabezado H1 del archivo, y luego a un nombre de archivo embellecido. - Cada importación queda como borrador, nunca se publica automáticamente y nunca toca la publicación programada, por diseño explícito. - El aislamiento de errores por archivo reporta los archivos malos por nombre sin hacer fallar el resto del lote.

🐛 Correcciones

Lote de bugs del admin de Posts: 8 problemas reportados en vivo (PR #241) - Restaurar un borrador (Posts y Pages) guardaba silenciosamente nada: el cuerpo de la petición no se leía correctamente, y un bug del selector de formulario además apuntaba al <form> equivocado en la página de edición de Posts. - Los enlaces "View" del admin y el selector interno de enlaces construían mal las URLs de posts/páginas para páginas anidadas y para ajustes de permalink/idioma no predeterminados, divergiendo de lo que el site builder realmente publica. - Aprobar un post o página pendiente (flujo de revisión) nunca lo ponía realmente en vivo: cambiaba el estado de revisión pero no el flag de publicación. - El contenido del editor acumulaba espacios en blanco sueltos y deriva de formato en cada ciclo de guardado; ahora se normaliza del lado del servidor. - Publicar un post podía disparar una advertencia espuria del navegador de "changes not saved" que abortaba la petición. - Un bug de permisos en vivo en la subida de favicon (archivos propiedad de root tras el deploy) podía romper silenciosamente las actualizaciones de favicon y los rebuilds del site. - Falta un placeholder en el template del bloque hero cuando no hay imagen definida

⬆️ Actualización

Sin pasos manuales. Todos los cambios de esquema/configuración de este release se aplican automáticamente en el próximo arranque.

Full changelog: https://github.com/bigjohncobb/chinaski/compare/v1.8.0…v1.9.0

v1.8.0

2026-08-27

Minor release: los forms ganan campos condicionales, seguimiento de leído/no leído y un enlace de respuesta; la serie de modularización termina con Forms y Blocks extraídos a sus propios plugins; webhooks, jobs, nav, redirects, manejo de datetime/MIME y email/SMTP reciben refactors centralizados guiados por auditoría; además de un lote de correcciones de bugs reales, incluyendo un bug en vivo de favicon/rebuild, una violación de FK al restaurar revisiones y varias brechas en las puertas de permisos del admin.

✨ Funciones y UX

Forms: campos condicionales, seguimiento de no leídos, enlace de respuesta (PR #229) - condition_field ahora es un dropdown de los campos existentes del form (se acabaron los nombres de campo escritos libremente), con validación del lado del servidor y sugerencias de valores en datalist para fuentes select/radio/checkbox. - Las submissions rastrean el estado leído/no leído, las filas no leídas reciben un badge "new", la lista de forms muestra "12 (3 new)" y hay un "Mark all read" de un clic. - Un botón "Reply" en el detalle de la submission abre un enlace mailto: pre-dirigido cuando reply_to_field nombra un campo con apariencia de email.

🔧 Refactors

Forms y Blocks extraídos a sus propios plugins, cerrando la serie de modularización (PR #221 / PR #240) - lib/Chinaski/Plugin/Forms.pm y lib/Chinaski/Plugin/Blocks.pm ahora son dueños de toda la superficie de rutas de forms y de blocks/snippets/stacks, siguiendo el patrón establecido de Plugin::Media/Plugin::Settings; cms.pl se reduce en casi 2,000 líneas solo con el traslado de Forms. - Además en Blocks: create/update ahora usan validación con errores acumulados y renderizado de formulario compartido (igual que pages/posts), la tabla block_types de la DB pasa a ser la única fuente de verdad en lugar de un array paralelo @BLOCK_TYPES, y un partial compartido de selector de color reemplaza los selectores duplicados de 21 templates.

Orden de redirects, nav y forms centralizado (PR #230 / PR #231) - La lógica de create/update/importación CSV/recorrido de cadenas de Redirects se consolidó en helpers compartidos; la importación CSV ahora usa el mismo parser RFC-4180 que el resto en lugar de un split hecho a mano. - _swap_sort_order y _next_sort_order ahora se comparten entre nav, snippets y campos de form en lugar de tres implementaciones separadas; la validación de create/edit de nav se centralizó (~85 líneas eliminadas).

Webhooks, jobs programados y reporte de salud centralizados (PR #235 / PR #236 / PR #237) - La publicación/despublicación programada, los jobs recurrentes en segundo plano y los resúmenes de salud de backups se deduplicaron entre sus consumidores de admin y API. - El despacho de reintentos de webhooks, la validación de URL y el wrapper de job en segundo plano de restauración de backups se centralizaron; los hooks before_dispatch se reorganizaron en etapas con nombre; los helpers de estado de build/uso de disco se comparten entre el dashboard, health y los endpoints de API.

Manejo de datetime y MIME unificado; higiene de email/SMTP y migraciones (PR #238 / PR #239) - Un único par de helpers compartidos de conversión local↔︎UTC reemplaza los bucles repetidos por ruta; un nuevo módulo Chinaski::MIME es la fuente canónica del mapeo MIME↔︎extensión en media, forms y servicio de documentos. - La configuración de la conexión SMTP (incluyendo la corrección de CRLF que cierra la inyección de headers) se consolidó en un único sender; la documentación de migraciones y los helpers de verificación de existencia se limpiaron; 22 nuevas claves i18n x 4 idiomas cierran los strings del admin que seguían fijados en el código.

🐛 Correcciones

Borrar el favicon no disparaba un rebuild (PR #223): borrar un favicon limpiaba el setting pero dejaba el ícono viejo en vivo en output/ (y por tanto en el site público) hasta que un cambio no relacionado disparara el siguiente build. Encontrado en vivo en la instancia roiwire (desactualizado por ~1h44m).

La subida de favicon deformaba imágenes de origen no cuadradas (PR #225): una imagen de origen ancha/baja (p. ej. un logo tipo wordmark) producía silenciosamente un recorte distorsionado en lugar de un ícono; las subidas con más de 1.25:1 de desviación respecto a lo cuadrado ahora se rechazan con un error claro.

La restauración de revisiones de bloques siempre fallaba para bloques ordinarios (PR #222): restaurar escribía '' en lugar de NULL para form_id/content_json, violando las restricciones FK/CHECK en cualquier bloque que no fuera de form ni estructural.

La decodificación JSON del diff de revisiones usaba el decodificador equivocado en uno de dos casos (auditoría PR #224 + corrección PR #232): decompress_value devuelve bytes crudos para filas comprimidas pero un string ya decodificado para las no comprimidas; un único decodificador JSON general era incorrecto para uno de los casos sin importar cuál se eligiera. Dos puntos de llamada (vista previa de revisión de snippets, diff genérico de pages/posts) reintrodujeron esto justo después de que la primera auditoría lo corrigiera en otro lugar; ahora ambos se bifurcan según utf8::is_utf8 al momento de decodificar.

Turnstile mostraba una falsa nota de "could not be loaded" bajo un widget que funcionaba (PR #227).

La suite de pruebas filtraba sidecars .db-wal/.db-shm y directorios de docs por ejecución, llenando dos veces el disco de la máquina de CI (PR #234), se añadió limpieza adecuada más una red de seguridad por cron para procesos de prueba terminados a la fuerza.

El lote de caza de bugs del admin de esta sesión (7 correcciones, sin números de ticket; encontradas mediante auditoría directa del código y no del backlog): - Los enlaces "View" de la página de búsqueda se resolvían contra el subdominio de admin en lugar del site en vivo (siempre daban 404), y no consideraban los slugs padre de las páginas anidadas. - Create/update/delete/bulk de Redirects no tenían ninguna puerta de permiso de entidad. Cualquier editor con cualquier otro permiso podía gestionar redirects sin importar lo que realmente se le hubiera concedido. - El publish de Documents no verificaba el estado de la versión del lado del servidor, permitiendo que un no-admin forzara en vivo una versión rechazada aunque la UI ya ocultaba esa opción; duplicate/delete carecían por completo de su puerta de permiso. - El create de Snippets perdía el código enviado en una página de error genérica ante una colisión de nombre, en lugar del re-render amigable que update ya tenía. - El delete de Themes no verificaba que el theme existiera en la DB antes de eliminar su directorio en disco. - El create de Users no aplicaba el formato de username que la importación CSV ya exige. - El update de Nav ponía silenciosamente en cero sort_order cuando el campo se omitía de la petición, en lugar de conservar la posición del elemento.

⬆️ Actualización

Sin pasos manuales. La migración 061 (form_submissions.read_at) y todos los demás cambios de esquema de este release se aplican automáticamente por la vía normal de migración en el próximo arranque.

Full changelog: https://github.com/bigjohncobb/chinaski/compare/v1.7.1…v1.8.0

v1.7.1

2026-07-22

Patch release: los forms ganan tipos de esquema JSON-LD amigables para SEO, tres nuevos tipos de campo (date, reglas de validación, checkbox de consentimiento), una UI de admin más densa y accesible, y una corrección de un bug real de producción en la edición de páginas/posts.

✨ Funciones y UX

Tipos de esquema JSON-LD: Article, FAQ, Product, Event, HowTo (#2559, PR #216) - schema_type opcional en páginas y posts: elige FAQ, Product, Event o HowTo (los posts se limitan a Article/FAQ, ya que los posts no tienen los campos de producto/evento para respaldar los demás) y el builder emite automáticamente los datos estructurados correspondientes. - Nuevos editores de pregunta/respuesta de FAQ y de pasos de HowTo en el formulario de página.

Forms: tipo de campo date, validación por campo, checkbox de consentimiento (PR #218) - Nuevo tipo de campo date, renderizado como un <input type="date"> nativo. - Reglas de validación por campo (longitud mínima/máxima, valor mínimo/máximo y patrón regex) aplicadas tanto del lado del cliente (atributos HTML5) como del lado del servidor al enviar. - Nuevo tipo de checkbox consent para el reconocimiento de la política de privacidad, con un enlace configurable que se abre en una pestaña nueva.

Admin de forms: pestaña de ajustes más densa + lista de campos más accesible (PR #217) - La pestaña Form Settings ahora son secciones plegables en lugar de un solo scroll largo, con una barra Save fija. - La lista de Fields muestra tipo/obligatorio como badges, tiene targets táctiles más grandes, y los botones de reordenar se deshabilitan correctamente en la parte superior/inferior de la lista con etiquetado ARIA completo.

🔧 Refactors

Ajustes PWA y lista de assets centralizados (PR #215) - El builder y la ruta de borrado de favicon de Settings ahora comparten una sola fuente de verdad para los nombres de archivo de los assets PWA generados, en lugar de dos listas que podían desviarse silenciosamente.

🐛 Correcciones

Las actualizaciones de páginas y posts podían fallar con "no such table: main.*_old" (PR #214) - Una referencia sobrante de una migración antigua hacía que page_snippets, post_snippets, page_area_blocks y otras 3 tablas de unión pudieran apuntar a tablas que ya no existían, rompiendo las actualizaciones de páginas/posts existentes (crear nuevos seguía funcionando) en cualquier instancia que llevara corriendo desde aproximadamente v1.6.1 o antes.

Pulido del admin de forms (PRs #212, #213) - Editar un campo de form ya no te devuelve a la pestaña Settings. - Los errores de validación de Add Field ya no borran lo que habías escrito. - Se añadió una advertencia de cambios sin guardar a la pestaña Settings. - El diálogo de confirmación de borrado en la lista de forms ahora dice correctamente "moved to trash" en lugar de insinuar un borrado permanente. - Los fallos de SMTP ahora registran una razón específica en lugar de un error genérico. - La subida de un theme corrupto ahora reporta "corrupt archive" en lugar del engañoso "missing required files".

⬆️ Actualización

Sin pasos manuales. Si ejecutas una instancia anterior a este release, la corrección de actualización de páginas/posts (PR #214) se aplica automáticamente por la vía normal de migración en el próximo arranque.

Full changelog: https://github.com/bigjohncobb/chinaski/compare/v1.7.0…v1.7.1

v1.7.0

2026-07-22

Minor release: backup/restore extraído a su propio plugin, Backups y API Keys promovidos a páginas reales, y las pantallas de admin de Posts terminan su migración al design system.

✨ Funciones y UX

Backups y API Keys ahora son páginas reales, no pestañas de settings (PR #209) - /admin/backups y /admin/api-keys son rutas canónicas con sus propias URLs: los enlaces antiguos /admin/settings?tab=backups / ?tab=api-keys ahora hacen 302 hacia ellas. - El template de settings de 1,796 líneas se divide en partials por pestaña (templates/admin/settings/_*.html.ep) en lugar de un monolito; 344 atributos style= inline se extrajeron a clases CSS compartidas.

🔧 Refactors

Backup/restore extraído a Chinaski::Plugin::Backups (PR #208) - Las 10 rutas /admin/backups/**, 3 rutas /api/backups** y ~30 helpers de apoyo salieron de cms.pl a su propio plugin, siguiendo el mismo patrón de las extracciones anteriores de Media/Settings. - El manejo de creación de backup y de resultado de restauración ahora se comparte entre las rutas de admin y de API en lugar de que cada una duplique su propia lógica.

Las pantallas de admin de Posts terminan la migración del design system po-* → chinaski-* (PR #210, seguimiento de) - Se eliminaron las declaraciones font-family inline y los literales de color que no son tokens de los templates de formulario/lista, papelera y diff de revisiones de Posts.

🐛 Correcciones

  • Una condición de carrera con el timeout de restauración de 120s en la que el resultado de un subproceso que llegaba tarde podía aplicarse silenciosamente después de que la petición ya le hubiera mostrado al usuario un error de "timed out".

⬆️ Actualización

Sin pasos manuales: si tienes /admin/settings?tab=backups o ?tab=api-keys guardados como marcadores o enlazados en algún lugar fuera de la app, actualízalos a /admin/backups / /admin/api-keys (los enlaces antiguos siguen funcionando mediante redirect, solo con un salto extra).

Full changelog: https://github.com/bigjohncobb/chinaski/compare/v1.6.1…v1.7.0

v1.6.1

2026-07-06

Patch release: corrección de la dependencia faltante Crypt::PBKDF2.

  • cms.pl usa Crypt::PBKDF2 directamente para la migración de hashes de contraseñas, pero nunca se declaró en cpanfile, así que cualquier instancia 1.6.0 que no tuviera ya el módulo instalado entraba en crash-loop al arrancar (Can’t locate Crypt/PBKDF2.pm in @INC). Corregido declarando la dependencia en cpanfile.

v1.6.0

2026-07-06

Minor release: todo lo integrado desde v1.5.3.

  • Endurecimiento de backups: manifest.json con SHA-256 por archivo en cada archive, PRAGMA integrity_check antes de archivar, publicación local atómica, validación de rutas de restauración en las 4 fuentes, verificación posterior al backup (backup_runs) con badges Verified, retención configurable con poda, métricas de backup en /admin/metrics, vista previa de restauración en dry-run + confirmación, tipo/esquema por fila en la pestaña Backups, puente de data-loading-text en formularios.
  • Builder: las páginas exponen sus páginas hijas publicadas a los templates como ‘children’; page_list comparte el mismo mapa precalculado.
  • Editor de posts: WYSIWYG restaurado en la página de nuevo post (SyntaxError de JS en la clave de autosave), paridad completa del diseño de dos paneles del design system con Pages, botones de revisión mediante formaction.
  • La vista previa compartible de páginas renderiza bloques dirigidos por content_json (faq, pricing_table,…) en lugar de solo encabezados.
  • MCP: process manager, health, logging de reintentos, sesiones, discovery, operaciones masivas, resources.
  • Seguridad: subidas de media SVG rechazadas; hashing de contraseñas de posts.
  • Refactors: el despacho de webhooks unificado en Chinaski::Webhook; la biblioteca de media extraída a Chinaski::Plugin::Media.

Los cuatro PRs de funciones fueron revisados en código antes del merge; las correcciones de la revisión están en los commits squash de los PRs. Suite completa en verde en CI para el árbol final integrado.

v1.5.3

2026-07-03

Landing pages, forms y una pasada de endurecimiento de seguridad, además de un lote de limpieza de integridad de datos/velocidad de build.

✨ Funciones y UX

Landing pages sin theme - Nuevo template raw.tt: el admin escribe un documento HTML completo como cuerpo de la página, sin header/footer/envoltorio de CSS del site, para landing pages que no deberían llevar la marca del site. Los shortcodes {{block:...}} aún se resuelven. - Nuevo landing.tt: la misma postura sin marca, pero con una hoja de estilos por defecto autocontenida que cubre los 15 tipos de bloque, de modo que los bloques hero/CTA/stat etc. se renderizan con un estilo razonable sin CSS escrito a mano. - El dropdown de templates ahora también lista los templates provistos por el theme, y conserva el template de una página al cambiar de theme en lugar de corromperlo silenciosamente a la primera opción alfabética. - La aplicación del password gate ahora verifica si el template resuelto realmente implementa el gate (no solo el nombre de archivo raw.tt), cerrando un bypass en el que cualquier template sin gate podía publicar contenido protegido con contraseña sin UI de gate. - Bulk-create ganó un selector de template y un body_template compartido con mail-merge de {{title}}/{{slug}}, de modo que N páginas de un mismo diseño pueden llevar titulares distintos sin editar cada una a mano.

Forms - Captura de atribución de marketing: los parámetros UTM, los click IDs (gclid/fbclid/msclkid/ttclid) y la URL completa de la landing page se extraen del header Referer y se guardan en la submission, respetando DNT/GPC. Lista de submissions rediseñada (filtros por fuente/campaña, badge de fuente derivada) y una nueva pantalla de detalle de una sola submission. - Submit-gate de Turnstile: un usuario que envía rápido ya no recibe un falso "Bot verification failed"; el envío se retiene hasta que el widget emite un token y luego se reenvía automáticamente. - Pre-relleno de campos de formularios públicos desde parámetros de query de la URL, cubriendo campos text/email/checkbox/checkboxes/address. - Contenido de cuerpo distinto por ítem en bulk-create mediante items_input: pega bloques repetidos de título/cuerpo en lugar de un template compartido para todos los ítems. - Historial de revisiones de forms: cada guardado de settings/campos toma un snapshot de la versión anterior; consulta una lista de revisiones, compara con la actual y restaura. - Almacenamiento normalizado de submissions: las respuestas de las submissions ahora se escriben en una tabla consultable submission_values (además del blob heredado por compatibilidad hacia atrás), más un tipo de campo number. - Cuotas de subida por form y almacenamiento privado: limita el tamaño total de subida por form y, opcionalmente, guarda los archivos subidos fuera del directorio público con una ruta de descarga solo para admin.

Posts y páginas - Los area blocks (hero/CTA/stat) ahora se renderizan en posts, no solo en páginas; se recolectaban silenciosamente pero nunca se pasaban al template del post. - Selector de punto focal de la imagen destacada: selector visual X/Y persistido por página/post, aplicado mediante object-position en el markup de imagen responsive.

Herramientas de build - Sembrador de fixtures de benchmark + instrumentación permanente de tiempos por fase en el builder, que establece la línea base contra la cual se medirá el resto de la serie de velocidad de build.

🔒 Seguridad

Mensajes de bloqueo, headers y limitación de rutas de abuso - Los mensajes de bloqueo con tiempo de espera exacto se reemplazaron por un mensaje genérico en login/forgot-password/cuenta suspendida, cerrando una fuga de información. - Se añadió el header Permissions-Policy, que restringe funciones del navegador que este CMS nunca usa. - Entradas señuelo Disallow en robots.txt que apuntan a rutas honeypot monitoreadas. - Retardo tarpit en fallos de login, envíos de formularios limitados por tasa y hits de honeypot: no bloqueante, de modo que el tráfico legítimo no se retiene mientras un atacante gasta tiempo de reloj.

Fingerprinting del servidor, abuso de registro, logging forense - Se suprimió el header de respuesta Server: Mojolicious (Perl). - Limitación de tasa por IP en /register (cada intento fallido cuenta, no solo username-taken/fallo de DB; cierra una brecha por la que envíos malformados podían inundar el endpoint sin activar nunca el bloqueo) más una verificación de existencia de username en tiempo constante. - Los eventos de seguridad de alta señal ahora también se envían a un log externo de solo anexado (permisos 0600), de modo que el registro forense sobrevive a un compromiso de la base de datos SQLite. - Los endpoints honeypot (/wp-login.php, /.env, /phpmyadmin, etc.) identifican escáneres automatizados. Alcance en el site público: la configuración de ejemplo de Caddy (deploy/chinaski.Caddyfile.example) ahora hace proxy de estas rutas a la app también en los vhosts públicos, no solo en admin.*; un deploy de producción que use la configuración de Caddy en vivo necesitará aplicar manualmente el bloque de proxy equivalente (ver Actualización).

🐛 Correcciones y endurecimiento

  • Integridad de datos / escala (Phase 40): blocks/globals.content_json ahora se validan como JSON al escribir (UI, API, importaciones) con una restricción CHECK de SQLite correspondiente; build_log limitado a 1000 filas; las consultas ilimitadas de ancestros de página se acotaron con LIMIT; se corrigió la renumeración del sort-order de nav_items; el script de backup ahora hace checkpoint del WAL y vacuum.
  • Lote de quick-wins: se eliminó CRLF de las etiquetas de campo antes de llegar a los cuerpos de los correos de notificación (cierra una brecha de suplantación del cuerpo del correo); se eliminó el fallback falsificable de X-Country-Code en el geo-blocking; se corrigió el pre-relleno tras un fallo de validación en campos address y checkbox multivalor; los tokens de referencia de submission ahora son un valor aleatorio CSPRNG en lugar de uno reversible/enumerable.
  • SRI/caché: las URLs de CSS del admin ahora se invalidan por hash de contenido, y se eliminó el frágil hash integrity de la etiqueta script de Turnstile (que Cloudflare rota sin aviso).
  • i18n: los strings de traducción del admin se extrajeron de cms.pl a Chinaski::I18n, sin cambio de comportamiento.
  • Lista de posts: un crash en el filtro del lado del cliente (lanzado por una fila de header/cola que carecía de los atributos data que el selector asumía) que rompía el filtrado de todas las filas cada vez que existía un post programado, ahora alcanzable a través de filtros restaurados desde la URL.
  • CI: se corrigió un fallo intermitente de la prueba documents_module causado por una ruta de archivo compartida /tmp/private entre ejecuciones de pruebas concurrentes como root/sin privilegios en el mismo host de CI.
  • Las pasadas de revisión posteriores al merge sobre el trabajo de landing pages y forms descrito arriba encontraron y corrigieron varios bugs reales antes/después del merge, incluyendo: un bug de reinterpolación de mail-merge y una brecha de escapado por ruptura de atributos en bulk-create; una fuga de archivos subidos y una condición de carrera TOCTOU en la aplicación de la cuota de subida; una fuga de auto-poda por retención que nunca liberaba cuota; snapshots de revisión registrados incluso cuando el guardado que los precedía fallaba; un falso positivo de la vista de diff tras una restauración; un typo que rompía el renderizado de campos address en la página de detalle de submission; una migración de submission-values no transaccional y no idempotente; y una regresión de Permissions-Policy que rompía el pantalla completa de videos embebidos en rutas de preview.

⬆️ Actualización

Sin pasos manuales de DB: los cambios de esquema se aplican automáticamente y de forma idempotente al arrancar; las bases de datos antiguas se actualizan en su lugar.

Un paso manual si usas el ejemplo de Caddy incluido como punto de partida para tu propia configuración: el bloque de proxy de rutas honeypot añadido a deploy/chinaski.Caddyfile.example debe copiarse a tu configuración de Caddy en vivo y aplicarse (docker restart caddy o equivalente) para que las sondas de escáneres contra el site público lleguen al logging/tarpit de la app; el archivo de ejemplo de este repositorio se actualizó, pero el Caddyfile de un deployment en vivo se mantiene por separado y este release no lo toca.

Full changelog: https://github.com/bigjohncobb/chinaski/compare/v1.5.2…v1.5.3

v1.5.2

2026-06-30

Correcciones

  • Borrado masivo de submissions: every_param('ids') devuelve un arrayref; al faltar la desreferencia @{}, el array nunca se desempaquetaba y no se borraban filas en cada intento de borrado masivo.

v1.5.1

2026-06-30

Correcciones de bugs

  • fix(forms): autenticación SMTP LOGIN sin Authen::SASL: Net::SMTP->auth requiere Authen::SASL, que no está instalado; reemplazado por un intercambio manual de AUTH LOGIN tanto en _send_form_email como en _send_admin_email. Los correos salientes de forms y de notificación de build ahora funcionan.
  • fix(forms): falta la traducción btn_delete_selected: el botón de borrado masivo en la página de submissions mostraba el nombre crudo de la clave en lugar de "Delete selected" (en los 4 idiomas). El borrado masivo de submissions de forms ahora funciona.

v1.3.0

2026-06-14

Release de Phase 80 (Pages) más una corrección de seguridad y una migración de seguridad para actualizaciones.

✨ Funciones y UX, Phase 80: Pages

  • Búsqueda: filtro q= del lado del servidor por título/slug en las listas de páginas y posts, que se combina con sort/dir + paginación.
  • Flujo de revisión: aprobar una página/post ahora envía un correo al creador del contenido (refleja el flujo de rechazo) y lo registra en el audit trail.
  • Ida y vuelta de exportar/importar: las exportaciones CSV de páginas y posts ahora emiten el conjunto completo de columnas en el orden de la importación (metadatos OG, URL canónica, programación, parent_id, recurring, …); los datetimes de programación se convierten a la zona horaria del site para que la reimportación haga el viaje completo.
  • Accesibilidad: aria-sort en encabezados ordenables, aria-labels en inputs de campos personalizados y checkboxes de seleccionar todo, role=status/aria-live en el flash informativo, señal no basada en color en los cambios del diff de revisiones.
  • Los flashes de acciones masivas ahora nombran lo que hicieron; los timestamps de revisiones se renderizan en la zona horaria del site.

🔒 Seguridad

  • Los tokens de acceso a documentos ahora usan un CSPRNG. Reemplaza un token derivado de rand no criptográfico + entradas predecibles por un secreto bearer de 256 bits de /dev/urandom, igual que los tokens de sesión/API-key. Los tokens existentes siguen siendo válidos; no se requiere migración.

🐛 Correcciones y endurecimiento

  • Los re-renders de error del formulario de edición (fallos de validación y de permisos) ahora conservan los datos enviados, incluido el estado de los checkboxes de los paneles de snippets/áreas.
  • La exportación JSON de posts ya no usaba SELECT *: una lista explícita de columnas excluye password_hash de las exportaciones compartibles.
  • Seguridad de actualización: se añadió una migración idempotente de arranque de og_image_url para pages/posts, ordenada antes de la reconstrucción de tabla de phase41 que lee la columna, de modo que las bases de datos anteriores a ella se actualicen limpiamente.

⬆️ Actualización

Sin pasos manuales. Los cambios de esquema se aplican automáticamente y de forma idempotente al arrancar; las bases de datos antiguas se actualizan en su lugar. Los tokens de documentos emitidos bajo el esquema anterior siguen siendo válidos.

Full changelog: https://github.com/bigjohncobb/chinaski/compare/v1.2.3…v1.3.0

v1.2.0

2026-06-12

Novedades

Nuevos tipos de bloque (14)

Text, Button Group, Divider, Spacer, Heading, Pricing Table, Feature Grid, Callout, FAQ, Code Block, Team, Timeline, Logo Bar, Audio: todos puro Template Toolkit + CSS, seguros para air-gap, con formularios de admin y pruebas de render.

Stacks y composición

  • Seguimiento de dependencias, vista de usado-en y panel de radio de impacto
  • Historial de revisiones con restauración
  • Ruta independiente Preview Stack

Pages y Posts (Phase 47)

  • Campos personalizados, panel de Authors, panel de Translations en la barra lateral
  • Módulo de Documents
  • Migraciones 026 a 039 automatizadas al arrancar

Health y build

  • Endpoint estructurado /health con estado y latencia por chequeo
  • Suite de validación previa a la promoción (validate_build) con chequeos de HTML, sitemap y enlaces
  • Guardia de promoción para failover siempre en línea

Seguridad

  • XSS de estilos de bloque: lista de valores CSS permitidos en todos los campos de estilo; filtro | html en los 33 templates de bloque; el JSON-LD de FAQ se genera con JSON::PP (sin escapado hecho a mano)
  • Sanitización de URLs de contenido: las URLs javascript: y otras que no son http/https se eliminan de content_json al guardar en todos los tipos de bloque
  • CSRF: guardia de token añadida a POST /register y POST /forgot-password
  • Timing de login: verificación bcrypt ficticia cuando el username no se encuentra; el tiempo de respuesta ya no revela si la cuenta existe
  • TTL de sesión: las sesiones ahora expiran (8 h por defecto, 30 d con remember-me); las sesiones previas a la migración sin TTL se podan en el primer arranque
  • Aplicación de permisos de Pages: guardia can_edit_entity_type('pages') en las 17 rutas que antes no tenían guardia
  • Pages require_approval: bulk-publish y publish-now respetan el flujo de aprobación para editores que no son admin

Correcciones

Backups - SQLite Online Backup API para snapshots consistentes (elimina la condición de carrera con WAL) - Helper compartido _backup_paths, las cuatro rutas de restauración usan convenciones de directorio idénticas - Los metadatos de la tabla Themes se exportan a themes.json en cada archive; se restauran en las cuatro rutas de restauración - Se corrigió la firma SigV4 por query-string de DO Spaces, la paginación más allá de 1000 objetos ahora funciona - Tope de subida de 50 MiB en la restauración - Los cambios de credenciales de Backup/DO Spaces ya no disparan un rebuild completo del site - Los errores de credenciales/red de S3 se muestran en lugar de mostrar silenciosamente una lista vacía

Pages y operaciones masivas - Revisiones fantasma corregidas: save_revision movido dentro de la transacción de bloqueo optimista - El borrado y duplicado de una sola página envueltos en transacciones; duplicate ahora copia page_area_blocks - Bulk publish/unpublish/schedule/unschedule todos atómicos - Lista de IDs masivos limitada a 500; lista de revisiones limitada a 500

Admin - El mover arriba/abajo de Snippets reescrito para intercambiar ítems adyacentes en una transacción (antes era ±1 a ciegas) - Se añadieron wrappers de transacción al mover arriba/abajo de campos de form - El flash de error de importación CSV se sanitizó (el error completo se registra solo del lado del servidor) - i18n: se corrigió el doble escapado de entidades HTML en el helper t - Se resolvieron consultas N+1, listas ilimitadas e ineficiencias de build - Se añadieron las migraciones de arranque 035 y 039 para columnas de asignación de stacks (corrige el crash del builder en deploys nuevos)


Notas de actualización

  • Las migraciones 026-039 se ejecutan automáticamente en el primer arranque, sin SQL manual.
  • La columna user_sessions.expires_at se añade automáticamente; las sesiones existentes se invalidan en el primer reinicio (todos los admins tendrán que iniciar sesión de nuevo).
  • El sidecar themes.json se incluye en los backups a partir de esta versión. Los backups antiguos se restauran limpiamente: el sidecar simplemente está ausente.

v1.1.2

2026-06-05

Novedades

Correcciones

  • Build: se recuperó el chequeo de enlaces rotos de subdominios; los hrefs absolutos ahora se resuelven contra la raíz del idioma en modo subdominio; se endureció la validación de last_built contra timestamps futuros/inválidos
  • Build: se revierte el renderizado incremental inteligente a favor de dos salvaguardas corregidas (evita que las páginas desaparezcan tras builds incrementales)
  • Bulk create: deja de recortar títulos que contienen comas; escapado de comillas corregido en el helper de título de bulk_create
  • i18n: se repararon helpers de título rotos y claves de léxico mal anidadas; se añadió la clave de léxico btn_upload que faltaba
  • Auth: se exige autenticación de admin en la ruta del dashboard /admin

Tareas de mantenimiento

  • Branding: avatar de SBS establecido como favicon

Full Changelog: https://github.com/bigjohncobb/chinaski/compare/v1.1.0…v1.1.2

v1.1.0

2026-06-05

Novedades

Funciones

  • Panel de sugerencia de enlaces internos: cajón del editor que escanea el contenido del cuerpo y sugiere menciones sin enlazar de páginas/posts publicados, con acciones Link it / Link 1st / Link All / Skip y accesibilidad por teclado
  • Seguimiento del progreso de build en tiempo real: barra de progreso en vivo, conteos de páginas/posts y visualización del ítem actual en el dashboard del admin durante los builds
  • Sistema de prevención de fallos de build: chequeo de seguridad cuando se renderizan 0 páginas, override con la variable de entorno CHINASKI_FORCE_FULL, endpoint de monitoreo /api/health, validación de fecha futura de last_built, script de rebuild forzado y script de monitoreo por cron

Correcciones

  • i18n: se repararon UTF-8 doblemente codificado / mojibake en caracteres acentuados en mayúscula (É, Ú, À, Ã, etc.) en las traducciones ES, FR, PT
  • Templates: se corrigieron las directivas de título en las páginas de dashboard y búsqueda
  • CMS: $DOCS_DIR declarado de antemano antes del primer uso

v1.0.2

2026-06-04

Qué ha cambiado

  • fix(i18n): fix remaining mojibake for uppercase accented chars (É, Ú, À) by @bigjohncobb in https://github.com/bigjohncobb/chinaski/pull/79

Full Changelog: https://github.com/bigjohncobb/chinaski/compare/v1.0.1…v1.0.2

v1.0.1

2026-06-04

Qué ha cambiado

  • feat(editor): move page action buttons to top of sidebar por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/44
  • feat(blocks): add page_list block type por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/45
  • fix(favicon): generate and deploy favicon.svg on upload por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/46
  • feat(i18n): Group A: translate auth layout, login, and register por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/47
  • feat(i18n): Group B: translate pages and posts templates por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/48
  • fix(builder): render [form:slug​] shortcodes inline instead of iframe por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/49
  • feat(i18n): Group F: translate forms builder and translation workflows por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/50
  • feat(i18n): Group G: settings, themes, and calendar por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/51
  • fix: add design brief upload UI to themes generate panel por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/52
  • fix: use per-language subdomain for View link in pages admin por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/53
  • i18n: Group I: dashboard, admin tools, and maintenance por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/54
  • i18n: Group J: flash messages in cms.pl por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/55
  • feat(documents): make published documents publicly accessible por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/56
  • feat: build performance + configurable API rate limit por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/57
  • fix: six one-liner bug fixes: settings and search por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/58
  • fix: search UX and settings layout bugs por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/59
  • fix(build): increase timeout and lock TTL; add page-list block styles por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/60
  • fix: settings correctness and search result quality por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/61
  • fix: settings tab data, security_contact validation, webhook events por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/62
  • fix: API key banner visibility and audit_log retention por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/63
  • fix: pages list: add page-jump input to pagination por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/64
  • fix: search results, full action set and resolved URL paths por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/65
  • fix: search results: body match context excerpt por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/66
  • fix: move settings audit and snapshots to dedicated History tab por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/67
  • feat: expose API key rate limit in settings UI por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/68
  • fix: trim verbose settings panel hint texts por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/69
  • fix: move DO Spaces credentials from Integrations to Backups tab por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/70
  • fix: cancel dashboard build-poll timer on page unload por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/71
  • fix: History tab routing and DO Spaces credential reset por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/72
  • feat(schema): Organization JSON-LD on every page por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/73
  • fix(builder): skip stale cleaner on incremental builds por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/74
  • fix(cms): forward-declare $DOCS_DIR before first use por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/75
  • fix(templates): use double quotes for title tags containing t por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/76
  • fix(i18n): repair double-encoded UTF-8 in all translation strings por @bigjohncobb en https://github.com/bigjohncobb/chinaski/pull/78

Full Changelog: https://github.com/bigjohncobb/chinaski/compare/v1…v1.0.1

Lee este sitio en