Manual do Programador de ConectoresGuia comunitário para construir, validar e distribuir integrações
Use o modelo, adapte os campos e valide
Guia comunitário oficial

Construa conectores como peças bem encaixadas.

Este manual foi feito para programadores da comunidade. A ideia é simples: você copia o modelo, troca os nomes e contratos, implementa o handler, valida localmente e envia um pacote limpo, sem segredos e sem depender de detalhes internos da instalação.

DeclarativoManifesto, formato e catálogo dizem ao sistema o que existe.
ExecutávelO handler recebe uma mensagem JSON e faz o trabalho real.
SeguroSegredos ficam fora do pacote; respostas usam o canal oficial.
Rosa vivo = preencher/adaptarNomes do conector, campos do payload, ações, exemplos, URLs, credenciais de exemplo e mensagens de negócio.
Verde vivo = automático/fixo do kitValores preservados pelo ambiente, correlação recebida, padrões do kit e campos resolvidos pelo canal oficial.
manual-conector.html / visão-geral

O que é um conector

Um conector é uma ponte entre o SISC e um serviço externo: pagamento, CRM, agenda, estoque, OCR, mensageria, planilhas, ERP etc.

Em uma frase: o conector recebe um comando padronizado, valida os dados, chama o serviço externo e devolve um resultado padronizado.

Mapa mental

No pacote real, pense assim:

entrada JSON ──► handler executável ──► serviço externo
      ▲                                      │
      └──────── resultado pelo canal oficial ◄┘
Manifesto

Identifica o conector e lista seus arquivos.

Formato

Define campos de entrada e saída.

Handler

Executa a integração de verdade.

Catálogo

Declara as mensagens públicas aceitas.

manual-conector.html / passo-a-passo

Passo a passo recomendado

Siga esta ordem para evitar retrabalho.

Roteiro de construção

No trabalho real, execute mentalmente esta sequência:

1. Copie o conector-modelo
2. Renomeie para conector-<nome-do-servico>
3. Atualize manifesto, formato e catálogo
4. Implemente o handler
5. Crie uma mensagem de teste segura
6. Rode o validador local
7. Corrija avisos/erros
8. Empacote e envie pelo canal comunitário
1
Comece pequeno
Implemente uma operação simples, teste, depois adicione outras.
2
Valide sempre
Não espere o final para descobrir que o pacote está fora do padrão.
3
Documente como se outra pessoa fosse usar amanhã
Porque provavelmente será exatamente isso que vai acontecer.
manual-conector.html / legenda-de-valores

Legenda: o que você preenche e o que não mexe

Exemplo visual

Nos blocos de código deste manual:

{
  "nome": "conector-<seu-servico>",
  "handler": "./conectores/conector-<seu-servico>/handlers/<executavel>",
  "processoId": "preservado-da-mensagem-recebida",
  "respostaA": "mensagem-original-recebida"
}
CorSignificado
RosaVocê deve trocar pelo nome, operação, campo, caminho ou exemplo do seu conector.
VerdeValor que vem do ambiente, da mensagem recebida, do kit ou do canal oficial. Não invente do zero.
conectores/conector-<nome>/conector-<nome>.json

Manifesto do conector

É a identidade do conector. Ele diz quem o conector é, onde está o handler, qual formato usa e quais arquivos formam o pacote.

Modelo de manifesto

No arquivo real, este tópico aparece assim:

{
  "nome": "conector-<seu-servico>",
  "titulo": "Conector <Seu Serviço>",
  "descricao": "Explique em uma frase qual serviço externo este conector integra.",
  "versao": "1.0.0",
  "ativo": true,
  "tipo": "conector",
  "controlador": {
    "executavel": "valor-fixo-fornecido-pelo-kit",
    "metodoLeitura": "ler-mensagem",
    "metodoEnvio": "canal-oficial-de-publicacao",
    "handlerLerMensagem": "./conectores/conector-<seu-servico>/handlers/<executavel>"
  },
  "formatoConector": "conectores/conector-<seu-servico>/formatos/formato-conector-<seu-servico>.json",
  "testeSandbox": {
    "permitido": true,
    "semEfeitoReal": true,
    "mensagem": "testes/mensagem-exemplo.json",
    "descricao": "Explique por que esta mensagem de teste não envia dados reais nem altera produção."
  },
  "dependencias": {
    "fonteSeguraImportacao": true,
    "arquivos": [
      {"papel": "manifesto", "origem": "conectores/conector-<seu-servico>/conector-<seu-servico>.json", "destino": "conectores/conector-<seu-servico>/conector-<seu-servico>.json", "obrigatorio": true},
      {"papel": "formato", "origem": "conectores/conector-<seu-servico>/formatos/formato-conector-<seu-servico>.json", "destino": "conectores/conector-<seu-servico>/formatos/formato-conector-<seu-servico>.json", "obrigatorio": true},
      {"papel": "handler", "origem": "conectores/conector-<seu-servico>/handlers/<executavel>", "destino": "conectores/conector-<seu-servico>/handlers/<executavel>", "obrigatorio": true}
    ]
  }
}
CampoComo preencher
nomeUse conector- + nome curto em minúsculas e hífens.
tituloNome humano para aparecer em documentação.
controladorMantenha os valores fixos que vêm no modelo e altere apenas o caminho do handler.
testeSandboxDeclare somente quando a mensagem de teste puder rodar sem efeito real; isso habilita o selo de sandbox no servidor.
dependencias.arquivosListe todo arquivo que precisa viajar no pacote.
formatos/formato-conector-<nome>.json

Formato do payload

O formato é o contrato entre quem chama e quem executa. Sem ele, cada pessoa imagina um payload diferente.

Modelo de formato

No arquivo real, este tópico aparece assim:

{
  "tipo": "formato-conector",
  "nome": "formato-conector-<seu-servico>",
  "versao": "1.0.0",
  "conector": "conector-<seu-servico>",
  "descricao": "Contrato de entrada e saída do conector.",
  "entrada": {
    "modelos": {
      "comando-principal": {
        "campos": {
          "acao": {"tipo": "string", "obrigatorio": true, "valoresAceitos": ["executar"]},
          "identificador": {"tipo": "string", "obrigatorio": true},
          "opcoes": {"tipo": "object", "obrigatorio": false}
        },
        "regras": ["acao deve ser executar", "identificador deve existir"],
        "exemplo": {"acao": "executar", "identificador": "ABC-123"}
      }
    }
  },
  "saida": {
    "modelos": {
      "resultado": {
        "campos": {
          "sucesso": {"tipo": "bool", "obrigatorio": true},
          "dados": {"tipo": "object", "obrigatorio": false},
          "erro": {"tipo": "object", "obrigatorio": false}
        }
      }
    }
  }
}
Dica: descreva o payload como se o consumidor nunca tivesse visto seu serviço externo. Campo sem descrição vira dúvida na integração.
handlers/<executavel>

Handler

O handler é o programa executável. Ele recebe o caminho de um arquivo JSON de mensagem, valida tudo e executa a integração.

Esqueleto mínimo em pseudocódigo

No arquivo real, a lógica deve seguir esta forma:

iniciar programa
se quantidade_de_argumentos != 1:
  encerrar_com_erro("uso: handler <arquivo-mensagem>")

mensagem = ler_json(argumento_1)
protocolo = mensagem["_protocolo"]
dados = mensagem["payload"]["dados"]

validar campos obrigatórios
carregar configuração segura, se necessário
chamar serviço externo
montar resultado
publicar ou imprimir resposta conforme contrato
encerrar_com_sucesso()

Exemplo mínimo em Python

No arquivo real, poderia ser assim:

#!/usr/bin/env python3
import json, sys

if len(sys.argv) != 2:
    print("uso: handler <arquivo-mensagem>", file=sys.stderr)
    sys.exit(64)

with open(sys.argv[1], "r", encoding="utf-8") as f:
    msg = json.load(f)

dados = msg.get("payload", {}).get("dados", {})
if not isinstance(dados, dict):
    print("payload.dados ausente ou inválido", file=sys.stderr)
    sys.exit(65)

