# CMS V2 - Implementacao Atual e Guia Tecnico

Atualizado em: 2026-02-26

## Objetivo
Este documento consolida o estado real do CMS V2 no FastApp apos Sprint 1 e Sprint 1.5, com foco em:

- implementacoes entregues
- mapa de arquivos
- contratos de dados
- fluxo de edicao e runtime
- integracao com objetos do app
- limites atuais e proximos passos

## Escopo Entregue (Sprint 1 + 1.5)

Status geral:

- [x] Secoes verticais com reorder via drag and drop
- [x] Fallback de reorder por botoes (up/down)
- [x] Renderer CMS generico por registro de componentes
- [x] Grid 12 colunas + rows (modelo compativel com Tailwind/Bootstrap)
- [x] Binding de dados para objetos via `/api/v1/data/:object`
- [x] Rich text editavel com toolbar + tokens de dados
- [x] Secoes `object_list` e `object_cards`
- [x] Persistencia de draft no `localStorage` com versao v2
- [x] Migracao automatica de chave legacy de `localStorage`
- [x] Validacao/sanitizacao server-side no `PATCH /api/app/:id`
- [x] Integracao do CMS no Schema Manager (`schema-v3`) e no runtime de paginas custom

Ainda nao entregue (ja mapeado no contrato):

- [x] renderer para `object_table`
- [x] renderer para `kpi_strip`
- [ ] drag and drop espacial de grid (hoje e reorder vertical)
- [ ] fluxo publish com versao/historico de pagina
- [ ] permissao/auditoria por usuario no nivel de secao

## Mapa de Arquivos (Implementacao CMS)

### Contratos e utilitarios

- `app/types/schema.ts`
  - Define `PageSchemaV2`, `CmsSection`, `CmsSectionLayout`, `CmsSectionBinding`.
  - `CmsSectionType` inclui: `rich_text`, `object_list`, `object_cards`, `object_table`, `kpi_strip`.
  - Layout com grid: `col_span`, `row_span`, `col_start`, `row_start`, `min_height`.

- `app/utils/cms-page.ts`
  - Fabrica e normaliza secoes (`createCmsSection`, `normalizeCmsSections`).
  - Migra pagina legacy html para secao `rich_text`.
  - Forca defaults de `layout_mode`, `theme_preset`, `sections` (`ensurePageSchemaV2`).
  - Templates rapidos de secao (`createCmsTemplateSection`) para `rich_text`, `object_list`, `object_cards`.

- `app/composables/useCmsBinding.ts`
  - Resolve binding de dados de secao.
  - Converte `filters`, `sort`, `limit`, `projection` para query string.
  - Interpola contexto em filtros (`{{route.params.*}}`, `{{route.query.*}}`, etc).
  - Faz fetch generico em `/api/v1/data/:object`.

### Core CMS components

- `app/components/core/cms/CoreCmsRenderer.vue`
  - Runtime principal de renderizacao.
  - Registry atual:
    - `rich_text` -> `CoreCmsSectionRichText`
    - `object_list` -> `CoreCmsSectionObjectList`
    - `object_cards` -> `CoreCmsSectionObjectCards`
  - Usa grid de 12 colunas com `gridColumn`/`gridRow`.
  - Fallback visual para tipo de secao nao suportado.

- `app/components/core/cms/CoreCmsSectionPalette.vue`
  - Catalogo de templates de secao.
  - Adiciona secao nova com defaults de binding e props.

- `app/components/core/cms/CoreCmsSectionStack.vue`
  - Lista vertical de secoes com drag and drop (`vuedraggable`).
  - Exibe metadados de cada secao (tipo, grid, objeto).
  - Fallback de reorder por botoes.

- `app/components/core/cms/CoreCmsSectionInspector.vue`
  - Editor da secao selecionada.
  - Edita:
    - base: label, type, enabled
    - grid: span/start/min height
    - binding: source, object, limit
    - props especificas por tipo (`rich_text`, `object_list`, `object_cards`)

- `app/components/core/cms/CoreCmsSectionRichText.vue`
  - Bloco editavel (contenteditable) com toolbar.
  - Suporte a tokens em modo leitura:
    - `{{record.campo}}`
    - `{{object.count}}`
    - `{{object.name}}`
    - `{{image:https://...}}`

- `app/components/core/cms/CoreCmsSectionObjectList.vue`
  - Lista de registros conectada ao objeto.
  - Usa `CoreDynamicList`.
  - Suporte a layout `list`/`grid` e `columns`.

