# Camada de Transformacao CMS -> API

**Versao:** 1  
**Status:** Normativo para implementacao  
**Ultima revisao:** 2026-06-19

## Objetivo

Definir a camada intermediaria entre os dados lidos do CMS e os payloads externos de `/api/v1`.

Essa camada existe para impedir que schema de banco, aliases temporarios de leitura ou naming interno vazem para consumidores publicos. O banco pode evoluir; o contrato externo deve permanecer estavel.

## Regras obrigatorias

- Toda leitura publica do CMS deve passar por transformers dedicados antes de sair em JSON.
- Controllers e repositories podem lidar com aliases internos; apenas transformers conhecem o payload externo final.
- O contrato externo usa nomes orientados ao dominio publico, nunca nomes genericos como `content`, `taxonomies` ou colunas do banco.
- Campos ausentes internamente podem ser omitidos no payload externo, mas campos existentes nao podem trocar de nome em `/api/v1`.
- Datas devem sair em ISO 8601 UTC (`YYYY-MM-DDTHH:MM:SSZ`).
- IDs numericos devem sair como integer.
- Strings vazias devem ser normalizadas para ausencia de valor quando o campo for opcional.

## Responsabilidades por transformer

### `ContentTransformer`

Responsavel por estabilizar posts e paginas para o contrato de conteudo.

Aliases internos aceitos:

| Dominio externo | Aliases internos aceitos |
|---|---|
| `id` | `id`, `content_id`, `post_id`, `page_id` |
| `title` | `title`, `headline` |
| `excerpt` | `excerpt`, `summary` |
| `content` | `content`, `body_html`, `content_html` |
| `published_at` | `published_at`, `published_on`, `published_date` |
| `updated_at` | `updated_at`, `updated_on`, `modified_at` |

Subobjetos delegados:

- `featured_image` -> `MediaTransformer`
- `categories` e `tags` -> `TaxonomyTransformer`
- `seo` -> normalizacao local de `title`, `description`, `canonical`
- `author` -> shape minimo estavel `{ "name": "..." }`

### `MediaTransformer`

Responsavel por estabilizar anexos e imagem destacada.

| Dominio externo | Aliases internos aceitos |
|---|---|
| `id` | `id`, `media_id`, `asset_id` |
| `url` | `url`, `src`, `path`, `relative_url` |
| `alt` | `alt`, `alt_text`, `description` |
| `mime_type` | `mime_type`, `mime` |

Campos opcionais adicionais permitidos em `v1`:

- `width`
- `height`

### `TaxonomyTransformer`

Responsavel por estabilizar categorias e tags.

| Dominio externo | Aliases internos aceitos |
|---|---|
| `id` | `id`, `term_id`, `taxonomy_id` |
| `name` | `name`, `label`, `title` |
| `post_count` | `post_count`, `count` |

`description` e `post_count` podem ser omitidos quando nao existirem ou nao fizerem sentido para o endpoint.

## Fluxo recomendado

```text
ReadConnection / repository
  -> payload canonico interno de leitura
  -> transformer por agregado
  -> envelope JSON padrao da v1
```

## Payload canonico interno recomendado

O shape abaixo nao e publico; ele e apenas a lingua franca entre a leitura do CMS e os transformers.

```php
[
  'content_type' => 'post|page',
  'id' => 42,
  'slug' => 'meu-primeiro-post',
  'title' => 'Meu Primeiro Post',
  'excerpt' => 'Resumo...',
  'content' => '<p>HTML...</p>',
  'featured_image' => [
    'id' => 10,
    'url' => '/uploads/2026/01/imagem.jpg',
    'alt' => 'Descricao da imagem',
  ],
  'categories' => [],
  'tags' => [],
  'seo' => [
    'title' => 'Meu Primeiro Post | Site',
    'description' => 'Meta description',
    'canonical' => 'https://example.com/meu-primeiro-post',
  ],
  'author' => [
    'name' => 'Admin',
  ],
  'published_at' => '2026-01-15 10:00:00',
  'updated_at' => '2026-01-16 08:30:00',
]
```

Repositories novos devem preferir esse shape canonico. Enquanto a leitura real do CMS ainda estiver heterogenea, os aliases aceitos pelos transformers permitem migracao incremental sem quebrar `/api/v1`.