print(json.dumps({"sucesso": True, "dadosRecebidos": dados}, ensure_ascii=False))
sys.exit(0)
manual-do-conector.html

Manual do seu conector

Cada conector deve ter seu próprio manual para quem vai consumi-lo depois de instalado. Escreva como programador do conector: o leitor precisa conhecer somente o conector, o destino SISC, o idmensagem no catalogo e o contrato de payload.dados.

Não documente bastidor do servidor: o manual do conector não deve citar scripts operacionais, comandos internos de aprovação, caminhos administrativos ou detalhes de instalação do servidor. Essas informações pertencem ao operador SISC, não ao consumidor do conector.

Padrão mínimo de qualidade

No HTML real, inclua seções equivalentes a estas:

<h1>Manual de uso do conector-<seu-servico></h1>
<h2>Identificação</h2>              <!-- conector, destino SISC, catalogo, idmensagem -->
<h2>Objetivo</h2>                   <!-- o que a integração entrega ao consumidor -->
<h2>Operações disponíveis</h2>      <!-- tabela: operação, idmensagem, campos, descrição -->
<h2>Payload de entrada</h2>         <!-- tabela: campo, tipo, obrigatoriedade, descrição -->
<h2>Exemplo de payload</h2>
<h2>Exemplo de mensagem SISC</h2>
<h2>Saída esperada</h2>
<h2>Programa de exemplo</h2>        <!-- caminho, o que demonstra e saída do --self-test -->
<h2>Credenciais necessárias</h2>    <!-- sem segredo real; diga o que o ambiente precisa -->
<h2>Erros comuns</h2>               <!-- tabela: erro, causa provável, ação -->
<h2>Limites</h2>                    <!-- timeout, precisão, rate limit, compatibilidade -->
<h2>Segurança de uso</h2>           <!-- cuidado com dados sensíveis e idempotencia -->
<h2>Boas práticas para consumidores</h2>

Critérios que o validador cobra

  • HTML completo com <html>, <head>, <body> e CSS próprio de leitura.
  • Conteúdo substancial, no padrão do manual-conector-email.html: não basta uma página curta.
  • Ao menos duas tabelas: uma para operações/campos e outra para erros, limites ou contrato.
  • Ao menos três blocos de exemplo em <pre><code>.
  • Identificação explícita de conector-<nome>, conector__conector-<nome>, catalogo e idmensagem.
  • Explicação de payload.dados, saída esperada, credenciais, erros comuns, limites, segurança de uso e idempotencia.
  • Programa de exemplo em conectores/conector-<nome>/exemplos/exemplo-uso.php, documentado no manual, demonstrando uma chamada realista do recurso do conector.
  • Nenhum token, senha, chave real, caminho administrativo ou instrução que dependa de detalhes internos do servidor.

Programa de exemplo obrigatório

Além do manual, entregue um programa PHP em conectores/conector-<nome>/exemplos/exemplo-uso.php. Ele deve montar a mensagem ou o payload com o idmensagem do catalogo e os campos reais de payload.dados.

php conectores/conector-<nome>/exemplos/exemplo-uso.php
php conectores/conector-<nome>/exemplos/exemplo-uso.php --self-test

O modo --self-test deve imprimir JSON válido com sucesso:true, conector, idmensagem, payload.dados e saidaEsperada. O validador executa esse modo e confere se o exemplo produz o que declarou produzir.

Como o programador sabe se está bom: copie o nível de detalhamento do conectores/conector-modelo/manual-conector-modelo.html, adapte para seu serviço e rode ./validar-conector. O validador reprova manual raso, genérico, sem exemplo validável ou com bastidor interno do servidor.
testes/mensagem-exemplo.json

Mensagem de teste

A mensagem de teste prova que o handler consegue ler o envelope e encontrar os dados.

Modelo seguro de teste

No arquivo real, este tópico aparece assim:

{
  "_sistema": {"transporte": "pp --api"},
  "_protocolo": {
    "nome": "siscore-protocolo-objetos",
    "versao": 1,
    "processoId": "processo-teste-local-0001",
    "mensagemId": "teste-conector-<seu-servico>-0001",
    "origem": "sistema__operador",
    "destino": "conector__conector-<seu-servico>",
    "tipo": "comando",
    "prioridade": "normal",
    "criadoEm": "2026-08-24T00:00:00Z"
  },
  "payload": {
    "idmensagem": "conector-<seu-servico>.executar",
    "dados": {
      "acao": "executar",
      "identificador": "ABC-123"
    }
  }
}
Atenção: use dados falsos ou ambiente sandbox. Teste local não deve disparar cobrança real, mensagem real ou alteração irreversível.
segredos.sample.json

Segredos e configuração

O pacote comunitário pode conter somente exemplo de configuração. Segredo real nunca viaja no pacote.

Arquivo permitido no pacote

No arquivo real de exemplo, use placeholders:

{
  "ativo": false,
  "descricao": "Exemplo de configuração. Copiar e preencher somente no ambiente real.",
  "servico": {
    "endpoint": "https://api.exemplo.invalid",
    "timeoutSegundos": 30,
    "token": "preencher-no-ambiente-real"
  }
}

Regras de ouro

  • Nunca envie token, senha, app password, certificado privado ou refresh token real.
  • O handler deve falhar com mensagem clara se a configuração real estiver ausente.
  • Não escreva segredos em logs.
  • Prefira começar com ativo:false até o operador configurar o ambiente.
execução / contrato-do-handler

Contrato obrigatório do handler

Checklist executável

No pacote real, seu handler deve cumprir:

[x] estar dentro de conectores/<nome>/handlers/
[x] usar caminho relativo seguro, sem / inicial, .., ., // ou barra invertida
[x] ser executável diretamente
[x] se for script, ter shebang na primeira linha
[x] receber exatamente 1 argumento: o caminho do JSON
[x] ler _protocolo e payload.dados do arquivo recebido
[x] validar campos antes de chamar serviço externo
[x] sair com código 0 em sucesso
[x] sair com código diferente de 0 em erro
[x] nunca manipular áreas internas do sistema diretamente
[x] publicar respostas apenas pelo canal oficial do ambiente
Não faça: não dependa de caminho absoluto da sua máquina, não use ../, não execute shell com entrada do usuário e não use arquivos internos da instalação como API. O runtime novo só executa handlers em conectores/<nome>/handlers/ e o sandbox só expõe o segredo do próprio conector.
execução / linguagens-suportadas

Handler em qualquer linguagem

O sistema não exige PHP. Ele exige um executável que cumpra o contrato.

Exemplos de execução

No desenvolvimento real:

# script com shebang
chmod +x conectores/conector-<seu-servico>/handlers/<handler.py>
./conectores/conector-<seu-servico>/handlers/<handler.py> testes/mensagem-exemplo.json

# binário compilado
./conectores/conector-<seu-servico>/handlers/<binario> testes/mensagem-exemplo.json
LinguagemCuidados
Python/Node/PHP/BashUse shebang e documente dependências.
C/Go/RustEnvie binário compatível ou instruções claras de compilação.
Qualquer linguagemValide JSON, trate timeout e não exponha segredos.
frontend opcional

Front-end é opcional

Um conector pode ser 100% backend. Só crie tela se houver necessidade real de usuário humano preencher formulário ou acionar botão.

Quando houver formulário

No catálogo, descreva a entrada de tela sem expor segredo:

"front-api": [
  {
    "ativo": false,
    "acao": "conector-<seu-servico>.executar.form",
    "metodo": "POST",
    "csrf": true,
    "autenticacao": "sessao-ou-token",
    "entrada": {
      "identificador": {"tipo": "string", "obrigatorio": true, "max": 120}
    },
    "dadosSisc": {
      "acao": "executar",
      "identificador": "$entrada.identificador"
    },
    "resposta": {"tipo": "json", "atualizar": "conector-<seu-servico>"}
  }
]
Regra do objeto visual: o elemento atualizado pelo AJAX deve ter exatamente o nome do conector. Exemplo: conector conector-email atualiza somente id="conector-email" ou name="conector-email".
Importante: navegador nunca deve chamar handler nem acessar configuração sensível. A tela chama somente o canal seguro disponibilizado pelo ambiente.
qualidade / segurança