- `app/components/core/cms/CoreCmsSectionObjectCards.vue`
  - Cards visuais conectados ao objeto.
  - Props: `image_field`, `title_field`, `description_field`, `cta_label`, `columns`.
  - Heuristica para inferir campos quando nao configurados.

### Integracao nas paginas

- `app/pages/fastapp/schema-v3.vue`
  - Editor de pagina no Architect com:
    - `CoreCmsSectionPalette`
    - `CoreCmsSectionStack`
    - `CoreCmsSectionInspector`
    - `CoreCmsRenderer` (preview)
  - `pageFields` inclui `layout_mode` e `theme_preset`.
  - Garante pagina em formato V2 via `ensurePageSchemaV2`.

- `app/pages/[app]/[module]/index.vue`
  - Runtime de pagina custom com edicao local.
  - Persistencia de draft em `localStorage`:
    - v2: `fastapp:cms:v2:draft:{appSlug}:{pageToken}`
    - legacy: `fastapp:cms:{appSlug}:{pageToken}`
  - Migracao automatica do legado para V2.

### Validacao de API

- `server/api/app/[id].patch.ts`
  - Sanitiza `pages`, `sections`, `layout`, `binding`.
  - Valida `layout_mode` permitido.
  - Valida tipo/shape de `filters`, `sort`, `projection`, `limit`.
  - Se payload CMS for invalido, retorna `400` antes da tentativa SQL fallback.

## Contrato de Dados (PageSchemaV2)

```ts
type CmsLayoutMode = 'flow_vertical' | 'split' | 'dashboard'

type CmsSectionType =
  | 'rich_text'
  | 'object_list'
  | 'object_cards'
  | 'object_table'
  | 'kpi_strip'

interface CmsSectionLayout {
  col_span?: number // 1..12
  row_span?: number // 1..12
  col_start?: number // 1..12
  row_start?: number // 1..12
  min_height?: string
  gap?: string | number
  width?: string
  align?: 'left' | 'center' | 'right' | 'stretch'
}

interface CmsSectionBinding {
  source_type?: 'none' | 'object' | 'static'
  object_name?: string
  filters?: Record<string, any>
  sort?: Record<string, 1 | -1>
  limit?: number
  projection?: string[]
}

interface CmsSection {
  id: string
  type: CmsSectionType
  label: string
  order: number
  enabled: boolean
  layout?: CmsSectionLayout
  style?: Record<string, any>
  binding?: CmsSectionBinding
  props?: Record<string, any>
  actions?: Record<string, any>
}

interface PageSchemaV2 {
  slug: string
  layout_mode?: CmsLayoutMode
  theme_preset?: string
  sections?: CmsSection[]
}
```

## Exemplo de Pagina CMS V2

```json
{
  "slug": "landing",
  "layout_mode": "flow_vertical",
  "theme_preset": "industrial_zen",
  "sections": [
    {
      "id": "sec_intro",
      "type": "rich_text",
      "label": "Hero",
      "order": 1,
      "enabled": true,
      "layout": { "col_span": 12, "row_span": 1, "min_height": "280px" },
      "binding": { "source_type": "object", "object_name": "lead", "limit": 1, "sort": { "id": -1 } },
      "props": {
        "html": "<h1>Leads ativos: {{object.count}}</h1><p>Ultimo lead: {{record.name}}</p><p>{{image:https://cdn.site/banner.jpg}}</p>"
      }
    },
    {
      "id": "sec_cards",
      "type": "object_cards",
      "label": "Leads em destaque",
      "order": 2,
      "enabled": true,
      "layout": { "col_span": 12, "row_span": 1 },
      "binding": { "source_type": "object", "object_name": "lead", "limit": 6, "sort": { "id": -1 } },
      "props": {
        "title": "Top leads",
        "columns": 3,
        "image_field": "image",
        "title_field": "name",
        "description_field": "description",
        "cta_label": "Abrir"
      }
    }
  ]
}
```

## Fluxo de Runtime e Persistencia

### Runtime em pagina custom

1. Normaliza pagina base para V2 (`ensurePageSchemaV2`).
2. Carrega draft do `localStorage` (chave v2).
3. Se v2 nao existir, tenta chave legacy.
4. Concatena base + draft para `cmsRuntimePage`.
5. Renderiza com `CoreCmsRenderer`.
6. Ao salvar draft:
   - grava payload com `version: 2`
   - remove chave legacy

### Payload salvo no localStorage

```json
{
  "version": 2,
  "updated_at": "2026-02-26T12:34:56.000Z",
  "page": {
    "layout_mode": "flow_vertical",
    "theme_preset": "industrial_zen",
    "sections": []
  }
}
```

