Saltar al contenido principal

Resumen

El desarrollo de aplicaciones locales gira en torno a la sincronización: la CLI recompila tu manifiesto y el servidor aplica solo la diferencia entre este y los metadatos que ya se encuentran en tu espacio de trabajo. Esta página explica qué comando usar, cómo leer qué cambió una sincronización y qué hacer, en orden, cuando el estado local parece inconsistente.

Qué comando usar y cuándo

Para la iteración local del día a día casi siempre quieres twenty app dev. La implementación y la publicación son para enviar versiones, no para el ciclo local.

La sincronización local no necesita un aumento de versión

La regla de version estrictamente creciente (VERSION_ALREADY_EXISTS al implementar, APP_ALREADY_INSTALLED / CANNOT_DOWNGRADE_APPLICATION al instalar) se aplica a twenty app publish / twenty app install — la ruta de publicación. twenty app dev sincroniza tu manifiesto en su lugar y nunca requiere un cambio de versión, por lo que no necesitas tocar package.json para iterar. Si te encuentras aumentando la versión para probar un cambio local, estás usando la ruta de publicación cuando lo que quieres es el ciclo de desarrollo.

Leer la salida de la sincronización

Cada sincronización imprime los cambios de metadatos que aplicó (o aplicaría, con plan), al estilo de Terraform: un bloque por entidad con sus atributos y luego una línea de resumen:
Este es tu primer diagnóstico: te indica exactamente qué objetos, campos y diseños cambiaron, para que puedas confirmar que una sincronización hizo lo que esperabas antes de revisar la interfaz de usuario. Los cambios destructivos (to destroy) se enumeran con lo que eliminan (p. ej., objectMetadata "auditNote" — drops the table and all its rows) y requieren confirmación interactiva, o --yes en scripts. Una sincronización elimina todas las entidades que posee tu aplicación y que tu fuente ya no declara. Cuando un plan contiene destrucciones, lo indica y señala --no-prune (anteriormente --no-delete, que sigue funcionando), lo que hace que la sincronización sea aditiva: se aplican las creaciones y actualizaciones, no se elimina nada que falte en su origen, y el componente de configuración y las vinculaciones del hook de desinstalación de la aplicación permanecen como están cuando su origen no los declara. Úsalo cuando tu fuente sea intencionadamente parcial, por ejemplo, mientras adoptas una aplicación creada en la interfaz de usuario. La aplicación personalizada del espacio de trabajo es la excepción: dado que pull aún no puede exportar todo lo que posee, su sincronización es aditiva a menos que pase --prune. Los servidores publicados antes de este cambio siguen eliminando de forma predeterminada, así que pase --no-prune al aplicar la aplicación personalizada a uno de ellos. Cuando una sincronización falla en una sola entidad, el error nombra la entidad implicada y su universalIdentifier, por ejemplo:
Usa ese identificador para encontrar la entidad en tu manifiesto (y, si es necesario, en el espacio de trabajo) en lugar de adivinar cuál entra en conflicto.

Previsualizar cambios (plan)

twenty app plan compila tu manifiesto, le pide al servidor el plan de migración y lo imprime — sin aplicar nada. Es la forma segura de responder “¿qué cambiaría esta sincronización?” antes de comprometerte a ella.
Un plan:
  • No cambia el espacio de trabajo, no realiza migraciones de metadatos, actualizaciones de registros de aplicaciones ni cambios en roles o pestañas predeterminados. Crea una instantánea local, pero no vuelve a generar el cliente de API.
  • Devuelve el mismo diff que aplicaría una sincronización real, para que puedas revisar por adelantado las entidades creadas/actualizadas/eliminadas.
  • Es útil antes de un cambio arriesgado, al revisar un cambio generado por IA o en un script que deba fallar si está a punto de producirse un cambio inesperado.