Segurança

Lista de proibições práticas

Antes de enviar, confirme que NÃO existe:

[ ] senha real no pacote
[ ] token real no pacote
[ ] chave privada no pacote
[ ] link simbólico no pacote
[ ] caminho absoluto da sua máquina
[ ] caminho com .., ., // ou barra invertida
[ ] dependência instalável fora de conectores/<nome>/ ou web-api/
[ ] escrita direta em área interna do sistema
[ ] comando shell com entrada não sanitizada
[ ] log imprimindo Authorization, senha ou token
[ ] operação irreversível sem idempotência

Segurança boa é a que sobrevive ao cansaço: se alguém rodar seu conector às 3h da manhã, ele deve falhar de forma segura e compreensível.

validar-conector

Validação local

O validador existe para proteger você e quem vai instalar seu conector.

Comando de validação

No terminal, rode:

chmod +x validar-conector
chmod +x conectores/conector-<seu-servico>/handlers/<executavel>
./validar-conector
StatusSignificado
OKAlgo foi encontrado e está correto.
AvisoNão bloqueia sempre, mas merece revisão.
ErroCorrija antes de empacotar.
validador / informações

Informações sobre o validador

O validador é o “inspetor de qualidade” do pacote. Ele não julga se sua regra de negócio é brilhante; ele confere se o conector está organizado, seguro e instalável pela comunidade.

Ideia principal: se o validador aprovar, o pacote tem estrutura mínima, não carrega segredos óbvios e o handler está pronto para ser executado no padrão esperado. A execução real fica para o sandbox do servidor, por meio dos selos operacionais.

O que o validador confere

No funcionamento real, pense nesta lista de verificações:

1. existe exatamente um conector no pacote
2. o nome segue o padrão conector-<seu-servico>
3. o manifesto existe e tem campos obrigatórios
4. o formato existe e declara entrada e saída
5. o catálogo existe e tem mensagem ativa
6. o handler existe, não está vazio e é executável
7. a mensagem de teste existe e possui payload.dados
8. o manual do conector existe e é HTML completo
9. não há segredos reais evidentes no pacote
10. não há caminhos absolutos ou comandos perigosos comuns
ÁreaPor que isso importa
EstruturaGarante que outra pessoa consiga abrir o pacote e encontrar cada peça no lugar esperado.
ManifestoConfirma identidade, versão, tipo, dependências e handler declarado.
FormatoEvita payload ambíguo. Quem consome o conector precisa saber exatamente o que enviar.
HandlerConfirma que o programa pode ser chamado diretamente e que não está vazio.
SegurançaBloqueia envio de senhas reais, tokens conhecidos e chaves privadas evidentes.

Como interpretar a saída

Uma execução saudável deve se parecer com isto:

VALIDACAO LOCAL DO CONECTOR
Diretorio: pacote-do-conector
Conector: conector-<seu-servico>

[OK] Handler localizado
[OK] Formato validado
[OK] Manual HTML validado
[OK] Catalogo validado
[OK] Mensagem de teste validada

Resumo: 5 OK, 0 aviso(s), 0 erro(s).
Status: APROVADO PARA EMPACOTAMENTO LOCAL.
MensagemO que fazer
[OK]Não precisa mexer; aquela checagem passou.
[AVISO]Leia com atenção. Pode não bloquear, mas indica documentação, clareza ou compatibilidade a revisar.
[ERRO]Bloqueia o envio. Corrija antes de compactar.

Erros comuns e correções

Quando algo falhar, procure padrões como estes:

ERRO: nome do diretório diferente do nome no manifesto
CORREÇÃO: use o mesmo conector-<seu-servico> em diretório, manifesto, formato e catálogo

ERRO: handler não executável
CORREÇÃO: chmod +x no arquivo do handler

ERRO: formato sem entrada ou saída
CORREÇÃO: declare modelos de entrada e modelo de resultado

ERRO: segredo real encontrado
CORREÇÃO: remova o segredo e deixe apenas arquivo .sample com placeholder

ERRO: mensagem de teste sem payload.dados
CORREÇÃO: coloque os dados de negócio dentro de payload.dados
Importante: o validador é uma rede de proteção, não uma auditoria perfeita. Mesmo aprovado, revise manualmente chamadas externas, permissões, privacidade, idempotência e tratamento de erro.

O que o validador não garante

Aprovação local não significa automaticamente:

[não garante] que a API externa está correta
[não garante] que o serviço externo está online
[não garante] que sua regra de negócio está completa
[não garante] que o runtime existe em todos os servidores
[não garante] que sua integração é segura contra todos os ataques
[não garante] que operações financeiras ou destrutivas têm aprovação humana

Por isso, além de validar, faça teste sandbox, leia os logs sem expor segredo e peça revisão de outra pessoa quando a integração alterar dados, enviar mensagens ou movimentar dinheiro.

empacotar-e-enviar / pacote validado

Como enviar o pacote depois de validado

Depois que o validador aprovar, você não envia arquivos soltos. Você envia um pacote fechado, com nome claro, versão clara e sem lixo de desenvolvimento.

Regra simples: só empacote quando o status final disser aprovado. Se houver erro, corrija. Se houver aviso, revise antes de decidir enviar.

Fluxo correto depois da aprovação

No trabalho real, faça nesta ordem:

1. rode o validador local
2. confirme status aprovado
3. confira se não há segredos reais
4. confira versão e nome do conector
5. gere o arquivo compactado
6. teste se o pacote abre corretamente
7. envie pelo canal comunitário indicado pelo projeto
8. guarde o comprovante/hash/versão enviada
9. aguarde selo-validacao emitido pelo servidor
10. aguarde selo-sandbox emitido pelo testesis
11. somente depois disso o pacote poderá ir para o SISC real

O que acontece no servidor depois do envio

Depois que o pacote chega ao operador SISC:

# no servidor operacional do projeto (não no computador do programador):
./validar-recebidos       # gera <pacote>.selo-validacao.json
./testar-sandbox          # instala no testesis, faz dryRun + execução segura
./instalar-aprovados      # só instala no siscore real se os dois selos conferirem

Os selos são assinados pelo servidor e presos ao sha256 do pacote. Se o pacote for alterado depois, os selos deixam de valer. O servidor também bloqueia o selo-sandbox se SISC_SANDBOX_DESATIVADO estiver definido ou se o testesis não estiver com runtime-conector e sandbox-handler atualizados.

Comando recomendado para gerar pacote

No terminal, a partir da raiz do pacote:

mkdir -p dist
./validar-conector && tar \
  --exclude='./dist' \
  --exclude='.git' \
  --exclude='*.log' \
  --exclude='.env' \
  -czf dist/conector-<seu-servico>-1.0.0.tar.gz .

O nome do arquivo deve ajudar quem recebe: inclua o nome do conector e a versão. Exemplo: conector-pagamentos-1.0.0.tar.gz.

Formatos aceitos

Use um destes formatos:

dist/conector-<seu-servico>-1.0.0.tar.gz
dist/conector-<seu-servico>-1.0.0.tgz
dist/conector-<seu-servico>-1.0.0.zip
FormatoQuando usar
.tar.gzPreferencial em Linux. Preserva bem permissões de executável.
.tgzMesma ideia do .tar.gz, só com nome menor.
.zipÚtil quando o desenvolvedor está em Windows, mas confira permissões do handler depois.

Checklist antes de clicar em enviar

Confira item por item:

[ ] status aprovado no validador
[ ] pacote contém um único conector
[ ] manifesto, formato, catálogo, handler, manual e teste estão presentes
[ ] handler está executável
[ ] não existe senha, token, certificado privado ou arquivo .env real
[ ] arquivos de exemplo usam placeholders seguros
[ ] README/manual explicam objetivo, payload, saída, erros e credenciais
[ ] testeSandbox está declarado com permitido=true, semEfeitoReal=true e descrição clara
[ ] testes/mensagem-exemplo.json não causa cobrança, envio real ou alteração irreversível
[ ] versão do manifesto bate com o nome do pacote
[ ] pacote abre em uma pasta temporária sem erro

