---
name: shopify-datos-estructurados-producto
description: "Completa los campos de producto y variante que alimentan los datos estructurados (código de barras GTIN, SKU, proveedor, tipo de producto, peso) para que los agentes de IA citen artículos exactos y disponibles. Úsala cuando a tus fichas les falten esos datos."
---

## Propósito
Los agentes de compra con IA leen los datos estructurados de un producto (los campos que los temas de Shopify publican como JSON-LD de `schema.org/Product`) para confirmar precio, disponibilidad e identidad. Si faltan códigos de barras (GTIN), SKU, proveedor o tipo de producto, la ficha queda ambigua: el agente la salta o recomienda a un competidor con los datos completos. Esta skill encuentra los productos y variantes con esos vacíos y los completa: proveedor y tipo de producto a nivel de producto, código de barras y SKU a nivel de variante. Corrige tres problemas: datos estructurados de producto incompletos, fichas sin GTIN ni SKU y variantes sin datos estructurados.

## Requisitos
- Sesión autenticada de Shopify CLI: `shopify store auth --store <tu-tienda>.myshopify.com --scopes read_products,write_products`
- Las consultas se ejecutan con `shopify store execute`.
- Permisos (scopes) de API necesarios: `read_products`, `write_products`

## Parámetros
Todas las skills aceptan estos parámetros generales:

| Parámetro | Tipo   | Obligatorio | Predeterminado | Descripción |
|-----------|--------|-------------|----------------|-------------|
| store     | string | sí          | —              | Dominio de la tienda (p. ej., mitienda.myshopify.com) |
| format    | string | no          | human          | Formato de salida: `human` (predeterminado) o `json` |
| dry_run   | bool   | no          | false          | Muestra las mutaciones sin ejecutarlas |

Parámetros propios de esta skill:

| Parámetro | Tipo | Obligatorio | Predeterminado | Descripción |
|-----------|------|-------------|----------------|-------------|
| collection_id | string | no | — | Limita a una colección (GID); si no, todo el catálogo |
| tag | string | no | — | Limita a una etiqueta de producto |
| set_vendor | string | no | — | Proveedor que se asigna donde falte (si no se indica, solo se reporta) |
| set_product_type | string | no | — | Tipo de producto que se asigna donde falte |
| barcodes_csv | string | no | — | Ruta a un CSV con `sku,barcode` para asignar los GTIN a las variantes que coincidan |
| fields | string | no | all | Lista separada por comas de los campos a completar: `vendor,product_type,barcode,sku` |

## Seguridad

> ⚠️ El paso 3 (`productUpdate`) y el paso 4 (`productVariantsBulkUpdate`) modifican datos reales de productos y variantes. Los códigos de barras y los SKU se cruzan con tu `barcodes_csv`; un cruce equivocado le da a un producto una identidad falsa ante todos los agentes. Ejecuta siempre primero con `dry_run: true` y revisa el CSV de cambios. Esta skill nunca sobrescribe un campo que ya tiene valor: solo llena los vacíos.

## Pasos

1. **OPERACIÓN:** `products` — consulta
   **Entradas:** `first: 250`, opcionalmente `query: "tag:'<tag>'"` o un filtro por colección; campos `vendor`, `productType`, `variants{ id sku barcode }`; pagina hasta `hasNextPage: false`.
   **Resultado esperado:** Productos y variantes a los que les faltan los campos objetivo.

2. **CÁLCULO (sin API):** arma el conjunto de cambios: solo campos vacíos, cruzados con `barcodes_csv` por SKU para los códigos de barras. Muestra el CSV de vista previa.

3. **OPERACIÓN:** `productUpdate` — mutación
   **Entradas:** por producto, `{ id, vendor?, productType? }` (solo donde esté vacío y se haya indicado un valor).
   **Resultado esperado:** Producto actualizado; recoge los `userErrors`.

4. **OPERACIÓN:** `productVariantsBulkUpdate` — mutación
   **Entradas:** por producto, `productId` + `variants: [{ id, barcode?, inventoryItem: { sku? } }]` para los campos de variante vacíos.
   **Resultado esperado:** Variantes actualizadas; recoge los `userErrors` de todos los lotes.

