# Solicitações demonstrativas da ÂMBAR Solar

ÂMBAR Solar é uma marca fictícia. Use nome, telefone e cidade de teste. O formulário organiza contexto; não calcula preço, geração, economia ou potência, não inicia homologação e não envia mensagens.

## Uso local

Escolha tipo de imóvel, cidade/UF e faixa de consumo em kWh/mês. “Não sei” é uma opção válida. Área de instalação e turno são opcionais, sem compromisso de viabilidade ou horário. Informe nome e telefone fictícios e marque o aceite de demonstração. Revise antes de registrar.

O padrão salva somente neste navegador, em `ambarSolarDemo:solar-quotes:v1`. A confirmação exige gravação, releitura e validação. `/demo/` mostra registros válidos deste navegador: contagens globais de recebidas e canceladas e contagens de recebidas por tipo. Os filtros de tipo, estado, cidade e UF combinam com AND. Cancelar, excluir a cópia local e apagar dados exigem confirmação. Exclusão local não exclui dados remotos.

As abas compartilham alterações por eventos de armazenamento e coordenam mutações com Web Locks quando disponíveis. Sem Web Locks, a releitura e deduplicação por nonce continuam, mas não há garantia de atomicidade entre abas. Não use dados reais em dispositivo compartilhado; esta visão local não é autenticação comercial. Armazenamento corrompido é conservado até exclusão confirmada, desde que não haja operação pendente.

## Executar o projeto

Requer Node.js compatível com Astro 7 e Python 3 para o empacotamento ZIP.

```sh
npm ci
npm test
npm run check
npm run package
npm run build
npm run proof
npm run serve
```

O servidor estático lê `dist` e escolhe uma porta livre. O terminal mostra a URL. Para desenvolvimento, use `npm run dev`.

## Google Apps Script opcional

O projeto funciona sem GAS. A variável `PUBLIC_DEMO_GAS_ENDPOINT` permanece vazia por padrão. Um endpoint configurado não comprova integração ativa. Para ativar, o operador deve instalar `Code.gs` em seu próprio Apps Script, executar `setup`, revisar permissões e publicar um Web App `/exec` sob uma conta autorizada. Sheets permanece privado. Defina `SPREADSHEET_ID`, `CREATE_TOKEN`, `ADMIN_TOKEN` e `CANCEL_SECRET` nas Script Properties. `setup` cria valores aleatórios quando ausentes; consulte-os somente no painel privado do operador. Nunca inclua segredos em variáveis `PUBLIC_*`, arquivos exportados ou URLs.

O Sheet usa três abas com cabeçalhos exatos:

- `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.

As células usam texto; o payload JSON preserva Unicode e evita interpretar nomes como fórmulas. Não altere cabeçalhos nem edite o ledger manualmente. Os enums são derivados do catálogo controlado de `content/site.json` durante `npm run package`, não de dados recebidos do navegador. Defina retenção com o operador; tombstones e ledger não devem expirar enquanto retries puderem ocorrer. A retenção automática não é implementada.

Em `.env`, informe somente o endpoint autorizado. Reconstrua o frontend. O visitante escolhe o modo remoto, vê o destino, fornece um token somente em RAM e marca o aceite separado de envio. O POST usa JSON com `Content-Type: text/plain;charset=UTF-8`. O transporte deve ser legível no navegador; não há promessa de CORS nativo configurável em GAS. O único GET público é `?op=health`, sem dados pessoais. Listagem privada utiliza POST `list_records` com token administrativo em RAM; a visão remota é separada das métricas locais. Cancelamento usa o token de criação e capability privada. Remover o token apaga também capabilities da memória.

O contrato completo está em `integration.md`. Ele especifica `register_quote`, `solar_quote`, fingerprint SHA-256, envelopes, validação, locks, ledger e respostas. `rejected` usa `ok:false`; não confirma recebimento. O código limita corpo a 8192 bytes e 60 operações autenticadas por minuto por papel, sob ScriptLock. Isso é um limite demonstrativo, não infraestrutura comercial de proteção contra abuso.

## Recuperar uma tentativa

Antes da rede, o navegador preserva payload, nonce, fingerprint e destino em `ambarSolarDemo:solar-quotes:v1:pending`. Timeout, resposta opaca, IDs incompatíveis ou falha de cache não autorizam novo pedido, edição, exclusão, reset ou fallback. Recarregue, informe novamente o token e consulte o resultado ou retome a mesma tentativa. Não apague a pendência para contornar o bloqueio.

Uma rejeição definitiva só encerra a criação quando comprova tombstone e não aceitação para a mesma marca, nonce e fingerprint. O visitante pode então escolher uma nova gravação local, com outro nonce. Um cancelamento desconhecido mantém o mesmo operationId. Uma consulta que ainda mostra received não confirma cancelamento; retome a operação. O GAS recupera gravações parciais sob lock e nunca ressuscita pedidos cancelados ou excluídos por replay.

## Recursos e limites

Os downloads são exibidos somente quando habilitados no conteúdo e presentes no build. O ZIP inclui fonte e dependências declaradas, imagens públicas, fontes OFL, GAS e guias; não inclui credenciais, dados de teste armazenados, artefatos de QA ou imagens originais de geração. As quatro imagens são cenas conceituais próprias, sem obras ou clientes reais. Os arquivos não comprovam um `/exec` ativo, operação comercial, análise técnica ou publicação.