Teste rápido do pacote gerado

Antes de enviar, abra em uma pasta temporária:

mkdir -p /tmp/teste-conector
cd /tmp/teste-conector
tar -xzf /caminho/para/dist/conector-<seu-servico>-1.0.0.tar.gz
./validar-conector

Esse teste evita o clássico problema: “na minha pasta funcionava, mas o arquivo enviado ficou incompleto”.

Envio pelo canal comunitário

Envie o pacote validado na página oficial de upload:

https://costarrear.com/gitconectores/upload.php

Na página, informe:

nome do conector: conector-<seu-servico>
versão: 1.0.0
arquivo: dist/conector-<seu-servico>-1.0.0.tar.gz
resumo: o que o conector faz em uma frase
operações: lista curta das ações suportadas
observações: dependências, sandbox, limitações e contato do mantenedor
Não dependa de conversa externa: tudo que o revisor precisa saber deve estar dentro do pacote, principalmente no manual do conector e no README. Se quiser selo-sandbox automático, explique no manifesto por que o teste é sem efeito real.

Depois do envio

Guarde estas informações:

arquivo enviado
versão enviada
data do envio
hash sha256 do pacote
mensagem ou protocolo de recebimento
resultado do selo-validacao
resultado do selo-sandbox
lista de alterações desde a versão anterior

Se precisar reenviar, incremente a versão ou deixe claro que é uma correção do mesmo pacote. Isso evita que a comunidade instale uma versão errada sem perceber.

exemplos/conector-clima/manifesto

Clima / previsão do tempo: manifesto

Este arquivo identifica o conector de exemplo e mostra quais nomes você deve adaptar se construir uma integração parecida.

Como ficaria

No arquivo real, este tópico apareceria assim:

{
  "nome": "conector-clima",
  "titulo": "Conector Clima / previsão do tempo",
  "descricao": "Integração para clima / previsão do tempo.",
  "versao": "1.0.0",
  "ativo": true,
  "tipo": "conector",
  "controlador": {
    "metodoLeitura": "ler-mensagem",
    "metodoEnvio": "canal-oficial-de-publicacao",
    "handlerLerMensagem": "./conectores/conector-clima/handlers/conector-clima"
  },
  "formatoConector": "conectores/conector-clima/formatos/formato-conector-clima.json"
}
O que adaptar: troque nome, título, descrição, caminho do handler e caminho do formato para o seu serviço real.
exemplos/conector-clima/formato

Clima / previsão do tempo: formato do payload

Aqui ficam os campos que o consumidor deve enviar para esta integração funcionar.

Campos do exemplo

No arquivo real, este tópico apareceria assim:

{
  "tipo": "formato-conector",
  "nome": "formato-conector-clima",
  "conector": "conector-clima",
  "entrada": {
    "modelos": {
      "comando-principal": {
        "campos": {
          "acao": {"tipo": "string", "obrigatorio": true, "valoresAceitos": ["consultar_previsao"]},
          "cidade": {"tipo": "string", "obrigatorio": "sim"},
          "data": {"tipo": "date", "obrigatorio": "não"},
          "unidade": {"tipo": "string", "obrigatorio": "não"}
        }
      }
    }
  },
  "saida": {"modelos": {"resultado": {"campos": {"sucesso": "bool", "dados": "object", "erro": "object"}}}}
}
CampoTipoObrigatórioExplicação
cidadestringsimCidade pesquisada, exemplo: São Paulo
datadatenãoData opcional no formato AAAA-MM-DD
unidadestringnãocelsius ou fahrenheit
exemplos/conector-clima/handler

Clima / previsão do tempo: handler

O handler traduz o comando padronizado para a API ou mecanismo externo.

Lógica recomendada

No arquivo real, a lógica seria:

ler arquivo JSON recebido
extrair _protocolo e payload.dados
validar acao == "consultar_previsao"
validar cidade e data
chamar API de clima
normalizar temperatura, chuva e alertas
retornar previsão estruturada pelo canal oficial
encerrar com código 0 em sucesso ou erro claro em falha

Exemplo pertinente em PHP

Abaixo está um exemplo simplificado, mas alinhado com este conector:

#!/usr/bin/env php
<?php
declare(strict_types=1);

function falhar(string $msg, int $codigo = 65): never {
    fwrite(STDERR, "conector-clima: ERRO: {$msg}\n");
    exit($codigo);
}
function responder(array $dados): never {
    echo json_encode($dados, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
    exit(0);
}

if ($argc !== 2) falhar('uso: conector-clima <arquivo-mensagem>', 64);
$msg = json_decode(file_get_contents($argv[1]) ?: '', true, 512, JSON_THROW_ON_ERROR);
$dados = $msg['payload']['dados'] ?? null;
if (!is_array($dados)) falhar('payload.dados ausente');

$acao = $dados['acao'] ?? '';
$cidade = trim((string)($dados['cidade'] ?? ''));
$data = trim((string)($dados['data'] ?? date('Y-m-d')));
$unidade = $dados['unidade'] ?? 'celsius';

if ($acao !== 'consultar_previsao') falhar('acao invalida');
if ($cidade === '') falhar('cidade obrigatoria');
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $data)) falhar('data deve estar em AAAA-MM-DD');
if (!in_array($unidade, ['celsius', 'fahrenheit'], true)) falhar('unidade invalida');

$config = json_decode(file_get_contents('segredos/conector-clima.json') ?: '{}', true);
$endpoint = rtrim((string)($config['servico']['endpoint'] ?? ''), '/');
$apiKey = (string)($config['servico']['apiKey'] ?? '');
if ($endpoint === '' || $apiKey === '' || str_contains($apiKey, 'preencher')) falhar('configuracao de clima incompleta', 78);

$url = $endpoint . '/previsao?' . http_build_query(['cidade' => $cidade, 'data' => $data, 'unidade' => $unidade]);
$ctx = stream_context_create(['http' => ['timeout' => 20, 'header' => "Authorization: Bearer {$apiKey}\r\n"]]);
$raw = @file_get_contents($url, false, $ctx);
if ($raw === false) falhar('servico de clima indisponivel', 75);
$externo = json_decode($raw, true);

responder([
    'sucesso' => true,
    'conector' => 'conector-clima',
    'cidade' => $cidade,
    'data' => $data,
    'previsao' => $externo['previsao'] ?? $externo
]);
Cuidado deste conector: baixo risco: normalmente apenas consulta dados externos. Mesmo assim, trate timeout e limite de requisições.
exemplos/conector-clima/manual

Clima / previsão do tempo: manual do conector

O manual ensina outro programador a consumir este conector sem abrir o código.

Estrutura mínima

No HTML real, inclua:

<h1>Manual do conector-clima</h1>
<h2>Objetivo</h2>
<p>Explicar clima / previsão do tempo.</p>
<h2>Operação principal</h2>
<code>consultar_previsao</code>
<h2>Payload</h2>
<pre>exemplo completo com dados seguros</pre>
<h2>Erros comuns</h2>
exemplos/conector-clima/mensagem-de-teste

Clima / previsão do tempo: mensagem de teste

A mensagem de teste permite rodar o handler localmente sem dados reais perigosos.

Payload de teste

No arquivo real, este tópico apareceria assim:

{
  "_protocolo": {
    "nome": "siscore-protocolo-objetos",
    "versao": 1,
    "processoId": "processo-teste-local-0001",
    "mensagemId": "teste-conector-clima-0001",
    "origem": "sistema__operador",
    "destino": "conector__conector-clima",
    "tipo": "comando",
    "prioridade": "normal"
  },
  "payload": {
    "idmensagem": "conector-clima.executar",
    "dados": {
      "acao": "consultar_previsao",
      "cidade": "São Paulo",
      "data": "2026-08-25",
      "unidade": "celsius"
    }
  }
}
Boa prática: a mensagem de teste deve ser realista, mas segura. Nada de senha, token ou operação financeira real.
exemplos/conector-clima/segredos.sample