## Operaciones GraphQL

```graphql
# products:query — validada con api_version 2025-01
query BackfillProducts($first: Int!, $after: String, $query: String) {
  products(first: $first, after: $after, query: $query) {
    edges {
      node {
        id
        title
        vendor
        productType
        variants(first: 100) {
          edges { node { id sku barcode } }
        }
      }
    }
    pageInfo { hasNextPage endCursor }
  }
}
```

```graphql
# productUpdate:mutation — validada con api_version 2025-01
mutation BackfillProductFields($input: ProductInput!) {
  productUpdate(input: $input) {
    product { id vendor productType }
    userErrors { field message }
  }
}
```

```graphql
# productVariantsBulkUpdate:mutation — validada con api_version 2025-01
mutation BackfillVariantFields($productId: ID!, $variants: [ProductVariantsBulkInput!]!) {
  productVariantsBulkUpdate(productId: $productId, variants: $variants) {
    productVariants { id sku barcode }
    userErrors { field message }
  }
}
```

## Seguimiento de la sesión

**Claude DEBE mostrar lo siguiente en cada etapa. Es obligatorio.**

**Al iniciar**, muestra:
```
╔══════════════════════════════════════════════╗
║  SKILL: <nombre de la skill>                 ║
║  Tienda: <dominio de la tienda>              ║
║  Inicio: <AAAA-MM-DD HH:MM UTC>              ║
╚══════════════════════════════════════════════╝
```

**Después de cada paso**, muestra:
```
[N/TOTAL] <CONSULTA|MUTACIÓN>  <OperationName>
          → Parámetros: <resumen breve de las entradas clave>
          → Resultado: <cantidad o desenlace>
```

Si `dry_run: true`, antepón `[SIMULACIÓN]` a cada paso de mutación y no lo ejecutes.

**Al terminar**, muestra:

Para `format: human` (predeterminado):
```
══════════════════════════════════════════════
RESUMEN DEL RESULTADO
  <Métrica>:        <valor>
  Errores:          0
  Archivo:          <nombre del archivo o "ninguno">
══════════════════════════════════════════════
```

Para `format: json`, muestra:
```json
{
  "skill": "<slug-de-la-skill>",
  "store": "<dominio>",
  "started_at": "<ISO8601>",
  "completed_at": "<ISO8601>",
  "dry_run": false,
  "steps": [
    {
      "step": 1,
      "operation": "<OperationName>",
      "type": "query",
      "params_summary": "<texto>",
      "result_summary": "<texto>",
      "skipped": false
    }
  ],
  "outcome": {
    "metric_key": 0,
    "errors": 0,
    "output_file": null
  }
}
```

## Formato de salida
`human`: cantidad de productos y variantes actualizados por campo, más un CSV con cada cambio (`product, variant, field, old, new`). `json`: `{ products_updated, variants_updated, by_field{...}, errors, output_file }`.

## Manejo de errores
| Error | Causa | Solución |
|-------|-------|----------|
| `THROTTLED` | Límite de solicitudes de la API | Espera 2 s y reintenta hasta 3 veces |
| `userErrors` con contenido | Formato de código de barras o SKU inválido, o duplicado | Registra el mensaje, omite esa variante y continúa |
| SKU que no está en el CSV | No se indicó un cruce para esa variante | Deja el código de barras vacío y repórtalo como pendiente |

## Buenas prácticas
- Ejecuta primero `shopify-auditoria-agentes-ia` para medir el tamaño del problema y luego esta skill con `dry_run: true` para revisar el conjunto exacto de cambios.
- Los códigos de barras son GTIN/UPC/EAN: pídeselos a tu proveedor, nunca los inventes. Un GTIN equivocado es peor que uno vacío.
- Esta skill solo llena vacíos; para corregir valores que existen pero están mal, haz ediciones puntuales al estilo de `shopify-ajuste-masivo-precios`.
- Combínala con `shopify-metacampos-para-ia`: los códigos de barras le dan identidad al producto en los datos estructurados y los metacampos permiten que los agentes filtren; por lo general necesitas ambos.