Un plan solo muestra una vista previa de los cambios de metadatos. También funciona para una aplicación que nunca se sincronizó: el servidor evalúa el manifiesto frente a una aplicación vacía, por lo que el plan enumera todo lo que crearía tu código fuente.

Extraer una aplicación instalada al código fuente

twenty app pull es experimental. Actualmente solo cubre parte de una aplicación, la estructura de su salida puede cambiar entre versiones y sobrescribe los archivos que definen las entidades que extrae. Restaura las traducciones publicadas en locales/, y conserva las entradas cuyas cadenas de origen aún no están en tu árbol en locales/compiled/ para que una subida no las pierda. Confirma tu trabajo antes de ejecutarlo y revisa el diff.
twenty app pull es la operación inversa de apply: lee una aplicación desde el espacio de trabajo y restaura sus archivos de definición, traducciones y archivos de dependencias almacenados.
Dentro de una aplicación, pull lee su identificador local defineApplication() y recupera esa aplicación. Fuera de una aplicación, solicita un directorio y confirmación, crea un proyecto local para la aplicación personalizada del espacio de trabajo seleccionado, instala las dependencias con Yarn y luego extrae las definiciones. El nuevo proyecto incluye archivos de paquete y configuración, sin las entidades de demostración del inicializador. Usa --path para seleccionar una aplicación existente o un directorio nuevo o vacío. La creación no interactiva requiere --path y --yes; pull se niega a sobrescribir un directorio no vacío no relacionado. Crear un proyecto no registra una aplicación ni cambia el espacio de trabajo. Un proyecto de SDK existente sin una definición de aplicación también extrae la aplicación personalizada. No existe la opción --universal-identifier. Si falla la instalación de dependencias para un proyecto nuevo, se conserva la estructura base. Ejecuta yarn install dentro de ella y, luego, vuelve a intentar la extracción. Los proyectos existentes no instalan las dependencias automáticamente. Si no se puede leer su identificador de aplicación, la extracción informa de ese error en lugar de crear otra aplicación. Añade --verbose para ampliar las secciones de cobertura del informe, que entonces nombran hasta 20 identificadores por tipo de metadatos en lugar de solo los totales. Qué escribe:
  • la configuración de la aplicación;
  • archivos de dependencias package.json y yarn.lock almacenados, en la raíz del proyecto;
  • objetos, con sus campos en línea;
  • campos que tu aplicación añadió a objetos que no posee;
  • índices creados;
  • las banderas de permisos que declara tu aplicación, como archivos definePermissionFlag();
  • los roles, con sus permisos de objeto, permisos de campo, predicados de permisos a nivel de fila y grupos, y banderas de permisos en línea. El rol predeterminado de tu aplicación se escribe con defineApplicationRole(). Un permiso de objeto o de campo cuyo identificador es el que genera la compilación se escribe sin él. Cuando el rol predeterminado no es uno de los roles propios de tu aplicación, como en el caso de la aplicación Custom del espacio de trabajo, la configuración de la aplicación conserva defaultRoleUniversalIdentifier en su lugar;
  • vistas, con sus campos, grupos de campos, filtros, grupos de filtros, ordenaciones y grupos en línea;
  • campos de vista que tu aplicación añadió a vistas que no le pertenecen, como archivos independientes de defineViewField();
  • diseños de página, con sus pestañas y widgets integrados;
  • pestañas que tu aplicación agregó a diseños de página que no le pertenecen, como archivos definePageLayoutTab() independientes;
  • elementos del menú de navegación, como archivos defineNavigationMenuItem(), carpetas incluidas;
  • widgets que tu aplicación añadió a pestañas que no le pertenecen, como archivos independientes de definePageLayoutWidget();
  • flujos de trabajo, como archivos defineWorkflow(), con el código fuente de cada paso de Código en su propio archivo \<workflow-file-name>/\<step-name>.code.ts junto al flujo de trabajo, cuando su versión almacenada sea la que escribió la última sincronización. Para la aplicación personalizada del espacio de trabajo, es la versión activa, independientemente de si la publicó una sincronización o el generador de flujos de trabajo, y la aplicación publica una definición modificada como una nueva versión, tal como se describe en Flujos de trabajo;
  • habilidades, como archivos defineSkill();
  • agentes, como archivos defineAgent(), con sus desencadenadores y el rol al que los vincula tu aplicación;
  • reglas de validación, como archivos defineValidationRule() con su expresión como una cadena;
  • traducciones publicadas, como locales/\<locale>.json para que la extracción de cadenas pueda leerlas de nuevo a partir de los metadatos y el origen extraídos, y locales/compiled/\<locale>.json para el resto.