Clima / previsão do tempo: segredos de exemplo

Este arquivo é só um molde. O valor real será preenchido apenas no ambiente de instalação.

Sample seguro

No arquivo de exemplo, use placeholders:

{
  "ativo": false,
  "descricao": "Copiar e preencher somente no ambiente real.",
  "servico": {
    "endpoint": "https://api.clima.example.invalid",
    "apiKey": "preencher-no-ambiente-real",
    "timeoutSegundos": 30
  }
}
Nunca envie: token real, senha real, chave privada, certificado privado ou qualquer segredo que permita acesso ao serviço externo.
exemplos/conector-crm-leads/manifesto

CRM / leads comerciais: manifesto

Este arquivo identifica o conector de exemplo e mostra quais nomes você deve adaptar se construir uma integração parecida.

Como ficaria

No arquivo real, este tópico apareceria assim:

{
  "nome": "conector-crm-leads",
  "titulo": "Conector CRM / leads comerciais",
  "descricao": "Integração para crm / leads comerciais.",
  "versao": "1.0.0",
  "ativo": true,
  "tipo": "conector",
  "controlador": {
    "metodoLeitura": "ler-mensagem",
    "metodoEnvio": "canal-oficial-de-publicacao",
    "handlerLerMensagem": "./conectores/conector-crm-leads/handlers/conector-crm-leads"
  },
  "formatoConector": "conectores/conector-crm-leads/formatos/formato-conector-crm-leads.json"
}
O que adaptar: troque nome, título, descrição, caminho do handler e caminho do formato para o seu serviço real.
exemplos/conector-crm-leads/formato

CRM / leads comerciais: formato do payload

Aqui ficam os campos que o consumidor deve enviar para esta integração funcionar.

Campos do exemplo

No arquivo real, este tópico apareceria assim:

{
  "tipo": "formato-conector",
  "nome": "formato-conector-crm-leads",
  "conector": "conector-crm-leads",
  "entrada": {
    "modelos": {
      "comando-principal": {
        "campos": {
          "acao": {"tipo": "string", "obrigatorio": true, "valoresAceitos": ["criar_lead"]},
          "nome": {"tipo": "string", "obrigatorio": "sim"},
          "email": {"tipo": "email", "obrigatorio": "sim"},
          "telefone": {"tipo": "string", "obrigatorio": "não"},
          "origemLead": {"tipo": "string", "obrigatorio": "não"}
        }
      }
    }
  },
  "saida": {"modelos": {"resultado": {"campos": {"sucesso": "bool", "dados": "object", "erro": "object"}}}}
}
CampoTipoObrigatórioExplicação
nomestringsimNome do lead
emailemailsimEmail usado também para evitar duplicidade
telefonestringnãoTelefone de contato
origemLeadstringnãoCampanha, formulário ou canal de origem
exemplos/conector-crm-leads/handler

CRM / leads comerciais: handler

O handler traduz o comando padronizado para a API ou mecanismo externo.

Lógica recomendada

No arquivo real, a lógica seria:

ler arquivo JSON recebido
extrair _protocolo e payload.dados
validar acao == "criar_lead"
validar email
consultar se lead já existe
criar ou atualizar lead
retornar id do lead e status pelo canal oficial
encerrar com código 0 em sucesso ou erro claro em falha

Exemplo pertinente em PHP

Abaixo está um exemplo simplificado, mas alinhado com este conector:

#!/usr/bin/env php
<?php
declare(strict_types=1);

function falhar(string $msg, int $codigo = 65): never {
    fwrite(STDERR, "conector-crm-leads: ERRO: {$msg}\n");
    exit($codigo);
}
function responder(array $dados): never {
    echo json_encode($dados, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
    exit(0);
}
function post_json(string $url, array $body, string $token): array {
    $ctx = stream_context_create(['http' => [
        'method' => 'POST',
        'timeout' => 25,
        'header' => "Content-Type: application/json\r\nAuthorization: Bearer {$token}\r\n",
        'content' => json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
    ]]);
    $raw = @file_get_contents($url, false, $ctx);
    if ($raw === false) falhar('CRM indisponivel', 75);
    return json_decode($raw, true) ?: [];
}

if ($argc !== 2) falhar('uso: conector-crm-leads <arquivo-mensagem>', 64);
$msg = json_decode(file_get_contents($argv[1]) ?: '', true, 512, JSON_THROW_ON_ERROR);
$dados = $msg['payload']['dados'] ?? null;
if (!is_array($dados)) falhar('payload.dados ausente');

$acao = $dados['acao'] ?? '';
$email = trim((string)($dados['email'] ?? ''));
$nome = trim((string)($dados['nome'] ?? ''));
if (!in_array($acao, ['criar_lead', 'consultar_lead'], true)) falhar('acao invalida');
if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) falhar('email invalido');
if ($acao === 'criar_lead' && $nome === '') falhar('nome obrigatorio para criar lead');

$config = json_decode(file_get_contents('segredos/conector-crm-leads.json') ?: '{}', true);
$endpoint = rtrim((string)($config['servico']['endpoint'] ?? ''), '/');
$token = (string)($config['servico']['token'] ?? '');
if ($endpoint === '' || $token === '' || str_contains($token, 'preencher')) falhar('configuracao de CRM incompleta', 78);

$payloadCrm = [
    'email' => $email,
    'nome' => $nome,
    'telefone' => $dados['telefone'] ?? null,
    'origem' => $dados['origemLead'] ?? 'sisc-comunidade',
    'idempotencia' => hash('sha256', strtolower($email))
];
$resultado = $acao === 'criar_lead'
    ? post_json($endpoint . '/leads/upsert', $payloadCrm, $token)
    : post_json($endpoint . '/leads/consultar', ['email' => $email], $token);

responder(['sucesso' => true, 'conector' => 'conector-crm-leads', 'resultado' => $resultado]);
Cuidado deste conector: médio: pode criar registros duplicados. Use idempotência baseada em email, documento ou referência externa.
exemplos/conector-crm-leads/manual

CRM / leads comerciais: manual do conector

O manual ensina outro programador a consumir este conector sem abrir o código.

Estrutura mínima

No HTML real, inclua:

<h1>Manual do conector-crm-leads</h1>
<h2>Objetivo</h2>
<p>Explicar crm / leads comerciais.</p>
<h2>Operação principal</h2>
<code>criar_lead</code>
<h2>Payload</h2>
<pre>exemplo completo com dados seguros</pre>
<h2>Erros comuns</h2>
exemplos/conector-crm-leads/mensagem-de-teste

CRM / leads comerciais: mensagem de teste

A mensagem de teste permite rodar o handler localmente sem dados reais perigosos.

Payload de teste

No arquivo real, este tópico apareceria assim:

{
  "_protocolo": {
    "nome": "siscore-protocolo-objetos",
    "versao": 1,
    "processoId": "processo-teste-local-0001",
    "mensagemId": "teste-conector-crm-leads-0001",
    "origem": "sistema__operador",
    "destino": "conector__conector-crm-leads",
    "tipo": "comando",
    "prioridade": "normal"
  },
  "payload": {
    "idmensagem": "conector-crm-leads.executar",
    "dados": {
      "acao": "criar_lead",
      "nome": "Maria Cliente",
      "email": "maria@example.com",
      "telefone": "+5511999999999",
      "origemLead": "landing-page"
    }
  }
}
Boa prática: a mensagem de teste deve ser realista, mas segura. Nada de senha, token ou operação financeira real.
exemplos/conector-crm-leads/segredos.sample

CRM / leads comerciais: segredos de exemplo

Este arquivo é só um molde. O valor real será preenchido apenas no ambiente de instalação.

Sample seguro

No arquivo de exemplo, use placeholders:

