Skip to content

1. O policial entra em serviço e a guarnição fica disponível ​

Sem em não há a quem despachar. O pool de são as guarnições com status disponivel, e uma guarnição só chega lá depois de quatro atos. A é da pessoa; a é da guarnição. Quem serve na central tem jornada igual, só não entra em guarnição.

A cena ​

A cena 3D deste caso (roteiro entrar-em-servico) entra aqui quando a operação 3D publicar os roteiros dos casos de uso; até lá, o diagrama abaixo é a cena.

A ordem é cobrada pelo domínio, e as recusas dizem o que falta: declararProntidao antes de assumirComando devolve comando-nao-assumido; assumirComando com a jornada do ainda apresentada devolve jornada-nao-iniciada. Pausas (iniciarPausa, da pessoa; iniciarPausaDaGuarnicao, da ) tiram do pool e devolvem ao estado anterior ao encerrar. O não alcança pausa.

quemverbos
policialregistrarApresentacao, iniciarJornada, iniciarPausa, encerrarJornada
comandanteassumirComando, declararProntidao, retirarDeProntidao, iniciarPausaDaGuarnicao
supervisorconstituirGuarnicao, substituirIntegrante, dissolverGuarnicao, liberarPolicial
integrador ()tudo acima menos pausa, e liberação: ele declara a escala dele

Pelo app do policial ​

O primeiro GET depois do login responde "onde estou": tenho jornada? integro guarnição?

ts
/** O primeiro GET depois do login: tenho jornada? integro guarnição? */
async ondeEstou(): Promise<SituacaoDoPolicial> {
  const [jornada, guarnicao] = await Promise.all([
    this.jornada.obterJornadaAtiva(this.usuario),
    this.jornada.obterGuarnicaoDoUsuario(this.usuario),
  ]);
  if (jornada === undefined) return { situacao: 'fora-de-servico' };
  if (guarnicao === undefined) return { jornada, situacao: 'em-jornada' };
  return { guarnicao, jornada, situacao: 'em-guarnicao' };
}
js
/** O primeiro GET depois do login: tenho jornada? integro guarnição? */
async ondeEstou() {
  const [jornada, guarnicao] = await Promise.all([
    this.jornada.obterJornadaAtiva(this.usuario),
    this.jornada.obterGuarnicaoDoUsuario(this.usuario),
  ]);
  if (jornada === undefined) return { situacao: 'fora-de-servico' };
  if (guarnicao === undefined) return { jornada, situacao: 'em-jornada' };
  return { guarnicao, jornada, situacao: 'em-guarnicao' };
}
sh
curl https://geohub.exemplo.gov.br/plugins/policiais/$USUARIO/jornada-ativa -H "Authorization: Bearer $TOKEN"
# {"dados":{"id":"…","status":"iniciada",…}}  ou {"dados":null}
curl https://geohub.exemplo.gov.br/plugins/policiais/$USUARIO/guarnicao -H "Authorization: Bearer $TOKEN"
# {"dados":{"id":"…","viatura":"RP-1207","status":"disponivel",…}}  ou {"dados":null}

Comparecer e entrar em serviço são dois verbos, porque entre um e outro existe um intervalo real: quem se apresentou ainda não trabalha.

ts
/**
 * Comparecer (UC-06) e entrar em serviço (UC-14) são dois verbos: entre um
 * e outro existe um intervalo real, e quem se apresentou ainda não
 * trabalha. O app que só tem "entrou de serviço" chama os dois em seguida.
 */
async apresentarSeEIniciar(posto: PostoOcupado): Promise<JornadaId> {
  const jornadaId = exigir(
    await this.jornada.registrarApresentacao(this.usuario),
  );
  exigir(await this.jornada.iniciarJornada({ id: jornadaId, posto }));
  return jornadaId;
}
js
/**
 * Comparecer (UC-06) e entrar em serviço (UC-14) são dois verbos: entre um
 * e outro existe um intervalo real, e quem se apresentou ainda não
 * trabalha. O app que só tem "entrou de serviço" chama os dois em seguida.
 */
async apresentarSeEIniciar(posto) {
  const jornadaId = exigir(
    await this.jornada.registrarApresentacao(this.usuario),
  );
  exigir(await this.jornada.iniciarJornada({ id: jornadaId, posto }));
  return jornadaId;
}
sh
curl -X POST https://geohub.exemplo.gov.br/plugins/policiais/$USUARIO/apresentacao -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)"
# {"dados":"<jornadaId>"}
curl -X POST https://geohub.exemplo.gov.br/plugins/jornadas/$JORNADA/inicio -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)" -H "Content-Type: application/json" \
  -d '{"posto":{"modalidade":"radio_patrulhamento"}}'
# {"dados":null}

Com a guarnição constituída pelo supervisor, o comandante assume e põe a equipe no pool.

ts
/**
 * Só o comandante faz isto, e só com a guarnição já constituída: assumir
 * o comando e pôr a equipe no pool de despacho. Fora de ordem, o domínio
 * responde `comando-nao-assumido` ou `jornada-nao-iniciada`.
 */
