2. A central ou o CAD registra a ocorrência e despacha viaturas
O é por : cada empenhada é um despacho com id e status próprios, e o que acontece com um não diz nada sobre os outros. Quem traduz "viatura RP-1207" em "a que está nela agora" é o plugin de
; por isso "viatura sem guarnição disponível" é um resultado, não umerro.
A cena
A cena 3D deste caso (roteiro registrar-e-despachar) entra aqui quando a operação 3D publicar os roteiros dos casos de uso; até lá, o diagrama abaixo é a cena.
Quem faz: o e o despacham; o operador de central registra e consulta mas não despacha.
O que se informa ao registrar
| campo | o que é |
|---|---|
classificacao | obrigatório. natureza, subnatureza?, prioridade de 1 a 5 (1 é a mais alta), gravidade? em baixa, media, alta, critica |
descricao | texto livre |
local | coordenada, precisaoMetros, endereco, referencia; raramente vêm juntos: a central tem o endereço, o app a coordenada |
solicitante | nome?, telefone?, canal em telefone, aplicativo, radio, sensor, integracao, presencial |
envolvidos[] | papel em vitima, suspeito, autor, testemunha, desaparecido, envolvido; descricao? |
referenciaExterna | o protocolo no sistema de origem; obrigatória para o integrador e imutável, identifica uma só por originador |
registradaEm | sem ela vale o relógio do ; é ISO 8601 em UTC (Z): converta o horário local antes de enviar |
O PATCH complementa só dados de negócio. O status não entra: ele muda por verbo próprio. A referenciaExterna também não. Campo desconhecido no corpo é 400.
Pelo CAD
import { criarClienteOcorrencia } from '@geocontrol/geohub-sdk/ocorrencia';
import { CONEXAO } from './conexao.js';
const ocorrencia = criarClienteOcorrencia(CONEXAO);
// O cliente cunha um UUID v7 por comando: é a chave de idempotência.
const registro = await ocorrencia.registrarOcorrencia({
classificacao: { natureza: 'roubo a transeunte', prioridade: 1 },
local: {
endereco: {
logradouro: 'Av. Dante Michelini',
municipio: 'Vitória',
uf: 'ES',
},
},
// O protocolo no CAD: identifica uma só ocorrência por integrador.
referenciaExterna: 'CAD-2026-004512',
solicitante: { canal: 'telefone' },
});
if (!registro.success) throw new Error(registro.error.codigo);
export const ocorrenciaId = registro.data;
// Complementar depois: só dados de negócio, nunca o status.
export const atualizacao = await ocorrencia.atualizarOcorrencia({
alteracoes: { descricao: 'Dois suspeitos em motocicleta.' },
id: ocorrenciaId,
});import { criarClienteOcorrencia } from '@geocontrol/geohub-sdk/ocorrencia';
import { CONEXAO } from './conexao.js';
const ocorrencia = criarClienteOcorrencia(CONEXAO);
// O cliente cunha um UUID v7 por comando: é a chave de idempotência.
const registro = await ocorrencia.registrarOcorrencia({
classificacao: { natureza: 'roubo a transeunte', prioridade: 1 },
local: {
endereco: {
logradouro: 'Av. Dante Michelini',
municipio: 'Vitória',
uf: 'ES',
},
},
// O protocolo no CAD: identifica uma só ocorrência por integrador.
referenciaExterna: 'CAD-2026-004512',
solicitante: { canal: 'telefone' },
});
if (!registro.success) throw new Error(registro.error.codigo);
export const ocorrenciaId = registro.data;
// Complementar depois: só dados de negócio, nunca o status.
export const atualizacao = await ocorrencia.atualizarOcorrencia({
alteracoes: { descricao: 'Dois suspeitos em motocicleta.' },
id: ocorrenciaId,
});curl -X POST https://geohub.exemplo.gov.br/plugins/ocorrencias -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)" -H "Content-Type: application/json" \
-d '{"classificacao":{"natureza":"roubo a transeunte","prioridade":1},
"local":{"endereco":{"logradouro":"Av. Dante Michelini","municipio":"Vitória","uf":"ES"}},
"solicitante":{"canal":"telefone"},
"referenciaExterna":"CAD-2026-004512"}'
# {"dados":"<ocorrenciaId>"}
# 409 {"erro":{"codigo":"referencia-externa-ja-registrada","contexto":{"ocorrenciaId":"…"}}}
curl -X PATCH https://geohub.exemplo.gov.br/plugins/ocorrencias/$OCORRENCIA -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)" -H "Content-Type: application/json" \
-d '{"alteracoes":{"descricao":"Dois suspeitos em motocicleta."}}'Despachar a viatura são dois passos: achar a guarnição disponível dela e empenhá-la. O servidor troca a composição pela que a jornada conhece.
import { criarClienteJornada, viaturaId } from '@geocontrol/geohub-sdk/jornada';
import {
criarClienteOcorrencia,
recursoDaGuarnicao,
} from '@geocontrol/geohub-sdk/ocorrencia';
import { CONEXAO } from './conexao.js';
import { ocorrenciaId } from './registrar-ocorrencia.js';
const jornada = criarClienteJornada(CONEXAO);
const ocorrencia = criarClienteOcorrencia(CONEXAO);
// "Viatura RP-1207" vira "a guarnição que está nela agora", ou nada.
const guarnicao = await jornada.guarnicaoDisponivelNaViatura(
viaturaId('RP-1207'),
);
if (guarnicao === undefined)
throw new Error('viatura sem guarnição disponível');
// Cada viatura empenhada é um despacho, com id e status próprios.
export const despacho = await ocorrencia.despachar({
instrucoes: 'Abordagem com apoio.',
ocorrenciaId,
recurso: recursoDaGuarnicao(guarnicao),
});import { criarClienteJornada, viaturaId } from '@geocontrol/geohub-sdk/jornada';
import {
criarClienteOcorrencia,
recursoDaGuarnicao,
} from '@geocontrol/geohub-sdk/ocorrencia';
import { CONEXAO } from './conexao.js';
import { ocorrenciaId } from './registrar-ocorrencia.js';
const jornada = criarClienteJornada(CONEXAO);
const ocorrencia = criarClienteOcorrencia(CONEXAO);
// "Viatura RP-1207" vira "a guarnição que está nela agora", ou nada.
const guarnicao = await jornada.guarnicaoDisponivelNaViatura(
viaturaId('RP-1207'),
);
if (guarnicao === undefined)
throw new Error('viatura sem guarnição disponível');
// Cada viatura empenhada é um despacho, com id e status próprios.
export const despacho = await ocorrencia.despachar({
instrucoes: 'Abordagem com apoio.',
ocorrenciaId,
recurso: recursoDaGuarnicao(guarnicao),
});curl https://geohub.exemplo.gov.br/plugins/viaturas/RP-1207/guarnicao-disponivel -H "Authorization: Bearer $TOKEN"
# {"dados":{"guarnicaoId":"…","viatura":"RP-1207","composicao":[…]}} ou {"dados":null}
curl -X POST https://geohub.exemplo.gov.br/plugins/ocorrencias/$OCORRENCIA/despachos -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)" -H "Content-Type: application/json" \
-d '{"recurso":{"tipo":"guarnicao","guarnicaoId":"…","viatura":"RP-1207","composicao":[…],"identificador":"RP-1207"},
"instrucoes":"Abordagem com apoio."}'
# {"dados":"<despachoId>"}
# 422 {"erro":{"codigo":"viatura-sem-guarnicao-disponivel"}}Uma referência, uma ocorrência
A por solicitacaoId cobre o retry com a mesma chave. A referenciaExterna cobre o caso que ela não alcança: o que perdeu a resposta e reenvia com chave nova. O reenvio não abre uma segunda ocorrência: a resposta é 409 referencia-externa-ja-registrada, com o id da que já existe em erro.contexto.ocorrenciaId.
Cancelar o último despacho aberto devolve a ocorrência a registrada.
Pela REST
Cada rota está na API, com corpo, respostas e erros.
| rota | verbo |
|---|---|
POST /plugins/ocorrencias | registrarOcorrencia |
PATCH /plugins/ocorrencias/{id} | atualizarOcorrencia |
GET /plugins/viaturas/{viatura}/guarnicao-disponivel | guarnicaoDisponivelNaViatura |
POST /plugins/ocorrencias/{ocorrenciaId}/despachos | despachar |
GET /plugins/ocorrencias/{ocorrenciaId}/despachos | listarDespachos |
POST /plugins/despachos/{id}/cancelamento | cancelarDespacho |
POST /plugins/ocorrencias
{"classificacao":{"natureza":"roubo","prioridade":1},
"local":{"endereco":{"logradouro":"Av. Dante Michelini","municipio":"Vitória","uf":"ES"}},
"solicitante":{"canal":"telefone"},
"referenciaExterna":"CAD-2026-004512"} → 200 {"dados":"<ocorrenciaId>"}
PATCH /plugins/ocorrencias/{id} {"alteracoes":{"descricao":"dois suspeitos"}}
GET /plugins/viaturas/RP-1207/guarnicao-disponivel → 200 {"dados":{"guarnicaoId":"…","viatura":"RP-1207","composicao":[…]}} ou null
POST /plugins/ocorrencias/{ocorrenciaId}/despachos
{"recurso":{"tipo":"guarnicao","guarnicaoId":"…","viatura":"RP-1207","composicao":[…],"identificador":"RP-1207"},
"instrucoes":"abordagem com apoio"} → 200 {"dados":"<despachoId>"}