{
  "ativo": false,
  "descricao": "Copiar e preencher somente no ambiente real.",
  "servico": {
    "endpoint": "https://crm.example.invalid",
    "token": "preencher-no-ambiente-real",
    "timeoutSegundos": 30
  }
}
Nunca envie: token real, senha real, chave privada, certificado privado ou qualquer segredo que permita acesso ao serviço externo.
exemplos/conector-pagamentos/manifesto

Pagamentos / cobrança: manifesto

Este arquivo identifica o conector de exemplo e mostra quais nomes você deve adaptar se construir uma integração parecida.

Como ficaria

No arquivo real, este tópico apareceria assim:

{
  "nome": "conector-pagamentos",
  "titulo": "Conector Pagamentos / cobrança",
  "descricao": "Integração para pagamentos / cobrança.",
  "versao": "1.0.0",
  "ativo": true,
  "tipo": "conector",
  "controlador": {
    "metodoLeitura": "ler-mensagem",
    "metodoEnvio": "canal-oficial-de-publicacao",
    "handlerLerMensagem": "./conectores/conector-pagamentos/handlers/conector-pagamentos"
  },
  "formatoConector": "conectores/conector-pagamentos/formatos/formato-conector-pagamentos.json"
}
O que adaptar: troque nome, título, descrição, caminho do handler e caminho do formato para o seu serviço real.
exemplos/conector-pagamentos/formato

Pagamentos / cobrança: formato do payload

Aqui ficam os campos que o consumidor deve enviar para esta integração funcionar.

Campos do exemplo

No arquivo real, este tópico apareceria assim:

{
  "tipo": "formato-conector",
  "nome": "formato-conector-pagamentos",
  "conector": "conector-pagamentos",
  "entrada": {
    "modelos": {
      "comando-principal": {
        "campos": {
          "acao": {"tipo": "string", "obrigatorio": true, "valoresAceitos": ["criar_cobranca"]},
          "valor": {"tipo": "number", "obrigatorio": "sim"},
          "moeda": {"tipo": "string", "obrigatorio": "não"},
          "referenciaPedido": {"tipo": "string", "obrigatorio": "sim"},
          "vencimento": {"tipo": "date", "obrigatorio": "não"}
        }
      }
    }
  },
  "saida": {"modelos": {"resultado": {"campos": {"sucesso": "bool", "dados": "object", "erro": "object"}}}}
}
CampoTipoObrigatórioExplicação
valornumbersimValor positivo da cobrança
moedastringnãoMoeda, padrão BRL
referenciaPedidostringsimChave do pedido para idempotência
vencimentodatenãoData limite para pagamento
exemplos/conector-pagamentos/handler

Pagamentos / cobrança: handler

O handler traduz o comando padronizado para a API ou mecanismo externo.

Lógica recomendada

No arquivo real, a lógica seria:

ler arquivo JSON recebido
extrair _protocolo e payload.dados
validar acao == "criar_cobranca"
validar valor monetário
gerar chave idempotente a partir do pedido
criar cobrança no gateway
retornar id, status e link/qr pelo canal oficial
encerrar com código 0 em sucesso ou erro claro em falha

Exemplo pertinente em PHP

Abaixo está um exemplo simplificado, mas alinhado com este conector:

#!/usr/bin/env php
<?php
declare(strict_types=1);

