# Iteración: Feeds de productos — Google Shopping, Meta/Facebook, RSS
**Fecha:** 2026-05-17  
**Hora:** 23:48  
**Branch:** `feature/development-ai`  
**Commit:** `07dbda8`

---

## Resumen

Implementación de feeds públicos de catálogo de productos para integración con plataformas de publicidad y SEO.

## Archivos creados

| Archivo | Rol |
|---|---|
| `packages/Webkul/Shop/src/Http/Controllers/FeedController.php` | Controller con los 3 builders de feed |
| `app/Console/Commands/GenerateFeedCommand.php` | Comando artisan `feed:generate` |

## Archivos modificados

| Archivo | Cambio |
|---|---|
| `packages/Webkul/Shop/src/Routes/store-front-routes.php` | Rutas `GET /feed/{google,facebook,rss}` |
| `app/Console/Kernel.php` | Schedule `feed:generate` diario a las 02:00 |

---

## URLs públicas

| Feed | URL | Formato | Destino |
|---|---|---|---|
| Google Merchant Center | `/feed/google` | XML RSS 2.0 + namespace `g:` | Google Shopping / Performance Max |
| Facebook/Meta Catalog | `/feed/facebook` | TSV (CSV tabulado) | Meta Ads, Instagram Shopping |
| RSS general | `/feed/rss` | RSS 2.0 estándar | Suscriptores, agregadores |

## Estrategia de caché

- Cache Laravel con TTL **24 horas** por feed
- Headers HTTP: `Cache-Control: public, max-age=86400`
- Scheduler: `feed:generate` a las **02:00 diariamente**
- **Lógica inteligente**: compara `MAX(product_flat.updated_at)` vs timestamp de última generación — si no hubo cambios, no regenera
- Forzar regeneración: `php artisan feed:generate --force`

## Datos por producto (Google feed)

- `g:id` (SKU), `g:title`, `g:description` (5000 chars max, strip_tags)
- `g:link` → `https://migatitoregalon.pe/{url_key}`
- `g:condition` = `new`, `g:availability` via `haveSufficientQuantity(1)`
- `g:price` en PEN, `g:sale_price` si existe precio especial < precio base
- `g:image_link` + hasta 9 `g:additional_image_link`
- `g:brand` = nombre canal, `g:google_product_category` = `5605` (Gifts & Special Event Items)
- `g:shipping`: país `PE`, servicio "Envío a Lima"

## Filtros de query

```
status = 1
locale = 'es'
channel = 'default'
visible_individually = 1
```

RSS además filtra: `featured = 1` (máx 50 productos).  
Google y Facebook: hasta 2000 productos activos.

## Decisión técnica

Se usa `Product::with([...])` (Eloquent directo) en lugar de `ProductRepository->with()->whereHas()` porque el encadenamiento del repository Bagisto (prettus/l5-repository) produce conflicto entre `Collection::get()` y `Builder::get()` al combinar `with()` + `whereHas()` + `limit()` + `get()`.
