# Feed RSS — Distribuição de Conteúdo V2

O Serviço de Feed RSS da V2 permite que módulos publiquem seu conteúdo em um feed RSS 2.0 consolidado, disponível em `/feed.xml`. O feed inclui suporte a namespaces modernos (`media:content`, `content:encoded`, `dc`, `atom`) para enriquecimento dos itens.

## 🏗️ Arquitetura

O FeedRSS segue o mesmo **Explicit Sender Pattern** adotado pelo Search Service:

1. **DTO** (`FeedItemDTO`): Dados do item são encapsulados em um objeto de transferência.
2. **Sender** (`FeedSender`): Adaptador que cada módulo usa para publicar/remover itens.
3. **Service** (`FeedRssService`): Lógica central — UPSERT na tabela `v2_feed_rss_items`, geração do XML, estatísticas e gerenciamento.
4. **Cache Table**: Os itens são armazenados na tabela `v2_feed_rss_items` para consulta rápida sem depender dos models originais.

## 📦 Estrutura do Serviço

```
V2/Services/FeedRSS/
├── Consumer/
│   └── FeedSender.php          # Adaptador para módulos
├── Controllers/
│   ├── FeedRssController.php   # GET /feed.xml (público)
│   └── FeedRssSupportController.php  # CMS restrito ao suporte
├── DTOs/
│   └── FeedItemDTO.php         # DTO do item do feed
├── Migrations/
│   └── 2026_07_20_000001_create_v2_feed_rss_items_table.php
├── Models/
│   └── FeedRssItem.php         # Eloquent Model (SoftDeletes, UUID)
├── Providers/
│   └── FeedRssServiceProvider.php  # Singleton do serviço
├── Routes/
│   ├── web.php                 # /feed.xml
│   └── cms.php                 # Painel de suporte
├── Services/
│   └── FeedRssService.php      # Lógica central
└── Views/
    ├── rss.blade.php           # Template XML RSS 2.0
    └── cms/
        └── index.blade.php     # Página de monitoramento
```

## 🛠️ Como Implementar em um Novo Módulo

### 1. Importar o FeedSender

```php
use V2\Services\FeedRSS\Consumer\FeedSender;
```

### 2. Adicionar no Evento `saved` do Model

No método `boot()` do Model, dentro do closure `static::saved`:

```php
static::saved(function ($model) {
    // Sincronização existente (ex: Search) ...

    try {
        if ($model->isActive() || $model->status === 'published') {
            FeedSender::forModule('meu-modulo')->pushFromArray([
                'entity_type'  => 'meu_tipo',
                'entity_id'    => $model->id,
                'title'        => $model->title,
                'link'         => route('v2.modulo.portal.show', ['slug' => $model->slug]),
                'description'  => $model->summary ?? '',
                'published_at' => $model->published_at ?: $model->created_at,
                'author'       => optional($model->author)->name,
                'categories'   => ['categoria1', 'categoria2'],
                'image_url'    => $model->getImageUrl(),
            ]);
        } else {
            FeedSender::forModule('meu-modulo')->remove('meu_tipo', $model->id);
        }
    } catch (\Exception $e) {
        \Log::error('[MeuModulo] Falha ao sincronizar feed RSS: ' . $e->getMessage());
    }
});
```

### 3. Adicionar no Evento `deleted` do Model

```php
static::deleted(function ($model) {
    // Limpeza existente (ex: Search) ...

    try {
        FeedSender::forModule('meu-modulo')->remove('meu_tipo', $model->id);
    } catch (\Exception $e) {
        \Log::error('[MeuModulo] Falha ao remover do feed RSS: ' . $e->getMessage());
    }
});
```

### 4. Parâmetros do `pushFromArray`

| Parâmetro | Tipo | Obrigatório | Descrição |
|-----------|------|-------------|-----------|
| `entity_type` | string | Sim | Identificador do tipo de entidade (ex: `news`, `evento`) |
| `entity_id` | string | Sim | UUID do registro de origem |
| `title` | string | Sim | Título do item |
| `link` | string | Sim | URL absoluta para o conteúdo |
| `description` | string | Sim | Resumo/description |
| `published_at` | Carbon | Sim | Data de publicação |
| `content` | string | Não | Conteúdo completo (inserido via `<content:encoded>`) |
| `author` | string | Não | Nome do autor |
| `categories` | array | Não | Tags para `<category>` |
| `image_url` | string | Não | URL da imagem de destaque |

> O campo `module` é preenchido automaticamente pelo `FeedSender::forModule('nome')`.

## 🔗 Rotas

| Método | URI | Descrição | Acesso |
|--------|-----|-----------|--------|
| GET | `/feed.xml` | Feed RSS 2.0 completo | Público |
| GET | `cms/v2/feed-rss` | Painel de monitoramento | Suporte (CmsAuthenticate) |
| POST | `cms/v2/feed-rss/{id}/toggle` | Habilitar/desabilitar item | Suporte |
| DELETE | `cms/v2/feed-rss/{id}` | Remover item do feed | Suporte |

## 📊 Painel de Suporte

A página `cms/v2/feed-rss` (acessível apenas para super-admin ou email de suporte) exibe:

- **Cards de estatísticas**: total de itens, habilitados, desabilitados, URL do feed
- **Itens por módulo**: gráfico de distribuição
- **Tabela paginada**: todos os itens com status, data de publicação e ações (habilitar/desabilitar, remover)

## ⚙️ Configuração

No arquivo `config/v2.php`:

```php
'feed_rss' => [
    'limit' => env('V2_FEED_RSS_LIMIT', 50),  // Limite de itens no feed
],
```

## 🧪 Testes

```bash
docker compose exec app vendor/bin/phpunit --filter FeedRSS
```

Os testes cobrem:
- Criação de DTO (dados mínimos, completos, fromArray, toArray)
- Serviço: addItem (UPSERT), removeItem, getFeedItems (limite e filtro enabled)
- Geração de XML (estrutura, conteúdo dos itens)
- Toggle e soft delete de itens
- Estatísticas

## 📍 Localização do Código

- **Código Base**: `V2/Services/FeedRSS/`
- **Tabela**: `v2_feed_rss_items`
- **Feed Público**: `GET /feed.xml`
- **Painel de Suporte**: `GET cms/v2/feed-rss`

---

*Documentado em Julho de 2026.*