function falhar(string $msg, int $codigo = 65): never {
    fwrite(STDERR, "conector-pagamentos: ERRO: {$msg}\n");
    exit($codigo);
}
function responder(array $dados): never {
    echo json_encode($dados, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
    exit(0);
}
function dinheiro(mixed $valor): float {
    if (!is_int($valor) && !is_float($valor) && !is_string($valor)) falhar('valor invalido');
    $v = (float)$valor;
    if ($v <= 0) falhar('valor deve ser positivo');
    return round($v, 2);
}

if ($argc !== 2) falhar('uso: conector-pagamentos <arquivo-mensagem>', 64);
$msg = json_decode(file_get_contents($argv[1]) ?: '', true, 512, JSON_THROW_ON_ERROR);
$dados = $msg['payload']['dados'] ?? null;
if (!is_array($dados)) falhar('payload.dados ausente');

$acao = $dados['acao'] ?? '';
$referencia = trim((string)($dados['referenciaPedido'] ?? ''));
if (!in_array($acao, ['criar_cobranca', 'consultar_cobranca', 'cancelar_cobranca'], true)) falhar('acao invalida');
if ($referencia === '') falhar('referenciaPedido obrigatoria');

$config = json_decode(file_get_contents('segredos/conector-pagamentos.json') ?: '{}', true);
$endpoint = rtrim((string)($config['servico']['endpoint'] ?? ''), '/');
$clientId = (string)($config['servico']['clientId'] ?? '');
$clientSecret = (string)($config['servico']['clientSecret'] ?? '');
if ($endpoint === '' || $clientId === '' || $clientSecret === '') falhar('configuracao de pagamento incompleta', 78);

$idempotencia = hash('sha256', $referencia . ':' . $acao);
$body = ['referenciaPedido' => $referencia, 'idempotencia' => $idempotencia];
if ($acao === 'criar_cobranca') {
    $body['valor'] = dinheiro($dados['valor'] ?? null);
    $body['moeda'] = $dados['moeda'] ?? 'BRL';
    $body['vencimento'] = $dados['vencimento'] ?? null;
}

$ctx = stream_context_create(['http' => [
    'method' => 'POST',
    'timeout' => 30,
    'header' => "Content-Type: application/json\r\nIdempotency-Key: {$idempotencia}\r\n",
    'content' => json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
]]);
$raw = @file_get_contents($endpoint . '/' . $acao, false, $ctx);
if ($raw === false) falhar('gateway de pagamento indisponivel', 75);

responder(['sucesso' => true, 'conector' => 'conector-pagamentos', 'resultado' => json_decode($raw, true)]);
Cuidado deste conector: alto: pagamento duplicado é problema sério. Nunca crie cobrança sem idempotência e sem referência de negócio.
exemplos/conector-pagamentos/manual

Pagamentos / cobrança: manual do conector

O manual ensina outro programador a consumir este conector sem abrir o código.

Estrutura mínima

No HTML real, inclua:

<h1>Manual do conector-pagamentos</h1>
<h2>Objetivo</h2>
<p>Explicar pagamentos / cobrança.</p>
<h2>Operação principal</h2>
<code>criar_cobranca</code>
<h2>Payload</h2>
<pre>exemplo completo com dados seguros</pre>
<h2>Erros comuns</h2>
exemplos/conector-pagamentos/mensagem-de-teste

Pagamentos / cobrança: mensagem de teste

A mensagem de teste permite rodar o handler localmente sem dados reais perigosos.

Payload de teste

No arquivo real, este tópico apareceria assim:

{
  "_protocolo": {
    "nome": "siscore-protocolo-objetos",
    "versao": 1,
    "processoId": "processo-teste-local-0001",
    "mensagemId": "teste-conector-pagamentos-0001",
    "origem": "sistema__operador",
    "destino": "conector__conector-pagamentos",
    "tipo": "comando",
    "prioridade": "normal"
  },
  "payload": {
    "idmensagem": "conector-pagamentos.executar",
    "dados": {
      "acao": "criar_cobranca",
      "valor": 149.90,
      "moeda": "BRL",
      "referenciaPedido": "PED-987",
      "vencimento": "2026-08-30"
    }
  }
}
Boa prática: a mensagem de teste deve ser realista, mas segura. Nada de senha, token ou operação financeira real.
exemplos/conector-pagamentos/segredos.sample

Pagamentos / cobrança: segredos de exemplo

Este arquivo é só um molde. O valor real será preenchido apenas no ambiente de instalação.

Sample seguro

No arquivo de exemplo, use placeholders:

{
  "ativo": false,
  "descricao": "Copiar e preencher somente no ambiente real.",
  "servico": {
    "endpoint": "https://pagamentos.example.invalid",
    "clientId": "preencher-no-ambiente-real",
    "clientSecret": "preencher-no-ambiente-real",
    "timeoutSegundos": 30
  }
}
Nunca envie: token real, senha real, chave privada, certificado privado ou qualquer segredo que permita acesso ao serviço externo.
exemplos/conector-estoque/manifesto

Estoque / ERP: manifesto

Este arquivo identifica o conector de exemplo e mostra quais nomes você deve adaptar se construir uma integração parecida.

Como ficaria

No arquivo real, este tópico apareceria assim:

{
  "nome": "conector-estoque",
  "titulo": "Conector Estoque / ERP",
  "descricao": "Integração para estoque / erp.",
  "versao": "1.0.0",
  "ativo": true,
  "tipo": "conector",
  "controlador": {
    "metodoLeitura": "ler-mensagem",
    "metodoEnvio": "canal-oficial-de-publicacao",
    "handlerLerMensagem": "./conectores/conector-estoque/handlers/conector-estoque"
  },
  "formatoConector": "conectores/conector-estoque/formatos/formato-conector-estoque.json"
}
O que adaptar: troque nome, título, descrição, caminho do handler e caminho do formato para o seu serviço real.
exemplos/conector-estoque/formato

Estoque / ERP: formato do payload

Aqui ficam os campos que o consumidor deve enviar para esta integração funcionar.

Campos do exemplo

No arquivo real, este tópico apareceria assim:

{
  "tipo": "formato-conector",
  "nome": "formato-conector-estoque",
  "conector": "conector-estoque",
  "entrada": {
    "modelos": {
      "comando-principal": {
        "campos": {
          "acao": {"tipo": "string", "obrigatorio": true, "valoresAceitos": ["ajustar_saldo"]},
          "sku": {"tipo": "string", "obrigatorio": "sim"},
          "quantidade": {"tipo": "int", "obrigatorio": "sim para ajuste"},
          "deposito": {"tipo": "string", "obrigatorio": "não"},
          "motivo": {"tipo": "string", "obrigatorio": "sim para ajuste"}
        }
      }
    }
  },
  "saida": {"modelos": {"resultado": {"campos": {"sucesso": "bool", "dados": "object", "erro": "object"}}}}
}
CampoTipoObrigatórioExplicação
skustringsimCódigo do produto
quantidadeintsim para ajusteQuantidade final ou delta, conforme regra documentada
depositostringnãoDepósito/filial
motivostringsim para ajusteJustificativa do ajuste
exemplos/conector-estoque/handler

Estoque / ERP: handler

O handler traduz o comando padronizado para a API ou mecanismo externo.

Lógica recomendada

No arquivo real, a lógica seria:

ler arquivo JSON recebido
extrair _protocolo e payload.dados
validar acao == "ajustar_saldo"
validar SKU
confirmar motivo para operações de escrita
consultar ou ajustar saldo no ERP
retornar saldo atualizado pelo canal oficial
encerrar com código 0 em sucesso ou erro claro em falha

Exemplo pertinente em PHP

Abaixo está um exemplo simplificado, mas alinhado com este conector:

#!/usr/bin/env php
<?php
declare(strict_types=1);

function falhar(string $msg, int $codigo = 65): never {
    fwrite(STDERR, "conector-estoque: ERRO: {$msg}\n");
    exit($codigo);
}
function responder(array $dados): never {
    echo json_encode($dados, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
    exit(0);
}

if ($argc !== 2) falhar('uso: conector-estoque <arquivo-mensagem>', 64);
$msg = json_decode(file_get_contents($argv[1]) ?: '', true, 512, JSON_THROW_ON_ERROR);
$dados = $msg['payload']['dados'] ?? null;
if (!is_array($dados)) falhar('payload.dados ausente');

$acao = $dados['acao'] ?? '';
$sku = strtoupper(trim((string)($dados['sku'] ?? '')));
$deposito = trim((string)($dados['deposito'] ?? 'principal'));
if (!in_array($acao, ['consultar_saldo', 'ajustar_saldo'], true)) falhar('acao invalida');
if ($sku === '' || !preg_match('/^[A-Z0-9._-]{2,80}$/', $sku)) falhar('sku invalido');

$body = ['sku' => $sku, 'deposito' => $deposito];
if ($acao === 'ajustar_saldo') {
    if (!is_int($dados['quantidade'] ?? null)) falhar('quantidade deve ser inteiro');
    $motivo = trim((string)($dados['motivo'] ?? ''));
    if ($motivo === '') falhar('motivo obrigatorio para ajuste');
    $body['quantidade'] = $dados['quantidade'];
    $body['motivo'] = $motivo;
}

$config = json_decode(file_get_contents('segredos/conector-estoque.json') ?: '{}', true);
$endpoint = rtrim((string)($config['servico']['endpoint'] ?? ''), '/');
$token = (string)($config['servico']['token'] ?? '');
if ($endpoint === '' || $token === '') falhar('configuracao de estoque incompleta', 78);

$ctx = stream_context_create(['http' => [
    'method' => $acao === 'consultar_saldo' ? 'GET' : 'POST',
    'timeout' => 25,
    'header' => "Content-Type: application/json\r\nAuthorization: Bearer {$token}\r\n",
    'content' => $acao === 'consultar_saldo' ? '' : json_encode($body, JSON_UNESCAPED_UNICODE)
]]);
$url = $acao === 'consultar_saldo'
    ? $endpoint . '/estoque?' . http_build_query($body)
    : $endpoint . '/estoque/ajuste';
$raw = @file_get_contents($url, false, $ctx);
if ($raw === false) falhar('ERP indisponivel', 75);

responder(['sucesso' => true, 'conector' => 'conector-estoque', 'sku' => $sku, 'resultado' => json_decode($raw, true)]);
Cuidado deste conector: alto quando altera saldo. Documente se quantidade é saldo final ou variação, e proteja contra concorrência.
exemplos/conector-estoque/manual

Estoque / ERP: manual do conector

O manual ensina outro programador a consumir este conector sem abrir o código.

Estrutura mínima

No HTML real, inclua:

<h1>Manual do conector-estoque</h1>
<h2>Objetivo</h2>
<p>Explicar estoque / erp.</p>
<h2>Operação principal</h2>
<code>ajustar_saldo</code>
<h2>Payload</h2>
<pre>exemplo completo com dados seguros</pre>
<h2>Erros comuns</h2>
exemplos/conector-estoque/mensagem-de-teste

Estoque / ERP: mensagem de teste

A mensagem de teste permite rodar o handler localmente sem dados reais perigosos.

Payload de teste

No arquivo real, este tópico apareceria assim:

{
  "_protocolo": {
    "nome": "siscore-protocolo-objetos",
    "versao": 1,
    "processoId": "processo-teste-local-0001",
    "mensagemId": "teste-conector-estoque-0001",
    "origem": "sistema__operador",
    "destino": "conector__conector-estoque",
    "tipo": "comando",
    "prioridade": "normal"
  },
  "payload": {
    "idmensagem": "conector-estoque.executar",
    "dados": {
      "acao": "ajustar_saldo",
      "sku": "CAMISETA-AZUL-M",
      "quantidade": 25,
      "deposito": "principal",
      "motivo": "inventario"
    }
  }
}
Boa prática: a mensagem de teste deve ser realista, mas segura. Nada de senha, token ou operação financeira real.
exemplos/conector-estoque/segredos.sample

Estoque / ERP: segredos de exemplo

Este arquivo é só um molde. O valor real será preenchido apenas no ambiente de instalação.

Sample seguro

No arquivo de exemplo, use placeholders:

{
  "ativo": false,
  "descricao": "Copiar e preencher somente no ambiente real.",
  "servico": {
    "endpoint": "https://erp.example.invalid",
    "token": "preencher-no-ambiente-real",
    "timeoutSegundos": 30
  }
}
Nunca envie: token real, senha real, chave privada, certificado privado ou qualquer segredo que permita acesso ao serviço externo.
exemplos/conector-documentos-ocr/manifesto

Documentos / OCR: manifesto

Este arquivo identifica o conector de exemplo e mostra quais nomes você deve adaptar se construir uma integração parecida.

Como ficaria

No arquivo real, este tópico apareceria assim:

{
  "nome": "conector-documentos-ocr",
  "titulo": "Conector Documentos / OCR",
  "descricao": "Integração para documentos / ocr.",
  "versao": "1.0.0",
  "ativo": true,
  "tipo": "conector",
  "controlador": {
    "metodoLeitura": "ler-mensagem",
    "metodoEnvio": "canal-oficial-de-publicacao",
    "handlerLerMensagem": "./conectores/conector-documentos-ocr/handlers/conector-documentos-ocr"
  },
  "formatoConector": "conectores/conector-documentos-ocr/formatos/formato-conector-documentos-ocr.json"
}
O que adaptar: troque nome, título, descrição, caminho do handler e caminho do formato para o seu serviço real.
exemplos/conector-documentos-ocr/formato

Documentos / OCR: formato do payload

Aqui ficam os campos que o consumidor deve enviar para esta integração funcionar.

Campos do exemplo

No arquivo real, este tópico apareceria assim:

{
  "tipo": "formato-conector",
  "nome": "formato-conector-documentos-ocr",
  "conector": "conector-documentos-ocr",
  "entrada": {
    "modelos": {
      "comando-principal": {
        "campos": {
          "acao": {"tipo": "string", "obrigatorio": true, "valoresAceitos": ["extrair_texto"]},
          "arquivo": {"tipo": "string", "obrigatorio": "sim"},
          "tipoDocumento": {"tipo": "string", "obrigatorio": "não"},
          "idioma": {"tipo": "string", "obrigatorio": "não"},
          "extrairCampos": {"tipo": "bool", "obrigatorio": "não"}
        }
      }
    }
  },
  "saida": {"modelos": {"resultado": {"campos": {"sucesso": "bool", "dados": "object", "erro": "object"}}}}
}
CampoTipoObrigatórioExplicação
arquivostringsimCaminho permitido ou URL assinada temporária
tipoDocumentostringnãocontrato, nota, comprovante ou generico
idiomastringnãoIdioma esperado, padrão pt-BR
extrairCamposboolnãoSe deve retornar campos estruturados
exemplos/conector-documentos-ocr/handler

Documentos / OCR: handler

O handler traduz o comando padronizado para a API ou mecanismo externo.

Lógica recomendada

No arquivo real, a lógica seria:

ler arquivo JSON recebido
extrair _protocolo e payload.dados
validar acao == "extrair_texto"
validar caminho permitido
validar tamanho e tipo do arquivo
enviar ao OCR externo
retornar texto, campos e confiança pelo canal oficial
encerrar com código 0 em sucesso ou erro claro em falha

Exemplo pertinente em PHP

Abaixo está um exemplo simplificado, mas alinhado com este conector:

#!/usr/bin/env php
<?php
declare(strict_types=1);

function falhar(string $msg, int $codigo = 65): never {
    fwrite(STDERR, "conector-documentos-ocr: ERRO: {$msg}\n");
    exit($codigo);
}
function responder(array $dados): never {
    echo json_encode($dados, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
    exit(0);
}

if ($argc !== 2) falhar('uso: conector-documentos-ocr <arquivo-mensagem>', 64);
$msg = json_decode(file_get_contents($argv[1]) ?: '', true, 512, JSON_THROW_ON_ERROR);
$dados = $msg['payload']['dados'] ?? null;
if (!is_array($dados)) falhar('payload.dados ausente');

$acao = $dados['acao'] ?? '';
$arquivo = trim((string)($dados['arquivo'] ?? ''));
$idioma = $dados['idioma'] ?? 'pt-BR';
$tipoDocumento = $dados['tipoDocumento'] ?? 'generico';
if ($acao !== 'extrair_texto') falhar('acao invalida');
if ($arquivo === '' || str_contains($arquivo, '..') || str_starts_with($arquivo, '/')) falhar('arquivo deve ser caminho relativo permitido');
if (!is_file($arquivo) || !is_readable($arquivo)) falhar('arquivo nao encontrado ou sem leitura', 66);
if (filesize($arquivo) > 20 * 1024 * 1024) falhar('arquivo maior que 20MB');
if (!in_array($tipoDocumento, ['contrato', 'nota', 'comprovante', 'generico'], true)) falhar('tipoDocumento invalido');

$config = json_decode(file_get_contents('segredos/conector-documentos-ocr.json') ?: '{}', true);
$endpoint = rtrim((string)($config['servico']['endpoint'] ?? ''), '/');
$apiKey = (string)($config['servico']['apiKey'] ?? '');
if ($endpoint === '' || $apiKey === '') falhar('configuracao OCR incompleta', 78);

$boundary = '----sisc-ocr-' . bin2hex(random_bytes(8));
$conteudo = file_get_contents($arquivo);
$multipart = "--{$boundary}\r\n"
  . "Content-Disposition: form-data; name=\"metadata\"\r\n\r\n"
  . json_encode(['idioma' => $idioma, 'tipoDocumento' => $tipoDocumento], JSON_UNESCAPED_UNICODE) . "\r\n"
  . "--{$boundary}\r\n"
  . "Content-Disposition: form-data; name=\"arquivo\"; filename=\"documento\"\r\n"
  . "Content-Type: application/octet-stream\r\n\r\n"
  . $conteudo . "\r\n--{$boundary}--\r\n";

$ctx = stream_context_create(['http' => [
    'method' => 'POST',
    'timeout' => 60,
    'header' => "Authorization: Bearer {$apiKey}\r\nContent-Type: multipart/form-data; boundary={$boundary}\r\n",
    'content' => $multipart
]]);
$raw = @file_get_contents($endpoint . '/extrair', false, $ctx);
if ($raw === false) falhar('servico OCR indisponivel', 75);

responder(['sucesso' => true, 'conector' => 'conector-documentos-ocr', 'resultado' => json_decode($raw, true)]);
Cuidado deste conector: privacidade. Não envie documentos sigilosos a provedor não autorizado; apague temporários e limite tamanho.
exemplos/conector-documentos-ocr/manual

Documentos / OCR: manual do conector

O manual ensina outro programador a consumir este conector sem abrir o código.

Estrutura mínima

No HTML real, inclua:

<h1>Manual do conector-documentos-ocr</h1>
<h2>Objetivo</h2>
<p>Explicar documentos / ocr.</p>
<h2>Operação principal</h2>
<code>extrair_texto</code>
<h2>Payload</h2>
<pre>exemplo completo com dados seguros</pre>
<h2>Erros comuns</h2>
exemplos/conector-documentos-ocr/mensagem-de-teste

Documentos / OCR: mensagem de teste

A mensagem de teste permite rodar o handler localmente sem dados reais perigosos.

Payload de teste

No arquivo real, este tópico apareceria assim:

{
  "_protocolo": {
    "nome": "siscore-protocolo-objetos",
    "versao": 1,
    "processoId": "processo-teste-local-0001",
    "mensagemId": "teste-conector-documentos-ocr-0001",
    "origem": "sistema__operador",
    "destino": "conector__conector-documentos-ocr",
    "tipo": "comando",
    "prioridade": "normal"
  },
  "payload": {
    "idmensagem": "conector-documentos-ocr.executar",
    "dados": {
      "acao": "extrair_texto",
      "arquivo": "uploads/seguros/doc-123.pdf",
      "tipoDocumento": "contrato",
      "idioma": "pt-BR",
      "extrairCampos": true
    }
  }
}
Boa prática: a mensagem de teste deve ser realista, mas segura. Nada de senha, token ou operação financeira real.
exemplos/conector-documentos-ocr/segredos.sample

Documentos / OCR: segredos de exemplo

Este arquivo é só um molde. O valor real será preenchido apenas no ambiente de instalação.

Sample seguro

No arquivo de exemplo, use placeholders:

{
  "ativo": false,
  "descricao": "Copiar e preencher somente no ambiente real.",
  "servico": {
    "endpoint": "https://ocr.example.invalid",
    "apiKey": "preencher-no-ambiente-real",
    "timeoutSegundos": 30
  }
}
Nunca envie: token real, senha real, chave privada, certificado privado ou qualquer segredo que permita acesso ao serviço externo.