async assumirComandoEDeclararProntidao(): Promise<void> {
  const onde = await this.ondeEstou();
  if (onde.situacao !== 'em-guarnicao') {
    throw new SituacaoInesperadaError(onde.situacao, 'em-guarnicao');
  }
  exigir(
    await this.jornada.assumirComando({
      guarnicaoId: onde.guarnicao.id,
      jornadaId: onde.jornada.id,
    }),
  );
  exigir(await this.jornada.declararProntidao(onde.guarnicao.id));
}
js
/**
 * Só o comandante faz isto, e só com a guarnição já constituída: assumir
 * o comando e pôr a equipe no pool de despacho. Fora de ordem, o domínio
 * responde `comando-nao-assumido` ou `jornada-nao-iniciada`.
 */
async assumirComandoEDeclararProntidao() {
  const onde = await this.ondeEstou();
  if (onde.situacao !== 'em-guarnicao') {
    throw new SituacaoInesperadaError(onde.situacao, 'em-guarnicao');
  }
  exigir(
    await this.jornada.assumirComando({
      guarnicaoId: onde.guarnicao.id,
      jornadaId: onde.jornada.id,
    }),
  );
  exigir(await this.jornada.declararProntidao(onde.guarnicao.id));
}
sh
curl -X POST https://geohub.exemplo.gov.br/plugins/guarnicoes/$GUARNICAO/comando -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)" -H "Content-Type: application/json" \
  -d '{"jornadaId":"…"}'
curl -X POST https://geohub.exemplo.gov.br/plugins/guarnicoes/$GUARNICAO/prontidao -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)"
# {"dados":null}   (a guarnição entra no pool, status disponivel)

Pelo CAD ​

O integrador faz o mesmo em nome da escala dele. Aqui o usuario é a matrícula no sistema do CAD, que a exposição traduz para o UsuarioId pela tabela integrador_identidade.

ts
import {
  criarClienteJornada,
  matricula,
  modalidadeDeServicoId,
  usuarioId,
} from '@geocontrol/geohub-sdk/jornada';
import { CONEXAO } from './conexao.js';

const jornada = criarClienteJornada(CONEXAO);

// Na sessão de integrador, o usuário dos verbos é a matrícula do policial.
const policial = usuarioId(matricula('123456'));

// Dois verbos: comparecer à unidade e entrar em serviço no posto ocupado.
const apresentacao = await jornada.registrarApresentacao(policial);
if (!apresentacao.success) throw new Error(apresentacao.error.codigo);

export const jornadaId = apresentacao.data;

export const inicio = await jornada.iniciarJornada({
  id: jornadaId,
  posto: { modalidade: modalidadeDeServicoId('radio_patrulhamento') },
});
js
import {
  criarClienteJornada,
  matricula,
  modalidadeDeServicoId,
  usuarioId,
} from '@geocontrol/geohub-sdk/jornada';
import { CONEXAO } from './conexao.js';
const jornada = criarClienteJornada(CONEXAO);
// Na sessão de integrador, o usuário dos verbos é a matrícula do policial.
const policial = usuarioId(matricula('123456'));
// Dois verbos: comparecer à unidade e entrar em serviço no posto ocupado.
const apresentacao = await jornada.registrarApresentacao(policial);
if (!apresentacao.success) throw new Error(apresentacao.error.codigo);
export const jornadaId = apresentacao.data;
export const inicio = await jornada.iniciarJornada({
  id: jornadaId,
  posto: { modalidade: modalidadeDeServicoId('radio_patrulhamento') },
});
sh
# O usuário é a matrícula: a exposição a traduz pela tabela de identidades.
curl -X POST https://geohub.exemplo.gov.br/plugins/policiais/123456/apresentacao -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)" \
  -H 'x-autoria: {"tipo":"integrador","id":"'$INTEGRADOR'"}'
# {"dados":"<jornadaId>"}
curl -X POST https://geohub.exemplo.gov.br/plugins/jornadas/$JORNADA/inicio -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)" -H "Content-Type: application/json" \
  -d '{"posto":{"modalidade":"radio_patrulhamento"}}'
# {"dados":null}
ts
import {
  criarClienteJornada,
  matricula,
  modalidadeDeServicoId,
  usuarioId,
  viaturaId,
} from '@geocontrol/geohub-sdk/jornada';
import { CONEXAO } from './conexao.js';

const jornada = criarClienteJornada(CONEXAO);
const posto = { modalidade: modalidadeDeServicoId('radio_patrulhamento') };

// Os dois policiais já em serviço (apresentação e início, cada um).
const comandante = usuarioId(matricula('123456'));
const motorista = usuarioId(matricula('654321'));
const jornadaDoComandante = await jornada.registrarApresentacao(comandante);
if (!jornadaDoComandante.success)
  throw new Error(jornadaDoComandante.error.codigo);
