Migrar un sitio existente a Crafty

Prompt de MCP: migrate-site. Ejecuta todo este runbook por ti y se detiene en cada punto de control para que lo confirmes. Argumentos: site_id (el sitio de destino), source (la URL del sitio antiguo, su sitemap.xml o una descripción de la exportación) y, opcionalmente, environment (por defecto production) y research (por defecto yes: también investiga la marca en la web y propone contenido que el sitio antiguo no tiene; usa no para una migración 1:1 estricta). Necesita un token con crafty:write.

En Claude Code, escribe / y elige mcp__<server>__migrate-site, donde <server> es el nombre que le diste al servidor de Crafty; otros clientes lo muestran en su menú de prompts. Si tu cliente no muestra los prompts de MCP, pide al agente que llame a get_guide migrate y que lo siga.

¿Rediseño en lugar de una migración 1:1? Prompt de MCP: redesign-site. Estudia el sitio actual del cliente, sus redes sociales y lo que el resto de la web dice de él, resume su marca, tono y contenido, y propone un sitio nuevo (mapa del sitio, secciones construidas con tus tipos de bloque, textos borrador y dirección visual) antes de crear nada. Una vez que apruebes la propuesta, lo construye como borradores y nunca publica. Argumentos: website (la URL del sitio actual) y, opcionalmente, social (URLs de perfiles o usuarios), goals y site_id (omítelo para hacer la propuesta antes de que el cliente tenga un sitio en Crafty). Necesita un token con crafty:write. Las redes sociales suelen bloquear la lectura automatizada, así que prepárate para pegar la biografía y algunas publicaciones o compartir capturas de pantalla.

Runbook para mover un sitio que ya existe (WordPress, Webflow, Wix, un sitio estático, otro CMS headless) a Crafty con un agente y el servidor MCP, sin romper sus URLs. Trabaja en este orden; cada fase tiene un punto de control donde una persona confirma antes de pasar a la siguiente.

Herramientas usadas: bulk_upsert_entries, import_media_from_urls, upsert_redirects (además de las habituales create_block_type, create_collection, create_page, publish_*). Ámbitos del token: crafty:read + crafty:write; añade crafty:publish solo para la fase final.

Reglas básicas

  • Todo se guarda como borrador. Nunca pases publish: true hasta que una persona haya revisado el contenido en el panel.
  • dry_run: true primero en cada lote de bulk_upsert_entries y upsert_redirects; corrige los elementos failed y luego ejecútalo de verdad.
  • Usa external_id (el ID de la entrada o página del CMS antiguo, o la URL antigua si no hay ID) en cada entrada. Volver a ejecutar una importación actualiza en lugar de duplicar.
  • Lotes: hasta 100 entradas, 50 URLs de medios y 500 redirecciones por llamada. Mantén un manifiesto local (JSON/CSV) de lo que envió cada lote y de lo que devolvió (entry_id, media_id), para poder reanudar una ejecución fallida.
  • Cuota de medios: las importaciones cuentan contra la cuota de medios del tenant. Importa solo lo que usan las páginas, omite miniaturas y copias redimensionadas (las variantes -300x200.jpg de WordPress) y pregunta antes de importar más de unos cientos de archivos.
  • Trabaja contra el entorno production del sitio de destino salvo que el usuario pida otro (las herramientas aceptan environment).

Fase 1 — Rastreo

Crea un inventario de cada URL del sitio antiguo:

  1. Fuentes, de mejor a peor: la exportación o API del CMS (REST de WordPress /wp-json/wp/v2/posts?per_page=100&page=N, /pages, /media; o la exportación WXR), sitemap.xml (y los índices de sitemap) y, después, un rastreo de los enlaces internos desde la página de inicio.
  2. Para cada URL registra: ruta antigua, título, tipo estimado, idioma, última modificación, contenido principal (HTML), imágenes y archivos que usa y el ID antiguo si lo conoces.
  3. Recopila también las URLs que ya redirigen (HTTP 301/302) y todo lo que esté en el plugin de redirecciones o en el .htaccess del sitio antiguo: también hay que trasladarlas.
  4. Investiga la marca más allá de su sitio: busca su nombre en la web (perfil de Google Business y reseñas, redes sociales, prensa, directorios y marketplaces, páginas de premios o socios). Enumera lo que le falta al sitio antiguo como adiciones propuestas: reseñas y testimonios, preguntas frecuentes tomadas de las consultas de clientes, horarios, ubicaciones, servicios o productos publicados en otros lugares, premios, menciones en prensa y enlaces a redes sociales. Indica la URL de origen de cada una y qué tan seguro estás de ella, marca la información que contradiga el sitio o parezca desactualizada, y nunca inventes datos. Mantén las adiciones separadas del inventario: son propuestas, no contenido migrado. Omite este paso en una migración 1:1 estricta (el prompt migrate-site usa research: "no").

Punto de control: muestra al usuario los recuentos por tipo, las URLs que no pudiste obtener y las adiciones propuestas. Solo se añaden las adiciones que el usuario elija, en la fase 5, como borradores nuevos.

Fase 2 — Clasificar

Agrupa las URLs en:

  • Páginas únicas (inicio, nosotros, contacto, páginas de aterrizaje) → páginas de Crafty construidas con tipos de bloque.
  • Contenido repetitivo (entradas, noticias, productos, miembros del equipo, casos de estudio, eventos) → una colección por tipo, una entrada por elemento.
  • Archivos y listados de taxonomía (/category/x, /tag/y, /page/2, páginas de autor, archivos por fecha) → normalmente no se migran como contenido: el nuevo frontend los genera; solo necesitan redirecciones.
  • Basura (resultados de búsqueda, feeds, páginas de adjuntos, ?replytocom= …) → descártala; redirige a la página útil más cercana si tenía tráfico.