Cada entidad va al archivo que ya la define, por lo que una segunda extracción vuelve a escribir solo lo que cambió en el servidor. Un archivo también se vuelve a escribir cuando usa una función de definición distinta de la que escribiría pull; por ejemplo, un rol que se convirtió en el rol predeterminado o dejó de serlo. Las entidades nuevas se colocan junto a los archivos existentes de su tipo, y un nombre generado que coincidiría con un archivo no relacionado se califica en lugar de sobrescribirlo. Archivos de dependencias. Cuando cambia el package.json o yarn.lock almacenado, pull reemplaza el archivo local e informa de cualquier edición local sobrescrita. Si el archivo remoto no ha cambiado desde el pull anterior, se conservan las ediciones locales. La ausencia de un archivo remoto no elimina su equivalente local. Cuando el paquete exportado omite twenty-sdk, como hace la aplicación Custom del espacio de trabajo, pull conserva la dependencia local del SDK para que los comandos de CLI aún puedan cargar el proyecto. Los archivos de dependencias, los metadatos y la base se escriben juntos y se revierten juntos si se produce un error de escritura. Ejecuta yarn install después de obtener los cambios de dependencias. Pull instala dependencias solo al crear un proyecto nuevo, antes de restaurar los archivos remotos; no las reinstala después de reemplazar package.json o yarn.lock. Pull no vuelve a generar el cliente tipado. Ejecuta twenty app generate-client cuando necesites tipos actualizados del espacio de trabajo. Qué no escribe:
  • Aún no se exportan — elementos del menú de comandos y del menú de configuración, funciones lógicas y componentes frontend, proveedores de conexión, variables de aplicación, recursos públicos, tipos de actividad de cronología y la fuente almacenada de tus funciones.
  • Derivado por el motor — campos del sistema, relaciones predeterminadas, vistas predeterminadas e índices subyacentes, y los diseños de página predeterminados de cada objeto. El servidor los reconstruye al aplicar. Un objeto aún puede apuntar su identificador de etiqueta a uno de ellos, como hacen los objetos de unión creados en la interfaz de usuario; se escribe la referencia y la compilación la resuelve sin añadir un campo.
  • Colocados en una vista predeterminada o ajena — los filtros, grupos de filtros, ordenaciones, agrupaciones y grupos de campos que se agregan a una vista predeterminada del motor, o a una vista propiedad de otra aplicación, aún no tienen un formulario de origen y se notifican. Los campos de vista agregados allí se escriben como archivos independientes, ya que se conoce el identificador de la vista.
  • Colocados en un diseño de página predeterminado o ajeno — las pestañas y los widgets añadidos a un diseño de página predeterminado del motor, o a uno que pertenece a otra aplicación, se escriben como archivos independientes de definePageLayoutTab() y definePageLayoutWidget(), ya que se conoce el identificador al que se adjuntan.
  • Widgets que la exportación aún no puede incluir — en cualquier diseño, incluido el suyo, se informa de un widget del tipo obsoleto VIEW, un widget que muestra uno de los componentes de frontend o elementos del menú de comandos de su propia aplicación, o un widget sin posición para el modo de diseño de su pestaña, y el diseño o la pestaña se escribe sin él.
  • Flujos de trabajo que la exportación aún no puede incluir — un flujo de trabajo modificado en el constructor de flujos de trabajo desde la última sincronización, un flujo de trabajo del sistema o privado, uno con un paso de Código creado antes de que los pasos almacenaran su código fuente y uno que llama a la acción de flujo de trabajo de otra aplicación se notifican y se dejan en su lugar. Un flujo de trabajo que se deja en su lugar conserva sus archivos .code.ts. La aplicación personalizada del espacio de trabajo es la excepción para el primer y el último caso: el generador también publica sus flujos de trabajo, y estos pueden llamar a las acciones de cualquier aplicación, por lo que se incorporan. En su lugar, se informa de uno de sus flujos de trabajo cuando no tiene una versión activa o cuando su versión activa utiliza configuraciones que una definición no puede expresar. Se extraen los pasos de correo electrónico y calendario: una cuenta compartida con el espacio de trabajo se escribe como su connectedAccountHandle, mientras que la cuenta privada de un miembro y las variables se conservan tal como están. En cambio, se informa sobre el flujo de trabajo cuando la cuenta de un paso está archivada, ya no puede ejecutar el paso o comparte su dirección con una cuenta más antigua, ya que aplicar el identificador seleccionaría otra cuenta.
  • Agentes que la exportación aún no puede transportar — se informa de un agente con más de un rol, o vinculado a un rol que la extracción no escribe, y se deja en su lugar.
  • Reglas de validación que la exportación aún no puede incluir — se informa de una regla sin expresión ni mensaje, como un borrador sin terminar de Configuración o una que lee un campo eliminado del espacio de trabajo, y se deja en su lugar.
  • El estado de ejecución del espacio de trabajo, los adjuntos de registros, los adjuntos de correo electrónico, las asignaciones de roles de miembros y claves de API, los webhooks, la navegación por usuario y los elementos de navegación fijados a un registro, todo excluido por diseño, incluso para la aplicación Custom del espacio de trabajo.
  • Propiedad de otra aplicación — se informa de ello, pero nunca se extrae.
