# Segmentacao para Multi-site e Multi-front-end

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

## 1. Objetivo

Definir como um unico CMS desacoplado suporta:

- um site institucional principal;
- multiplos hotsites;
- multiplos frontends consumindo a mesma API publica;
- segregacao coerente de conteudo, configuracao, SEO e exposicao publica.

Esta decisao complementa [docs/architecture.md](./architecture.md) e [docs/contracts/api-v1.md](./contracts/api-v1.md) sem reabrir a arquitetura-base.

## 2. Decisao principal

### 2.1 Eixo primario: `site`

O eixo primario de segmentacao e o `site`.

`site` representa uma unidade editorial e de configuracao publica com:

- identidade propria;
- dominio(s) ou hostname(s) proprios;
- configuracao de SEO propria;
- menus e assets institucionais proprios;
- conjunto proprio de conteudos publicados.

Todo conteudo publico deve ser resolvido dentro de um `site`.

### 2.2 Eixo secundario: `frontend_consumer`

`frontend_consumer` representa a aplicacao consumidora da API.

Ele existe para:

- mapear origem autorizada de browser via CORS;
- identificar o canal consumidor para observabilidade e rate limiting;
- apontar o `site` padrao consumido por aquele frontend;
- declarar capacidades opcionais do consumidor, como preview futuro, locale fixo ou recursos experimentais.

`frontend_consumer` **nao** cria uma nova particao editorial. A segregacao editorial continua pertencendo a `site`.

## 3. Regras de modelagem

### 3.1 Entidades novas ou evoluidas

O modelo alvo deve introduzir as seguintes entidades:

#### `sites`

- `id`
- `site_key` estavel e unico, usado em integracoes
- `slug`
- `name`
- `status` (`draft`, `active`, `archived`)
- `site_type` (`institutional`, `hotsite`, `campaign`, `other`)
- `primary_locale`
- `timezone`
- `default_domain`
- `created_at`
- `updated_at`

#### `site_domains`

- `id`
- `site_id`
- `host`
- `is_primary`
- `created_at`

Serve para resolver qual `site` atende cada dominio publico.

#### `frontend_consumers`

- `id`
- `consumer_key`
- `name`
- `site_id` padrao
- `allowed_origin`
- `status`
- `rate_limit_profile`
- `created_at`
- `updated_at`

#### `site_settings`

Substitui a nocao atual de configuracao publica singleton por configuracao segmentada por site.

- `site_id`
- `setting_key`
- `setting_value`
- `created_at`
- `updated_at`

Exemplos: `site_name`, `seo_default_title`, `seo_default_description`, `logo_media_id`, `favicon_media_id`, `social_links`.

#### `content_sites`

Pivot entre conteudo e sites.

- `content_id`
- `site_id`
- `publication_status`
- `published_at`
- `canonical_path`
- `sort_order`
- `created_at`
- `updated_at`

Essa pivot permite que um mesmo conteudo-base seja reutilizado em mais de um site sem duplicar o registro editorial principal.

### 3.2 Slugs e unicidade

- Slugs publicos deixam de ser globalmente unicos.
- A unicidade passa a ser por escopo de site e tipo de conteudo.
- Regra alvo: `UNIQUE(site_id, content_type, slug)`.

Consequencia: `/sobre` pode existir no site institucional e em um hotsite sem colisao, desde que pertençam a sites diferentes.

### 3.3 Menus, SEO e branding

Os seguintes artefatos passam a ser obrigatoriamente site-scoped:

- configuracao de SEO default;
- menus por location;
- logo, favicon e assets institucionais;
- links sociais;
- paginas institucionais compartilhadas apenas quando explicitamente vinculadas ao site.

## 4. Regras de resolucao da API

### 4.1 Contexto obrigatorio de site

Toda resposta publica da API deve ser resolvida dentro de um `site`.

A resolucao deve seguir esta ordem:

1. `X-Site-Key` em requisicoes server-to-server ou integracoes confiaveis.
2. `Origin` mapeado para um `frontend_consumer` autorizado.
3. `Host` ou dominio publico explicitamente mapeado em `site_domains`, quando a topologia de deploy permitir essa inferencia.