await jornada.iniciarJornada({ id: jornadaDoComandante.data, posto });
const jornadaDoMotorista = await jornada.registrarApresentacao(motorista);
if (!jornadaDoMotorista.success)
  throw new Error(jornadaDoMotorista.error.codigo);
await jornada.iniciarJornada({ id: jornadaDoMotorista.data, posto });

// A guarnição na viatura: constituir, o comandante assume, prontidão.
const constituida = await jornada.constituirGuarnicao({
  composicao: [
    { posto: 'comandante', usuario: comandante },
    { posto: 'motorista', usuario: motorista },
  ],
  viatura: viaturaId('RP-1207'),
});
if (!constituida.success) throw new Error(constituida.error.codigo);

export const guarnicaoId = constituida.data;

await jornada.assumirComando({
  guarnicaoId,
  jornadaId: jornadaDoComandante.data,
});
export const prontidao = await jornada.declararProntidao(guarnicaoId);
js
import {
  criarClienteJornada,
  matricula,
  modalidadeDeServicoId,
  usuarioId,
  viaturaId,
} from '@geocontrol/geohub-sdk/jornada';
import { CONEXAO } from './conexao.js';
const jornada = criarClienteJornada(CONEXAO);
const posto = { modalidade: modalidadeDeServicoId('radio_patrulhamento') };
// Os dois policiais já em serviço (apresentação e início, cada um).
const comandante = usuarioId(matricula('123456'));
const motorista = usuarioId(matricula('654321'));
const jornadaDoComandante = await jornada.registrarApresentacao(comandante);
if (!jornadaDoComandante.success)
  throw new Error(jornadaDoComandante.error.codigo);
await jornada.iniciarJornada({ id: jornadaDoComandante.data, posto });
const jornadaDoMotorista = await jornada.registrarApresentacao(motorista);
if (!jornadaDoMotorista.success)
  throw new Error(jornadaDoMotorista.error.codigo);
await jornada.iniciarJornada({ id: jornadaDoMotorista.data, posto });
// A guarnição na viatura: constituir, o comandante assume, prontidão.
const constituida = await jornada.constituirGuarnicao({
  composicao: [
    { posto: 'comandante', usuario: comandante },
    { posto: 'motorista', usuario: motorista },
  ],
  viatura: viaturaId('RP-1207'),
});
if (!constituida.success) throw new Error(constituida.error.codigo);
export const guarnicaoId = constituida.data;
await jornada.assumirComando({
  guarnicaoId,
  jornadaId: jornadaDoComandante.data,
});
export const prontidao = await jornada.declararProntidao(guarnicaoId);
sh
curl -X POST https://geohub.exemplo.gov.br/plugins/guarnicoes -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)" -H "Content-Type: application/json" \
  -d '{"viatura":"RP-1207","composicao":[{"usuario":"123456","posto":"comandante"},{"usuario":"654321","posto":"motorista"}]}'
# {"dados":"<guarnicaoId>"}
curl -X POST https://geohub.exemplo.gov.br/plugins/guarnicoes/$GUARNICAO/comando -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)" -H "Content-Type: application/json" \
  -d '{"jornadaId":"<jornadaId do comandante>"}'
curl -X POST https://geohub.exemplo.gov.br/plugins/guarnicoes/$GUARNICAO/prontidao -H "Authorization: Bearer $TOKEN" -H "x-solicitacao-id: $(uuidv7)"
# {"dados":null}

Pela REST ​

Cada rota está na API, com corpo, respostas e erros.

rotaverbo
POST /plugins/policiais/{usuario}/apresentacaoregistrarApresentacao
POST /plugins/jornadas/{id}/inicioiniciarJornada
POST /plugins/guarnicoesconstituirGuarnicao
POST /plugins/guarnicoes/{guarnicaoId}/comandoassumirComando
POST /plugins/guarnicoes/{guarnicaoId}/prontidaodeclararProntidao
GET /plugins/policiais/{usuario}/jornada-ativaobterJornadaAtiva
GET /plugins/policiais/{usuario}/guarnicaoobterGuarnicaoDoUsuario
GET /plugins/viaturas/{viatura}/guarnicao-disponivelguarnicaoDisponivelNaViatura
POST /plugins/policiais/{usuario}/apresentacao          → 200 {"dados":"<jornadaId>"}
POST /plugins/jornadas/{jornadaId}/inicio
     {"posto":{"modalidade":"radio-patrulhamento"}}      → 200 {"dados":null}
POST /plugins/guarnicoes
     {"viatura":"RP-1207","composicao":[{"usuario":"…","posto":"comandante"},{"usuario":"…","posto":"motorista"}]}
                                                          → 200 {"dados":"<guarnicaoId>"}
POST /plugins/guarnicoes/{guarnicaoId}/comando  {"jornadaId":"…"}
POST /plugins/guarnicoes/{guarnicaoId}/prontidao          → guarnição disponivel

Os cabeçalhos e o formato das respostas estão em REST e WebSocket.