El informe al final de una extracción enumera todo ello, agrupado por tipo y motivo. Todo lo que indique como no escrito sigue estando en su espacio de trabajo, así que vuelva a enviar un árbol extraído con twenty app apply --no-prune hasta que se cubran los tipos que faltan. La aplicación personalizada del espacio de trabajo ya se aplica de esta forma de manera predeterminada. Una aplicación con depuración (la predeterminada para otras aplicaciones, --prune para la aplicación personalizada) los eliminaría, y twenty app plan enumera exactamente cuáles. Estado local del espacio de trabajo. Una entidad desactivada en el espacio de trabajo se escribe como una definición activa, y las anulaciones que el espacio de trabajo realizó en una entidad, como una etiqueta renombrada, no se escriben. El informe enumera esas filas bajo “Escritas sin su estado local del espacio de trabajo”. Aplicar el árbol de nuevo al mismo espacio de trabajo deja ese estado intacto; otro espacio de trabajo recibe la entidad activa y sin las anulaciones. El archivo base. Pull registra lo que obtuvo en .twenty/cli/pull-base.json, que se ignora en git y es específico de cada copia de trabajo. Ese archivo es con lo que una extracción posterior compara para dejar intactos los archivos cuya entidad no cambió y para eliminar el archivo de una entidad que ya no está en el espacio de trabajo. Un checkout sin él simplemente escribe todo y no elimina nada.

Escalera de recuperación