Se nenhum `site` puder ser resolvido de forma univoca, a API deve retornar `400 BAD_REQUEST` ou `403 FORBIDDEN`, conforme a causa:

- `400 BAD_REQUEST` para contexto ausente ou ambiguo;
- `403 FORBIDDEN` para origem nao autorizada.

### 4.2 Contexto de frontend

Quando a origem for browser, a API deve identificar tambem o `frontend_consumer` responsavel.

Esse contexto serve para:

- aplicar CORS por origem permitida;
- separar metricas por consumidor;
- permitir limite de taxa por consumidor alem do IP;
- habilitar futuras politicas por canal sem quebrar o modelo editorial.

### 4.3 Metadados de resposta

Sem quebrar o envelope atual, a API deve passar a incluir contexto de segmentacao em `meta`.

Exemplo alvo:

```json
{
  "data": {},
  "meta": {
    "version": "1",
    "site": {
      "key": "institucional",
      "domain": "www.example.com"
    },
    "frontend": {
      "key": "web-publica"
    }
  },
  "error": null
}
```

Adicionar novos campos em `meta` e compativel com `v1`.

## 5. Efeito sobre os endpoints atuais

### `GET /api/v1/site`

- deixa de representar uma configuracao singleton da instalacao;
- passa a retornar a configuracao do `site` resolvido na requisicao.

### `GET /api/v1/posts`
### `GET /api/v1/posts/{slug}`
### `GET /api/v1/pages/{slug}`
### `GET /api/v1/categories`
### `GET /api/v1/tags`
### `GET /api/v1/menus/{location}`

- passam a responder apenas dados publicados para o `site` resolvido;
- nao podem misturar conteudo de sites diferentes por padrao;
- devem considerar `content_sites` e configuracao do site para canonical, SEO e menus.

## 6. Politica de compartilhamento de conteudo

O modelo padrao deve ser:

- conteudo nasce uma vez no CMS;
- publicacao e visibilidade acontecem por site;
- override por site e permitido apenas para campos publicos de entrega, como canonical, ordem e SEO derivado, e nao como regra geral de duplicacao editorial.

Na pratica:

- um post global pode ser publicado em mais de um site;
- uma pagina institucional pode existir apenas em um site;
- um hotsite pode ter menu, home e configuracao propria sem afetar o institucional.

## 7. O que nao entra nesta decisao

Esta definicao nao introduz:

- multi-tenant por empresa ou banco separado;
- workflow editorial independente por site nesta etapa;
- tema/renderizacao dentro do CMS;
- agregacao multi-site em um unico endpoint publico por padrao.

Se um frontend precisar agregar multiplos sites no futuro, isso deve nascer como capacidade explicita de um consumidor ou como endpoint novo, e nao como comportamento implicito dos endpoints base.

## 8. Migracao esperada a partir do estado atual

O estado atual do projeto ainda opera com:

- configuracao singleton em `settings`;
- endpoint `GET /api/v1/site` sem escopo real;
- ausencia de entidades formais para `sites` e `frontend_consumers`.

Evolucao recomendada:

1. Introduzir `sites`, `site_domains`, `frontend_consumers` e `site_settings`.
2. Migrar `settings` globais atuais para um primeiro `site` institucional.
3. Introduzir a pivot `content_sites`.
4. Tornar a resolucao de site obrigatoria na API publica.
5. Atualizar o frontend para declarar explicitamente seu `consumer_key` e operar sempre dentro de um `site` resolvido.

## 9. Decisoes normativas finais

- A unidade editorial e de configuracao publica e `site`.
- `frontend_consumer` segmenta consumo, nao ownership de conteudo.
- Todo endpoint publico deve responder dentro de um `site` resolvido.
- Configuracoes publicas deixam de ser singleton e passam a ser site-scoped.
- Compartilhamento entre sites ocorre por pivot de publicacao, nao por duplicacao obrigatoria de conteudo.