Decide con el usuario el nuevo esquema de URLs (por ejemplo /blog/2019/05/hello-world → /blog/hello-world) y escribe ya en el inventario la asignación de antiguo a nuevo.

Punto de control: el usuario aprueba los tipos de contenido y el esquema de URLs.

Fase 3 — Modelar

Sigue "Modelar el contenido con tipos de bloque primero" en SKILL.md:

  1. Inspecciona los esquemas actuales: list_block_types, list_collections.
  2. Para las páginas únicas, create_block_type por cada sección recurrente (hero, texto + imagen, tarjetas → repeater, preguntas frecuentes → repeater, CTA). Reutiliza los tipos de bloque existentes cuando encajen.
  3. Para cada tipo repetitivo, create_collection con los campos que el contenido realmente tiene: title (string), excerpt (text), body (longText, HTML), cover (reference, model: "Media"), gallery (multiReference), published_on (datetime), tags (stringList), category (select) y campos de SEO (seo_title, seo_description). Sin campos json para contenido que las personas editoras mantienen.
  4. Marca primero como público el repositorio al que irán las imágenes si el sitio necesita URLs permanentes: manage_media_collection con is_public: true.

Punto de control: el usuario revisa los esquemas en el panel antes de cualquier importación.

Fase 4 — Medios

  1. Del inventario, lista las URLs distintas de imágenes y archivos que usa el contenido migrado (solo los originales a tamaño completo).
  2. import_media_from_urls en lotes de hasta 50: { site_id, urls, collection_name }. Cada resultado tiene status (imported, existing cuando la URL ya se había importado, duplicate dentro del lote, failed) y media_id / original_url.
  3. Guarda el mapa de URL antigua → media_id / original_url. Reintenta una vez los elementos failed e informa del resto (los hosts privados, las redirecciones, los archivos demasiado grandes o de tipos no compatibles se rechazan a propósito: descárgalos localmente y usa request_media_upload).

Fase 5 — Contenido (como borradores)

  1. Transforma cada elemento al esquema de la colección: limpia el HTML (elimina shortcodes del constructor, estilos en línea y píxeles de seguimiento), reescribe los enlaces internos a las rutas nuevas y reemplaza las URLs de imágenes en el HTML por los valores original_url de la fase 4. Pasa las referencias de medios (cover, gallery) como valores media_id.
  2. bulk_upsert_entries con { site_id, collection_slug, entries: [{ slug, external_id, data }], dry_run: true }. Corrige cada elemento failed (los errores indican el campo, por ejemplo data.published_on: …) y revisa los warnings (claves descartadas = un campo que falta en el esquema).
  3. Ejecuta el mismo lote sin dry_run. Las entradas se crean como borradores; las existentes (mismo external_id o slug) se actualizan con una revisión.
  4. Escribe las adiciones que el usuario eligió en la fase 1 como borradores nuevos (sin external_id del sitio antiguo) y enuméralas, con sus fuentes, en el informe de revisión.
  5. Páginas únicas: create_page con blocks en el idioma predeterminado; también empiezan como borradores. Los otros idiomas del sitio antiguo se añaden con configure_locales y upsert_translation, no como páginas adicionales.

Fase 6 — Redirecciones

  1. Del inventario, una redirección por cada URL antigua cuya ruta cambie: { source: "/old/path", destination: "/new/path", status_code: 301 }. Usa 301 para los cambios permanentes; 302/307 solo para los temporales.
  2. Agrupa los patrones en reglas dinámicas cuando sea posible (/category/* → /blog, /blog/:year/:month/:slug → /blog/:slug): el alojamiento de Crafty permite 2000 reglas estáticas y 100 dinámicas por despliegue, incluido el _redirects propio del sitio.
  3. source debe ser una ruta (sin dominio, sin ?query, sin #fragment); destination una ruta o una URL absoluta http(s). No redirijas una URL a sí misma ni crees cadenas (A → B → C: apunta A directamente a C).
  4. upsert_redirects con dry_run: true, corrige los failed y luego ejecútalo de verdad (500 por llamada). Verifica con list_redirects.
  5. Alojado en Crafty: se aplican en el siguiente despliegue. Frontend propio: lee GET /api/v1/redirects en el middleware (middleware.ts de Next.js, middleware de servidor de Nuxt) y responde con el status_code y la cabecera Location.

Fase 7 — Revisión humana

Entrega al usuario un informe breve: recuentos de creados, actualizados y fallidos por tipo; medios importados y omitidos; redirecciones creadas; y la lista de elementos que necesitan una persona (transformaciones fallidas, imágenes que faltan, páginas que no se asignaron a un tipo de bloque). Pídele que revise los borradores en el panel (y en el editor visual si está configurado). Aplica sus correcciones con update_entry / update_page, o vuelve a ejecutar el lote de importación (actualiza por external_id).

Fase 8 — Publicar y cambiar el tráfico

Solo después de la aprobación explícita del usuario:

  1. Publica: bulk_upsert_entries de nuevo con publish: true (token con crafty:publish) o publish_entry / publish_page por elemento; o schedule_publication para una hora de lanzamiento programada.
  2. Despliega el nuevo frontend, apunta el dominio a él y luego revisa una muestra de URLs antiguas (deben responder 301 a las nuevas) y el sitemap.
  3. Mantén las redirecciones: eliminarlas más adelante rompe enlaces y el posicionamiento en buscadores.

Aún no cubierto

El panel no tiene importador WXR de WordPress, importador de sitemap ni informe de enlaces rotos: el agente realiza esos pasos por sí mismo con las herramientas anteriores.