Cuando los metadatos locales parezcan incorrectos, ve escalando en este orden y detente en cuanto te hayas desbloqueado. Cada paso es más disruptivo que el anterior.
  1. Volver a sincronizar. Ejecuta twenty app apply de nuevo. Las sincronizaciones son idempotentes: volver a ejecutar un manifiesto limpio es seguro y suele resolver un problema transitorio.
  2. Previsualizar el plan. Ejecuta twenty app plan para ver exactamente qué pretende cambiar la siguiente sincronización, sin aplicarlo.
  3. Lee el error identificado. Un conflicto suele señalar un identificador duplicado o reutilizado.
  4. Desinstalar y volver a instalar. twenty app uninstall, luego vuelve a sincronizar (twenty app dev). Esto reconstruye los metadatos de la aplicación desde cero manteniendo intacto el resto de tu espacio de trabajo.
  5. Restablecimiento completo (último recurso). Para un entorno local administrado por la CLI, ejecuta twenty local reset, después twenty local start y vuelve a conectarte antes de sincronizar de nuevo. Para una copia del código fuente, restablece y vuelve a inicializar su base de datos de desarrollo en su lugar.
Restablecer tu entorno local o la base de datos de desarrollo del repositorio elimina todos los datos de tu instancia local, cada espacio de trabajo, registro y aplicación. Úsalo solo cuando los pasos anteriores hayan fallado.
¿Te has encontrado con un error de metadatos? Por favor, abre una incidencia e incluye el mensaje de migración con error (con su tipo de metadatos y universalIdentifier), la salida de Metadata changes de la sincronización y los comandos que ejecutaste.

Evita sincronizaciones concurrentes en un mismo espacio de trabajo

La sincronización aplica migraciones de metadatos. Ejecutar varias operaciones de sincronización, implementación o instalación contra el mismo espacio de trabajo al mismo tiempo (por ejemplo, múltiples terminales o agentes de IA iterando en paralelo) puede entremezclar esas migraciones y dejar los metadatos en un estado parcialmente aplicado. El servidor serializa las sincronizaciones por espacio de trabajo para evitar esto, pero aun así deberías canalizar las operaciones de metadatos sensibles a través de un proceso único en lugar de lanzarlas de forma concurrente. Si orquestas el desarrollo con varios agentes, enruta sus llamadas de sincronización/implementación/instalación a través de una sola cola de modo que solo una se ejecute a la vez.

Distinguir los tipos de error

Cuando algo sale mal, el diff de metadatos y los errores con nombre te permiten situar el fallo:
  • Error de compilación del manifiesto: la CLI falla antes de sincronizar (MANIFEST_BUILD_FAILED, TYPECHECK_FAILED); corrige el código fuente de tu aplicación.
  • Error de propiedad del registro — se rechaza la sincronización porque el universalIdentifier de la aplicación pertenece a otro espacio de trabajo, o no pertenece a ningún espacio de trabajo; consulta Propiedad del registro.
  • Error de sincronización / migración: la compilación tiene éxito, pero aplicar el diff falla, nombrando la entidad y el universalIdentifier; corrige los metadatos en conflicto.
  • Error de tamaño de dependencias — la sincronización o la instalación fallan porque las dependencies de producción de la aplicación son demasiado grandes para instalarse como una capa de tiempo de ejecución (LOGIC_FUNCTION_DEPENDENCIES_SIZE_EXCEEDED); mueve a devDependencies los paquetes que tus funciones de lógica no importan en tiempo de ejecución (bibliotecas de UI, herramientas de desarrollo).
  • Migración diferida en curso — se rechaza la sincronización porque todavía se está ejecutando una migración en segundo plano del modelo de datos de una sincronización anterior (DEFERRED_WORKSPACE_MIGRATION_ACTIONS_IN_PROGRESS); espera a que finalice y luego vuelve a sincronizar.
  • Error de tiempo de ejecución del código de la aplicación: la sincronización se completa correctamente, pero tus funciones lógicas o componentes se comportan de forma incorrecta en tiempo de ejecución; revisa los registros de funciones.
  • Estado de instancia local: nada de lo anterior aplica y el espacio de trabajo sigue viéndose mal; desciende por la escalera de recuperación.