## Binding com Objetos (Query Mapping)

Contrato de binding para `source_type: object`:

- `object_name` define endpoint base.
- `filters` vira query plana.
- `sort` vira `$sort[field]=1|-1`.
- `limit` vira `$limit`.
- `projection` vira `$select=campo1,campo2`.

Exemplo:

```ts
binding = {
  source_type: 'object',
  object_name: 'lead',
  filters: { status: 'open', owner_id: '{{route.params.id}}' },
  sort: { created_at: -1 },
  limit: 10,
  projection: ['id', 'name', 'status']
}
```

Request gerada:

`/api/v1/data/lead?status=open&owner_id=123&$sort[created_at]=-1&$limit=10&$select=id,name,status`

## Grid 12 Colunas + Rows (Sprint 1.5)

Implementacao atual:

- `CoreCmsRenderer` usa grid `grid-cols-12`.
- Cada secao aplica:
  - `gridColumn: span X / span X` ou `start / span X`
  - `gridRow: span Y / span Y` ou `start / span Y`
- Inspector controla:
  - `col_span`, `row_span`
  - `col_start`, `row_start`
  - `min_height`
- Presets rapidos no inspector: `12/1`, `6/1`, `4/1`, `8/2`.

Observacao:

- O posicionamento na grade ainda e configurado por formulario (nao por drag espacial).
- O reorder de secoes continua vertical.

## Pontos Fortes Atuais

- Abstracao generica: a pagina e schema-driven, sem branch por app.
- Reuso de objetos: secoes conectam em qualquer objeto via metadados.
- Composicao visual: palette + stack + inspector + preview no mesmo fluxo.
- Migrao suave: legado html e convertido para secao `rich_text`.
- Seguranca de contrato: API valida shape de pages/secoes antes de persistir.

## Gaps para ficar "CMS real" (mais faceis agora)

Prioridade P0/P1 de baixo custo tecnico:

1. Sanitizacao de HTML no `rich_text` antes de render (`v-html` hoje aceita html bruto).
2. Blocos mistos em rich text:
   - insercao visual de "chips de objeto" (campo dinamico)
   - seletor de imagem do app/asset object (alem de URL)
3. `object_table` renderer reaproveitando tabela dinamica.
4. `kpi_strip` renderer com agregacoes simples (`count`, `sum`, `avg`).
5. Toolbar de rich text moderna (evitar dependencia total de `document.execCommand`).

## Diferencial FastApp (Abstracao + IA)

Direcao recomendada para agentes IA no CMS:

1. "Pilot mode":
   - agente cria/reordena secoes por prompt
   - gera bindings com base em objetos e relacoes existentes
2. "Data-aware content":
   - agente sugere tokens (`{{record.*}}`, `{{object.count}}`) conforme schema
   - propoe card/list/table mais aderente ao tipo de objeto
3. "Layout copilot":
   - agente ajusta `col_span/row_span` para responsividade
   - aplica presets visuais por intencao (landing, dashboard, catalogo)
4. "Safe patch":
   - agente escreve patch em `sections[]` validado por contrato server-side

## Guia Rapido para Adicionar Novo Tipo de Secao

Exemplo: `object_table`

1. Garantir o tipo em `app/types/schema.ts` (ja existe).
2. Criar componente `app/components/core/cms/CoreCmsSectionObjectTable.vue`.
3. Registrar no `SECTION_REGISTRY` de `CoreCmsRenderer.vue`.
4. Adicionar template em `CoreCmsSectionPalette.vue`.
5. Expor props no `CoreCmsSectionInspector.vue`.
6. Definir template default em `createCmsTemplateSection` (`app/utils/cms-page.ts`).
7. Validar comportamento com binding via `useCmsBinding`.

## Checklist de Validacao

- Criar pagina nova no Architect e confirmar defaults `layout_mode/theme_preset/sections`.
- Adicionar secoes `rich_text`, `object_list`, `object_cards`.
- Reordenar por drag e por botoes.
- Alterar grid no inspector e validar preview.
- Conectar secao a objeto real e validar fetch.
- Salvar draft em pagina custom e recarregar browser.
- Testar migracao da chave legacy `fastapp:cms:*`.
- Enviar `PATCH /api/app/:id` com payload invalido e validar erro `400`.

## Conclusao

O CMS V2 ja saiu do modo "html editavel simples" e entrou em um modelo composavel, orientado a schema, com binding de objetos, grid de 12 colunas e persistencia local versionada. A base para evolucao com IA ja esta pronta, especialmente no eixo de geracao/edicao automatica de `sections[]`.
