# Integração demonstrativa EIXO

A EIXO registra solicitações fictícias de escopo. O modo padrão é local, sem endpoint; não gera orçamento, visita, análise técnica ou contratação. Use apenas nome e telefone inventados. O contrato completo está em `content/integration.md` e os schemas e catálogos em `content/site.json`.

## Configuração

1. Crie um projeto Google Apps Script com runtime V8 e copie `gas/Code.gs` para o editor.
2. Execute `setup` com a conta responsável pelo destino. A função cria uma planilha e configura colunas como texto. Não divulgue propriedades privadas ou o retorno dessa função.
3. Confira Script Properties: `SPREADSHEET_ID`, `CREATE_TOKEN`, `ADMIN_TOKEN`, `CANCEL_SECRET` e `RATE_LIMIT_PER_MINUTE`. O padrão é 60 operações por minuto por papel, com limite configurável de 1 a 600. O operador define permissões, retenção, rotação e revogação. Nunca coloque segredos em URLs, logs, arquivos públicos ou variáveis `PUBLIC_*`.
4. Publique como aplicativo web sob a conta responsável, com acesso compatível com requisições da demonstração. Conhecer a URL não autoriza operações; elas exigem envelope POST autenticado.
5. Configure somente `PUBLIC_DEMO_GAS_ENDPOINT` com `https://script.google.com/macros/s/IDENTIFICADOR/exec` e refaça o build. A variável começa vazia.
6. Em `/demo/#acesso`, informe autorização de teste, escolha remoto, confira o destino e marque o opt-in separado antes de revisar. Tokens e capabilities ficam em memória e precisam ser recuperados após reload; a intenção pendente é preservada.

Não use `no-cors` ou proxy para ocultar resposta ilegível. Um health positivo não comprova criação, CORS, idempotência ou persistência.

## Catálogo e planilha

O catálogo GAS é gerado a partir do contrato com `node scripts/catalog.mjs`. Seus nove campos são `schemaVersion,brandId,requestId,kind,serviceId,stage,name,phone,demoAcknowledged`; `kind` é `engineering_request`. Frentes: `planejamento`, `projetos_coordenacao`, `acompanhamento`, `reformas_adequacoes`, `nao_sei`. Etapa: `null`, `ideia`, `organizando`, `em_andamento`. Não há cidade, relato, referência de projeto, arquivo ou orçamento numérico.

`setup` cria três abas; colunas incompatíveis interrompem a operação e preservam os dados.

| Aba | Colunas na ordem |
| --- | --- |
| pedidos | RecordId, BrandId, RequestId, Fingerprint, PayloadJson, Status, CreatedAt, CancelledAt, CancelHash, DeletedAt |
| tentativas | BrandId, RequestId, Fingerprint, State, RecordId, CreatedAt |
| operacoes | OperationId, Kind, RecordId, RequestId, State, CreatedAt |

Strings são gravadas em colunas de texto; `PayloadJson` conserva JSON canônico, nunca fórmula. O servidor revalida tipos, campos exatos, constantes, enums, UUIDs, trim/NFC, controles e limites de pontos de código.

## Operações

GET aceita somente `op=health` e retorna exatamente `{ok,schemaVersion,brandId}` sem PII. POST recebe `{op,authToken,payload}` exato em `text/plain;charset=UTF-8`, corpo até 8.192 bytes. Tokens/capabilities têm até 512 pontos de código e não aceitam controles ou substitutos isolados.

| Operação | Payload | Autoridade |
| --- | --- | --- |
| register_request | Nove campos normalizados | Usuário |
| request_status | brandId, requestId, fingerprint | Usuário ou admin |
| cancel_record | brandId, requestId, recordId, operationId, cancelCapability | Usuário ou admin com capability |
| list_records | brandId | Admin |
| delete_record | brandId, recordId, operationId | Admin |

Respostas privadas correlacionam versão, marca, operação e outcome. Criação/status vinculam requestId e SHA-256 do payload na ordem canônica; cancelamento/exclusão vinculam também recordId e operationId. HTTP 200, `ok:true` ou animação não comprovam persistência.

## Recuperação e idempotência

Script Lock e ledger durável antecedem efeitos; releitura verifica escritas. Mesmos código/dados devolvem o resultado anterior. Dados diferentes não alteram a tentativa original. Uma interrupção entre registro e ledger é reparada pelo vínculo de marca, código e fingerprint. Cancelamento não reativa por replay; exclusão mantém tombstone.

O navegador grava e relê a intenção antes da rede, sob guard síncrono e Web Lock. HTML, timeout, resposta opaca, not-found, divergência ou rejeição incompleta conservam pending e bloqueiam edição, nova tentativa, reset, exclusão, seleção e fallback. Reconciliar usa os mesmos dados, código e destino. Uma falha de cache após aceitação remota preserva a intenção para recuperar o mesmo registro.

Rejeição terminal exige `ok:false,outcome:rejected,definitive:true,accepted:false,tombstoned:true`, código autorizado, marca/requestId/fingerprint correspondentes e ausência de registro. Só então um novo teste local pode ser escolhido, com novo código. Um cancelamento que ainda responde Recebido usa `cancelStillReceived`, conserva operationId e estado anterior, até Cancelado verificável. Capability vinculada à tentativa/registro pode ser recuperada por status privado autorizado.

`/demo` mostra registros deste navegador; consulta administrativa remota é separada. Métricas globais e contagens por frente não mudam com filtros. Excluir cópia ou limpar local não exclui remoto. Cancelar, excluir e limpar exigem confirmação; pendência ilegível bloqueia todas as mutações. Sem Web Locks, use uma aba.

## Limites

O template não comprova endpoint ativo, persistência em Sheets, autenticação comercial, conformidade ampla ou prestação profissional. Teste efeito e retorno em destino autorizado com dados inventados antes de afirmar integração ativa. Nunca forneça dados reais ou credenciais comerciais à demonstração.
