EmDash mantiene la versión publicada de una entrada separada de los cambios no publicados. El panel de administración, la API REST, la interfaz de línea de comandos (CLI) y las herramientas del Model Context Protocol (MCP) usan las mismas reglas de ciclo de vida.
Una entrada puede estar en draft, scheduled o published. Una entrada publicada también puede tener un borrador y una
programación futura: los visitantes siguen recibiendo la revisión en vivo hasta que se publique el borrador
programado. La papelera es independiente del estado. Una entrada en la papelera conserva sus metadatos de ciclo de vida pero se
excluye de las lecturas ordinarias de contenido.
Transiciones de estado
La tabla siguiente es el contrato canónico para el estado del contenido, los punteros de revisión y las marcas de tiempo de publicación. «Sin cambio» significa que la operación conserva el valor almacenado.
| Acción | Estado inicial | Resultado | Efecto en la revisión | publishedAt | scheduledAt | Llamada repetida |
|---|---|---|---|---|---|---|
| Guardar cambios | Cualquier entrada activa | El estado no cambia | En una colección con revisiones, sustituye la revisión de borrador mientras la revisión en vivo sigue pública | Sin cambio | Sin cambio | Un _rev suministrado rechaza un guardado obsoleto; omitirlo hace que la escritura REST sea incondicional |
| Publicar | Borrador, programada o publicada | Publicada | Promueve la revisión de borrador a en vivo y borra el puntero de borrador | Se establece en la primera publicación; se conserva en publicaciones posteriores salvo que un llamador autorizado lo sobrescriba | Borrado | Conserva el contenido en vivo y la hora de publicación, pero devuelve un _rev nuevo |
| Publicar cuando toque | Programada, o publicada con un borrador programado | Publicada | Igual que publicar | Usa la hora programada en la primera publicación; conserva el valor existente al publicar un borrador nuevo sobre el contenido en vivo | Borrado | Un paso posterior del programador omite una entrada cuya programación ya se borró |
| Despublicar | Cualquier entrada activa | Borrador | Borra el puntero en vivo; conserva el borrador existente o crea uno a partir de la revisión en vivo | Conservado | Borrado | Una entrada que ya es un borrador simple no cambia |
| Programar | Borrador, programada o publicada | Un borrador pasa a programada; una entrada publicada sigue publicada | Sin cambio | Sin cambio | Se establece en la hora futura solicitada | Sustituye la programación existente y devuelve un _rev nuevo |
| Desprogramar | Programada, o publicada con una programación | Una entrada programada pasa a borrador; una entrada publicada sigue publicada | Sin cambio | Sin cambio | Borrado | Una entrada sin programación no cambia |
| Descartar borrador | Cualquier entrada activa | El estado no cambia | Borra el puntero de borrador; la revisión en vivo no cambia | Sin cambio | Sin cambio | Una entrada sin borrador no cambia |
| Mover a la papelera | Cualquier entrada activa | En la papelera y ausente de las lecturas ordinarias | Conservado | Conservado | Conservado | Una solicitud de una entrada que ya está en la papelera devuelve no encontrado |
| Restaurar desde la papelera | En la papelera | Borrador | Borra el puntero en vivo; conserva cualquier puntero de borrador | Conservado | Borrado | Requiere una entrada que siga en la papelera |
| Eliminar permanentemente | En la papelera | Eliminada | Elimina la entrada y sus revisiones | Eliminado | Eliminado | No se puede repetir ni deshacer |
| Restaurar una revisión | Cualquier entrada activa | El estado no cambia | En una colección con revisiones, sustituye el borrador por una copia de la revisión seleccionada; la revisión en vivo no cambia | Sin cambio | Sin cambio | Crea una revisión nueva y devuelve un _rev nuevo |
En una colección sin soporte de revisiones, guardar y publicar usan la fila de contenido en lugar de punteros en vivo y de borrador. Restaurar una revisión escribe los valores de campo seleccionados directamente en esa fila.
Restaurar una revisión en una colección con revisiones no la publica. Publica la entrada después de revisar el borrador restaurado.
Permisos y protección de escritura
Los permisos dependen de la propiedad. Un Author puede actuar sobre una entrada que posee; un Editor puede realizar la misma acción sobre cualquier entrada. La eliminación permanente requiere un Admin.
Establecer publishedAt durante la publicación requiere content:publish_any, incluso cuando el llamador posee la
entrada.
La API REST acepta _rev como una precondición opcional de concurrencia optimista donde se indica. Las herramientas MCP
lo exigen para las mismas operaciones, de modo que un agente debe leer la entrada antes de cambiarla. Un token obsoleto
devuelve CONFLICT. Las escrituras de administración y REST protegidas por un bloqueo de entrada devuelven ENTRY_LOCKED salvo que una
solicitud autorizada use la anulación de bloqueo admitida. Las escrituras MCP no participan en los bloqueos de entrada.
| Acción | Permiso | REST _rev | MCP _rev | Bloqueo de admin y REST | Hooks |
|---|---|---|---|---|---|
| Guardar cambios | content:edit_own o content:edit_any | Opcional | Obligatorio | Aplicado | content:beforeSave, content:afterSave |
| Publicar | content:publish_own o content:publish_any | Opcional | Obligatorio | Aplicado | content:beforePublish, content:afterPublish |
| Despublicar | content:publish_own o content:publish_any | Opcional | Obligatorio | Aplicado | content:beforeUnpublish, content:afterUnpublish |
| Programar | content:publish_own o content:publish_any | Opcional | Obligatorio | Aplicado | content:beforeSchedule, content:afterSchedule |
| Desprogramar | content:publish_own o content:publish_any | No aceptado | No aceptado | Aplicado | content:afterUnschedule |
| Descartar borrador | content:edit_own o content:edit_any | Opcional | Obligatorio | Aplicado | Ninguno |
| Mover a la papelera | content:delete_own o content:delete_any | No aceptado | No aceptado | Aplicado | content:beforeDelete, content:afterDelete |
| Restaurar desde la papelera | content:edit_own o content:edit_any | No aceptado | No aceptado | No aplicado | content:afterRestore |
| Eliminar permanentemente | content:delete_permanent | No aceptado | No aceptado | No aplicado | content:afterDelete |
| Restaurar una revisión | content:edit_own o content:edit_any | No aceptado | No aceptado | No aplicado | Ninguno |
El evento content:afterDelete establece permanent en false cuando una entrada se mueve a la papelera y en true
tras la eliminación permanente. Los after-hooks correctos se ejecutan después del cambio de estado y pueden ejecutarse después de que se
haya enviado la respuesta. Un plugin puede rechazar guardar, publicar, despublicar, programar o mover a la papelera desde
el before-hook correspondiente.
Cuando la publicación programada llega a su hora, usa los hooks de publicación. Si un
hook content:beforePublish rechaza ese intento programado, EmDash borra la programación y ejecuta
content:afterUnschedule.
Conflictos y reintentos
Usa el _rev devuelto por cada lectura o escritura para la siguiente operación protegida. EmDash rechaza un
token desactualizado en lugar de sustituir un cambio concurrente. Vuelve a leer la entrada, revisa el estado
más reciente y decide entonces si reintentar.
Una respuesta de error no siempre demuestra que no cambió ningún estado. Si una conexión termina antes de que el cliente reciba una respuesta, lee la entrada antes de reintentar una operación de ciclo de vida. Esto también evita que un reintento sustituya el trabajo completado por otro editor.
La restauración de una revisión confirma el contenido restaurado y su revisión de auditoría juntos. Si cualquiera de las escrituras falla, EmDash conserva el contenido y el historial de revisiones de antes de la solicitud.
Consulta la referencia de la API REST para los esquemas de solicitud y respuesta HTTP, la referencia del servidor MCP para las entradas de las herramientas y la referencia de hooks para las cargas útiles de los eventos.