1 Introdução

O Perfuse move mensagens clínicas entre sistemas que nunca foram projetados para se comunicar. Um laboratório envia resultados em HL7 v2; o sistema de gerenciamento de práticas espera-os com posições de campo diferentes, um identificador de paciente diferente e um reconhecimento dentro de cinco segundos. Algo tem que ficar no meio, e esse algo é um motor de integração.

Este manual descreve o que o Perfuse faz, todas as opções que ele aceita e — onde uma decisão não é óbvia — por que ele funciona da maneira que faz.

1.1 Para que serve o Perfuse

Uma interface única entre dois sistemas clínicos é comumente custada em dezenas de milhares, com quinze a vinte por cento disso novamente todos os anos em manutenção. Grande parte desse custo não é o trabalho; é que o trabalho requer alguém que tenha feito HL7 antes, e a maioria das práticas não emprega um.

O Perfuse é construído com base na suposição de que a pessoa que o configura tem um problema para resolver e nenhuma experiência prévia com HL7. Essa suposição se manifesta em lugares específicos:

O capítulo sobre testes e o sobre migração existem porque a resposta para "por que devo confiar nisso" tem que ser evidência que você mesmo coleta, não uma afirmação feita aqui.

1.2 O que está incluído

Tudo abaixo está no mesmo binário. Cada linha nomeia o capítulo que o cobre.

1.3 Padrões e versões

Qual versão de cada padrão o Perfuse implementa e como isso foi verificado. "Verificado" nomeia a ferramenta ou referência externa que julgou o resultado; onde nada externo o julgou, diz isso. Os resultados são de dados de teste, não de um site de produção.

1.3.1 Mensagens e documentos

PadrãoVersãoVerificado
HL7 v2qualquer versão: as mensagens são lidas por seus próprios separadores, não por um esquema de versão; confirmações padrão para 2.5.1Validador HL7 v2 da NIST; tráfego real do Mirth e OIE
HL7 v2 para FHIRMapeamento V2-FHIR da HL7 (ADT, ORU, SIU, MDM, VXU e os segmentos neles)Validador FHIR da HL7 contra US Core, UK Core, FR Core, ISiK, nl-core e HL7 Europa
FHIRR4 (4.0.1), com R4B e R5 lidos e escritosValidador FHIR da HL7; Inferno
C-CDA e CDAC-CDA 2.1SITE da ONC (amostras C-CDA enviadas e recebidas via XDR); não por um esquema CDA
HL7 v3PIX e PDQ (IHE ITI-44, 45, 47)Esquemas NE2008 da IHE e mensagens de exemplo
DICOM e DICOMwebDIMSE C-STORE, C-FIND, C-MOVE, C-GET, C-ECHO; QIDO-RS, WADO-RS, WADO-URI, STOW-RSOrthanc
X12 (HIPAA)005010: 837, 835, 270/271 (X279A1), 276/277 (X212), 834, 278 solicitação (X217) e consulta (X215); 275 em 006020 (X314)Guias de companhia publicados pelos pagadores; amostras esMD da CMS
CAQH CORE conectividadevC2.2.0 SOAP e MIME, vC4.0.0 com MTOMUm sistema UM substituto escrito a partir das regras da CAQH
NCPDPTelecomunicação D.0; SCRIPT 2023011 (e 2017071) com ePA; Benefício de prescrição em tempo real v13Escrito a partir das guias de companhia públicas da Surescripts e seus exemplos; não contra os esquemas licenciados da NCPDP
UN/EDIFACTsintaxe 3 e 4, CONTRLpydifact 0.1.8
Compartilhamento de documentos da IHEXDS.b, XCA, XDR, MHD 4.2.2, PIXm, PDQm, XDMKit de ferramentas XDS da NIST; SITE da ONC
Mensagens seguras diretasDeclaração de aplicabilidade 1.2, XDR e XDM para Direto, DNS e descoberta de certificado LDAPSITE da ONC; Ferramenta de descoberta de certificado da ONC (18 de 18)
AS2RFC 4130, compressão RFC 5402pyas2lib
Anexos assinadosHL7 DSDR, XAdES-X-Lxmlsec1, OpenSSL

1.3.2 Guias de implementação do FHIR

GuiaLançamentoVerificado
US Coreconversões para 9.0.0 (USCDI v6); servidor FHIR contra 6.1.0 e 7.0.0o validador HL7; Inferno US Core
SMART App Launch2.2Inferno: 80 de 80 (aplicativo público)
Bulk Data Access2.0.0Inferno: 48 de 48
Subscriptions R5 Backportpara R4um receptor HTTP real; os testes de notificação do kit PAS
Da Vinci CRD2.2.1 e 2.1.0Inferno 2.2.1: 92 passam, nenhum falha; 2.1.0 pelos próprios exemplos do guia
Da Vinci DTR2.2.0 e 2.1.0Inferno 2.2.0: 43 passam, 2 falham (um defeito do kit); 2.1.0 pelos próprios exemplos do guia
Da Vinci PAS2.2.1 e 2.1.0Inferno 2.2.1: 82 de 84; 2.1.0 pelos próprios exemplos do guia
Da Vinci PAS, enviando (lado do provedor)2.2.1a implementação de referência do pagador do HL7 Da Vinci PAS; não é um pagador de produção
Da Vinci PDex2.2.0Inferno PDex 2.0: pagador para pagador 19 de 19
Da Vinci HRex $member-match1.2.0Inferno PDex pagador para pagador
Da Vinci ATR2.1.0não verificado por uma ferramenta externa
Da Vinci CDex $submit-attachment2.1não verificado por uma ferramenta externa
Da Vinci Plan-Net1.1.0Inferno: 199 passam, 10 falham (um defeito do kit)
Da Vinci US Drug Formulary2.1.0o validador HL7
ISiK (hospitais alemães), servidor FHIRStufe 5, módulo básicoconjunto de testes ISiK 3.0.9 da gematik: 421 de 421
PACIO Transitions of Care, Perfil de Medicamento, Diretivas Antecipadas, Funcionamento1.0.0, 1.0.0, 2.0.0-ballot, 2.0.0kits Inferno do PACIO com os próprios dados do PACIO: cada falha nos dados ou no kit. C-CDA para documento TOC: o validador HL7 nos exemplos do HL7, um erro restante, os próprios
CARIN Blue Button2.2.0o validador HL7
eCR2.1.2o validador HL7
ELRHL7 2.5.1 ELR Release 1 com suas erratasferramenta ELR da ONC: 28 de 28
Resumo Internacional de Paciente2.0.0o validador HL7
DEQM5.0.0o validador HL7
SQL no FHIRv2o conjunto de testes oficial: 144 de 144
Cartões e Links de Saúde SMARTCartões 1.4, Links STU 1o cartão de exemplo das especificações; uma biblioteca de visualização de Links de Saúde SMART publicada
Segurança UDAPSTU 1um servidor de autorização real e uma comunidade de confiança
FHIR Facilitado pela TEFCASOP v2.0não verificado contra um QHIN real

1.3.3 Perfis nacionais e europeus

Verificado convertendo mensagens HL7 v2 publicadas ou inventadas e validando todos os recursos; os resultados completos e os motivos de cada falha estão na pasta conformance/national do repositório.

PerfilLançamentoRecursos válidos
UK CoreSTU2 2.0.2185 de 187
FR Core2.2.0138 de 156
ISiK Basismodul4.0.3 (Stufe 4)18 de 47; 42 de 47 com o script de bundle próprio do hospital
Nictiz nl-core0.12.1-beta.1 (zib 2020)12 de 24; 18 de 24 com o script de bundle próprio do hospital
Relatório de Laboratório HL7 Europa2.1.0106 de 426 (o guia espera um documento, um resultado v2 não é)
Relatório de Alta Hospitalar HL7 Europa1.0.068 de 69

Nenhum desses é um certificado. O Perfuse não foi certificado pela ONC, CMS, gematik, Nictiz, NHS England ou qualquer outra entidade.

1.4 O que ele substitui

O Perfuse cobre o terreno ocupado pelo Mirth Connect e pode importar exportações de canais do Mirth diretamente. O capítulo sobre migração descreve o que se traduz limpa e claramente, o que precisa de uma decisão e como provar o resultado antes de substituir.

As diferenças que importam no uso diário são depuração e silêncio. No Mirth, ver o que um transformador fez com uma mensagem geralmente significa reimplantar o canal com logging adicionado. No Perfuse, qualquer mensagem registrada pode ser reproduzida pela configuração atual e inspecionada passo a passo, sem tocar no canal em execução. E onde um alerta do Mirth sobre "nenhum tráfego" é um limiar fixo que é inútil em qualquer feed que esteja quieto à noite, o Perfuse aprende o que cada feed normalmente parece e alerta contra isso.

1.5 Como ler este manual

Os primeiros capítulos são conceituais e valem a pena ler em ordem: canais, fluxo de mensagens, então transformação. Tudo depois disso pode ser lido conforme necessário.

Os capítulos de referência perto do final listam cada chave de configuração, seu tipo, se é necessária e seu valor padrão. Esses capítulos são gerados a partir do código-fonte, então não podem descrever uma opção que não existe ou omitir uma que existe. Se uma chave aparece em um arquivo de configuração e não no índice, ela não é uma chave do Perfuse.

1.6 Convenções

A configuração é YAML. A maioria das chaves é snake_case na rede — max_message_size, idle_timeout — e este manual sempre fornece a forma na rede, porque é isso que você digita. Há uma exceção antiga, dataType em um canal, que é camelCase; é documentada dessa forma na referência de canal e aceita apenas nessa grafia.

As referências de campo em HL7 utilizam a notação usual: PID-5 é o quinto campo do segmento PID, PID-5.1 é o seu primeiro componente e PID-3(2) é a segunda repetição do terceiro campo. Um caminho escrito sem uma repetição aborda todas as repetições (veja caminhos).

Durações são escritas como um número e uma unidade — 30s, 5m, 2h. Um número nu não é uma duração e será recusado em vez de adivinhado.

2 Introdução

O Perfuse é um binário único com uma interface web incorporada. Não há servidor de aplicação para instalar, não há base de dados para provisionar e não há console de administração separado.

2.1 Executando-o

perfuse serve -channels ./channels -db ./perfuse.db -addr 0.0.0.0:8443 \
  -tls-cert ./cert.pem -tls-key ./key.pem

-channels é um diretório de ficheiros YAML, um por canal. -db é um ficheiro SQLite que contém mensagens registadas, utilizadores e histórico de auditoria; é criado se não existir.

Na primeira execução sem utilizadores configurados, uma conta de administrador é criada e a sua palavra-passe é escrita no registo uma vez. Essa palavra-passe não pode ser recuperada depois.

Executar sem -tls-cert e -tls-key serve HTTP simples. Isso é aceitável em um endereço de loopback para uma primeira olhada e não é aceitável em nenhum outro lugar: a interface web carrega credenciais e conteúdo de mensagem, ambos legíveis na rede sem TLS. Veja segurança.

2.2 O primeiro canal

Um canal precisa de um nome, uma fonte e pelo menos um destino. O menor canal útil recebe HL7 sobre MLLP e escreve cada mensagem num ficheiro:

name: first-feed
dataType: hl7
source:
  type: mllp
  listen: "0.0.0.0:6661"
destinations:
  - name: to-disk
    type: file
    file:
      root: /var/spool/perfuse
      dir: incoming

Guarde isso como channels/first-feed.yaml e ele é detectado sem reiniciar.

Três coisas sobre esse ficheiro valem a pena notar, porque são a forma de todos os canais:

2.3 Construir um canal a partir da interface

Tudo o que está acima pode ser feito a partir da interface web em vez disso, e para um primeiro canal, essa é a melhor rota porque o formulário não deixará que você produza um ficheiro que não carregue.

O construtor oferece três maneiras de entrar:

  1. A partir de uma mensagem que alguém enviou a você. Cole a amostra que o laboratório ou fornecedor enviou por e-mail. O Perfuse lê e propõe um canal, junto com três listas separadas: o que a amostra mostra, o que foi adivinhado e o que nenhuma amostra pode dizer. Isso é descrito em testes.
  2. A partir de algo que já funciona. Um conjunto de canais completos que precisam apenas dos endereços preenchidos.
  3. A partir do nada. Um formulário em branco. Disponível, mas é o mais lento dos três e o mais fácil de errar.

2.4 Verificar se funciona antes de conectar qualquer coisa

Duas coisas podem ser feitas antes de o sistema de envio existir.

Envie uma mensagem à mão a partir da interface — o remetente de mensagens aceita texto colado e relata o que aconteceu com ele, incluindo quais destinos o aceitaram e o que cada transformação fez.

Ou gere tráfego de teste. Se o canal já lidou com alguma mensagem, o Perfuse pode aprender sua forma e produzir mais mensagens semelhantes, nas mesmas proporções, sem nenhum conteúdo original. Veja testes.

2.5 O que fazer em seguida

3 A Interface Web

O Perfuse é construído com a suposição de que tudo é possível a partir do navegador, e uma funcionalidade que só pode ser alcançada editando um arquivo é tratada como um defeito. Este capítulo é um tour do que está por trás de cada parte da navegação, organizado da forma como a interface é: pela pergunta que você está fazendo.

A barra carries Painel de Controle e Canais diretamente, porque esses são onde a maioria das sessões começa e termina. Tudo o mais é agrupado, e os grupos são nomeados após perguntas em vez de após subsistemas — você não vai para o "subsistema de auditoria", você vai e descobre quem alterou algo.

3.1 Lendo o cabeçalho

Cinco coisas no cabeçalho são fáceis de perder.

Cada vista tem um endereço. A barra de endereços segue a vista — #/channels, #/messages, #/settings — por isso, uma recarga retorna a ela, um favorito a abre, um link enviado a um colega o leva até lá, e o botão de voltar move entre vistas em vez de sair da consola. Um endereço que nomeia uma vista acima do seu papel abre o painel de instrumentos em vez disso.

Pesquisa, ou ⌘K. Ele pesquisa em canais, configurações, mensagens e no manual, o que significa que é geralmente mais rápido do que navegar — particularmente para uma configuração cujo nome você meio lembra.

Tema. Três deles: Meia-Noite, Escuro e Claro. Meia-Noite é quase preto e é o que uma exibição de parede em uma sala de servidores geralmente quer; Escuro é um cinza neutro mais suave; Claro é para um laptop ao lado de uma janela. A escolha é armazenada no navegador em vez de contra a conta, porque um tema é uma propriedade de onde alguém está sentado, não de quem eles são — o mesmo operador quer Meia-Noite na parede e Claro no trem. A preferência da própria máquina é consultada uma vez, para escolher um padrão sensato na primeira vez.

Língua. A consola em Inglês (ordem de data do Reino Unido ou dos EUA), Alemão, Francês, Holandês, Espanhol, Italiano, Português, Polaco, Sueco, Dinamarquês, Norueguês ou Finlandês, com datas e números escritos da forma como essa localidade os escreve. A escolha é mantida no navegador e a língua própria do navegador é usada até que uma seja feita. As traduções foram feitas por máquina e ainda não foram revisadas por falantes nativos; o Inglês é a referência e o seletor assim o indica. Código, mensagens, payloads, nomes de canal e qualquer coisa digitada nunca são traduzidos. O manual é publicado nas mesmas línguas em https://perfuse.health/manual/<language>/ (o próprio Manual deste servidor é o Inglês).

Manual. O documento que você está lendo, servido pelo servidor em execução. É o mesmo arquivo que o binário pode escrever no disco, então ele sempre descreve a versão à sua frente em vez da versão mais recente.

3.2 Monitor — se está funcionando e o que aconteceu

3.2.1 Painel de Controle

O estado de cada canal, throughput e qualquer coisa atualmente errada. Esta é a tela para deixar aberta.

3.2.2 Mensagens

Toda mensagem que chegou, o que foi transformado, por destino, e o que aconteceu com ela. Pesquisável, incluindo por uma expressão de filtro, então "mostre-me as que vieram deste remetente que foram rejeitadas" é uma consulta em vez de uma tarde.

Uma mensagem pode ser reproduzida a partir daqui e reprocessada pela *configuração atual* em vez da que estava ao vivo no momento — o que é como você confirma que uma correção funciona contra o tráfego que a quebrou. Veja o repositório de mensagens para o que é mantido e por quanto tempo.

3.2.3 Fila

O que está esperando para ser entregue e por quê. Uma fila que não está drenando é o mais útil aviso antecipado que um motor de integração produz, e vale a pena emparelhá-lo com uma regra de alerta para que ninguém precise estar observando. Veja entrega.

3.2.4 Alertas

O que foi acionado e quais são as regras. Regras são editadas aqui em vez de em um arquivo. Veja alertas.

3.2.5 Métricas

Throughput, latência e taxas de erro ao longo do tempo. Útil para questões de capacidade e, mais frequentemente, para pacotes de diretoria — o que é por que o logotipo do site aparece nele se um foi carregado.

3.2.6 SQL no FHIR

SQL em vistas FHIR: escolha um exemplo ou uma vista salva, ou escreva uma, execute-a sobre o repositório FHIR deste servidor (todos os pacientes ou um) ou sobre recursos colados, veja as linhas com seus tipos e faça o download em CSV, NDJSON ou Parquet. Salvar mantém para o endpoint FHIR $sql-run. Veja formatos de mensagem.

3.2.7 Medidas de Qualidade

Medidas de qualidade digital: escolha um exemplo ou uma Medida no repositório FHIR, ou escreva uma com critérios FHIRPath. Escolha um período de medição e um relatório (resumo, resumo com listas de pacientes ou um paciente) e avalie-o sobre o repositório FHIR ou recursos colados. A tela mostra a contagem de cada população e pacientes, a pontuação e as estratificações. Baixar MeasureReport salva o resultado FHIR, e Salvar no repositório FHIR mantém a Medida para Measure/$evaluate-measure. Medidas em CQL são recusadas: Perfuse não tem um mecanismo CQL. Veja medidas de qualidade digital.

3.2.8 Mapa de fluxo

Uma imagem de como as mensagens realmente se movem: quais fontes alimentam quais canais e quais destinos elas atingem.

Seu valor não é decoração. Cada propriedade acumula um canal que ninguém se lembra de ter encomendado e um destino que ninguém percebeu que ainda estava recebendo, e ambos são visíveis aqui de uma maneira que não é em uma lista de arquivos de canal.

3.2.9 Painéis de equipe

Um painel para cada tipo de pessoa que observa as interfaces: Operações, Conexões, Analista de interface, Autorização prévia, Imagem, Ciclo de receita, Laboratório, Privacidade e segurança, e um resumo de Departamento em palavras simples. Azulejos mostram contagens, estados e tempos, nunca uma mensagem ou um paciente, para que um painel possa ser enviado a um gerente ou a uma tela de parede sem ampliar quem vê os dados do paciente.

Cada pessoa abre no painel o grupo de diretório ou papel que lhe é atribuído. -dashboards dashboards.yaml os mapeia:

groups: {PACS-Admins: imaging, Network-Team: connections}
roles: {viewer: manager}

Um grupo vence sobre uma função, e qualquer pessoa não correspondida abre em Operações. Organizar azulejos esconde e reordena azulejos, o seletor de canal filtra-os, e Salvar como minha visão mantém isso como seu próprio painel até Redefinir.

Exportar para Grafana transfere o dashboard como JSON do Grafana sobre /metrics, com uma variável de fonte de dados e um filtro de canal, para qualquer pessoa que necessite de mais do que uma configuração leve. Azulejos sem métricas por trás deles são omitidos, e a descrição da exportação nomeia-os.

O azulejo Conexões verifica cada destino em rede em camadas. Ele procura o nome, abre uma conexão TCP, completa o TLS onde é usado e lê a última entrega e falha do destino a partir do tráfego real. Cada falha diz o que significa, por exemplo "recusado: o motor do parceiro provavelmente está parado", "tempo limite: um firewall ou um túnel VPN que está down", ou "um certificado de uma autoridade que este servidor não confia". Nada é enviado ao parceiro, com uma exceção: um registro de imunização que não teve tráfego por sete dias é perguntado sobre o teste de conectividade CDC connectivityTest, que não envia nada. Com -vpn tunnels.yaml o azulejo Túneis VPN ao lado lê o estado de cada túnel de parceiro do AWS Site-to-Site VPN, uma conexão do Azure VPN Gateway ou strongSwan neste host, para que um tempo limite possa ser distinguido de um túnel que está down. Ele também compara as configurações IKE e IPsec de ambos os lados, pois a nuvem relata as nossas e o arquivo lista as deles, e diz onde elas não podem concordar. Folha de conexão baixa as configurações de um parceiro lado a lado como Markdown para enviá-las; ele nunca mantém uma chave pré-compartilhada. Figuras que um painel precisa que ainda não são registradas são listadas em Não medido ainda em vez de serem desenhadas como azulejos vazios.

Os painéis de departamento calculam suas próprias figuras no servidor, e cada um diz qual janela e fonte ele cobre:

3.2.10 Compartilhando o que uma fonte realmente contém

Perfil desta fonte relata o que realmente está chegando: quais eventos de disparo, quais campos estão preenchidos e com que frequência, quais formas os valores tomam e quais códigos um remetente realmente usa. O último é geralmente o fato mais útil em si.

Um perfil pode ser baixado e enviado a outra pessoa. Ele precisa de um nome e — obrigatório — qual sistema produziu a fonte, porque a pergunta que um estranho faz a um perfil compartilhado é se ele descreve o sistema dele, e um campo opcional faria "Desconhecido" a resposta mais comum em qualquer coleção compartilhada.

Ele não contém dados de paciente, e isso é verificado em vez de suposto. Um perfil é estatístico: contagens, taxas, comprimentos, formas. Valores são mantidos apenas para campos que o padrão define como tabelas de código, porque um valor de tabela de código não é identificável. Valores de identificador nunca são listados.

Duas coisas decorrem disso ser uma promessa em vez de uma esperança. O servidor reconstrói o perfil a partir das mensagens armazenadas quando o exporta, em vez de enviar o que está na sua tela — portanto, o que deixa o prédio foi montado pelo perfilador, que tem um teste que comprova esta propriedade, e não por um navegador. E a exportação recusa-se categoricamente se um perfil alguma vez listar valores para um campo que não é uma tabela de códigos, nomeando o campo, mas não os valores.

Um perfil que chega de outro lugar é verificado da mesma forma ao entrar, por um motivo diferente: foi produzido por alguém cujo cuidado é desconhecido, e mostrar os identificadores dos pacientes seria uma violação de confidencialidade por parte deste servidor. Importar um não muda nada — um perfil descreve uma fonte de dados, e o que fazer com ela é uma decisão separada.

3.3 Construir — alterar o que um canal faz e testá-lo antes de estar ativo

3.3.1 Canais

O construtor de canais. Fontes, destinos, filtros, transformações, scripts e testes, com o YAML gerado exibido ao lado do formulário à medida que você trabalha — portanto, o arquivo nunca é um mistério, e qualquer pessoa que prefira o arquivo pode ler junto.

Veja canais para saber quais são as partes, e transformação para saber o que as etapas fazem.

3.3.2 Scripts

Um local de trabalho para scripts, separado do construtor porque escrever um script e conectar um script são atividades diferentes.

Todos os sete slots são oferecidos — filtro, transformador, pré-processador, pós-processador, escritor, ciclo de vida e leitor — e escolher o slot certo é importante, porque o slot decide o que o script recebe e o que é esperado que ele retorne. Verificar um script como o tipo errado não é uma solução; ele compila uma coisa diferente.

JavaScript, Lua e WebAssembly estão todos disponíveis. Veja transformação.

3.3.3 Contratos

Expectativas sobre como uma fonte deve parecer, criadas e verificadas aqui, bem como a partir de perfuse contract. Veja a linha de comando.

3.3.4 Tabelas

Tabelas de pesquisa e conjuntos de códigos: os mapeamentos que convertem os códigos de um sistema em outro. Editáveis aqui para que adicionar um código não seja uma implantação.

3.3.5 Mapeador de IA

Propõe mapeamentos de campos com uma pontuação de confiança para cada um e se abstém em vez de adivinhar. Apesar do nome, não utiliza nenhum modelo de linguagem e não faz nenhuma chamada de rede: as sugestões vêm de regras, nomes de campos e do conteúdo da amostra, neste servidor. Ele também propõe um canal a partir de uma única amostra de mensagem e declara explicitamente o que a amostra não pode dizer. Essa segunda metade é a parte que o torna confiável — uma proposta que parecesse completa convidaria a acreditar em coisas que a mensagem nunca disse.

3.3.6 Área de Testes

Um local para testar mensagens e transformações. Cole uma mensagem, aplique etapas, veja o resultado.

Nada é enviado para lugar algum uma vez que a página foi carregada, o que é o motivo pelo qual existe nesta forma: é seguro colar algo real nele, com a compreensão de que fica no navegador.

3.3.7 Sombra

Executa tráfego por meio de uma configuração de candidato ao lado da configuração ao vivo e relata as diferenças, para que uma alteração possa ser comprovada antes de ser confiada. A mesma ideia que perfuse compare, aplicada a uma alteração em vez de uma migração. Veja testes.

3.4 Troca — os padrões que este servidor fala com outras organizações

3.4.1 Laboratório FHIR

Converte HL7 v2 para FHIR, valida um recurso e inspeciona o resultado. As amostras cobrem admissões, resultados de laboratório, compromissos, notas clínicas, imunizações e uma visita relatável. A validação inclui US Core, que é o perfil contra o qual a regulamentação americana é escrita, portanto, isso responde à pergunta "o que eles nos enviaram é realmente conforme" sem adotar nada.

Relatório de caso de saúde pública constrói o eCR eICR que um destino de relatório de caso enviaria para a mensagem. Ele mostra qual código de gatilho tornou a visita relatável, o que o relatório teve que marcar como faltando e o documento em si. Uma mensagem com nada relatável obtém o motivo em vez disso. Nada é enviado a partir daqui.

3.4.2 Assinaturas

Assinaturas FHIR e se as suas notificações estão a chegar: eventos, aceites, à espera e o último motivo pelo qual uma foi recusada. As assinaturas são criadas por clientes FHIR através da API FHIR, não a partir desta página, e as credenciais que deram ao servidor nunca são exibidas. Veja formatos de mensagem.

3.4.3 Documentos

Documentos clínicos — CDA e a forma impressa de um documento. Útil quando a coisa que está a ser trocada é um resumo de alta em vez de uma mensagem.

3.4.4 Partilha de documentos

O registro e repositório XDS.b da IHE começou com -xds: quantos documentos, pacientes e conjuntos de envio ele contém e quantos foram substituídos; os endereços do repositório, registro, gateway XCA e MHD; uma busca por documentos de um paciente neste registro ou de outra comunidade (um registro ITI-18 ou um gateway ITI-38, com um token para ele); e publicação de um documento CDA manualmente, com o tipo de instalação e configuração de prática que um documento não diz. Veja formatos de mensagem.

3.4.5 Direct

Mensagens seguras diretas. Os endereços Direct deste servidor lista todos os endereços que um canal envia ou recebe, com seu certificado, quando expira, os âncoras que confia e qualquer coisa errada (um arquivo ausente, um certificado expirado). O Livro de Endereços mantém correspondentes e os certificados para os quais o correio é criptografado: cole um do HISP deles ou Salve com o certificado do DNS; um certificado que não é para o endereço ou seu domínio é recusado. Encontre um certificado no DNS pergunta sem salvar. Veja formatos de mensagem.

Links e Cartões de Saúde SMART, para *Kill the Clipboard* do CMS. Receba um Link de Saúde SMART lê o link ou código QR que um paciente mostra no check-in, verifica os cartões de saúde dentro e envia para um canal. Compartilhe um registro de visita cria um link hospedado por este servidor, opcionalmente com um código de passagem, e um código QR para o paciente; Use o resumo do paciente preenche com o Resumo Internacional do Paciente do repositório FHIR deste servidor. Links hospedados por este servidor lista-os com a frequência com que cada um foi recuperado, quando expira e as tentativas de código de passagem restantes, e revoga um. Verifique um Cartão de Saúde SMART verifica a assinatura e o emissor de um cartão por conta própria. Veja CMS-0057 para as opções do servidor que ele precisa.

3.4.7 Imagem

O arquivo que este servidor mantém ao executar -dicomweb-archive: contagens de estudos, séries, instâncias e espaço utilizado, o endereço DICOMweb e o bloco de fonte de dados para um visualizador OHIF, e uma busca por estudo por nome do paciente, ID, acesso e data feita com a mesma solicitação QIDO-RS que um visualizador faz. Um estudo abre para suas séries e instâncias, e uma instância é baixada como um arquivo DICOM. Nada é renderizado: Perfuse move imagens e um visualizador as exibe. Sem um arquivo, a tela diz como ativá-lo. Veja DICOMweb.

3.4.8 TEFCA

O registo de auditoria para troca através de uma Rede Qualificada de Informação de Saúde, e as regras de propósito de uso que a governam.

Dois transportes, em estágios genuinamente diferentes, e a tela diz qual é qual. Uma bandeira que cubra ambos estaria errada em qualquer direção que fosse arredondada.

FHIR facilitado é implementado, e nunca falou com um QHIN real. Ele segue o Procedimento Operacional Padrão do Projeto Sequoia efetivo a 8 de março de 2026: descobrir os metadados UDAP do parceiro, verificá-los, registrar dinamicamente, obter um token de acesso que carrega o propósito de uso e consultar. O UDAP é uma infraestrutura de chave pública sobre o OAuth 2.0 — uma comunidade de confiança emite certificados X.509 para os seus membros, e um membro autentica assinando JWTs com a chave privada e anexando a cadeia de certificados.

A camada de segurança é verificada contra a implementação de outra pessoa, que é a única verificação que vale a pena aqui. Um registo assinado por esta compilação foi enviado para um servidor de referência de terceiros ao vivo e recusado com unapproved_software_statement — Untrusted: Certificate is not a member of community. Para produzir essa resposta, o servidor decodificou o pedido, analisou a declaração de software como um JWT, verificou a assinatura, percorreu a cadeia de certificados e chegou a uma decisão sobre a adesão. É a diferença entre ser rejeitado à porta e ser devolvido um carta ilegível.

O que resta não pode ser feito a partir daqui. O certificado que prova a adesão à comunidade sai do processo de integração do QHIN e não é algo que o software produz. Até que um exista, nenhuma troca com um parceiro real é concluída.

Como um canal pede. Um destino do tipo tefca pede ao conjunto de parceiros FHIR facilitados nas Configurações, TEFCA (tefca.partnerFHIRBase) para cada mensagem do paciente: por identificador quando a mensagem tiver um (PID-3, ou um identificador de paciente FHIR), caso contrário por nome de família com data de nascimento, e nunca por um nome sozinho, porque uma correspondência errada em um nome retorna o registo de outra pessoa sem erro. O destino define o propósito de uso (tratamento, pagamento, operações, saúde pública, acesso individual); um propósito que o participante não declara é recusado antes que algo seja enviado. Os propósitos vão como os códigos de propósito de troca TEFCA (T-TRTMNT, T-PYMNT, T-HCO, T-PH, T-IAS, sistema urn:oid:2.16.840.1.113883.3.7204.1.5.2.1), ou com tefca.purposeCodes: hl7 como códigos de propósito de uso HL7 para comunidades que usam esses. O Conjunto encontrado é a resposta do destino e pode ser passado para outro canal com results_to. Todas as consultas, incluindo as recusadas, estão no rasto nesta tela, que nomeia o parceiro.

Todo o caminho, desde a descoberta até um token que o servidor FHIR do parceiro aceita, é testado contra o servidor de referência udap-dotnet (ver verificação).

A troca QHIN-para-QHIN mais antiga construída sobre os perfis IHE não é implementada. Uma tentativa é recusada com um erro que diz isso, e a recusa é auditada como uma falha. Isso é deliberado em vez de pendente de uma limpeza: uma troca simulada que relata sucesso colocaria entradas no registo de auditoria para trocas que nunca aconteceram, e um registo que discorda do que aconteceu é pior do que nada, porque o registo é o que é acreditado.

Ao longo de tudo, os pontos de extremidade usados para a troca vêm da parte assinada dos metadados de um parceiro, nunca do corpo do documento. Verificar uma assinatura e, em seguida, ler os pontos de extremidade da cópia não assinada seria uma maneira elaborada de confiar na rede: um atacante capaz de reescrever a resposta deixa o elemento assinado intacto, aponta o ponto de extremidade do token para o seu próprio servidor e coleta asserções de cliente de todos que verificaram a assinatura e, em seguida, ignoraram o que ela cobria.

Um pacote de âncoras de confiança é necessário e a sua ausência é recusada no arranque. Verificar os metadados assinados de um parceiro contra o certificado que chegou dentro dele prova apenas que uma parte fez ambos — um erro que esta base de código fez antes, em SAML, onde o verificador preferiu o certificado incorporado e autenticou um atacante como administrador enquanto todos os testes passaram. Inclua os intermediários no pacote: um servidor UDAP precisa apenas enviar o seu certificado folha, e o servidor de referência público faz exatamente isso.

3.5 Pagadores — reclamações, autorização prévia, medicamentos e regras do pagador CMS

3.5.1 Reclamações e autenticação

Construa um anexo de reclamação X12 275 no formato 006020 adotado pelo CMS-0053-F, a partir de um C-CDA colado ou de um PDF, TIFF ou JPEG carregado, e veja-o lido novamente. Leia um 275 e faça o download do documento interior. Converta uma decisão X12 278 em uma resposta de reclamação Da Vinci PAS ClaimResponse. Nada nesta página é armazenado ou enviado. Consulte formatos de mensagem para saber de que o 275 é construído e o que ele não faz.

3.5.2 Medicamentos

O formulário de medicamentos carregado com -formulary, e os dois padrões NCPDP respondidos a partir dele. Formulário lista os planos e os medicamentos com seu nível e requisitos, e onde o API de Formulário de Medicamentos Da Vinci US e os pontos de extremidade NCPDP estão. Verificação de preço (RTPB) preços um medicamento para um membro como uma solicitação de Benefício de Prescrição em Tempo Real de um prescritor: o status de cobertura, as restrições em palavras com seus códigos, a participação do membro e do plano, e as alternativas mais baratas. Autorização prévia (ePA) envia uma inicialização de SCRIPT para o próprio ponto de extremidade deste servidor, mostra o conjunto de perguntas como um formulário, envia as respostas e mostra a decisão; abaixo, cada caso com onde está e se o prescritor foi informado, as respostas do caso, um botão para enviar uma decisão não enviada novamente, e as figuras de medicamentos que o CMS-0062-P propõe. Veja CMS-0057.

3.5.3 CMS-0057

O lado pagador da regra de interoperabilidade e autorização prévia do CMS, como cinco ferramentas:

e o que cada uma ainda necessita.

certificar menos unidades. Veja a fila de revisor.

As conversões não armazenam nada e não enviam nada.

3.5.4 Rede Alinhada com o CMS

Prontidão para o Quadro de Interoperabilidade do CMS: cada um dos seus 26 critérios, agrupados como o CMS os agrupa, com o que o Perfuse fornece, se está ativado aqui, a configuração que o ativa e o que a organização deve fazer. As contagens no topo filtram a lista. Consulte CMS-0057.

3.6 Administrar — quem pode fazer o quê, e como este servidor está configurado

3.6.1 Usuários

Contas, funções (monitor, visualizador, operador, editor, administrador) e grupos de canais. Os grupos de canais de cada pessoa são editados no local na lista; vazio significa todos os canais, e lab=editor, adt fornece uma função diferente em um grupo. Um administrador limitado a alguns grupos vê apenas as pessoas desses grupos. O cabeçalho mostra seus próprios grupos ao lado de sua função quando você tem alguma. Veja segurança.

Credenciais de máquina também estão aqui. Um token é para uma máquina em vez de uma pessoa: ele não expira e não é afetado por alguém que sai, o que é o que um servidor que pesquisa seu vizinho precisa. Apenas um hash é armazenado, então um token é mostrado uma vez quando é criado e não pode ser recuperado — um banco de dados roubado não produz um token útil. Dê a ele a função mais baixa que faz o trabalho.

Com o MCP ativado, a seção também mostra o endereço que um agente de IA se conecta, uma configuração de cliente para copiar e cada ferramenta com a função que ela precisa; emitir um token com Deixe um agente de IA agir com ele lhe dá o escopo mcp:write. Veja segurança.

3.6.2 Inquilinos

Em um servidor compartilhado, a lista de organizações do operador da plataforma: cada uma com a contagem de canais e tamanho armazenado ao lado de seus limites (canais, mensagens por minuto, armazenamento), que são definidos no local. Mostrado apenas para o papel da plataforma. Veja segurança para saber o que cada limite faz.

3.6.3 Certificados

Os certificados TLS em uso e quando eles expiram. As datas de expiração são o ponto: um certificado que expirou em um domingo é uma classe de interrupção que é completamente evitável e rotineiramente não é evitada.

3.6.4 Atividade

Quem mudou o quê, e quando. Cada alteração de configuração é registrada, o que é o que torna "começou a falhar na terça-feira" respondível.

3.6.5 Proteção de dados

Os pedidos de uma pessoa ao abrigo do GDPR e do GDPR do Reino Unido, ordens de retenção legal, o registo de eliminação, retenção e o registo de atividades de tratamento; apenas administradores. Consulte proteção de dados.

3.6.6 Frota

Cada instância do Perfuse em uma página.

A Mirth vende isto como um produto separado; aqui é um ficheiro de configuração e um token de leitura. O motivo pelo qual vale a pena tê-lo é estreito e importante: um servidor morto não se parece com um servidor silencioso. O painel de um único exemplo não pode dizer que um segundo site parou de relatar, e uma vista de frota também não.

3.6.7 Migrar

Coloque um canal de exportação Mirth ou OIE e veja quantos de seus canais funcionariam aqui inalterados. A mesma análise que perfuse explain e perfuse translate, sem precisar de um terminal. Veja migração.

3.6.8 Definições

Cada definição que o servidor tem, com um controlo para cada — incluindo as que tradicionalmente só vivem num ficheiro. Cada uma diz se entra em vigor de imediato ou precisa de um reinício, e se foi definida explicitamente ou está sentada no seu valor predefinido.

As configurações abrangem todas as opções perfuse serve que ativam uma funcionalidade: o endpoint FHIR e sua versão, as APIs de pagadores, PAS e as regras CRD, a ponte X12 278, eCR, o servidor de autorização SMART, TLS e assinatura, métricas, frota e VPN. Elas são agrupadas como FHIR, Pagadores, Saúde Pública, SMART, Segurança e assim por diante. Cada uma também é exibida com a flag correspondente.

Reiniciar a partir do console. Uma configuração marcada *Requer reinicialização* é salva imediatamente, mas lida apenas quando o servidor é iniciado. Enquanto alguma estiver aguardando, uma faixa no topo das Configurações lista-as com um botão Reiniciar o servidor (o editor de entrada e os arquivos de configuração oferecem o mesmo botão após uma salvar). Ele pergunta primeiro, porque cada canal para por alguns segundos: cada um finaliza a mensagem que está lidando, como faz quando o serviço é interrompido, e os remetentes reenviam o que chega entretanto. O console, em seguida, aguarda o servidor responder novamente e lê as configurações novamente. Apenas um administrador pode reiniciar, e cada reinicialização é registrada no log de atividades como server.restart.

No Linux e macOS, o processo substitui a si mesmo por uma cópia fresca do mesmo programa e argumentos, mantendo seu ID de processo, então o systemd, launchd ou um tempo de execução de contêiner não vê nada acontecer. No Windows, o servidor reinicia dentro do mesmo processo, que mantém um serviço do Windows sob o gerenciador de serviços. Se o servidor não tiver respondido após dois minutos, o console diz isso; a razão está no log do servidor.

Flags e arquivo de configuração. Na primeira vez que o servidor é iniciado, as flags que ele recebeu são escritas no arquivo de configuração. A partir daí, o arquivo tem prioridade sobre as flags, então alterar uma configuração é feito no console (ou no arquivo), não editando a linha de comando do serviço. Uma flag que o arquivo ainda não menciona é registrada quando o servidor é iniciado com ela. Remover uma flag da linha de comando posteriormente não desativa sua funcionalidade: desative-a nas Configurações.

SNMP tem um painel abaixo das configurações: se o agente está respondendo e em qual endereço, as redes que ele responde, quantas armadilhas de alerta foram enviadas ou falharam, e Baixar o MIB para o OID base em uso. Os valores são definidos em Monitoramento, SNMP.

Marca também está aqui: um site pode definir o nome do produto, uma linha de slogan, uma cor de acento e fazer o upload de um logótipo. O logótipo aparece então no cabeçalho, na página de inscrição, no painel e nas telas de relatórios. Se nenhum for carregado, nada é substituído — uma instalação sem marca permanece sem marca em vez de adquirir decoração.

3.7 O que as cores significam

Quatro registos, e cada um diz algo diferente. A distinção é digna de menção porque é a diferença entre uma tela que pode ser lida de um olhar e uma onde tudo compete por atenção.

Texto simples é um facto sobre como o Perfuse funciona. A maior parte da interface. Nada é colorido para dizer que é importante.

Verde significa que algo teve sucesso agora, porque de algo que fez. Aparece após uma ação e não persiste.

Âmbar é uma advertência: vale a pena saber antes de agir, e não é uma falha. Uma funcionalidade que não está ativada, uma definição cujas alterações são auditadas, uma conversão que aproxima em vez de reproduzir, um transporte que o Perfuse lida, mas não pode verificar completamente. Âmbar é a cor de "leia antes de continuar".

Vermelho significa que algo está errado neste momento. Um valor que foi rejeitado, um pedido que falhou, um certificado que expirou, um alerta crítico que está a disparar. Nada mais o usa.

Essa última regra é por que uma tela não abre vermelha. Vermelho é a única cor que carrega uma instrução — pare, e pode ser algo que fez — e uma tela que a gasta em decoração não tem nada para dizer quando a entrada realmente está errada. Isso não era sempre verdade: a tela de utilizadores costumava abrir com "o servidor enviou uma resposta que não podia ser lida" em cada instalação que não configurou passkeys, e a tela de definições marcava valores auditados na mesma cor que um rejeitado. Um teste em web/src/RedMeansWrong.test.ts agora falha se uma frase que descreve algo ausente ou aproximado é dada um estilo vermelho.

Dentro de uma caixa de código, o vocabulário é diferente. Lá, vermelho é um tipo de token — um nome de segmento HL7, um elemento XML — e não carrega nenhum julgamento.

4 Canais

Um canal é um fluxo de mensagens: somewhere elas vêm, mudanças opcionais e um ou mais lugares para onde elas vão. É a unidade de configuração, a unidade de monitorização e a unidade de implementação. Tudo o resto no Perfuse existe para servir canais.

4.1 Anatomia

Um ficheiro de canal tem estas partes, pela ordem em que têm efeito:

ParteChaveObrigatórioO que faz
IdentidadenamesimNomeia o canal. Deve ser único.
Tipo de dadosdataTypenãoComo analisar as mensagens. O valor predefinido é HL7 v2.
OrigemsourcesimDe onde as mensagens chegam. Exatamente um.
FiltrofilternãoDecide quais mensagens aceitar.
TransformaçõestransformationsnãoMudanças ordenadas na mensagem.
DestinosdestinationssimPara onde as mensagens vão. Um ou mais.

Mais vários que se aplicam a todo o canal: scripts, shadow, contract, tables, attachments, group e enabled. Cada um está na referência do canal.

4.2 Uma origem, muitos destinos

Esta assimetria é deliberada e vale a pena entender cedo, porque é a fonte mais comum de confusão quando se vem de um motor diferente.

Um canal tem exatamente uma origem. Se as mensagens chegam de dois lugares, isso são dois canais. Tentar expressá-lo como um canal produz uma configuração em que uma falha em qualquer transporte parece a mesma por fora, e em que o tráfego das duas fontes é misturado nas estatísticas — então uma queda em um é ocultada pelo outro.

Um canal tem qualquer número de destinos, e eles são independentes. Uma falha não impede os outros, e cada um tem sua própria fila, sua própria política de repetição e seu próprio registo de entrega. Uma mensagem que atingiu três de quatro destinos é registada como exatamente isso, e não como um sucesso ou uma falha.

4.3 Os destinos não são uma cadeia

Cada destino recebe a mensagem como ela estava após as transformações do canal. Um destino não recebe a saída do destino anterior.

Isso importa quando um destino tem suas próprias transformações, o que pode ter. Essas se aplicam apenas à cópia desse destino. Um erro comum é colocar uma mudança no primeiro destino e esperar que o segundo a veja.

Se você realmente precisa de uma cadeia — a saída de um fluxo alimentando outro — use um destino de canal, que envia para outro canal por nome. Isso é explícito, aparece no histórico da mensagem como dois canais e pode ser monitorado como duas coisas, o que uma cadeia oculta não pode.

4.4 Nomenclatura

O nome é a identidade do canal em todos os lugares: no ficheiro, no repositório de mensagens, em alertas, no registo de auditoria e na URL. Alterá-lo não é um renomeação; é um novo canal, e a história do antigo permanece com o nome antigo.

group é separado e existe para organizar a interface. Um grupo não tem efeito no comportamento, e agrupar canais não os faz compartilhar nada.

Em uma implementação multi-facilidade, coloque a facilidade no nome em vez de apenas no grupo. Implementações Mirth em vários sites tendem a se tornar inconsistentes, e o ponto em que isso se torna doloroso é um incidente às duas da manhã em que a lista de canais tem quatro coisas chamadas adt-inbound.

4.5 Ativação e desativação

enabled: false impede que um canal comece sem apagá-lo. Sua configuração, história e estatísticas permanecem.

Um canal desativado não é um canal pausado. Sua origem não está ouvindo, então um remetente que tenta se conectar obtém uma conexão recusada em vez de uma conexão suspensa. Para MLLP, esse é o comportamento correto — o remetente irá enfileirar e repetir —, mas isso significa que o log de erros do remetente irá encher, então um canal desativado não é um substituto para organizar uma interrupção com quem está enviando.

4.6 Onde os canais vivem

Um ficheiro YAML por canal, no diretório dado por -channels. O nome do ficheiro não é o nome do canal; a chave name é. Manter ambos iguais é fortemente aconselhado e nada o impede.

Os ficheiros são lidos novamente sem uma reinicialização. Um ficheiro que não é analisado é relatado e a versão carregada anteriormente continua a funcionar, então um erro de sintaxe não pode tirar um feed de funcionamento do ar.

Um canal editado na interface web é escrito de volta para o seu ficheiro. Se esses ficheiros estiverem em controle de versão — o que é recomendado —, espere confirmações de alterações de configuração feitas através da interface, e não edite manualmente um ficheiro ao mesmo tempo que alguém o tem aberto no construtor.

4.7 Criptografar o ouvinte de um canal

Um canal que ouve numa porta é o seu próprio servidor, e o seu TLS é separado do TLS na interface web do Perfuse. Definir um não define o outro. Para uma fonte HTTP, as definições estão em TLS e limites na fonte.

Ativar o TLS pede um certificado e uma chave privada. Exigir um certificado de cliente o transforma em TLS mútuo: o remetente deve apresentar um assinado por uma autoridade que nomeia, o que é autenticação, por isso um ouvinte com ele ativado não precisa também de um token compartilhado — embora ter ambos não esteja errado.

A autoridade é pedida apenas uma vez que um certificado de cliente é exigido e é omitida do ficheiro até então. Um canal que nomeia uma autoridade que nunca é consultada lê como se os remetentes estivessem a ser verificados quando não o estão.

Um ouvinte MLLP tem as mesmas definições em Encryptar este ouvinte, com uma diferença digna de menção: no MLLP, um certificado de cliente é a única autenticação disponível. Não há token e não há cabeçalho, por isso um ouvinte sem um aceita mensagens de qualquer anfitrião que possa alcançar a porta.

Dois limites estão ao lado dele. Desistir de ler após uma duração, porque um remetente que abre uma ligação e para de escrever de outra forma mantém-na aberta. E maior mensagem aceite, em bytes, porque zero significa sem limite e o limite é então a memória — um remetente que publica um gigabyte é recusado em vez de absorvido.

4.8 Validação

Um canal é verificado quando é carregado, e as verificações são recusas em vez de avisos onde a alternativa seria um canal que funciona e faz a coisa errada.

Exemplos de coisas recusadas abertamente: um destino sem tipo, uma transformação que aborda um caminho que não pode existir no tipo de dados declarado, um modo de confirmação que o transporte de fonte não pode entregar e uma prescrição de classe II com reenchimentos.

A distinção que o Perfuse tenta manter é que qualquer coisa que possa produzir um resultado errado plausível é recusada, e qualquer coisa que seja apenas incomum é permitida e relatada. Um canal que não pode estar errado é mais valioso do que um canal que começa.

5 Fluxo de Mensagem

Este capítulo segue uma mensagem desde o momento em que chega até o momento em que é entregue ou desistida. Saber esta ordem é a forma mais rápida de descobrir onde uma alteração pertence e por que algo não está acontecendo.

5.1 A ordem dos eventos

Arrival de-frame Parse Record as received Filter Transform Destination A Destination B Destination C unparseable filtered Filtered is a normal outcome, not an error. Unparseable is recorded and stops. The acknowledgement is sent after delivery by default, so a sender is not told "received" before it is true.
  1. Arrival. The source accepts the bytes. For a stream transport this includes de-framing — finding where one message ends and the next begins.
  2. Parse. The bytes become a tree according to the channel's dataType. A message that cannot be parsed stops here and is recorded as a parse failure.
  3. Record. The message is written to the message store as received, before anything modifies it. This is what makes replay and reprocessing possible.
  4. Filter. If the channel has a filter, it decides whether to accept the message. A rejected message is recorded as filtered, which is a normal outcome and not an error.
  5. Transform. The channel's transformations run in order, each against the result of the last.
  6. Fan out. Each destination gets a copy of the transformed message, applies its own transformations if it has any, and delivers.
  7. Record the outcome. Per destination: delivered, queued, failed, or filtered.
  8. Acknowledge. If the source expects an acknowledgement, it is generated and sent. By default this happens here, after delivery — see below.

5.2 Quando a confirmação é enviada

Esta é a definição mais consequente em um canal, porque decide o que o remetente está a ser prometido. É ack.when, e tem dois valores.

on_delivery é o padrão. A confirmação é enviada apenas após todos os destinos habilitados terem aceitado a mensagem. Uma confirmação positiva significa, portanto, que os dados realmente chegaram a algum lugar, o que é a afirmação mais forte que um motor no meio pode fazer honestamente.

on_receipt confirma assim que a mensagem é analisada e enfileirada, antes que qualquer destino tenha sido escrito.

O Perfuse usa on_delivery por padrão porque prometer entrega e então perder a mensagem é pior do que ser lento. Em on_receipt, uma mensagem que foi confirmada ainda pode ser perdida se o processo morrer com trabalho enfileirado — o remetente acredita que está entregue, nada a montante irá reenviá-la, e o único registro de que existiu está no repositório próprio do Perfuse.

5.3 Quando escolher on_receipt

O caso para isso é real, e são os tempos limite. Um remetente MLLP que não recebe uma confirmação dentro de alguns segundos geralmente reenvia, por isso um destino lento em on_delivery produz duplicados em vez de atraso. Se um destino for um arquivo lento ou um sistema que está regularmente indisponível, on_delivery acopla o tempo limite do remetente ao pior caso desse destino.

O comércio é explícito: on_receipt move o risco de duplicatas para perda. Escolher isso significa aceitar que uma mensagem confirmada pode ser perdida em uma falha, e vale a pena combiná-lo com alertas de profundidade de fila para que uma fila que parou de drenar seja notada. Veja alertas.

Em qualquer uma das definições, uma confirmação positiva não é uma promessa de que o aplicativo receptor *processou* a mensagem — apenas que aceitou os bytes. Se você precisar saber que um resultado foi arquivado, isso tem que vir do sistema receptor, e nenhum motor de integração pode fornecê-lo.

5.4 Onde a mensagem é registrada

Antes do filtro e, portanto, antes de qualquer transformação. Três consequências:

A forma transformada também é registrada, por destino, ao lado do resultado. Então, a loja contém o que chegou, o que foi enviado e o que aconteceu — que é o que uma investigação precisa.

5.5 Falha em cada estágio

FaseComo a falha se manifestaO que acontece
ChegadaErro de estruturação, conexão interrompida no meio da mensagemRegistrado, conexão fechada, remetente tenta novamente
AnáliseNão é válido para o tipo declaradoRegistrado como falha de análise, confirmação negativa se a fonte espera uma
FiltroO próprio filtro apresenta um erroTratado como recusa, registrado com o erro
TransformaçãoUma etapa falhaDependendo do on_error da etapa; consulte transformação
EntregaDestino inacessível ou rejeitaEnfileirado e retentado de acordo com a política do destino; consulte entrega

A assimetria importante: uma falha de análise é permanente e uma falha de entrega geralmente não é. Repetir uma mensagem não analisável nunca ajudará, então não é repetida. Repetir um destino inacessível geralmente ajudará, então é repetida.

5.6 Ordenação

Dentro de um destino, as mensagens são entregues na ordem em que chegaram, e uma mensagem que falha e entra na fila mantém sua posição — mensagens posteriores esperam atrás dela em vez de ultrapassá-la.

Este é o padrão correto para dados clínicos, onde uma admissão seguida de uma alta entregue na ordem errada é pior do que ambas serem atrasadas. Isso também significa que uma mensagem envenenada pode segurar uma fila, o que é por que a profundidade da fila vale a pena ser alertada.

Entre destinos, não há garantia de ordenação, porque eles são independentes. Dois destinos não receberão necessariamente a mesma mensagem ao mesmo tempo, e um rápido pode estar várias mensagens à frente de um lento.

A ordenação entre canais não é garantida de forma alguma. Se dois feeds devem ser aplicados em uma ordem específica em relação um ao outro, essa ordenação deve ser imposta pelo sistema receptor, porque nada no meio pode saber qual de duas mensagens independentes chegou primeiro.

5.7 Concorrência

Uma origem pode lidar com várias ligações de uma vez, limitadas por max_connections. As mensagens de ligações diferentes são processadas concorrentemente.

Isso significa que a ordem de chegada de duas mensagens enviadas simultaneamente por duas conexões não é definida e não pode ser — elas chegaram genuinamente ao mesmo tempo. Um remetente que precisa de ordenação deve usar uma conexão, o que é o que quase todos eles fazem.

6 Transformação

Transformações alteram uma mensagem. Elas são uma lista, elas são executadas em ordem e cada uma delas vê o resultado da anterior.

As transformações do Perfuse são declarativas: cada passo nomeia uma operação e o campo a que se aplica. Não há linguagem de script no caminho comum. Esta é uma limitação deliberada e o raciocínio está em por que não um script abaixo.

6.1 As etapas

EtapaO que ela faz
setEscreve um valor literal em um caminho, criando-o se ausente.
copyCopia um caminho para outro, com um valor padrão opcional quando a fonte estiver ausente.
clearEsvazia um campo, deixando-o presente.
removeRemove um campo completamente.
mapProcura o valor atual em uma tabela e substitui-o.
replaceSubstituição de expressão regular dentro de um campo.
padPreenche um valor com uma largura fixa.
dateConverte uma data ou carimbo de data/hora entre formatos.
trimRemove espaços em branco circundantes.
caseConverte para maiúsculas ou minúsculas.

Cada passo também aceita description, que aparece no rasto e na interface, e when, que torna o passo condicional.

Uma etapa é escrita como o nome da operação com seu próprio bloco:

transformations:
  - description: Our record number, not theirs
    set:
      path: PID-3.4
      value: RIVERSIDE
  - copy:
      from: PID-19
      to: PID-3.1
      default: UNKNOWN
  - map:
      path: PID-8
      table:
        M: Male
        F: Female
set e value não são irmãos. set leva um bloco contendo path e value. Escrever set: PID-3.4 com value: ao lado é o erro mais comum em um canal escrito à mão e produz um erro de carregamento em vez de uma configuração silenciosamente incorreta.

6.2 Limpar, remover e a diferença

clear deixa o campo presente e vazio. remove o remove completamente.

Para HL7, essa distinção é real e atinge o receptor. Um campo vazio diz "Eu tenho este campo e ele não tem valor". Um campo ausente não diz nada. Alguns sistemas receptores tratam o primeiro como uma instrução para apagar o valor armazenado e o segundo como uma instrução para deixá-lo em paz — o que é a diferença entre excluir uma alergia registrada de um paciente e não mencioná-la.

Se você não souber qual o receptor deseja, pergunte. Adivinhar tem uma chance de 50% de destruir silenciosamente dados no lado oposto.

6.3 Condições

when aceita uma expressão e a etapa é executada apenas se for verdadeira:

  - when: MSH-9.2 == "A08"
    set:
      path: EVN-1
      value: A08

Uma etapa cuja condição é falsa é registrada como pulada, e isso é relatado separadamente de uma etapa que foi executada e não alterou nada. Essa distinção é o objetivo do depurador passo a passo e é abordada em depuração: uma condição falsa e um campo ausente parecem idênticos por fora e significam coisas opostas.

6.4 Caminhos

Um caminho aborda um campo: PID-5 é o quinto campo de PID, PID-5.1 é o seu primeiro componente, PID-3(2) é a segunda repetição de PID-3 e OBX(3)-5 é o quinto campo do terceiro segmento OBX.

Dois comportamentos dignos de nota:

6.5 Erros

A maioria das etapas não tem nada que possa falhar. Definir um valor, limpar um campo ou copiar de um caminho ausente com um valor padrão são todos definidos para cada entrada.

date é a exceção, porque um valor que não é uma data que ele reconhece não tem uma conversão correta. Ele aceita on_error:

O padrão é fail porque um carimbo de data/hora que não converte silenciosamente é pior do que uma mensagem que não chegou. Uma data no formato errado ainda parece uma data, então passa na validação do receptor e chega ao registro como o dia errado.

keep é legítimo quando o receptor tolera ambos os formatos, e quando usado, o rastreamento marca a alteração como deliberada, para que não pareça uma etapa que falhou silenciosamente.

6.6 A ordem importa, e o rastreamento mostra isso

Cada etapa vê a saída da etapa anterior. Duas consequências que pegam as pessoas:

Ambos são visíveis na visualização passo a passo, que mostra a mensagem inteira após cada etapa, em vez de apenas a alteração. Veja depuração.

6.7 Sugerir mapeamentos e o que fazer com uma sugestão

O Mapeador de IA propõe mapeamentos entre um conjunto de campos de origem e um conjunto de alvos. Seu comportamento definidor é que ele declina: abaixo do limiar de confiança, ele se abstém em vez de adivinhar, porque um mapeamento errado confiante em um sistema clínico é pior do que nenhum mapeamento.

6.7.1 Dê-lhe algo para ter confiança

Um nome sozinho é uma evidência fraca, mesmo quando corresponde exatamente. PatientMRN contra PatientMRN pontua 68, o que se abstém no limiar padrão de 70.

The engine knows what an HL7 path means — it will tell you PID-7 is Date/Time of Birth and score your field name against that rather than against the string PID-7, which shares no characters with anything. A locally defined Z segment means whatever your site decided, so nothing is claimed about it.

Isso obtém um mapeamento na maior parte do caminho. Para terminá-lo, forneça ambas as metades:

Com esses, o mecanismo pode ver que os valores concordam com o tipo do alvo, e uma sugestão se baseia em mais do que um nome.

6.7.2 A aprovação é feita um mapeamento de cada vez

Cada sugestão tem a sua própria caixa de aprovação. Não há uma opção "aceitar tudo acima de 80%", deliberadamente: o motor já utilizou a confiança para decidir se oferece o mapeamento e o que resta é um julgamento sobre este campo neste feed. Um número não é esse julgamento.

Uma abstenção não pode ser aprovada de todo. Ela não tem caixa, nem uma desabilitada, e a tela diz que o motor não sabe. Se você sabe a resposta, mapeie-a manualmente — isso é um ato diferente de concordar com uma sugestão.

Uma sugestão abaixo do seu limiar é mostrada sem caixa também, marcada como abaixo dele. Vale a pena ler — uma quase coincidência é frequentemente o mapeamento que você queria, e escondê-la deixaria você se perguntando se o motor considerou — mas não aprovável, porque o seu limiar é a linha que você desenhou.

6.7.3 Duas coisas a fazer com o que você aprovou

Adicionar a um canal transforma cada mapeamento em uma etapa de cópia. Isso só funciona onde a origem é um caminho na mensagem, como ZPI-1, porque uma etapa copia de um lugar na mensagem para outro. As etapas vão para o arquivo do canal e entram em vigor quando ele for carregado novamente — nada muda no tráfego até então. A descrição de cada etapa registra a confiança com que foi sugerida e que uma pessoa a aprovou, o que a torna responsável seis meses depois.

Baixar como uma receita é a resposta certa para o caso mais comum: um mapeamento de um nome de coluna, uma chave JSON ou um nome de campo de um fornecedor. Esses são mapeamentos reais, e um canal não pode ler esse campo diretamente, então uma etapa não pode expressá-los. A receita registra-os como aprovados e pode ser compartilhada.

6.8 Por que não um script

Mirth coloca um transformador JavaScript no centro de cada canal, e é o design mais flexível disponível. Perfuse oferece script — veja a chave scripts na referência do canal — mas não o torna o caminho comum, por três razões que vêm do que dá errado na prática.

Uma etapa declarativa pode ser inspecionada. Perfuse pode dizer que uma etapa lê PID-5 e escreve PID-8, antes de executá-la, e pode portanto mostrar um rastreamento de nível de campo, alertar que uma etapa endereça um caminho que o tipo de dados declarado não pode conter e gerar um replay por etapa. Nenhum disso é possível para código arbitrário.

Uma etapa declarativa pode ser raciocinada pela interface. O construtor pode oferecer os campos que existem no tráfego deste canal e uma alteração em uma etapa pode ser verificada contra mensagens históricas reais antes de ser salva.

E uma etapa declarativa não pode fazer algo não relacionado à mensagem. Um script pode chamar a rede, ler o sistema de arquivos ou depender do horário do dia. Quando um canal que funcionou por dois anos começa a produzir saída errada, a causa sendo fora da mensagem é o caso mais difícil de diagnosticar, e remover a possibilidade vale mais do que a flexibilidade que custa.

Onde uma transformação genuína não pode ser expressa declarativamente, use um script e aceite que o rastreamento mostrará como uma etapa opaca.

6.9 O que um script é permitido fazer

Um script é recusado qualquer coisa fora da mensagem, a menos que seja concedido, e as concessões estão na seção Scripts do construtor. Isso é deliberadamente diferente de Mirth, que concede a todos os scripts — então, um transformador pode começar a ler o sistema de arquivos após uma cópia e colar.

Há três.

Ler e escrever arquivos exige que você nomeie os diretórios que ele pode usar, e um canal que concede acesso a arquivos sem eles é recusado no carregamento. Essa exigência é a única diferença entre acesso a arquivos e acesso a arquivos irrestrito: concedê-lo sem diretórios uma vez alcançou todo o sistema de arquivos, incluindo o banco de dados do Perfuse, que contém hashes de senha, a senha da conta de serviço LDAP e o segredo do cliente OIDC. Criar um canal precisa apenas da função de editor, então a escalada foi concluída no momento em que um administrador iniciou o canal.

Consultar um banco de dados usa as conexões configuradas no canal. Um script com isso pode ler qualquer coisa que essas credenciais possam.

Encaminhar mensagens para outros canais permite que um script envie uma mensagem para outro canal, o que é como um loop entre dois canais se torna possível.

Conceder uma capacidade a um canal sem scripts não faz nada, e o arquivo gerado omite o bloco inteiro nesse caso.

6.10 Lidar com uma data que não corresponde ao seu formato

Uma etapa de data converte de um formato para outro, e a pergunta interessante é o que acontece quando um valor não corresponde ao formato que afirma.

O padrão é parar a mensagem, e é o padrão correto: um carimbo de data/hora que silenciosamente não converte é aceito downstream e então mal lido, o que é pior do que uma mensagem que falhou alto e está sentada onde alguém pode vê-la.

Deixar o valor como está o passa adiante no seu formato original. Downstream, então, vê dois formatos em um campo, o que é a falha que a etapa existia para prevenir — mas é a escolha certa onde o campo é opcional e um parceiro o envia de forma inconsistente.

Esvaziar o campo é honesto e melhor do que um formato errado, mas um receptor que exige o campo, então, rejeita a mensagem em vez disso.

6.11 As linguagens de script

Três são aceites, e qual delas escolher depende principalmente de se está migrando. O valor vai na chave language de um script:

ValorO que é
javascriptO padrão. Um script sem marcação é JavaScript.
luaA melhor escolha quando ninguém está migrando.
wasmOs bytes de um módulo WebAssembly compilado, não o código-fonte.

JavaScript é o padrão, e um script sem marcação é tratado como JavaScript. Ele está aqui como uma obrigação de compatibilidade, em vez de uma preferência: os scripts do Mirth são JavaScript e um site que se move para cá tem milhares de linhas disso. Isso inclui suporte para E4X, uma extensão antiga da linguagem que os scripts do Mirth usam para XML e que precisa ser traduzida antes que algo possa ser analisado.

Lua (lua) é a melhor escolha para quem não está migrando. Um tempo de execução menor, sem cadeia de protótipos para ser mal utilizada, e tabelas indexadas por inteiro que correspondem mais naturalmente ao endereçamento de segmentos e campos do que as do JavaScript. Sua biblioteca padrão é pequena o suficiente para ser enumerada, o que é o que torna sua sandbox mais fácil de ser confiável.

WebAssembly (wasm) não é uma linguagem, mas um módulo compilado, e o campo quer os bytes de um arquivo .wasm em vez do código-fonte. Use-o quando a transformação já existe em uma linguagem compilada, ou quando é pesada o suficiente para que o custo de tempo de execução seja importante.

Seu contrato é deliberadamente o mais simples disponível: um módulo lê a mensagem na entrada padrão e escreve seu resultado na saída padrão. Bytes de entrada, bytes de saída — o que é o que toda a cadeia de ferramentas já faz, e o que alguém testando um módulo na linha de comando já tem. A alternativa era uma função exportada sobre memória linear, que é mais rápida e exige que todos os autores de módulos concordem sobre alocação, codificação de strings e quem libera o que; para algo que é executado uma vez por mensagem, essa troca não vale a pena.

Qualquer coisa que um módulo escreva na saída de erro se torna linhas de log, então ele pode explicar a si mesmo do mesmo jeito que um script que chama logger pode.

Uma saída de erro diferente de zero significa que o módulo falhou, o que não é o mesmo que um filtro decidir rejeitar uma mensagem. Um módulo de filtro diz true ou false na saída padrão. Confundir os dois faria com que um módulo que está travando fosse indistinguível de um que está deliberadamente descartando tráfego.

6.11.1 O que a saída significa

As regras são as mesmas para as três linguagens, em vez de novas regras por tempo de execução, então o comportamento observável de um script — o que ele pode ver, o que ele pode fazer, quanto tempo ele pode levar, o que um veredito de filtro significa — é definido uma vez.

Para um transformador, pré-processador ou escritor, saída vazia significa que a mensagem não foi alterada. Cair no final de um script deixa a mensagem sozinha; tratar nenhuma saída como "a mensagem agora está vazia" descartaria tráfego por uma questão técnica.

Módulos WebAssembly são compilados quando o canal é carregado, não na primeira mensagem. A compilação não é gratuita — um módulo construído a partir de uma linguagem que traz seu próprio tempo de execução pode levar centenas de milissegundos — e pagar isso no momento do carregamento significa que a primeira mensagem que passa por um canal não é misteriosamente mais lenta do que o resto.

6.12 Tabelas de mapeamento compartilhadas

A outra metade do mesmo problema: os códigos de sexo e classes de paciente de um site são traduzidos de forma idêntica em todos os canais que os tocam, e uma tabela dentro de um canal é uma tabela que apenas esse canal pode usar.

# codes.codeset.yaml
tables:
  - name: sex-to-lab
    describes: the hospital's sex codes into the numeric codes the lab expects
    decided_by: Dave, during the 2019 migration
    decided_on: 2019-04-11
    source: the lab's interface specification, version 3
    entries:
      - from: M
        to: "1"
      - from: U
        to: "9"
        why: the lab has no 'unknown', and 9 is its 'not stated'
# in the channel
tables:
  - codes.codeset.yaml
transformations:
  - map:
      path: PID-8
      use: sex-to-lab

A proveniência é o ponto. A maior parte do que torna uma interface difícil de manter é que ninguém sabe *porquê* um mapeamento é do jeito que é, e a pessoa que sabia já se foi. Um mapeamento com um motivo pode ser discutido; um sem motivo torna-se algo que ninguém se atreve a alterar e ninguém se atreve a apagar.

Tabelas são criadas e alteradas em Construir → Tabelas, bem como no arquivo. Salvar uma tabela que está em vigor reinicia os canais em execução que carregam seu arquivo, então a próxima mensagem a usa; um rascunho não reinicia nada.

6.12.1 Versões e datas de vigência

Uma tabela pode manter várias edições sob um mesmo nome, cada uma com a sua própria version. A edição que uma mensagem utiliza é escolhida quando a mensagem chega: das edições aprovadas cujas datas abrangem esse dia (UTC), a que começou mais recentemente. Assim, uma alteração de código acordada para o primeiro dia do próximo mês é inserida agora e entra em vigor por si só.

tables:
  - name: sex-to-lab
    version: "3"
    effective_from: 2026-11-01   # optional; empty means from the start
    effective_until: 2027-10-31  # optional; the last day it applies
    source_system: urn:local:hospital-sex
    target_system: http://terminology.hl7.org/CodeSystem/v2-0001
    entries: [...]

(guardado para o registo, usado por nada).

caso contrário, os da tabela.

6.12.2 Aprovação

Com Settings → Data → Mapping tables "Alterações a uma tabela de mapeamento necessitam de aprovação de uma segunda pessoa" (data.tableApproval) ligado, todas as gravações são um rascunho, e a pessoa que o salvou não pode aprová-lo: alguma outra pessoa o faz, opcionalmente dando o dia em que entra em vigor. Uma edição aprovada não pode ser editada no local; Nova versão a partir desta copia para a próxima versão. Aprovar, aposentar e eliminar um rascunho são escritos no registo de auditoria, e aprovar reinicia os canais em execução que carregam o ficheiro.

6.12.3 Valores sem tabela de mapeamento

Todos os valores que um passo de mapeamento procurou e não encontrou são contados, por tabela, com os canais por onde passaram e quando foram vistos pela primeira e última vez. A tela Tabelas lista-os, com os mais frequentes primeiro. Mapear abre a tabela com esse valor já adicionado como uma linha; Descartar remove-o até que seja visto novamente. Valores com mais de 64 caracteres não são registados (não são códigos), e a lista mantém o que foi visto dentro do período de retenção de mensagens. A lista é mantida em terminology.db ao lado do banco de dados principal.

6.12.4 Sistemas de código

Sistemas de códigos publicados podem ser importados a partir dos ficheiros dos seus próprios editores, em Sistemas de códigos na tela Tabelas (administradores) ou com POST /api/terminology/import?format=… e o ficheiro como corpo:

FormatoFicheiroSistema
loincLoinc.csv a partir do lançamento da tabela LOINChttp://loinc.org
icd10cmo ficheiro de pedidos CMS (icd10cm_order_*.txt) ou ficheiro de códigoshttp://hl7.org/fhir/sid/icd-10-cm
rxnormRXNCONSO.RRF a partir do lançamento completo RxNormhttp://www.nlm.nih.gov/research/umls/rxnorm
snomeda descrição instantânea RF2 (sct2_Description_Snapshot-en_*.txt)http://snomed.info/sct
snomed-rf2um pacote de lançamento completo SNOMED CT RF2 (o zip que um centro de lançamento nacional publica)http://snomed.info/sct, versão http://snomed.info/sct/{module}/version/{date}
clamlum ficheiro ClaML: ICD-10 da OMS, ICD-10-GM e OPS (BfArM), CIM-10 FR (ATIH)a partir do título do ficheiro, ou do system fornecido
icd11a tabulação simples MMS ICD-11 da OMS (separada por tabulações, com colunas Code e Title)http://id.who.int/icd/release/11/mms
csvqualquer ficheiro delimitado, com system, codeColumn e displayColumn (CPT, HCPCS, códigos locais, tabelas nacionais)o system fornecido

Nenhum vem com o Perfuse: LOINC, SNOMED CT, RxNorm e CPT cada um têm a sua própria licença, e a tela pede ao importador que confirme que a organização a possui (registada com a importação). Códigos importados são usados de três maneiras:

guardadas, e os códigos que não estão no sistema são listados na edição;

para eles (ver as opções do servidor FHIR). Os códigos ICD-10-CM são aceites com ou sem o ponto.

Edições e classificações nacionais. Uma edição do SNOMED CT é importada a partir do seu pacote RF2 completo: conceitos com o seu estado real, todas as descrições ativas e os conjuntos de referência de linguagem. A edição é encontrada a partir do pacote (o módulo nacional com mais conceitos; edition nomeia em vez disso) e torna-se o URI da versão. language escolhe cujo termo preferido é o termo de exibição de cada conceito (sv, da, nl, de, fr, en-GB, en-US ...; inglês caso contrário), e o termo preferido e o nome totalmente especificado de cada linguagem são mantidos como designações: $lookup os retorna, e o seu displayLanguage escolhe um (de-CH recorre a de). As edições nomeadas pelo Perfuse (Internacional, Reino Unido, Alemanha, Países Baixos, Suécia, Dinamarca, Bélgica, Irlanda, Noruega, Suíça, Estônia, Espanha) são listadas por GET /api/terminology/editions, os IDs de módulo não verificados contra uma fonte publicada marcada como tal; qualquer outra edição também é importada, nomeada pelo seu módulo.

Ficheiros ClaML são lidos em UTF-8, ISO-8859-1, ISO-8859-15 ou Windows-1252, como a sua declaração XML diz. O título de cada categoria é o seu rubrico preferido (termos aninhados incluídos); um modificador (um quinto caractere para o local de uma fratura, por exemplo) faz os códigos que adiciona, com o título do modificador após o da categoria, a menos que a categoria o exclua; blocks=true importa capítulos e blocos também. As colunas da tabulação ICD-11 são encontradas pelo nome, uma vez que a sua ordem mudou entre lançamentos, e os traços que mostram a profundidade são removidos dos títulos. Um ficheiro delimitado aceita delimiter (, ; | ou tab), encoding (utf-8, iso-8859-1, iso-8859-15, windows-1252) e noHeader=true, com colunas numeradas a partir de 1. A consola oferece configurações para os ficheiros da 5ª Edição do ICD-10 do Reino Unido e OPCS-4 (TRUD), a tabela de rótulos CIM-10 FR da França (ATIH) e uma exportação ICD-10-BE; os seus editores não documentam todos os seus campos, por isso verifique-os contra o cabeçalho do ficheiro.

Datas de início de vigência. effective=YYYY-MM-DD importa uma versão agora e utiliza-a a partir daquele dia (ICD-10-GM, por exemplo, cada 1 de janeiro): até lá, uma pesquisa que não especifica uma versão é respondida pela versão já em vigor, e a tela exibe a data.

ICD-11 da OMS. Com um cliente registrado em icd.who.int (Configurações → Dados → Sistemas de código, serve -icd11-client-id e -icd11-client-secret; -icd11-release, 2025-01 por padrão), os códigos ICD-11 que não são importados são pesquisados na API ICD da OMS (codeinfo, então o título da entidade) e mantidos por um dia. Um código pós-coordenado (NC72.2&XK9K) é verificado por inteiro, então uma combinação ICD-11 que não é permitida é recusada, e seus nomes de exibição para cada parte ("Fratura do pescoço do fêmur (Direito)").

ICD-11 sem enviar códigos. A OMS publica a mesma API como um contêiner (whoicd/icd-api, gratuito, Intel e Arm). Execute-o em sua própria rede e forneça o endereço (serve -icd11-url http://icd-api.local, ou Endereço da API ICD nas mesmas configurações); ninguém cliente é necessário e nenhum código deixa sua rede. Testado contra esse contêiner (versão 2.6.0, lançamento 2025-01 em inglês e francês).

7 Filtragem

Um filtro decide quais mensagens um canal aceita. É uma expressão no canal, avaliada após a mensagem ter sido analisada e registrada, antes de qualquer transformação.

filter: MSH-9.1 == "ADT" && MSH-9.2 in ("A01", "A03", "A08")

Uma mensagem que o filtro rejeita é registada com o resultado filtrado. Isso é um resultado normal, não um erro, e não dispara um alerta ou produz uma confirmação negativa.

7.1 Filtrado não é falha

Esta distinção é importante porque confundir os dois é como um problema real se esconde.

Uma mensagem filtrada foi corretamente recusada: não era para este canal. Uma mensagem com falha foi uma que este canal deveria ter tratado e não conseguiu. Se ambas fossem registadas da mesma forma, um canal que começa a falhar em todas as mensagens pareceria exatamente como um canal que está filtrando a maior parte do seu tráfego, o que é o estado normal de muitos canais.

Portanto, as estatísticas contam-nas separadamente, as regras de alerta tratam-nas de forma diferente e a interface mostra-as em cores diferentes. Um aumento nas mensagens filtradas pode significar que o remetente começou a enviar algo novo; um aumento nas falhas significa que algo está quebrado.

7.2 O que um filtro pode ler

Qualquer campo na mensagem analisada, pelos mesmos caminhos que as transformações usam. O filtro é executado antes das transformações, por isso vê a mensagem como ela chegou — não como ela será enviada.

Essa ordem é deliberada. Um filtro que lê valores pós-transformação estaria decidindo se aceitar uma mensagem com base em alterações feitas com a suposição de que foi aceita, o que é circular e produz canais cujo comportamento depende da ordem de duas coisas que parecem independentes.

7.3 Expressões

Comparações: ==, != e para números <, <=, >, >=.

Membros: in ("A01", "A03"), o que é mais claro do que uma cadeia de || e é a forma que o construtor produz.

Combinação: &&, || e parênteses. Negação com !.

Ausência: um caminho que não está presente compara desigual a qualquer valor, incluindo a string vazia. Para testar a ausência explicitamente, compare com absent. Isto é importante porque um campo ausente e um campo vazio são diferentes, como descrito em transformation, e um filtro que os trata da mesma forma aceitará mensagens que foi escrito para excluir.

7.4 Um erro no filtro é uma recusa

Se o filtro em si falhar na avaliação — uma expressão malformada que passou pela validação, ou uma comparação que não pode ser feita — a mensagem é recusada e o erro é registado contra ela.

Recusar em vez de aceitar é o mais seguro dos dois, mas nenhum dos dois é bom, e o resultado é registado de forma distinta de uma recusa de filtro comum para que possa ser alertado. Um filtro que está dando erro em todas as mensagens está silenciosamente descartando toda a alimentação, e não deve parecer um filtro que está funcionando.

7.5 Filtre na origem quando possível

Um filtro é executado após a mensagem ter cruzado a rede e sido analisada. Algumas origens podem filtrar mais cedo e mais barato:

Filtrar na origem é uma decisão de desempenho, não de correção, e tem um custo: uma mensagem filtrada no corretor nunca é registada pelo Perfuse, por isso não aparece no repositório de mensagens e não pode ser inspecionada mais tarde. Se você precisar provar o que o remetente enviou, filtre aqui em vez de lá.

7.6 Testar um filtro

Um filtro pode ser verificado contra tráfego histórico real antes de ser salvo. A interface relata quantas das últimas N mensagens registadas o filtro aceitaria, rejeitaria e daria erro — o que é a forma mais rápida de descobrir que uma expressão que parece certa aceita nada.

O rastreamento também mostra, por mensagem, quais campos o filtro leu e quais valores encontrou. Um filtro que rejeita tudo inesperadamente geralmente está lendo um caminho que não existe nessa alimentação, e o rastreamento o nomeia.

8 Formatos de Mensagem

O dataType de um canal decide como bytes se tornam uma mensagem. Isso afeta a análise, o que os caminhos significam, como a mensagem é escrita novamente e quais transformações são válidas.

ValorFormato
hl7HL7 v2, o padrão delimitado por pipe. O padrão.
hl7v3Documentos HL7 v3 e CDA, que são XML.
x12ASC X12, utilizado para elegibilidade e reclamações.
ncpdpPadrão de telecomunicação NCPDP D.0 para reclamações de farmácia.
scriptNCPDP SCRIPT, prescrições eletrônicas. XML.
dicomObjetos de imagem DICOM.
delimitedTexto delimitado CSV e outros.
rawSem análise. Bytes de entrada, bytes de saída.

8.1 HL7 v2

O padrão e o que a maioria dos exemplos deste manual utiliza. Segmentos terminados por retorno de carro, campos por |, componentes por ^, repetições por ~.

Duas coisas sobre a codificação valem a pena saber porque causam falhas silenciosas.

Os delimitadores não são fixos. Eles são declarados em MSH-1 e MSH-2 de cada mensagem, e o Perfuse lê-os de lá em vez de supor pipes. Um remetente que usa um separador de campo diferente analisa corretamente.

A consequência é que uma mensagem cujos separadores foram substituídos — mais frequentemente por um processador de texto ou cliente de e-mail que substitui por semelhantes tipográficos — é analisada perfeitamente em campos que estão todos errados. Nada dá erro. É por isso que o leitor de amostra descrito em testing relata qual caractere de separador ele encontrou e se recusa a expressar confiança quando é incomum.

Quando alguém envia uma amostra e o canal construído a partir dela produz disparates, verifique os separadores antes de mais nada. Peça um anexo de texto simples em vez de uma mensagem colada no corpo de um e-mail.

8.2 HL7 v3 e CDA

XML em vez de delimitado. Caminhos são caminhos de elementos e atributos em vez de posições de campos.

Em v3, um valor é quase sempre um atributo em vez de texto de elemento. Uma comparação que lê apenas o texto de elemento relatará dois documentos como idênticos quando a data de nascimento, o gênero e todos os identificadores diferem. A comparação do Perfuse lê ambos, e é por isso: a alternativa consegue silenciosamente.

As opções hl7v3 estão na referência de formato.

8.3 X12

Segmentos terminados por ~ por convenção, com delimitadores declarados no segmento ISA. Como o HL7, eles são lidos da mensagem em vez de supostos.

A estrutura do X12 é envelopes dentro de envelopes — interchange, grupo funcional, conjunto de transações — e um único interchange pode conter muitas transações.

Por padrão, um interchange é uma mensagem. Todo o arquivo recebe um registro, um resultado e uma linha na interface, independentemente de quantas transações ele contenha.

8.3.1 O X12 XML do Mirth

Mirth Connect e Open Integration Engine mostram X12 como XML: uma raiz X12Transaction (ou EDIMessage quando a entrada não começa com ISA) que transporta os delimitadores como atributos, e um elemento por segmento e elemento nomeado ISA.01, NM1.03.1 e assim por diante. Canais e receptores construídos para Mirth lêem e gravam essa forma. Perfuse lê e grava a mesma forma:

O formato foi escrito a partir da saída observada e do formato publicado do Open Integration Engine 4.6, e é verificado contra ele: 25 intercâmbios gerados e 4 exemplos mantidos saem byte a byte como o OIE escreve, e de volta (ver verificação). Um DOCTYPE é recusado, como em todos os XML que o Perfuse lê.

8.3.2 Dividindo um interchange

Definir split torna cada conjunto de transações uma mensagem por direito próprio, com seu próprio registro, suas próprias métricas e sua própria linha. Um operador que procura uma reclamação então encontra uma reclamação em vez de um arquivo de quatrocentas.

Está desativado por padrão porque ativá-lo multiplica tudo downstream — contagens de mensagens, linhas, limiares de alerta — e um limiar ajustado para arquivos que é subitamente contando reclamações não significará o que costumava significar. Isso deve ser uma decisão que alguém tomou em vez de um padrão que herdou.

split e acknowledge não podem ser ambos definidos, e um canal com ambos é recusado no carregamento. Um reconhecimento é uma declaração sobre um interchange completo, então a divisão enviaria um por conjunto de transações, e um parceiro que recebe vários 999s que nomeiam o mesmo grupo funcional não tem como reconciliá-los.

8.3.3 Quando as contagens não batem

O X12 declara suas próprias contagens — quantos segmentos, quantas transações — e a chave envelope diz o que fazer quando elas discordam do que está realmente presente. Essas contagens são o único mecanismo que o X12 tem para detectar que metade de um arquivo de reclamações chegou.

ValorComportamento
requireRecusar o interchange. O padrão.
warnProcessá-lo e registrar a falha contra a mensagem.
ignoreNão verificar nada.

O warn existe para uma situação real: alguns parceiros têm software que gera contagens erradas há anos em arquivos de outra forma completos, e um site que precisa processá-los precisa de uma maneira de dizer isso em voz alta na configuração em vez de desativar a validação por completo.

O ignore é nomeado para ser desconfortável. Defini-lo joga fora o único meio que o X12 lhe dá de notar um arquivo truncado, e um arquivo de reclamações truncado é indistinguível de um pequeno.

8.3.4 Transações que o Perfuse lê como dados estruturados

Qualquer intercâmbio X12 pode ser encaminhado, filtrado e endereçado por caminho. Essas transações são adicionamente analisadas em campos nomeados, de modo que um canal pode perguntar o que um pagador decidiu em vez de qual elemento está na posição quatro.

TransaçãoO que ela transporta
835Aviso de remessa: o que foi pago, o que foi negado e os motivos de ajuste.
275Anexos de reclamações: documentação clínica que apoia uma reclamação.
277Status da reclamação, incluindo um pedido de documentação adicional do pagador.
278Autorização prévia: o pedido de revisão e a decisão do pagador.
999Confirmação funcional, que o Perfuse também gera.
271Elegibilidade: se um paciente está coberto e os valores de copagamento, coinsurance, dedutível e fora de bolso, dentro e fora da rede.
834Inscrição: membros adicionados, alterados e terminados, com cada linha de cobertura e suas datas.
837Reclamações, profissionais e institucionais (leia para a conversão CARIN do CMS-0057).

O Perfuse também constrói o 270 pedido de elegibilidade e o 276 pedido de status de reclamação, sob Payers → Reclamações & autorização ou através de POST /api/x12/eligibility/build e /api/x12/claimstatus/build. Ambos são as versões HIPAA 5010 (005010X279A1, 005010X212), lidos novamente e verificados antes de serem exibidos, e nenhum deles é enviado a partir dessa página: entregar um é um trabalho de um canal, onde o parceiro comercial e suas credenciais estão.

8.3.5 Elegibilidade e a regra de conteúdo de dados CAQH CORE

Um 271 é uma lista de segmentos EB, cada um um único fato: cobertura ativa, ou uma coparticipação de $25 para o tipo de serviço 30 na rede, ou $800 do dedutível individual restante. O leitor os reúne na resposta que uma secretária deseja - "cobertura ativa sob Gold PPO 2000; coparticipação na rede $25; dedutível individual restante na rede $800" - e nomeia uma rejeição (um segmento AAA) em palavras, com o que o pagador diz para fazer em seguida.

Ele também verifica a resposta contra a regra de conteúdo de dados de elegibilidade e benefícios CAQH CORE: para uma consulta sobre cobertura de plano de benefícios de saúde (tipo de serviço 30), uma resposta ativa deve transportar datas do plano, o nome do plano, copagamento, coinsurance, dedutível e dedutível restante ambos dentro e fora da rede, e os tipos de serviços básicos (1, 33, 35, 47, 48, 50, 86, 88, 98, AL, MH, UC). Cada um é listado como atendido ou faltante. Isso é a leitura do Perfuse da regra, útil para "por que este pagador nunca nos diz o dedutível?" - não é certificação CORE, que os fornecedores de teste autorizados da CAQH realizam.

8.3.6 Autorização prévia

O Perfuse implementa a autorização prévia duas vezes, propositadamente.

O lado FHIR é o que o CMS-0057-F exige que os pagadores exponham a partir de 1 de janeiro de 2027. O 278 é o que os pagadores aceitam hoje, e a regra não o substitui — Da Vinci PAS é, na prática, um mapeamento sobre essa transação, porque um 278 é o que um sistema de gestão de utilidade fala. Um motor que lê apenas a metade FHIR pode falar com os sistemas que existirão e não com os que existem.

Uma resposta 278 transporta o número de autorização, e esse é o campo para o qual toda a transação existe para entregar. Sem ele, um serviço certificado não é faturável: a reclamação entra sem número de autorização e é negada por falta de um, o que lê a jusante como uma negação clínica.

Uma negação e uma recusa em considerar não são a mesma coisa

Essa é a confusão mais cara na transação, e o Perfuse relata as duas separadamente.

O que chegouO que significaO que fazer
HCR com ação A3O pagador considerou o pedido e não o certificará.Apelar, ou mudar o plano de cuidados.
Um segmento AAAO pagador não o consideraria — paciente não encontrado, solicitante não reconhecido, revisão não coberta. Nada foi decidido.Corrigir o pedido e enviá-lo novamente.

Ambos são lidos como "não aprovados" para qualquer pessoa que os digitalize, e as ações corretas são opostas. Apelar de algo que ninguém julgou não alcança nada; reenviar uma negação produz a mesma negação. O resultado analisado nomeia o que aconteceu — denied contra not-considered — e AAA04 transporta o próprio conselho do pagador sobre se o pedido é recuperável.

A certificação parcial é relatada como partially-certified em vez de incorporada na aprovação. Há um número de autorização para faturar, então conta como aprovado, mas a quantidade certificada não é a quantidade solicitada — e uma clínica que agenda seis sessões contra três aprovadas descobre isso na quarta reclamação.

Um código de ação que o Perfuse não reconhece é relatado como unknown, não como pendente. Pendente lê como "espere", e esperar é a ação errada para a maioria do que um código não reconhecido pode ser.

Um canal pode encaminhar a decisão diretamente:

filter: HCR-1 == "A3"

Convertendo entre os dois

O Perfuse converte um 278 analisado em uma resposta de reclamação Da Vinci PAS ClaimResponse e relata todos os julgamentos que a conversão precisou em vez de apenas o resultado. A conversão segue três regras:

Reduzir para um vocabulário de três estados — aprovado, negado, pendente — está disponível e explícito sobre o que descarta. Reduzir uma recusa para considerar produz "negado" e diz em palavras que a ação correta é uma resubmissão corrigida em vez de um recurso.

Verificado contra PAS 2.2.1, não apenas contra si mesmo

O ClaimResponse é moldado para o perfil Da Vinci PAS 2.2.1 e foi verificado com o validador oficial HL7 carregado com o pacote PAS publicado. A primeira versão havia sido verificada apenas pelos testes próprios do Perfuse, e o validador a rejeitou com seis a oito erros por recurso. Cada um deles é algo que um endpoint PAS de um pagador também teria rejeitado:

O que estava erradoOnde o PAS coloca
A decisão estava em adjudication.category e reason.A extensão reviewAction, em uma adjudicação cuja categoria é submitted.
O código de motivo nomeado elemento X12 1034.Lista de códigos externos X12 886.
Um pedido pendente respondeu outcome: queued.outcome é sobre processamento e o PAS permite apenas complete, error e partial. Um pendente é complete, com ação de revisão A4.
processNote.type era um CodeableConcept.O R4 tem um código: print.
patient, created, insurer e request estavam faltando.Os quatro são obrigatórios. Eles são fornecidos como referências de identificador, porque a resposta se mantém sozinha em vez de em um bundle.

A saída corrigida valida sem erros para uma certificação, uma recusa e um pendente. Os avisos que permanecem são o validador dizendo que não pode carregar os sistemas de códigos X12, que o X12 licencia. O número de autorização é transportado em reviewAction.number, onde o exemplo próprio do guia o coloca, e em preAuthRef quando a resposta tem apenas um.

O validador não faz parte do make check, porque ele precisa do Java e de um download do guia e suas dependências. O que ele encontrou é mantido por um teste em vez disso: cada regra que ele aplicou é afirmada, então uma alteração que reintroduz um desses erros falha.

A visão Reclamações e autorização converte uma 278 colada e mostra as decisões, as notas e o recurso.

8.3.7 Anexos e por que eles precisam de tratamento especial

O CMS-0053-F torna o 275 um padrão HIPAA para anexos de reclamações, com conformidade exigida até 26 de maio de 2028. Ele transporta um documento — uma nota operativa, um relatório de imagem, um formulário digitalizado — vinculado à reclamação que ele apoia.

O 277 é a outra metade da mesma conversa. Um pagador recebe uma reclamação, decide que precisa de documentação e envia um 277 solicitando-a; o prestador responde com um 275.

Um canal pode rotear no código de status diretamente, porque STC01 é um composto e seu segundo componente é o status. Escrito em forma canônica, porque um componente é endereçado com um ponto e as duas notações não podem ser misturadas — STC-1.2 é o elemento 1, componente 2:

filter: STC-1.2 in ("227", "233", "252", "287")

Esses são os códigos que inegavelmente significam que um documento é desejado. A categoria de status em STC-1.1 é deliberadamente não usada sozinha: R4 significa uma solicitação de documentação em alguns guias de implementação e "encaminhado para outro local" em outros, então um filtro na categoria sozinha colocaria reclamações finalizadas na fila para alguém perseguir.

Dois identificadores decidem se um anexo é associado à sua reclamação, e ambos são relatados: o número de controle de anexo, que o prestador colocou na reclamação original para dizer que a documentação seguiria, e o número de rastreamento, que corresponde à solicitação do pagador. Um anexo que chega com nenhum dos dois é arquivado e nunca conectado a nada, enquanto a reclamação envelhece.

Um documento dentro de um 275 não é interpretado. O Perfuse relata seus bytes e o que o remetente diz que eles são. Um anexo pode ser um PDF, um TIFF, um documento CDA ou uma mensagem HL7, e um canal que precisa do conteúdo pode passar esses bytes para o formato que os lê.

O formulário 006020, que é o adotado pela regra

O CMS-0053-F adota a versão 006020, e seu 275 difere do formulário 005010 de duas maneiras que importam.

O Perfuse desenrola a entidade e relata o documento dentro dela, com o seu tipo de conteúdo e nome de ficheiro. Os bytes que relata são exatamente os que o remetente envolveu. Uma entidade que não pode ser desenrolada deixa a carga útil bruta no lugar, com uma nota que explica porquê.

Construir um 275. O Perfuse também constrói anexos 006020X314: um não solicitado para acompanhar um pedido de reembolso, ou uma resposta a um pedido 277 do pagador. A diferença está em BGN01 02 contra 11, e se TRN02 transporta o PWK06 do pedido de reembolso ou o TRN02 do 277. Cada intercâmbio construído é analisado novamente antes de ser devolvido, e a resposta diz se o documento dentro é o mesmo que entrou.

A estrutura vem das duas guias de acompanhamento publicadas para 006020X314: a guia esMD da CMS e a da UnitedHealthcare. Não vem do relatório técnico X12, que a X12 licencia e que este projeto não possui.

Não há validação contra o relatório técnico. A guia de acompanhamento do parceiro governa.

8.3.8 Assinaturas eletrónicas em anexos

O CMS-0053-F também adota um padrão de assinatura, no 45 CFR 162.2002(e): o Guia de Implementação HL7 para CDA Release 2, Assinaturas Digitais e Delegação de Direitos, Release 1. Aplica-se a assinaturas colocadas em informações de anexo quando são enviadas em uma transação de anexo HIPAA, a partir de 26 de maio de 2028. Um pagador não pode pedir mais do que o guia faz.

O Perfuse assina um C-CDA dessa forma ao entrar num 275, e verifica as assinaturas em todos os C-CDA num 275 que lê.

Se algum desses estiver indisponível, a assinatura ainda é feita e mantida. O resultado nomeia a forma XAdES que atingiu e diz o que o impediu de atingir X-L: por exemplo, um certificado auto-assinado (nenhum CA para perguntar) ou nenhuma autoridade de marca de tempo.

A chave é -signing-cert e -signing-key. Coloque os certificados CA após o certificado do signatário no mesmo ficheiro para que o caminho viaje com a assinatura. Para uma assinatura que signifique o que DSDR significa, o certificado deve nomear o clínico, com o seu NPI, em vez do servidor. A assinatura é uma ação de administração, como assinar qualquer documento.

O guia não nomeia um namespace para os seus próprios elementos. O Perfuse coloca digitalSignature, authorizedSigner e SignaturePurpose em urn:hl7-org:sdtc. Ele também afirma o propósito como um tipo de compromisso XAdES com o OID ASTM, que as ferramentas XAdES entendem. A delegação de direitos, onde um delegado assina com uma afirmação SAML do signatário autorizado, não é produzida, e uma recebida é relatada como não verificada.

O NPI do fornecedor é verificado contra o seu dígito de verificação. Um pagador associa um anexo ao seu pedido de reembolso em parte a esse número, e um número mal digitado deixa o anexo não associado enquanto o pedido de reembolso é negado por falta de documentação.

A vista Pedidos de reembolso e autenticação constrói um 275 a partir de um C-CDA colado ou de um ficheiro carregado, opcionalmente assinando o C-CDA, e lê um de volta com as descobertas de cada assinatura. Nada nessa página envia nada: o intercâmbio é devolvido para ser entregue através de um canal, que é onde o parceiro, as credenciais e o registo de auditoria pertencem.

8.3.9 Segmentos binários

Um segmento BIN transporta bytes brutos, e bytes brutos contêm delimitadores. Cada segmento X12 termina no terminador de segmento, por isso um analisador comum encontra segmentos procurando por um byte; um anexo não pode ser encontrado dessa forma. Um PDF que contenha um ~ seria cortado em pedaços, e cada pedaço é um segmento estruturalmente válido — por isso o documento é truncado, cada segmento após ele está desalinhado, e nada relata um erro.

O Perfuse lê a contagem de bytes que o segmento declara e pega exatamente esses bytes. Duas consequências dignas de nota:

O próprio guia esMD declara 16 bytes para a mesma carga útil de 53 bytes que a sua tabela conta corretamente como 53. O Perfuse recusa essa amostra, como deve ser. Um teste mantém tanto o exemplo da tabela quanto o erro de digitação da amostra, para que uma alteração em qualquer direção seja notada.

8.4 FHIR

8.4.1 O que uma mensagem HL7 v2 se torna

O tipo de mensagem decide o que é produzido, e cada conversão relata os julgamentos que precisou como notas ao lado do pacote.

v2FHIR
ADTPaciente, um Encontro quando há uma visita, uma Condição por diagnóstico DG1 (também listada no Encontro diagnosis, um admitido como AD), um Procedimento por PR1 e uma AlergiaIntolerância por AL1. A28, A31, A29 e A24 são sobre a pessoa, então não produzem Encontro ou diagnósticos, mas transportam alergias.
ORURelatório de Diagnóstico por OBR, com suas Observações e Espécime, e o pedido que responde como um ServiçoSolicitado (seu solicitante OBR-16 ou ORC-12, seu status ORC-5); OBR-32 é o intérprete dos resultados, OBR-34 e OBR-35 são os realizadores. Os resultados são agrupados sob o OBR antes deles por posição, porque OBX-4 não é confiável.
ORM, OML, OMGServiçoSolicitado.
SIUCompromisso, com o paciente, os profissionais de saúde de AIP e os locais de AIL.
MDMReferência de Documento que transporta o documento.
VXUImunização, uma por RXA.

Qualquer outra coisa produz o Paciente e um aviso que nomeia o tipo que não foi mapeado.

Agendamento. Uma reserva, uma reagendamento, um cancelamento e um não comparecimento todos aterrissam no mesmo Compromisso. A sua identidade vem dos próprios números do compromisso em SCH-1 e SCH-2, nunca da mensagem, então um cancelamento atualiza a reserva. A alternativa seria um segundo compromisso cancelado ao lado de um compromisso ativo, o que mostra o paciente reservado em um slot que não existe mais.

Documentos. Notas de texto (TX, FT, ST) mantêm suas quebras de linha, incluindo linhas em branco, porque uma repetição em branco em uma nota é uma quebra de parágrafo.

Isto é o que o critério 14 do Quadro de Interoperabilidade da CMS pede: notas de gráficos e documentos clínicos devolvidos como anexos FHIR.

Imunizações. Uma dose nunca é relatada como administrada quando a mensagem diz o contrário.

Entrada desconfortável. Cada uma dessas é relatada nas notas em vez de decidida silenciosamente:

Identifier.period. Uma autoridade de atribuição que carrega um OID ISO (AUSHIC&2.16.840.1.113883.3.879&ISO) se torna urn:oid:. Um código de tipo fora da tabela HL7 0203 é mantido como texto, não rotulado como um.

outro evento, como um A08, nada é fundido e um aviso diz que o identificador anterior ainda está ativo.

caso contrário, o offset em MSH-7 (v2 presume o tempo local do remetente), caso contrário, UTC. Um tempo de nascimento é a exceção: sem offset de qualquer um dos três, é omitido em vez de ser rotulado como UTC, porque um offset errado pode mover um nascimento para outro dia. birthDate é mantido, e um aviso diz que o tempo foi omitido e que definir um fuso horário para a fonte o mantém.

DocumentReference que a Observation aponta em derivedFrom, desde que uma Observation R4 não tenha um valor de anexo. Um comparador SN de = é omitido como redundante; <> mantém o texto, porque nenhuma quantidade pode dizer "não igual".

UNK, porque R4 exige uma classe.

8.4.2 O que um site adiciona: o script do pacote

Um perfil nacional frequentemente quer o que uma mensagem HL7 v2 não transporta: o número IK de um hospital ou o código ODS, qual nível de contato uma visita é (ISiK), se um nome próprio é um primeiro nome ou uma inicial (o nl-core holandês). O Perfuse não adivinha essas coisas. Um destino fhir com bundle_script é onde um site as escreve: JavaScript executado em cada Conjunto convertido, como bundle, antes de ser validado e enviado. O que o script deixa é o que sai, verificado como qualquer conversão, e um script que lança falha na mensagem como qualquer transformador faz. A console o tem sob o destino *Adicionar o que seus sistemas sabem*.

destinations:
  - name: kis
    type: fhir
    fhir:
      url: https://fhir.klinikum.example/fhir
      version: "4.0.1"
      identifier_systems: {KLINIKUM-MUSTERSTADT: "https://fhir.klinikum-musterstadt.example/sid/patientennummer"}
      bundle_script: |
        bundle.entry.forEach(function (e) {
          if (e.resource.resourceType === "Organization" && e.resource.name === "KLINIKUM-MUSTERSTADT") {
            e.resource.identifier = [{system: "http://fhir.de/sid/arge-ik/iknr", value: "260326822"}];
          }
        });

perfuse fhir convert -bundle-script FILE executa o mesmo script, para que um site possa testá-lo primeiro nas suas próprias mensagens. Dois exemplos funcionais estão no repositório: examples/isik/bundle-script.js (IKNR, Kontaktebene, número de paciente do tipo MR, Diagnosetyp) e examples/nictiz/bundle-script.js (nomes e iniciais). Com eles, as mensagens alemãs e holandesas inventadas em conformance/national passam de 18 para 42 de 47 recursos válidos contra ISiK e de 12 para 18 de 24 contra nl-core; o que resta está nas mensagens ou no servidor de terminologia e é listado lá.

O Pacote passa pelo modelo do Perfuse a caminho de volta, então as alterações de um script são verificadas e escritas na versão FHIR do destino. Membros que o modelo não tem campo para são mantidos como o script os escreveu, dentro de tipos de dados também.

8.4.3 US Core 9.0.0 e USCDI v6

-us-core (e claim_us_core em um destino fhir) coloca um perfil US Core em meta.profile, mas apenas em um recurso que foi verificado contra esse perfil e encontrado conforme. Um que não atende é ainda convertido e enviado sem a reivindicação, e uma nota fornece o motivo, como "US Core requer um tipo de encontro, e este Encontro não tem nenhum". As verificações são transcritas do US Core 9.0.0, a versão que o processo de avanço de padrões de 2026 da ONC aprova para USCDI v6. Elas cobrem Patient, Encounter, Observação e DiagnosticReport de laboratório, Specimen, Practitioner, Organization, Location, Immunization, DocumentReference, Condição de diagnóstico de encontro e AllergyIntolerance.

O que o conversor carrega, por classe de dados USCDI v6:

USCDI v6DeComo
Dados Demográficos do PacientePIDNome, data de nascimento, sexo, endereço, telefone e e-mail, identificadores. Raça e etnia (PID-10, PID-22) nas extensões do US Core quando codificadas em Raça e Etnia da CDC. Idioma preferido (PID-15) como BCP 47
Informações de EncontroPV1Encontro com tipo, classe, período, localização e participantes
Informações de InstalaçãoPV1-3Localização, com a instalação como sua Organização gerenciadora
Problemas, Data de InícioDG1Condição (diagnóstico de encontro). DG1-5 é o início, como o mapa HL7 v2 para FHIR o tem
Alergias e Intolerâncias, ReaçãoAL1AlergiaIntolerância com categoria, criticidade e reação
LaboratórioORURelatório de Diagnóstico, Observações, Espécime (de SPM), ServiceRequest
PedidosORM, OMLServiceRequest
ImunizaçõesVXUImunização
Notas ClínicasMDMDocumentReference
Membros da Equipe de CuidadosPV1, TXA, DG1Profissional

Não transportado, porque as mensagens v2 desses tipos não os contêm ou o Perfuse não os mapeia: Medicações, Procedimentos, Metas e Preferências, Avaliações de Status de Saúde, Plano de Cuidados, Histórico de Saúde Familiar, Dispositivos Médicos (UDI), Informações de Seguro de Saúde, Sinais Vitais como um perfil distinto, e Proveniência.

8.4.4 R4 em ambas as direções

Um servidor FHIR que declara R4 aceita R4. Isso não era verdade para Encontros até esta versão. O servidor convertia o que servia para R4, mas lia o que recebia como se já estivesse em sua forma interna, então um Encontro R4 era recusado com um 400. Assim também era recusado cada pacote que a própria conversão ADT do Perfuse produzia, porque cada um carrega Encounter.class, que R4 escreve como um único codificação.

Foi descoberto da primeira vez que algo postou uma ADT convertida para o próprio servidor R4 do Perfuse. Um teste agora faz isso para cada tipo de mensagem mapeada, e outro verifica que tudo escrito como R4 é lido de volta inalterado.

8.4.5 Resumo Internacional do Paciente

GET /fhir/Patient/{id}/$summary, ou GET /fhir/Patient/$summary?identifier=system|value, devolve um Resumo Internacional de Paciente (HL7 IPS 2.0.0): um conjunto de documentos FHIR document cuja Composição lista os problemas ativos do paciente, alergias, medicamentos, imunizações, resultados, sinais vitais, procedimentos, dispositivos, doenças passadas, história social e planos de cuidados, cada um com uma narrativa legível. É o registo curto que um clínico que nunca conheceu o paciente lê primeiro, e o resumo que o Espaço Europeu de Dados de Saúde troca entre países a partir de 2029.

É construído a partir do que o repositório FHIR mantém, e nada é inventado:

contém a razão codificada unavailable e afirma que o servidor não contém informações, "o que não significa que não existam". Uma lista de alergias vazia nunca deve ser lida como "nenhuma alergia conhecida".

O acesso segue $everything: um token limitado a um paciente recebe um 403 para outro, e um identificador que corresponde a dois pacientes é recusado em vez de adivinhado. Apenas o perfil IPS é construído; pedir outro profile é recusado. O documento que o Perfuse produz a partir dos seus registos de teste valida contra o perfil de Conjunto IPS 2.0.0 com o validador HL7, sem erros. Um registo construído a partir de feeds reais ainda pode falhar onde os próprios códigos do feed falham (por exemplo, um nome de exibição que o sistema de códigos não utiliza), porque o resumo passa os dados como foram recebidos.

Exchange → Health links → Share preenche o conteúdo com um resumo do paciente: digite o id FHIR do paciente e escolha Use o resumo do paciente, então leia-o e crie o link. A construção é auditada como fhir.summary.

8.4.6 Resumos de transferência para cuidados pós-agudos (PACIO)

Quando um paciente deixa o hospital para uma casa de repouso, uma unidade de reabilitação ou cuidados domiciliares, o EHR do hospital envia um C-CDA: um resumo de transferência, um resumo de alta ou um CCD. O Perfuse converte esse documento no resumo de transferência descrito no guia Transitions of Care do PACIO (hl7.fhir.us.pacio-toc 1.0.0): um conjunto de documentos FHIR R4 document, com US Core 8.0.1 interior, que o sistema da instalação receptora pode arquivar sem que ninguém leia XML.

allergies, behavioral health, functional status, immunizations, discharge instructions, medical devices, medications, plan of care, problems, procedures, reason for referral, results, social history and vital signs.

unavailable and the sentence "The sending document had no ... section". An empty allergy section must not read as "no known allergies".

status, behavioral health (the C-CDA's mental status section), advance directives, medical devices, plan of care, discharge instructions, reason for referral and social history are sent this way today; the notes say so for each.

problems and discharge diagnoses (US Core Condition, problem list or encounter diagnosis), procedures, immunizations, results, vital signs, and medications as a PACIO medication list of MedicationStatements (104204-3, discharged medication list, from a discharge medications section; 104202-7, active medication list, otherwise).

(85354-9) with two components, and a more specific code (body weight measured, 3141-9) also carries the code FHIR's vital-signs profiles fix (29463-7), beside the original.

digit is valid), its custodian the custodian Organization, its encompassing encounter the stay the summary closes. A document with no person as author, or no custodian, is refused: the guide requires both, and Perfuse will not put a name on a clinical record that nobody gave.

negated allergy to one drug is refused, because FHIR cannot say it and the resource would say the opposite; a negated problem is refuted.

Três maneiras de fazer um:

Bundle endpoint (url), or writes <document>.transfer.json to dir. In the channel builder: Emit › A PACIO transfer summary.

Verificado com o validador oficial FHIR contra o perfil de Bundle TOC 1.0.0, nos próprios exemplos de C-CDA da HL7 (um resumo de transferência, um resumo de alta e um CCD). O único erro que relata está no guia: cada sinal vital corresponde tanto à sua simple-observation como à sua fatia de entrada de vital-signs do Bundle, por isso não pode ser evitado por nenhum remetente. Ainda não feito: transformar as seções de texto apenas (estado funcional, estado mental, plano de cuidados, dispositivos) em recursos codificados e o DocumentReference do guia TOC que indexa um resumo de transferência armazenado.

8.4.7 Assinaturas

Com -fhir-subscriptions, o endpoint FHIR envia notificações quando um Encontro ou um Compromisso é criado ou alterado. Ele segue o R5 Backport IG para R4, que é o que o CMS Interoperability Framework criterion 15 e o TEFCA's FHIR roadmap usam para notificações de encontro e compromisso.

Um cliente cria uma Subscription que nomeia um tópico, e opcionalmente um filtro como Encounter?patient=Patient/123. Os tópicos estão listados na declaração de capacidade:

TópicoDispara emFiltros
https://perfuse.health/fhir/SubscriptionTopic/encounterEncontro criado ou atualizadopatient, status, class
https://perfuse.health/fhir/SubscriptionTopic/appointmentCompromisso criado ou atualizadopatient, status

Um filtro que nomeia qualquer outra coisa é recusado, não ignorado. Um filtro ignorado é uma assinatura que notifica sobre todos os pacientes quando o cliente pediu sobre um.

As propriedades em torno das quais a implementação é construída:

O que um cliente pode fazer o servidor fazer é limitado deliberadamente:

Está desligado a menos que seja solicitado, porque uma vez ligado, um cliente FHIR pode fazer com que este servidor envie dados do paciente para uma URL da escolha do cliente. Ele precisa de um endpoint R4 que aceite gravações e se recusa a iniciar caso contrário.

Não implementado, para que ninguém tenha que descobrir tentando:

A visão Subscriptions mostra o tópico de cada assinatura, filtro e endpoint, quantos eventos ela teve, quantos foram aceitos e quantos estão aguardando, e o último motivo pelo qual um foi recusado. Os valores de cabeçalho e a sequência de consulta do endpoint são retidos, porque é onde as credenciais do assinante vivem.

8.5 NCPDP Telecommunication Standard

Reivindicações de farmácia. Cabeçalho de largura fixa seguido por segmentos variáveis.

Dois detalhes que importam, ambos fáceis de errar e produzir resultados plausíveis:

O cabeçalho tem exatamente 56 bytes e largura fixa. Um cabeçalho curto não pode ser detectado apenas pelo comprimento, porque um cabeçalho truncado mais os segmentos seguintes ainda excede 56 bytes. A detecção é feita verificando se o cabeçalho contém um byte separador, portanto, o cabeçalho é verificado e uma mensagem que contém um é recusada com o número de bytes que está faltando.

0x1E e 0x1C são marcadores de início de grupo e campo, não separadores. Tratá-los como separadores desloca cada campo um lugar para a esquerda, e a maioria dos valores resultantes permanece plausível — uma quantidade cai onde uma oferta de suprimento diário era esperada e ambos são números.

Os canais NCPDP e SCRIPT são excluídos do enquadramento MLLP, e isso é aplicado em vez de aconselhado. Um pedido legítimo contém 0x1C, que é o byte de fim de bloco do próprio MLLP, então enquadrar um pedido truncaria no primeiro marcador de campo.

8.6 NCPDP SCRIPT

Prescrições eletrônicas, em XML. O pacote interno é chamado de eprescribe porque script foi usado pelo mecanismo JavaScript.

A principal preocupação de segurança é a flag de substituição, e ela lê de trás para a frente em relação à intuição: na rede, 0 significa que a substituição é permitida e 1 significa dispensar conforme escrito.

Uma flag de substituição ausente é recusada em vez de ser preenchida com um valor padrão. Ambos os valores padrão possíveis atingem o paciente — um pode dispensar um genérico onde o prescritor exigia a marca, o outro impede uma substituição que o prescritor permitiu — então não há uma suposição segura e a mensagem é interrompida.

Uma prescrição de Classe II com reabastecimento é recusada, e o construtor não produzirá uma.

Recusas e avisos são mantidos como listas separadas em vez de uma lista com uma etiqueta de gravidade, porque um leitor que precisa verificar um campo de gravidade para saber se a mensagem foi enviada eventualmente não verificará.

Autorização prévia eletrônica (PAInitiationRequest, PARequest, PAAppealRequest, PACancelRequest) e Benefício de Prescrição em Tempo Real são respondidos pelo lado pagador em /ncpdp/script e /ncpdp/rtpb, a partir do formulário de medicamentos; veja CMS-0057.

8.7 DICOM

Imagem. O Perfuse pode receber objetos DICOM, consultar um arquivo remoto e armazená-los em um, sobre os serviços de rede DICOM clássicos ou sobre o DICOMweb, e pode manter um arquivo próprio para visualizadores.

DICOM não é um formato de mensagem no mesmo sentido que os outros — os objetos são grandes, e o aperto de mão da associação é mais importante do que a análise da carga. Os títulos called_ae e calling_ae são a razão mais comum para que uma primeira conexão falhe, e a falha parece um problema de rede em vez de um problema de configuração.

8.7.1 O que um ouvinte C-STORE aceita

Deixar aberto, um ouvinte DICOM aceita qualquer coisa de qualquer pessoa que possa alcançar a porta. Quatro configurações em O que este ouvinte aceita restringem isso, e a primeira é a que vale a pena entender.

Apenas aceitar estes títulos AE de chamada é a restrição. O título AE *chamado* — o que está ao lado do endereço — é o nome que um remetente discar, então identifica este ouvinte em vez do remetente, e não é uma restrição. Qualquer pessoa que possa alcançar a porta pode usar o título AE chamado correto, porque ele é publicado para eles. Sem uma lista de chamadores permitidos, qualquer host na rede pode empurrar imagens em um canal clínico.

Apenas aceitar estas classes SOP e apenas aceitar estas sintaxes de transferência aceitam UIDs separados por vírgulas. Vazio aceita todos os tipos de objetos e negocia qualquer compressão que o remetente ofereça, o que inclui tipos que os destinos deste canal não podem lidar. Recusar na associação é mais claro para o remetente do que aceitar o objeto e falhar posteriormente.

Objeto maior aceito está em bytes, e zero significa sem limite. Imagens de lâmina inteira e séries longas chegam a gigabytes, então o limite é de outra forma de memória.

8.7.2 DICOMweb

DICOMweb é DICOM sobre HTTP: as pesquisas QIDO-RS, WADO-RS e WADO-URI recuperam, STOW-RS armazena. Visualizadores de navegador como o OHIF só falam DICOMweb, assim como os serviços de imagem em nuvem (Google Cloud Healthcare, Azure Health Data Services, AWS HealthImaging). O Perfuse utiliza-o em três locais.

O arquivo de imagens. Inicie o servidor com -dicomweb-archive DIR (Configurações › Dados › Arquivo de imagens) e ele manterá os objetos naquela pasta, indexados no SQLite, e os servirá em /dicomweb no endereço próprio da console: QIDO-RS nos níveis de estudo, série e instância, WADO-RS para objetos, metadados, quadros e dados em massa, WADO-URI em /dicomweb/wado e STOW-RS. A leitura assume o papel de visualizador e o armazenamento o papel de operador, com uma sessão ou um token de API; cada leitura e armazenamento é registrado em Atividade como dicomweb.read ou dicomweb.store. Uma conta limitada a um *tenant* ou a grupos de canais é recusada, porque o arquivo pertence ao servidor como um todo. Os objetos são mantidos exatamente como recebidos, então o que um visualizador recupera é byte a byte o que foi armazenado. Os quadros são devolvidos na sintaxe de transferência em que foram armazenados; um pedido que precisasse de transcodificação responde com 406 em vez de uma imagem convertida.

Uma pesquisa em um atributo que o arquivo não indexa responde 400 em vez de ignorar a condição e retornar mais estudos do que foram solicitados. Índices: nome do paciente (caracteres curinga e correspondência difusa com fuzzymatching=true), ID do paciente, data de nascimento, sexo, data e hora do estudo (intervalos), número de acesso, ID do estudo, descrição, médico que remeteu, estudo, série e UID de instância SOP (listas), modalidade, parte do corpo, número da série e descrição, classe SOP, número de instância, linhas, colunas e número de quadros.

A fonte. type: dicomweb ouve STOW-RS, em /dicom-web/studies por padrão (o caminho que Orthanc e dcm4chee usam), e envia todos os objetos pelo canal como uma mensagem DICOM. O canal precisa de dataType: dicom. Defina um token de portador ou um nome de usuário e senha: sem um, qualquer pessoa que possa alcançar a porta pode enviar imagens para o canal. A resposta lista cada objeto como armazenado ou com falha, com o motivo de falha DICOM, para que o remetente saiba quais reenviar.

name: imaging-from-viewers
dataType: dicom
source:
  type: dicomweb
  dicomweb:
    listen: 0.0.0.0:8043
    token: ${STOW_TOKEN}
    tls: { enabled: true, cert_file: /etc/perfuse/imaging.crt, key_file: /etc/perfuse/imaging.key }
destinations:
  - name: archive
    type: dicomweb
    dicomweb:
      url: https://perfuse.example/dicomweb
      token: ${ARCHIVE_TOKEN}

Apontar OHIF para o arquivo

Use uma fonte de dados DICOMweb com qidoRoot e wadoRoot definidos para o endereço do arquivo (a tela Imagem mostra, com o bloco de fonte de dados completo para copiar), wadoUriRoot para esse endereço seguido de /wado, imageRendering e thumbnailRendering para wadors, e supportsFuzzyMatching verdadeiro. Um visualizador em outra origem precisa dessa origem em -dicomweb-cors (Origens de navegador permitidas para chamá-lo), e suas solicitações precisam de um token de API no cabeçalho Authorization, porque um navegador em outra origem não envia o cookie de sessão da console. Servir OHIF da mesma origem por meio de um proxy reverso evita ambos.

Testado contra o Orthanc com o seu plugin DICOMweb, em ambas as direções: o destino armazena no Orthanc, e o cliente DICOMweb do Orthanc procura o arquivo do Perfuse e recupera um estudo byte-identical ao armazenado. O OHIF 3 lista os estudos do arquivo e exibe seus quadros com as configurações acima. O OHIF e vários outros clientes enviam type= não citado nos cabeçalhos Accept e Content-Type, o que o RFC 2045 não permite; o Perfuse aceita.

8.8 Compartilhamento de documentos IHE: XDS.b, XCA, XDR, MHD, PIXm e PDQm

Documentos clínicos partilhados entre organizações da forma como os intercâmbios de informações de saúde, Carequality e eHealth Exchange o fazem: um repositório os armazena, um registo indexa os seus metadados e uma comunidade responde às consultas de outras comunidades através de um gateway. Inicie o servidor com -xds REPOSITORY-OID (Configurações › Dados › Partilha de documentos) e ele desempenha as três funções, no banco de dados deste servidor, nestes endereços, cada um aceitando um token de API como um token de portador (o papel de visualizador para consultar e recuperar, o papel de operador para submeter; a maioria dos domínios de afinidade adiciona TLS mútuo na frente):

EndereçoAtorTransações
/xds/repositoryRepositório de DocumentosITI-41 Fornecer e Registrar Conjunto de Documentos-b, ITI-43 Recuperar Conjunto de Documentos
/xds/registryRegistro de DocumentosITI-18 Consulta de Registro Armazenada (todas as treze consultas armazenadas), ITI-42 Registrar Conjunto de Documentos-b
/xca/gatewayGateway de Resposta XCAITI-38 Consulta de Gateway Cruzado, ITI-39 Recuperar Gateway Cruzado, com -xds-home-community urn:oid:...
/mhdRecipiente e Responder de Documentos MHDITI-65 Fornecer Pacote de Documentos, ITI-66 Encontrar Listas, ITI-67 Encontrar Referências de Documentos, ITI-68 Recuperar Documento
/mhd/PatientFornecedor PDQm e Gerente PIXmITI-78 Consulta de Demografia de Paciente, ITI-83 Patient/$ihe-pix, a partir do armazenamento de Pacientes do FHIR
/pixv3Gerente PIX (HL7 v3)ITI-44 Alimentação de Identidade de Paciente HL7 V3, ITI-45 Consulta PIXV3, a partir do índice de pacientes (-mpi)
/pdqv3Fornecedor PDQ (HL7 v3)ITI-47 Consulta PDQV3, com continuação e cancelamento, a partir do índice de pacientes

As transações SOAP são SOAP 1.2 com WS-Addressing, e MTOM/XOP onde os documentos viajam (um documento inline como base64 também é aceito). Uma transação com falha é respondida com um RegistryResponse que carrega os códigos de erro da IHE, e não uma falha SOAP: XDSDuplicateUniqueIdInRegistry, XDSNonIdenticalHash, XDSPatientIdDoesNotMatch, XDSMissingDocument, XDSRegistryMetadataError (com o campo que está faltando), XDSStoredQueryMissingParam, XDSUnknownStoredQuery, XDSUnknownRepositoryId, XDSUnknownCommunity e UnresolvedReferenceException. Um substituto (RPLC, XFRM_RPLC) deprecia o documento que substitui, que então responde apenas a consultas que pedem documentos depreciados; APND, XFRM e signs são mantidos como associações. O hash e o tamanho são computados pelo repositório e verificados contra o que a submissão diz. Documentos e metadados sob demanda (ITI-57) não são suportados, e uma submissão que os pede é recusada com o motivo.

MHD é o mesmo registro em FHIR: um documento fornecido sobre MHD é encontrado por ITI-18 e sobre XCA, e um fornecido sobre XDS.b é encontrado por ITI-67. O id de um DocumentReference é o UUID da entrada, seu masterIdentifier é o uniqueId, e a url do seu anexo é o endereço ITI-68 do documento. Pacientes são resolvidos para o identificador do domínio de afinidade a partir do armazenamento FHIR: o primeiro identificador cujo sistema é urn:oid:, ou o Patient transportado no Bundle. PIXm responde a todos os outros identificadores do Patient com o fornecido (sourceIdentifier=system|value, estreitado por targetSystem), e 404 para um que não conhece; PDQm procura por identificador, nome, data de nascimento, gênero, endereço e telecom.

Publicação. O destino xds de um canal publica cada documento clínico que recebe, um documento CDA ou um transportado em uma mensagem HL7 v2, para qualquer repositório XDS.b com ITI-41. Os metadados são lidos do documento: o paciente (o identificador em patient_domain, a autoridade de atribuição do domínio de afinidade), título, tipo (como typeCode e, a menos que definido, classCode), tempos de criação e serviço, autor, confidencialidade, idioma e formato (corpo estruturado C-CDA 2.1 ou 1.1, XDS-SD, ou mimeTypeSufficient, a partir de seus modelos); e completados com o que um documento não diz: o source_id do remetente, o facility_type e practice_setting que cada registro exige. A resposta do repositório decide a entrega: uma Falha, ou um erro em uma PartialSuccess, é uma entrega com falha com os códigos de erro do registro.

destinations:
  - name: hie
    type: xds
    xds:
      url: https://hie.example/xds/repository
      source_id: 1.2.840.114350.1.13.99
      patient_domain: 1.2.840.114350.1.13.99.2.7.5.737384.14
      facility_type: { code: "225732001", scheme: 2.16.840.1.113883.6.96, display: Community hospital }
      practice_setting: { code: "394802001", scheme: 2.16.840.1.113883.6.96, display: General medicine }
      tls: { enabled: true, cert_file: /etc/perfuse/hie.crt, key_file: /etc/perfuse/hie.key }

XDR. Adicione direct_from (seu endereço Direct) e direct_to (dos destinatários) e o mesmo destino envia XDR como o transporte Direct, conforme descrito no *XDR e XDM para Mensagens Direct* do Projeto Direct: um bloco de endereçamento Direct (urn:direct:addressing) no cabeçalho SOAP nomeia o remetente e os destinatários, e o intendedRecipient da submissão nomeia cada destinatário (||^^Internet^address). Aponte url para o endpoint XDR do destinatário ou um HISP que aceita XDR. O XDR viaja sobre TLS, geralmente com um certificado de cliente (tls), e não é S/MIME. Uma origem direct também aceita XDR (veja Direct abaixo).

    xds:
      url: https://xdr.hisp.example/xdr
      source_id: 1.2.840.114350.1.13.99
      patient_domain: 1.2.840.114350.1.13.99.2.7.5.737384.14
      facility_type: { code: "225732001", scheme: 2.16.840.1.113883.6.96, display: Community hospital }
      practice_setting: { code: "394802001", scheme: 2.16.840.1.113883.6.96, display: General medicine }
      direct_from: referrals@direct.hospital.example
      direct_to: ["intake@direct.clinic.example"]
      tls: { enabled: true, cert_file: /etc/perfuse/xdr.crt, key_file: /etc/perfuse/xdr.key }

PIX e PDQ na versão 3 do HL7. Com o índice de paciente ativado (-mpi), /pixv3 é um Gestor de PIX e /pdqv3 um Fornecedor de PDQ sobre SOAP 1.2, para os hospitais e exchanges que ainda utilizam os perfis v3 do IHE. Uma fonte alimenta pacientes com ITI-44 (registro adicionado PRPA_IN201301UV02, revisado PRPA_IN201302UV02, duplicatas resolvidas PRPA_IN201304UV02): o primeiro identificador do paciente é o seu registro, os outros e aqueles em asOtherIDs são identificadores que ele possui, e uma mesclagem dobra o identificador do registro anterior no sobrevivente, como um A40 do HL7 v2. ITI-45 (PRPA_IN201309UV02) responde com os outros identificadores da pessoa que detém um, limitado por dataSource, em Patient.id; o identificador consultado retorna apenas na consulta repetida. ITI-47 (PRPA_IN201305UV02) combina dados demográficos (nome, gênero, hora de nascimento, identificador, endereço, telecom) com o próprio comparador de índice, minimumDegreeMatch como uma pontuação de 100, otherIDsScopingOrganization limitando os domínios, e initialQuantity paginando a resposta: o restante vem com QUQI_IN000003UV01 por dez minutos, ou é descartado pelo seu cancelamento. As respostas seguem os casos das transações: um paciente desconhecido ou domínio é AE com erro 204 e a localização do parâmetro, um paciente conhecido com nada nos domínios solicitados é NF. v3 nomeia uma autoridade por OID apenas, então um identificador cujo sistema é uma URL sem OID por trás (alguns números nacionais) é deixado de fora das respostas v3 e dado sobre FHIR; defina o sistema do identificador da empresa para um OID (urn:oid:..., nas configurações do índice) para o EUID e o custodiante aparecer. O papel do visualizador consulta e o papel do operador alimenta; cada transação é auditada com um identificador, nunca um nome. Uma mensagem v3 nua postada como application/xml é respondida da mesma forma, o que é útil para testes manuais.

Troca › Compartilhamento de documentos mostra o que o registro contém e onde é alcançado, encontra os documentos de um paciente neste registro ou em outro (um registro ITI-18 ou um gateway ITI-38), baixa um e publica um documento CDA manualmente com os metadados que um destino lhe daria.

Verificado contra a ferramenta XDS da NIST 7.13.0, a implementação de referência da IHE: Perfuse's ITI-41, ITI-18 e ITI-43 contra seu simulador de Registro/Repositório (aceito com nenhum erro de validação, o documento recuperado byte-identical), e seu simulador de Gateway de Iniciação que consulta e recupera do Gateway de Resposta do Perfuse sobre XCA, sem erros em seu log. Cada mensagem SOAP que o Perfuse escreve é válida contra os esquemas ebXML Registry 3.0 e XDS.b, e o DocumentReference e o SubmissionSet do MHD contra o validador FHIR da IHE MHD 4.2.2. O XDR de um destino xds com um bloco de endereçamento direto foi aceito pelo simulador de Recipiente de Documento da ferramenta, cuja validação de metadados encontrou o único defeito descrito em docs/verification.md, e pelo validador XDR do SITE da ONC, a lista de verificação XDR direta do teste de certificação (h)(2) aplicado. As respostas PIX e PDQ v3 são válidas contra os esquemas HL7 V3 da IHE (NE2008 multicacheschemas), e as próprias mensagens de amostra da IHE (a alimentação ITI-44, mesclagem, consulta ITI-45, consulta ITI-47, continuação e cancelamento) são respondidas como mostram as respostas publicadas. Ainda não verificado contra uma implementação independente de PIX ou PDQ v3, Gazelle ou um Connectathon.

8.9 Mensagens seguras diretas

Direct é como os provedores de saúde dos EUA enviam referências, resumos e resultados entre si por e-mail seguro: cada mensagem é assinada com o certificado do remetente e criptografada para o certificado do destinatário (S/MIME), e viaja entre HISPs (Provedores de Serviços de Informação de Saúde) que emitem os endereços e os garantem. O Perfuse é o sistema de borda ao lado do seu HISP, não um HISP: o HISP emite o seu endereço, seu certificado e sua chave, e você mantém o pacote de confiança do HISP (como o DirectTrust). Ele segue a Declaração de Aplicabilidade do Direct para Transporte de Saúde Seguro 1.2, o Guia de Implementação para Notificação de Entrega, XDM do IHE (ITI TF-1 Anexo 15) para documentos com metadados, o Guia de Implementação para Descoberta de Certificado do Projeto Direct (DNS e LDAP), e XDR e XDM para Mensagens Direct.

Sending. A direct destination signs each message as your address (SHA-256, RSA), encrypts it to every recipient's certificate and your own (AES-256-CBC, RSA key transport), and submits it to the HISP by SMTP with STARTTLS required. The message travels as an attachment named by its content (document.xml, message.hl7, resource.json), or, with xdm: true, a CDA document travels as an IHE XDM package (IHE_XDM/SUBSET01/METADATA.XML with the document and its hash and size, plus INDEX.HTM and README.TXT) that receiving EHRs import with its metadata. Recipient certificates come from the Direct address book (below), then from DNS, where Direct publishes them as CERT records (RFC 4398): under the address with its @ made a dot, else under its domain; then from the recipient domain's LDAP directory, which its _ldap._tcp SRV record names (or ldap: host:port; ldap: off never asks one): each naming context is searched anonymously for an entry whose mail is the address, then the domain, and its userSMIMECertificate or userCertificate read. A certificate is used only when it is for the address or its domain, has not expired, and chains to one of your anchors, fetching any intermediate issuer its Authority Information Access extension names; and it is refused when its issuer's revocation list (from its CRL distribution point, signed by that issuer) lists it. A list that cannot be fetched does not stop delivery. A recipient with no such certificate is a failed delivery, never plain e-mail. to and subject take field references such as {PV1-8.1}, and request_mdn asks the recipient for a delivery notification.

destinations:
  - name: referrals
    type: direct
    direct:
      address: referrals@direct.hospital.example
      cert_file: /etc/perfuse/direct/referrals.crt   # with its chain after it
      key_file: /etc/perfuse/direct/referrals.key
      anchors_file: /etc/perfuse/direct/anchors.pem
      to: ["intake@direct.clinic.example"]
      subject: "Referral for {PID-5.1}"
      text: "Please see the attached summary."
      xdm: true
      xdm_source_id: 1.2.840.114350.1.13.99
      smtp_host: smtp.hisp.example:587
      username: referrals
      password: ${DIRECT_HISP_PASSWORD}
      request_mdn: true

Recepção. Uma fonte direct é o servidor SMTP que o HISP entrega o correio da sua morada. Aceita apenas correio para essa morada (qualquer outra coisa é recusada no RCPT), exige STARTTLS quando fornecido um certificado e abre cada mensagem antes que algo a leia: decifra-a com a sua chave, verifica a assinatura contra os seus âncoras e verifica que o certificado de assinatura é para o endereço De ou seu domínio. Uma mensagem que não está encriptada S/MIME, é assinada por um remetente em quem não confia ou é assinada por um certificado para outra pessoa é recusada no DATA com o motivo, para que o HISP a mantenha e a relate ao remetente; o Perfuse nunca aceita o que depois rejeita. Um pacote XDM tem os seus documentos transformados em mensagens (verificados contra os hashes nos seus metadados); caso contrário, cada anexo o é, ou o texto quando não há anexos. Com smtp_host definido, cada mensagem recebida é respondida com uma notificação "processada" assinada e encriptada (MDN), e as notificações que chegam para o que enviou são registadas.

source:
  type: direct
  direct:
    address: intake@direct.clinic.example
    cert_file: /etc/perfuse/direct/intake.crt
    key_file: /etc/perfuse/direct/intake.key
    anchors_file: /etc/perfuse/direct/anchors.pem
    listen: 0.0.0.0:2525
    tls_cert: /etc/perfuse/tls/server.crt
    tls_key: /etc/perfuse/tls/server.key
    smtp_host: smtp.hisp.example:587

A partir da caixa de correio do HISP. Um HISP que mantém a correspondência em vez de entregá-la fornece o endereço de uma caixa de correio IMAP: imap lê (TLS ou STARTTLS, uma nova sessão a cada sondagem), abre cada mensagem como acima, move o que foi retirado para move_to (ou apaga) e o que não pôde ser aberto para error_folder, para que nada seja lido duas vezes. listen pode então ser omitido. Um HISP cujo servidor de correio tenha um certificado privado é confiável com tls.ca_file (seu certificado ou o da autoridade) e tls.server_name; a verificação não pode ser desativada.

    imap:
      host: imap.hisp.example
      username: intake@direct.clinic.example
      password: ${DIRECT_MAILBOX_PASSWORD}
      move_to: Processed

XDR. xdr aceita XDR em /xdr no seu próprio endereço HTTPS, como um HISP envia Direct convertido para SOAP ou um parceiro envia ponto a ponto: uma solicitação ITI-41 Provide and Register cujos documentos se tornam mensagens. Uma submissão cujo bloco de endereçamento Direct nomeia outro endereço é recusada, e uma que o canal não aceita é respondida com uma falha de RegistryResponse dizendo por quê. client_ca_file exige um certificado de cliente dessas autoridades. O XDR é protegido por TLS, não por S/MIME, então uma origem que aceita apenas XDR precisa do endereço, mas não do seu certificado, chave ou âncoras. Cada documento se torna uma mensagem do dataType do canal: documentos CDA precisam de raw (passado como está) ou hl7v3, desde que o padrão, hl7, espera HL7 v2 e os recusa.

    xdr:
      listen: 0.0.0.0:8445
      tls_cert: /etc/perfuse/tls/server.crt
      tls_key: /etc/perfuse/tls/server.key
      client_ca_file: /etc/perfuse/direct/hisp-clients.pem

Exchange › Direct lista os endereços Direct que os seus canais enviam e recebem, juntamente com os certificados, expiração e âncoras; mantém o livro de endereços dos correspondentes (nome, organização, notas e certificado, colados do HISP ou encontrados em DNS ou LDAP, e recusados quando não são para esse endereço ou domínio); e procura os certificados de um endereço em DNS ou LDAP sem salvá-los. O livro é o diretório direct-certs ao lado do banco de dados, um arquivo PEM por endereço ou domínio, que um destino lê a menos que especifique o seu próprio recipient_certs_dir.

Verificado contra OpenSSL 4.0's cms e smime em ambos os sentidos: o que Perfuse assina e criptografa o OpenSSL verifica e decriptografa (PKCS#1 v1.5 e transporte de chave OAEP), e Perfuse abre o que o OpenSSL assina e criptografa (AES-128 e AES-256). Uma mensagem feita com openssl smime e entregue via SMTP é recebida, aberta e armazenada por um canal, e uma que o Perfuse envia a outro por meio de um substituto HISP, que responde com um MDN que o remetente abre. Certificados são encontrados no OpenLDAP 2.4 (vinculados a endereços e domínios, escritos pelo próprio ldapadd do OpenLDAP); uma mensagem Direct é lida de uma caixa de correio IMAP do GreenMail e aberta, e uma que não é Direct é movida para a pasta de erros; XDR de um destino xds é retirado por uma fonte direct e recusado quando endereçado a outra pessoa, e aceito pelo NIST XDS Toolkit's Document Recipient e pelo validador XDR do ONC SITE; a ferramenta de teste de borda XDR Direct do SITE enviou ambas as mensagens de metadados mínimas e completas para uma fonte direct, que as retirou. Contra a ferramenta de descoberta de certificado Direct do ONC, um destino Direct escolhe o certificado correto, ou nenhum, em todos os 18 casos de descoberta (D1 a D18: certificados expirados, revogados e emitidos por AIA, prioridade e peso SRV, um diretório inacessível). Uma fonte Direct lê uma mensagem da própria HISP do SITE (Apache James) via IMAP com STARTTLS. Ainda não testado: troca de SMTP com a HISP do SITE (a AWS segura a correspondência de saída na porta 25 para novas contas) ou com um HISP acreditado.

8.10 SQL em vistas FHIR

Uma ViewDefinition (HL7 SQL no FHIR v2) transforma cada recurso FHIR de um tipo em linhas de colunas nomeadas, cada coluna uma expressão FHIRPath, para que os dados FHIR possam ser lidos como tabelas pelo DuckDB, Athena, Spark, um armazém de dados ou uma planilha. O Perfuse executa-as com o seu próprio mecanismo FHIRPath: column, select aninhado, forEach, forEachOrNull, repeat e unionAll, where, constant (todo o tipo de valor[x]), colunas collection, %rowIndex e as chaves de junção getResourceKey() e getReferenceKey(type).

{
  "resourceType": "ViewDefinition",
  "name": "blood_pressure",
  "resource": "Observation",
  "constant": [{ "name": "systolic", "valueCode": "8480-6" }],
  "where": [{ "path": "code.coding.exists(system = 'http://loinc.org' and code = '85354-9')" }],
  "select": [{ "column": [
    { "name": "id", "path": "getResourceKey()", "type": "id" },
    { "name": "patient_id", "path": "subject.getReferenceKey(Patient)", "type": "id" },
    { "name": "systolic", "path": "component.where(code.coding.code = %systolic).value.ofType(Quantity).value.first()", "type": "decimal" }
  ]}]
}

Monitorar › SQL no FHIR executa uma visão sobre o repositório FHIR deste servidor (um paciente ou todos) ou sobre recursos colados (NDJSON de uma exportação em massa, um Bundle, uma matriz JSON), mostra as linhas e as transfere como CSV, NDJSON ou Parquet. Começa com cinco visões de exemplo (demografia do paciente, observações com um valor, pressão arterial, condições, encontros) e salva as visões no diretório views ao lado do banco de dados, um arquivo JSON cada.

O endpoint FHIR responde à especificação $sql-run ao nível do sistema, por GET ou POST, para uma definição de vista sujeito fornecida inline (subjectResource), por subjectReference (ViewDefinition/<name>, uma vista guardada) ou por subjectCanonical (um url de uma vista guardada), com _format (csv, ndjson (o padrão), json ou parquet), header, patient, _since, _limit e resource para executar sobre recursos enviados com o pedido em vez da loja. É uma leitura: um token SMART precisa das permissões de leitura para o tipo de recurso da vista, um token vinculado a um paciente obtém apenas as linhas desse paciente e as permissões granulares restringem os recursos lidos, como fazem uma pesquisa. Mais de um milhão de linhas precisa de _limit, patient ou _since.

perfuse sof -view v.json [-format csv|ndjson|json|parquet] [-o out] files... executa uma vista sobre ficheiros FHIR sem servidor: os ficheiros NDJSON de uma exportação em massa, Bundles ou arrays.

perfuse sof -view blood_pressure.json -format parquet -o bp.parquet export/Observation.ndjson
duckdb -c "SELECT patient_id, avg(systolic) FROM 'bp.parquet' GROUP BY 1"

Os ficheiros Parquet têm um grupo de linhas e páginas PLAIN não comprimidas; os booleanos são BOOLEAN, os tipos inteiros INT64, os decimais DOUBLE e tudo o resto são cadeias de caracteres UTF-8 (uma coluna de coleção como o seu JSON).

Verificado com o conjunto de testes oficial SQL on FHIR (os 144 testes do repositório sql-on-fhir.js's tests/, executados em cada construção: todos passam), e a saída Parquet lida novamente pelo DuckDB 1.5.6 com os tipos e valores correctos. Não suportado: SQLQuery e SQLView Libraries (SQL sobre as tabelas das vistas), $sql-export, _format=fhir, e os parâmetros source e group; cada um é recusado com o motivo.

8.11 Medidas de qualidade digitais

Uma medida de qualidade digital conta os pacientes em cada população de uma medida FHIR Measure sobre um período de medição (população inicial, denominador, exclusões e exceções do denominador, numerador, exclusões do numerador) e pontua o resultado. A resposta é um relatório de medida FHIR MeasureReport, moldado como o guia Da Vinci Data Exchange for Quality Measures (DEQM) solicita. É aqui que os programas eCQM da CMS e os HEDIS digitais da NCQA estão se dirigindo.

No Perfuse, os critérios de população são FHIRPath ("language": "text/fhirpath"), executados pelo mesmo motor que o SQL on FHIR. Cada critério é avaliado uma vez por paciente. O seu foco é um Bundle do registo do paciente (o compartimento do Paciente), e tem estas variáveis: %subject (o Paciente), %periodStart e %periodEnd (o período, como dateTimes) e %"Measurement Period". Um critério dá verdadeiro ou falso; um único valor que existe conta como verdadeiro.

{
  "code": { "coding": [{ "system": "http://terminology.hl7.org/CodeSystem/measure-population", "code": "numerator" }] },
  "criteria": {
    "language": "text/fhirpath",
    "expression": "entry.resource.ofType(Observation).where(code.coding.where(system = 'http://loinc.org' and code = '4548-4').exists() and effective.ofType(dateTime) >= %periodStart and effective.ofType(dateTime) <= %periodEnd).exists()"
  }
}

As populações aninham-se como a especificação da Medida diz. Um paciente está no denominador apenas se estiver na população inicial. Uma exclusão do denominador remove o paciente antes que o numerador seja julgado. Uma exceção do denominador conta apenas para um paciente que não está no numerador. A pontuação de uma proporção é (numerador - exclusões do numerador) / (denominador - exclusões - exceções); a de uma razão é numerador / denominador; uma coorte tem contagens e não tem pontuação. Estratificadores de critério único dividem cada população pelo seu valor (sexo, por exemplo).

O Perfuse não tem um mecanismo CQL. As Medidas eCQM publicadas da CMS e as medidas digitais HEDIS são escritas em CQL, então não podem ser executadas como estão. Uma Medida cujos critérios são CQL é recusada com esse motivo. Escreva a lógica como FHIRPath em vez disso. A pontuação de variáveis contínuas, estratificadores multicomponentes e sujeitos Grupo ou Profissional são recusados da mesma forma.

Monitor › Medidas de qualidade avalia uma medida sobre o repositório FHIR deste servidor ou sobre recursos colados, por um período. Oferece três relatórios: um resumo, um resumo com os pacientes em cada população, ou um paciente. A tela mostra as populações, a pontuação e as estratificações, e faz o download do MeasureReport. Ele começa com três exemplos: pressão arterial controlada, diabetes com um teste de HbA1c e pacientes vistos no período. Eles são ilustrativos, escritos para este manual e não são medidas eCQMs da CMS ou HEDIS. Salvar no repositório FHIR verifica a Medida e a armazena como um recurso Measure.

O endpoint FHIR responde Measure/[id]/$evaluate-measure e Measure/$evaluate-measure?measure=<url>, por GET ou por POST de um recurso Parameters. Parâmetros:

O relatório é devolvido, não armazenado. A operação é uma leitura, por isso um token SMART precisa de acesso de leitura à Medida e ao Paciente. Um token vinculado a um paciente obtém um relatório individual sobre esse paciente e nenhum outro.

perfuse measure -measure m.json -period-start 2026-01-01 -period-end 2026-12-31 [-type summary|subject|subject-list] [-subject Patient/ID] [-o out] files... avalia uma medida sobre arquivos FHIR (um NDJSON de exportação em massa, Bundles, matrizes) sem um servidor. -measure example:example-bp-control executa um exemplo enviado e -examples lista-os.

Verificado. O validador HL7 FHIR verifica as Medidas fornecidas contra o FHIR R4, sem erros. Verifica um resumo, um indivíduo e um relatório de medida de lista de assuntos contra os perfis de resumo, indivíduo e lista de assuntos do DEQM 5.0.0, também sem erros. Não verificado: equivalência com qualquer eCQM publicado, desde que nenhum possa ser executado aqui sem CQL.

8.12 O índice de paciente (MPI)

Um índice de paciente mestre liga os registos que cada sistema mantém para uma pessoa (o MRN do hospital, o da clínica, o do laboratório) num identificador de empresa, o EUID. Está desligado até alguém decidir mantê-lo, porque é uma tabela de nomes de pacientes, datas de nascimento e identificadores: ative Configurações → Dados → Índice de paciente (ou serve -mpi) e reinicie. Vive em mpi.db ao lado do banco de dados principal.

Alimentando-o. Adicione um destino do tipo mpi (O índice de paciente no construtor) aos canais que transportam registros. Ele lê o PID de cada mensagem HL7 v2 ou um Paciente FHIR em um canal bruto. O identificador do próprio registro é a repetição PID-3 do tipo MR (id_type altera-o); os outros, e PID-19, tornam-se seus outros identificadores. Uma autoridade de designação com um identificador universal (PID-3.4.2 com tipo ISO) torna-se urn:oid:...; uma com apenas um namespace é mapeada por authorities, ou torna-se urn:perfuse:aa:<namespace>. Um A40, A34, A18 ou A39 mescla a pessoa que detém o identificador MRG-1 no pessoa que detém PID-3 (no_merge ignora-os).

destinations:
  - name: index
    type: mpi
    mpi:
      authorities: { HOSP: "urn:oid:1.2.840.114350.1.13.1" }

Correspondência. Um novo registo é vinculado nesta ordem:

  1. Identificadores confiáveis. Um registro que compartilha um identificador de um sistema listado como confiável (um identificador nacional, um número de empresa) é a mesma pessoa, sem pontuação. Nunca liste um sistema que uma família compartilha, como o número de assinante de um pagador.
  2. Pontuação. Caso contrário, as pessoas cujos registros podem corresponder são encontradas por bloqueio (o mesmo sobrenome sonoro e ano de nascimento, a mesma data de nascimento, ou o mesmo número de telefone) e pontuadas com pesos Fellegi-Sunter sobre nome de família e nome próprio (Jaro-Winkler e Soundex, acentos e pontuação ignorados, nomes trocados notados), data de nascimento (um dia e mês trocados é um acordo parcial), sexo, código postal, telefone e endereço. Apenas os campos que ambos os registros têm contam. A pontuação é a evidência encontrada como uma parte da evidência possível. O bloqueio usa cinco chaves, para que um erro não esconda uma pessoa: som de sobrenome e ano de nascimento, data de nascimento, telefone, som de ambos os nomes (em qualquer ordem) e código postal com o som do nome próprio.
  3. Decisão. Por padrão, nada é vinculado apenas com base na pontuação. Um registro com pontuação igual ou superior ao limiar de revisão (60%) torna-se uma nova pessoa e a correspondência possível aguarda na fila de revisão; aqueles com pontuação igual ou superior ao limiar automático (90%) com sobrenome e data de nascimento concordando são marcados como *certos*. Vincular duas pessoas em uma (uma sobreposição) coloca os resultados de um paciente no gráfico de outro, então o vinculação automática é um interruptor que um administrador ativa (Vincular correspondências certas sem perguntar a ninguém) uma vez que a fila tenha mostrado que os certos estão corretos. Com ele ativado, uma correspondência certa é vinculada quando nenhuma segunda pessoa tem pontuação tão alta. Abaixo do limiar de revisão, o registro é uma nova pessoa.

Números nacionais. O número do NHS (e o CHI da Escócia e o número de Saúde e Cuidados da Irlanda do Norte), o PPSN e o IHI da Irlanda, o KVNR da Alemanha, o SVNR da Áustria, o número AHV da Suíça, o BSN dos Países Baixos, o número do registro nacional da Bélgica, o matrícula do Luxemburgo, o INS (NIR e NIA) da França, o código fiscal da Itália, o DNI/NIE e o CIP-SNS da Espanha, o número do SNS de Portugal, os números pessoais nórdicos (Suécia, Dinamarca, Noruega com seu número D, Finlândia, Islândia), os códigos bálticos, o PESEL da Polônia, os números de nascimento tcheco e eslovaco, e os números húngaro, romeno, búlgaro, croata, esloveno e grego são conhecidos pelo índice. Cada um é armazenado de uma maneira: sob o sistema do seu esquema, espaços e pontos removidos, para que o número do NHS enviado como urn:oid:2.16.840.1.113883.2.1.4.1|999 000 0018 por um sistema e como https://fhir.nhs.uk/Id/nhs-number|9990000018 por outro é um identificador. Uma repetição PID-3 do HL7 v2 cujo tipo de identificador é NN e um código de três letras do país (NNDEU, NNNLD) é lido como o número principal daquele país, e o tipo NH da autoridade NHS como o número do NHS. O dígito de verificação de cada número é testado: um que falha é mantido em seu registro, relatado (maskado) na resposta e nunca usado para vincular ou encontrar alguém, pois um dígito digitado incorretamente geralmente torna o número de outra pessoa. O CPR da Dinamarca é verificado apenas para a data, pois os números emitidos desde 2007 não precisam passar no antigo módulo 11.

As configurações listam cada esquema com seu formato, sua verificação e o sistema em que é armazenado. Sistemas tirados do guia FHIR do próprio país (UK Core, fhir.de, Nictiz, CH Core, ANS, HL7 Italia, MedCom, os registros OID sueco, norueguês e finlandês) são marcados como tal; os outros são padrões que podem ser alterados para o valor nacional, o que um site pode fazer por esquema (o antigo ainda é reconhecido). Confiança em um esquema é um tick. Números nacionais são mostrados em sua totalidade para editores e acima por padrão e mascarados (os últimos caracteres) para todos os demais; Quem vê números em sua totalidade altera isso, até visualizadores ou até administradores apenas. Onde a lei de um país limita o uso de um número (Référentiel INS da França, PPSN da Irlanda, número do registro nacional da Bélgica, §290 SGB V da Alemanha), as configurações dizem isso. GET /api/mpi/schemes lista os esquemas e POST /api/mpi/check verifica um número sem armazená-lo. FHIR $match e PIXm respondem a clientes autorizados com números em sua totalidade.

Uma data escrita dia- ou mês-primeiro (08/15/1972) é mantida como escrita e não corresponde a uma data ano-primeira: as ordens dos EUA e europeias discordam, e adivinhar vincularia as pessoas erradas.

A tela de índice do paciente (Build) mostra os contadores, encontra pessoas por nome, número, EUID ou data de nascimento, e abre cada pessoa: seus registos, todos os identificadores e o histórico do que aconteceu com eles e quem o fez. Editores decidem revisões (A mesma pessoa liga-os; Pessoas diferentes mantém-nas separadas para sempre), movem um registo para outra pessoa, retiram um registo (Não é esta pessoa), e fundem duas pessoas. Administradores definem os limiares, os sistemas de identificadores de confiança, os números nacionais e o sistema de EUID. Toda a pesquisa e leitura de pessoa é escrita no registo de auditoria.

Responder a outros. POST /fhir/Patient/$match (a operação FHIR, como IHE PDQm ITI-119 a usa) aceita um Paciente e retorna as pessoas que podem ser ele, melhor primeiro, cada um um Paciente cujo id é o EUID, com todos os identificadores, search.score, e a extensão de grau de correspondência (certain, probable, possible); onlyCertainMatches e count são honrados. PIXm (/mhd/Patient/$ihe-pix, ITI-83) responde a partir do índice: todos os identificadores de todos os registros vinculados à pessoa, e o EUID. O mesmo fazem PIX e PDQ em HL7 v3 (/pixv3, /pdqv3; veja o compartilhamento de documentos IHE).

A API é /api/mpi (resumo e pesquisa), /api/mpi/persons/{euid}, /api/mpi/find, /api/mpi/reviews, /api/mpi/records (registo, ligar, desligar), /api/mpi/merge e /api/mpi/settings.

Pesos. Os pesos Fellegi-Sunter padrão vêm da literatura de ligação de registos para dados de registo hospitalar. Estimar a partir dos nossos registos (nas definições, administradores; POST /api/mpi/estimate) ajusta-os ao índice do site com maximização de expectativa, sem pares revisados necessários: m (acordo entre combinações verdadeiras) a partir dos pares que o bloqueio reúne, u (acordo por acaso) a partir de 20.000 pares extraídos aleatoriamente, desde que os pares bloqueados concordem com os nomes e datas por construção. A estimativa é mostrada ao lado dos pesos em uso e não muda nada até ser utilizada e guardada. Um campo comparado em demasiados pares mantém o seu padrão. A adaptação supõe que os campos são independentes dado a classe, o que não é completamente verdade, por isso trate uma grande alteração com suspeita.

Medido. No conjunto de dados FEBRL 3 (5.000 registos sintéticos de 2.000 pessoas, os duplicados com erros de digitação, campos trocados, valores em falta e apelidos; PERFUSE_TEST_FEBRL), registados na ordem do ficheiro com um revisor a responder a cada par de fila corretamente:

Ligados por si própriosColocados à frente de um revisor com a pessoa certaPerdidosLigações erradas
Ligação automática desligada (o predefinido)02.649 de 3.0003510
Ligada, pesos predefinidos1.6371.0123510
Ligada, pesos estimados a partir dos registos1.6221.0703080

Nenhum registo foi ligado à pessoa errada, e nenhum dos 2.000 novos indivíduos foi colocado desnecessariamente na fila. Os que não foram encontrados diferem em quase todos os campos (uma data de nascimento e um endereço ambos mal escritos, por exemplo) e pontuam abaixo do limiar de revisão. FEBRL é sintético e tem poucos nomes iguais; um índice real tem mais, por isso a sua fila de revisão será mais longa, e estes números são um piso para o cuidado, não uma promessa.

8.13 Delimitado

CSV e os seus parentes. As opções estão na origem no construtor, e a referência de formato lista as chaves do ficheiro.

Caminhos endereçam colunas. Uma coluna nomeada está disponível quando uma linha de cabeçalho é declarada ou os nomes são dados; caso contrário, as colunas são posicionais.

8.13.1 Nomear as colunas

Há duas maneiras, e elas são exclusivas. Ou a primeira linha do ficheiro as nomeia — a primeira linha nomeia as colunas — ou você as lista por si, por ordem. Declarar um cabeçalho significa que a linha não é tratada como dados.

Se nenhum for definido, as colunas só podem ser endereçadas por posição, por isso um filtro escrito contra um nome não tem nada para corresponder. Ativar o cabeçalho remove a lista de nomes em vez de manter ambos: com um cabeçalho, os nomes vêm do ficheiro, por isso uma lista deixada para trás seria ignorada, e um canal que lê como se tivesse escolhido os nomes quando o ficheiro os escolheu é mais difícil de depurar do que um que se recusa.

8.13.2 O que um filtro ou um script vê

Um documento delimitado se torna muitas mensagens, por isso isso precisa ser declarado antes de você escrever qualquer um.

Com a divisão ativada, tudo funciona por linha. Etapas declarativas, o filtro e o script de transformador veem uma linha, e um caminho significa *esta* linha da coluna. Um filtro que rejeita uma linha rejeita essa linha e nenhuma outra, e a contagem recebida é linhas em vez de documentos.

Com a divisão desativada, a mensagem é o documento inteiro e uma escrita que cruza linhas é recusada em vez de ser aplicada à primeira. Essa recusa é deliberada: escrever silenciosamente na linha um é o comportamento que produz um ficheiro que parece transformado e não é.

8.13.3 Os três que mudam o que conta como um erro

Aceitar linhas com o número errado de colunas está desativado por predefinição. Uma linha com demasiadas ou demasiadas poucas colunas é então um erro, o que é o que apanha um ficheiro cuja forma mudou sem aviso. Ativá-lo aceita a linha e deixa as colunas em falta vazias.

Recortar espaços em torno de cada valor corrige o caso comum de um valor preenchido para uma largura de coluna. Deixe-o desativado onde os espaços finais são significativos, o que ocasionalmente é em um identificador.

Manter linhas em branco como linhas está desativado por predefinição e geralmente deve ser. Ativado, uma linha em branco se torna uma linha de colunas vazias, o que só importa quando uma contagem tem que corresponder exatamente ao ficheiro.

8.14 Bruto

Nenhuma análise em absoluto. A mensagem é bytes.

Use isso quando o conteúdo não é algo que o Perfuse entenda e não precisa de: um PDF sendo movido entre sistemas, um formato proprietário, um documento já formado sendo encaminhado inalterado.

O custo é que nada que dependa da estrutura funciona — nenhuma transformação de nível de campo, nenhum filtro em um campo, nenhuma comparação de nível de campo no verificador de paridade. Um canal bruto é um tubo, e é honesto sobre ser um.

8.15 Escolhendo

Se a mensagem for HL7 v2, use hl7, mesmo que você apenas pretenda encaminhá-la inalterada. A análise fornece o rastreamento, as estatísticas de nível de campo, a capacidade de filtrar posteriormente e a capacidade de comparar. raw em conteúdo analisável não traz nenhum benefício e perde tudo isso.

Use raw quando a análise falhar ou for uma mentira sobre o conteúdo.

O *Kill the Clipboard* do CMS pede aos prestadores de cuidados que aceitem os registos de um paciente a partir de um código QR no check-in, e que devolvam o registo da visita da mesma forma. O código QR contém um SMART Health Link (shlink:/...): um endereço, uma chave de 256 bits e, opcionalmente, um rótulo, um prazo de validade e uma flag de código de acesso. Exchange → Health links lê um.

Recebimento. Cole o link, ou digitalize-o com a câmara onde o navegador puder (Chrome e Edge). O Perfuse busca o manifesto, decifra cada ficheiro com a chave do link, resume qualquer pacote FHIR - quem é o paciente, quantos recursos de cada tipo - e verifica qualquer SMART Health Card dentro contra a chave publicada do seu emitente. *Entregar ao canal* entrega o conteúdo FHIR a um canal como uma mensagem, que é como ele atinge o EHR. O busca é mantido à política de saída no momento da conexão, o HTTP simples é recusado, e a resposta de um servidor que não é um servidor de manifesto nunca é mostrada, porque o endereço veio de um código QR de um estranho.

Partilha. *Partilhar* cifra um pacote FHIR, aloja-o e mostra o link e o seu código QR uma vez. O servidor mantém o texto cifrado e não a chave - não pode abrir o que aloja, e não pode mostrar o link novamente. Um código de acesso é hash; dez códigos de acesso errados desativam o link. Os links expiram após 30 dias por predefinição, podem ser revogados e listam quantas vezes e por quem foram buscados. Inicie o servidor com -public-url definido para o endereço https que os telemóveis dos pacientes alcançam; o URL do manifesto que constrói deve caber nos 128 caracteres da especificação.

Verificar um cartão. *Verificar um cartão* aceita um código QR numérico shc:/ (um ou vários blocos), um ficheiro .smart-health-card ou um JWS, e diz se a assinatura corresponde à chave do emitente.

8.17 UN/EDIFACT

dataType: edifact lê intercâmbios UN/EDIFACT (ISO 9735): ORDERS, INVOIC, DESADV, IFTSTA e o resto, incluindo as mensagens de reivindicação de saúde e laboratório europeias. O conselho de sequência de serviço (UNA) é honrado, com o carácter de libertação e, para a versão de sintaxe 4, o separador de repetição; grupos funcionais (UNG/UNE) são opcionais. O intercâmbio é entregue exatamente como o remetente o escreveu.

name: supplier-orders
dataType: edifact
edifact:
  envelope: require      # require (default), warn, or ignore
  split: false           # true: one interchange per message
  acknowledge: contrl    # none (default) or contrl
filter: 'UNB-2.1 == "5412345000013"'
source:
  type: as2              # or http, sftp, file, email ...
  # ...
destinations:
  - name: orders
    type: file
    dir: /data/orders
    filter: 'UNH-2.1 == "ORDERS"'

O envelope. O número de segmentos e a referência de UNT, o número de mensagens e a referência de UNE, e o número e a referência de UNZ são comparados com o que o intercâmbio contém. Com require, o predefinido, uma discordância recusa o intercâmbio (é como uma transferência interrompida é mostrada); warn aceita-o e regista um aviso; ignore não verifica.

Caminhos, para os filtros de canal e destino, contam elementos e componentes a partir de 1 na ordem em que o segmento é escrito, como as guias de implementação os numeram: BGM-2 (o número do documento), BGM-1.1, NAD(2)-2.1 (a segunda parte do NAD), LIN-3(2).1 (uma repetição), UNB-2.1 (o remetente), UNH-2.1 (o tipo de mensagem). Um caminho sem ocorrência aborda todos eles.

Divisão entrega uma troca por mensagem, cada uma com o UNB original (e cabeçalho de grupo) e trailers que contam um, para que um pedido possa ser filtrado, procurado e reenviado por conta própria. Os filtros de destino veem cada peça. Um destino de arquivo nomeia arquivos por tipo de mensagem (ORDERS_INVOIC-20261017.edi), e ${control_id} é a referência da troca.

CONTRL. Com acknowledge: contrl, um remetente que publica sobre HTTP é respondido com um relatório de sintaxe e serviço CONTRL: ação UCI 7 quando o intercâmbio foi lido e entregue, 4 quando foi recusado ou não pôde ser entregue (então 400 ou 502 HTTP). Não pode ser combinado com split, uma vez que um CONTRL responde a um intercâmbio inteiro. Sobre AS2, o recibo do parceiro é o acuso de recibo.

Não oferecido: os diretórios de mensagens (que segmentos ORDERS D.96A permite), para que a estrutura seja verificada, não o conteúdo; transformações, que reescreveriam um documento de um parceiro; e scripts de filtro ou transformador (um pré-processador é executado, antes da análise). Verificado contra pydifact 0.1.8, um analisador independente, em ambos os sentidos.

9 Confirmações

Uma confirmação informa ao remetente o que aconteceu. Para HL7 v2 sobre MLLP, é uma mensagem ACK; o remetente não enviará a próxima mensagem até que ela chegue e geralmente a reenviará se não chegar.

Obter confirmações erradas é a maneira mais comum de uma integração perder silenciosamente dados, porque um remetente que está sendo confirmado não tem motivo para reclamar.

9.1 Temporização

Coberto em fluxo de mensagem, e o resumo é: ack.when é on_delivery por padrão, significando que a confirmação é enviada apenas após todos os destinos habilitados aceitarem a mensagem. on_receipt a envia assim que a mensagem for analisada e enfileirada.

9.2 O que o Perfuse envia

Um AA quando a mensagem foi aceita, um AE quando foi rejeitada por um motivo pelo qual o remetente pudesse agir e um AR quando foi rejeitada por um motivo pelo qual o remetente não pudesse.

A distinção entre AE e AR é quem tem que fazer algo. AE significa que a mensagem tinha um problema — um campo que não podia ser analisado como data, um segmento necessário ausente — e o remetente pode corrigi-lo e reenviá-lo. AR significa que o Perfuse não pôde aceitá-lo, independentemente do conteúdo, o que geralmente significa um problema de configuração ou disponibilidade nesta extremidade. Um remetente que reenvia após um AR obterá a mesma resposta.

9.3 Identificando este motor

ack.application e ack.facility preenchem MSH-3 e MSH-4 do acuso de recibo.

Quando ambos estão vazios, o acuso de recibo espelha o receptor original — usa o que a mensagem de entrada tinha em MSH-5 e MSH-6. É o que a maioria dos remetentes espera, e é o padrão por esse motivo.

Defina-os explicitamente quando o remetente os valida, ou quando várias instâncias do Perfuse lidam com o mesmo feed e você precisa saber qual delas respondeu.

9.4 O evento de disparo

ack.include_trigger_event envia ACK^A01 em vez de um simples ACK.

Alguns receptores exigem isso, enquanto outros o rejeitam, o que é por que é uma opção explícita sem um padrão inteligente. Se um remetente estiver recusando seus acusos de recibo e o conteúdo parecer correto, essa é a primeira coisa a tentar.

9.5 Acusos de recibo negativos não são falhas para ocultar

Um NACK tratado como sucesso é uma das piores configurações erradas possíveis, e é comum o suficiente para ser nomeado. Isso ocorre quando um destino envia de volta um acuso de recibo negativo e o lado que envia registra a *transmissão* como bem-sucedida porque os bytes foram enviados e algo foi retornado.

O Perfuse lê o acuso de recibo que recebe de um destino MLLP e registra o resultado de acordo. Um AE ou AR de um sistema downstream é uma falha de entrega, é repetido de acordo com a política do destino e conta para a taxa de falha que dispara alertas.

Se você está migrando de outro mecanismo, isso vale a pena verificar explicitamente em seu próprio tráfego, em vez de supor. O verificador de paridade mostrará: um destino que o mecanismo antigo registrou como entregue e o Perfuse registra como falha geralmente significa que o mecanismo antigo estava ignorando um NACK.

9.6 Tempos limite

Esperar por um acuso de recibo é limitado. Quando ele não chega a tempo, a entrega é uma falha e é enfileirada para repetição.

Um tempo limite não é o mesmo que uma rejeição e é registrado de forma diferente. Uma rejeição significa que o lado oposto considerou a mensagem e a recusou; um tempo limite significa que você não sabe se foi processado. Essa distinção decide se uma repetição é segura: repetir após uma rejeição é inútil, e repetir após um tempo limite arrisca uma duplicata. O Perfuse repete após um tempo limite, porque uma mensagem clínica ausente é geralmente pior do que uma duplicata, e o sistema receptor geralmente é capaz de detectar um ID de controle de mensagem repetido.

Seja qual for o comércio certo para um feed determinado é um julgamento, e vale a pena fazer deliberadamente para qualquer coisa em que uma duplicata tenha uma consequência clínica — um pedido, uma administração de medicamento — em vez de aceitar o padrão silenciosamente.

9.7 Fontes que não acusam recibo

Não todos os transportes têm o conceito. Uma fonte de arquivo não tem para onde enviar um acuso de recibo; uma fonte de corretor acusa recibo ao corretor em vez de ao remetente original; uma fonte HTTP responde com um código de status.

Onde a fonte não pode entregar o modo de acuso de recibo que um canal pede, o canal é recusado na carga em vez de começar e silenciosamente não acusar recibo. Um canal que acredita que está acusando recibo e não está é pior do que um que não começa.

9.8 Acusos de recibo X12

Tudo o que está acima é sobre HL7 v2. O X12 tem seus próprios acusos de recibo, e ao contrário do v2, eles estão desligados por padrão: um ajuste vazio significa nenhum.

Esse padrão é o seguro, porque um parceiro comercial que não espera um acuso de recibo e o recebe pode tratá-lo como uma troca não solicitada. A chave acknowledge em um canal X12 assume um dos quatro valores:

ValorO que é enviado
noneNada. O padrão.
999Acuso de recibo de implementação. Substitui o 997 para transações HIPAA.
997Acuso de recibo funcional. Mais antigo, e ainda o que muitas conexões de pagador esperam.
ta1Acuso de recibo de intercâmbio, sobre o envelope em vez de seu conteúdo.

Qual um enviar é uma propriedade da relação de parceiro comercial em vez de da mensagem, o que é por que tem que ser configurado e não pode ser inferido. Um 999 substitui um 997 para transações HIPAA, mas muitos parceiros — conexões de pagador mais antigas, especialmente — estão configurados para esperar um 997 e tratarão um 999 como um arquivo não reconhecido.

Enviar o acuso de recibo errado é pior do que não enviar nenhum. Responde a uma pergunta que ninguém fez, enquanto deixa a real aberta, e o remetente não tem como dizer a diferença.

9.9 Acusos de recibo HL7 v3

Um canal HL7 v3 envia um acuso de recibo por padrão, o que é o oposto do X12 e vale a pena saber.

A razão é o transporte e não o padrão: uma interação v3 geralmente chega sobre uma conexão síncrona com a aplicação de envio à espera de uma resposta, e um remetente que não recebe nada geralmente tenta novamente. É assim que um paciente é registado três vezes.

Desativá-lo é possível e deve ser feito explicitamente — "não definido" e "definido como falso" são deliberadamente diferentes, portanto, o padrão permanece a menos que alguém tenha dito o contrário.

10 Entrega, Filas e Retentativa

Um destino que não pode ser alcançado é o caso normal, e não a exceção. Sistemas reiniciam, redes caem, e um motor de interface de hospital está indisponível durante sua própria janela de manutenção. A entrega é construída em torno disso.

10.1 Fila por destino

Attempt Delivered queue on disk — per destination 1, 2, 3, 4 … Retry growing backoff Dead letter kept, never discarded the same message, at the front Each destination has its own queue, so one slow receiver does not hold up the others. The queue is on disk, so a restart does not lose it. Order is preserved: message 2 is not attempted before message 1 succeeds or is given up on. A message that exhausts its attempts is dead-lettered and kept. Nothing is deleted to make a queue look healthy.

Cada destino tem sua própria fila. Um destino que está falhando não afeta os outros, e cada um tem sua própria profundidade, idade e estado de retentativa.

A fila é por destino e não por canal, porque a falha é por destino. Uma fila em todo o canal seguraria a entrega para três sistemas funcionais porque um quarto está desligado, e as duas situações — um destino indisponível, todos os quatro indisponíveis — pareceriam as mesmas nas estatísticas.

10.2 Configurações de fila

queue on a destination:

ChaveO que faz
enabledSe as mensagens com falha são colocadas em fila.
max_attemptsQuantas vezes tentar antes de desistir.
backoffAguarde antes da primeira retentativa.
max_backoffTeto no tempo de espera crescente.
max_depthMaior número de mensagens a manter. Não definido significa sem limite.
retain_hoursQuanto tempo uma mensagem entregue é mantida. Não definido a mantém indefinidamente.

Os dois últimos estavam faltando nesta tabela e no construtor, e são o par que impede que um disco seja preenchido. Uma fila sem nenhum deles cresce até que o sistema de arquivos esteja cheio, e essa falha chega como algo não relacionado quebrando — uma gravação falhando em algum lugar completamente diferente — em vez de como um problema de fila.

O tempo de espera cresce entre as tentativas até max_backoff. Crescendo em vez de fixo, porque um destino que está desligado geralmente está desligado por minutos e não por segundos, e tentar novamente a cada segundo durante dez minutos produz várias centenas de entradas de log que enterram a que importa.

10.3 A ordem é preservada

Dentro de um destino, as mensagens são entregues na ordem de chegada, e uma mensagem que falha mantém seu lugar. Mensagens posteriores esperam atrás dela em vez de ultrapassá-la.

Este é o padrão correto para dados clínicos — uma admissão e uma alta aplicadas na ordem errada é pior do que ambas serem atrasadas — e tem uma consequência digna de ser entendida: uma mensagem que sempre falha segura tudo o que está atrás dela.

É por isso que a profundidade da fila e a idade da fila são condições de alerta separadas. Uma fila profunda que está drenando é um sistema ocupado. Uma fila cuja mensagem mais antiga continua envelhecendo está presa, e os tipos de alerta queue-depth, queue-age e queue-stuck distinguem-nas.

Uma mensagem tóxica — uma que nunca terá sucesso, não importa quantas vezes seja retentada — é a falha específica a que este design é vulnerável. max_attempts é o que limita o dano: após isso, a mensagem é registrada como falha e a fila continua. Definir max_attempts muito alto na esperança de sucesso eventual converte uma mensagem falha única em uma alimentação interrompida.

10.4 Quando a fila está desativada

Com queue.enabled falso, uma entrega com falha é uma entrega com falha. É registrada e não é retentada.

Essa é a escolha certa quando dados atrasados são piores do que nenhum dado — um display em tempo real, um sistema de paging, qualquer coisa em que uma mensagem entregue quarenta minutos após o evento seria enganosa em vez de apenas atrasada.

É a escolha errada para qualquer coisa que vá para um registro, onde a mensagem é igualmente válida uma hora depois.

10.5 Retentativa versus fila

Existem dois mecanismos e eles operam em níveis diferentes.

retry em um destino governa as tentativas imediatas dentro de uma entrega — uma conexão que falha é tentada novamente após uma breve pausa, sem sair do caminho de entrega. Isso lida com falhas transitórias: uma conexão caída, um momento de recusa.

queue governa o que acontece uma vez que as tentativas imediatas se esgotam. A mensagem deixa o caminho de entrega e é retentada mais tarde em um cronograma mais longo.

Ambos existem porque as duas falhas são diferentes. Um reset de conexão na primeira tentativa geralmente desaparece na segunda, e passar pela fila para isso adicionaria minutos de latência a uma falha que durou milissegundos. Um destino que foi desligado para manutenção não voltará dentro de três tentativas imediatas, e martelar nele é inútil.

10.6 O que um ponto de extremidade HTTP considera entregue

Um destino HTTP tem três configurações que decidem se uma mensagem é tratada como enviada, e todas as três estão no destino no construtor.

Códigos de status que significam entregue. Vazio significa qualquer 2xx. Alguns pontos de extremidade respondem 202 Accepted para algo que ainda não foi processado, e alguns respondem 200 com um erro no corpo — o segundo é para o que *Tratar como falha se a resposta contiver* é. Definir uma lista explícita vale a pena quando um parceiro informou quais códigos significam o quê, porque a alternativa é descobrir a diferença a partir de uma mensagem que nunca foi entregue e nunca foi enfileirada.

Seguir redirecionamentos. Desligado por padrão, e deliberadamente. Um redirecionamento pode apontar para um host diferente, então seguir um envia a mensagem para algum lugar que ninguém configurou e relata sucesso.

Token de portador. Enviado como um cabeçalho Authorization. Ele é armazenado com o canal e nunca é exibido novamente, então deixar a caixa vazia ao editar um canal existente mantém o token já salvo em vez de limpá-lo.

10.7 Nomear e podar uma pasta de arquivo

Um destino de ficheiro anexa a um ficheiro por dia e tipo de mensagem por predefinição (20261012-ADT_A01.hl7), enquadrado MLLP para que o ficheiro seja reproduzido com perfuse send. Quatro definições no destino alteram isso.

Nome do ficheiro (file_name) cria um ficheiro por mensagem, em vez disso, nomeado a partir de ${date}, ${timestamp}, ${control_id}, ${message_type} e ${destination}. Um nome que já está em uso (o mesmo ID de controlo duas vezes) obtém um sufixo único em vez de substituir a mensagem ali.

Anexar (append: true) escreve cada mensagem no arquivo Nome do arquivo nomeia, então ${date}.hl7 é um arquivo por dia para cada tipo.

Sufixo enquanto escreve (temp_suffix, um ficheiro por mensagem apenas) predefinido para .part e é removido por um renomeação uma vez que o ficheiro esteja completo. Quem recolhe estes ficheiros não deve pegar num ficheiro meio escrito, e uma renomeação dentro de uma pasta é atómica. Altere-o apenas se o recolhedor filtrar uma extensão diferente.

Excluir após (retain_hours) poda arquivos na pasta mais antigos do que o número dado de horas, verificado no máximo a cada dez minutos enquanto as mensagens chegam. Apenas arquivos simples diretamente na pasta são excluídos, nunca uma subpasta. Vazio ou zero os mantém para sempre, o que é o padrão e é uma decisão em vez de uma omissão — mas um arquivo que ninguém poda enche o disco, e um disco cheio para o canal em vez de o arquivo.

10.8 Enviar para um servidor FHIR

Três configurações decidem quanto é verificado antes que um pacote seja enviado.

Reivindicar conformidade US Core adiciona o perfil a cada recurso. Reivindique apenas quando o recurso carrega o que o perfil exige, porque um receptor pode validar contra a reivindicação e rejeitar um pacote que de outra forma teria sido aceito.

Validar antes de enviar verifica cada recurso aqui em vez de aprender com o receptor. Uma rejeição na extremidade distante diz menos, mais tarde e frequentemente apenas em um log que você não pode ler.

Tratar advertências como rejeições só tem efeito quando a validação está ativada, e o controle está indisponível até que esteja. É suficientemente rigoroso para parar um pacote que um receptor aceitaria, então pertence a uma alimentação sendo trazida em vez de uma em serviço.

10.8.1 Serviços FHIR hospedados

Um destino fhir com um bloco auth faz login nos serviços hospedados, onde um token de portador colado deixa de funcionar dentro de uma hora:

fhir:
  url: https://healthlake.us-east-1.amazonaws.com/datastore/<id>/r4/
  auth: {type: aws, access_key_id: ${AWS_ACCESS_KEY_ID}, secret_access_key: ${AWS_SECRET_ACCESS_KEY}}

aws assina cada pedido para AWS HealthLake com a Versão 4 de Assinatura, com a região lida a partir do URL. azure obtém um token de ID da Microsoft Entra para os Serviços de Dados de Saúde da Azure a partir de tenant_id, client_id e client_secret - um registo de aplicação que detém o papel de Contribuinte de Dados FHIR - com a URL do serviço FHIR como seu público-alvo. client_credentials faz o mesmo contra qualquer URL de token OAuth 2.0 token_url. Os tokens são reutilizados até um minuto antes de expirarem. As mesmas opções estão sob o Início de sessão do serviço hospedado no destino, no construtor de canal.

10.8.2 Relatório de caso de saúde pública

Marque Relatar condições relatáveis para saúde pública em um destino FHIR e ele enviará relatórios de caso em vez de conjuntos. Cada mensagem é verificada por um código de gatilho de condição relatável: um diagnóstico, um teste de laboratório ou um resultado codificado. Se tiver um, a mensagem se torna um eICR HL7 eCR 2.1.2, embrulhado em uma mensagem eCR e publicado na URL $process-message. Se não tiver nenhum, nada é enviado e nada falha; o destino conta como não relatável.

fhir:
  url: https://ecr.agency.example/fhir
  ecr:
    rctc: /etc/perfuse/rctc.json
    source: https://fhir.springfield-general.example/fhir
    facility: {name: Springfield General Hospital, phone: +1-217-555-0100, city: Springfield, state: IL}

rctc é o Conjunto de Códigos de Disparo de Condições Relatórias, como um Conjunto de Valores FHIR ou o pacote eRSD. Ele precisa de uma licença UMLS, por isso não está incluído; sem ele, um exemplo integrado curto é usado, apenas para testes. source é onde a agência envia sua Resposta de Relatibilidade. A instalação é necessária porque o eCR pede seu telefone e endereço, e uma mensagem v2 não tem nenhum deles.

Um relatório diz o que a mensagem faltou em vez de inventá-lo, e cada lacuna é registrada. Tente uma mensagem no painel de Relatório de Caso de Saúde Pública do laboratório FHIR antes de apontar um feed ao vivo para uma agência.

10.8.3 Resultados de laboratório para saúde pública: ELR

perfuse elr -config elr.yaml results.hl7 converte os resultados de um laboratório em mensagens ELR HL7 2.5.1 que os departamentos de saúde estaduais recebem, uma para cada mensagem com um resultado notificável, e apenas os pedidos que transportam um: uma contagem sanguínea completa ao lado de um teste SARS-CoV-2 positivo não é da responsabilidade da saúde pública. Os códigos de acionamento são os mesmos que os da notificação de casos, o RCTC que você carrega ou o exemplo integrado.

O ELR nomeia todos por OID ou número CLIA, que nenhum feed de laboratório transporta para o remetente e o destinatário, por isso esses vêm do ficheiro:

sending_application: {namespace: Perfuse, id: 2.16.840.1.113883.19.5.9, type: ISO}
sending_facility: {namespace: Springfield Lab, id: 2.16.840.1.113883.19.5, type: ISO}
receiving_application: {namespace: ELR, id: 2.16.840.1.113883.19.6.1, type: ISO}
receiving_facility: {namespace: State DOH, id: 2.16.840.1.113883.19.6, type: ISO}
processing: T
ordering_facility: {name: Springfield Clinic, phone: "+1 217 555 0100", line: 1 Main St, city: Springfield, state: IL, postalCode: "62701"}
performing_lab: {name: Springfield Lab, line: 2 Lab Rd, city: Springfield, state: IL, postalCode: "62701"}
performing_lab_clia: 14D0000000
placer_authority: {namespace: SPRINGFIELD-EHR, id: 2.16.840.1.113883.19.5.1, type: ISO}
filler_authority: {namespace: SPRINGFIELD-LAB, id: 2.16.840.1.113883.19.5.2, type: ISO}

A instalação que emite a ordem, o laboratório que realiza e as autoridades que fazem a atribuição são usadas apenas onde a mensagem do laboratório deixa-as de fora, e cada uso é uma nota. O que apenas o laboratório sabe nunca é preenchido: um resultado sem tipo de amostra vai com SPM-4 vazio e uma nota dizendo isso, porque uma amostra adivinhada em um relatório para saúde pública é pior do que uma lacuna que o estado pode perguntar. Comece com processing: T enquanto a equipe de integração do estado testa o feed.

O que o laboratório fez corretamente é mantido como foi enviado. Uma ordem filha (um painel de suscetibilidade ou um teste de reflexo que nomeia seu pai em OBR-29 e que não tem ORC próprio) vai como recebido, sem ORC ou espécime inventado para ele, e uma criança sem resultado relatável próprio vai com o de seu pai, desde que uma suscetibilidade não significa nada sem a cultura a que pertence. Uma nota após o PID permanece com o paciente, e ORC-14, o número de telefone de retorno, é copiado de OBR-17 quando o laboratório colocou apenas lá. Todas as 28 mensagens de exemplo que a ONC publica para sua ferramenta de certificação ELR saem válidas sem erros.

MSH-2 é escrito como ^~\&#, os cinco caracteres que a errata do ELR Release 1 exige e a ferramenta de certificação da ONC verifica. Se o guia do seu estado mostra os quatro mais antigos, adicione encoding_characters: "^~\\&" ao arquivo.

Para enviá-los a partir de um canal em vez de a partir da linha de comando, dê ao destino que atinge o estado um bloco elr que nomeia o mesmo arquivo. Cada resultado de laboratório é reorganizado ao sair, e um com nada relatável não é enviado, o que é contado como entregue, não falhou: o estado pediu apenas resultados relatáveis.

destinations:
  - name: state-elr
    type: mllp                 # or http, sftp, file: whatever the state's onboarding team gives you
    address: elr.health.state.example:6661
    tls: {enabled: true}
    elr:
      config: elr.yaml         # beside this channel file
      rctc: rctc.json          # optional; the built-in sample is for testing only

O bloco se aplica a um canal HL7 v2, a destinos que entregam a mensagem em si (mllp, http, tcp, arquivo, sftp, ftp, S3, Azure Blob, soap, os corretores de mensagens ou outro canal); o canal se recusa a carregar caso contrário, e quando o arquivo está faltando ou carece da instalação de envio, aplicação receptora ou instalação receptora. As notas são escritas no log com o ID de controle da mensagem.

O arquivo ELR é o companheiro do canal, não um canal: perfuse check e a tela Canais pulam isso em vez de relatar um canal que não carregará. No construtor de canal, as mesmas duas configurações estão sob o destino, em Relatório de Laboratório (ELR 2.5.1); o campo de códigos de disparo é aberto assim que um arquivo ELR é nomeado, e salvar recusa um arquivo que não está ao lado do canal.

10.8.4 Arquivos DICOMweb

type: dicomweb armazena cada objeto com STOW-RS: Orthanc, dcm4chee, os serviços de imagem em nuvem ou o próprio repositório de um servidor Perfuse. Forneça a raiz do serviço (https://pacs.example/dicom-web); /studies é adicionado, e uma URL que já termina em /studies é recusada em vez de publicar em /studies/studies. Autentique com token (um token de portador) ou username e password; headers adiciona outros, como o cabeçalho de projeto de um serviço de nuvem. O canal precisa de dataType: dicom.

A resposta do servidor decide o resultado, não apenas seu código de status. Um objeto que a resposta lista como falho é uma entrega falha com o motivo de falha DICOM, e também é um 202 que lista nada como armazenado: o servidor aceitou o pedido e manteve nada disso. O tempo limite padrão é de dois minutos, porque uma série grande é lenta.

10.8.5 Repositórios de documentos (IHE XDS.b)

type: xds publica cada documento clínico em um repositório XDS.b com ITI-41 Fornecer e Registrar: um documento CDA, ou um que uma mensagem HL7 v2 (MDM, ORU) transporta. Os metadados vêm do documento e das configurações do destino (source_id, patient_domain, facility_type, practice_setting), e a resposta do Registro do repositório decide a entrega. Veja compartilhamento de documentos IHE.

10.8.6 Registos de imunização

Cada registro de imunização estadual dos EUA (IIS) aceita mensagens HL7 2.5.1 na mesma interface SOAP, a publicada pela CDC em 2011 (namespace urn:cdc:iisb:2011). Ela tem duas operações: connectivityTest, que prova o ponto de extremidade, e submitSingleMessage, que transporta a mensagem. Um VXU^V04 relata uma vacinação e retorna como um ACK; um QBP^Q11 pede o histórico e previsão de um paciente e retorna como um RSP^K11.

Escolha Registo de imunização (serviço web IIS CDC) como o serviço de um destino SOAP, ou escreva profile: cdc-iis:

destinations:
  - name: state-registry
    type: soap
    soap:
      profile: cdc-iis
      url: https://iis.state.example/iis-ws/cdc
      username: clinic-submitter       # the registry account for this submitter
      password: "..."
      facility_id: FAC-1234            # optional in the WSDL; many registries require it
    queue: {enabled: true}

Perfuse constrói o envelope, então não há corpo para escrever. O nome de usuário e a senha vão dentro do pedido, onde a WSDL da CDC os coloca, não na autenticação HTTP. A versão é SOAP 1.2, a ligação da WSDL, a menos que você defina version: "1.1" para um registro cujo guia pede isso. Onde um registro exige um certificado de cliente, defina a tls do destino como para qualquer chamada HTTPS.

O registo de confirmação decide se a mensagem foi entregue, não o estado HTTP. Um registo responde a um pedido rejeitado com HTTP 200 e um AR por dentro, por isso um destino que confiasse no estado reportaria uma imunização perdida como entregue.

O registo respondeRegistos Perfuse
AA (ou CA)Entregue.
AE cujos segmentos ERR são todos avisos (ERR-4 W ou I)Entregue. Os avisos estão na resposta.
AE com qualquer ERR-4 E, ou um ERR sem gravidadeFalhou, com a localização, código e texto de cada ERR no erro.
AR ou CRFalhou, da mesma forma.
Uma falha SOAP (senha incorreta, mensagem muito grande)Falhou, com o motivo do registo.
Algo que não é uma mensagem HL7Falhou.

warnings_are_errors: true (Tratar avisos como falhas) faz com que cada AE espere por uma pessoa. A resposta, que os scripts de resposta e um chamador HTTP que espera no canal leem, é a mensagem HL7 do registo: o ACK, ou o RSP com o histórico e previsão. examples/iis contém três canais para começar: VXU a partir de um EHR sobre MLLP, consultas QBP sobre HTTP e um substituto local para um registo.

O painel de Conexões pede a um registo o seu connectivityTest quando nada foi submetido por sete dias. Essa operação existe para esse propósito e não submete nada, por isso é o único teste de nível de aplicação que o Perfuse realiza. Ele prova o endereço, TLS e o binding SOAP, não o nome de usuário e senha; apenas uma submissão real testa esses.

Uma fonte SOAP pode responder da mesma forma: Responda como um registo de imunização, ou profile: cdc-iis na fonte. Ele ecoa connectivityTest, pega a mensagem de submitSingleMessage, retorna o acuso de recebimento do canal em return e serve o WSDL da CDC em ?wsdl. Um nome de usuário e senha, quando definidos, são verificados contra os da solicitação, e um par incorreto obtém a SecurityFault do WSDL. Uma mensagem que o canal rejeita é devolvida como um NAK, nunca como uma falha, como diz o guia da CDC. Use-o como um teste duplo, ou para receber submissões da forma como um registo faz.

Não coberto: as partes específicas do estado de integração. Cada registo tem o seu próprio endpoint, processo de conta e perfil local do guia 2.5.1 (campos RXA e OBX necessários, elegibilidade VFC, códigos de recusa). Esses são o conteúdo das mensagens, que as transformações do canal moldam; nenhum endpoint do estado é construído. O Perfuse foi testado contra si mesmo e contra respostas de registo gravadas, mas não contra um registo de estado ao vivo.

10.9 Quando o transporte diz sim e a mensagem não chegou

"Chegou aqui" é frequentemente não uma pergunta que o transporte possa responder. Um receptor MLLP retorna um acuso de recebimento de aplicação cujo significado está em seu texto. Um receptor HTTP retorna 200 com um documento de erro. Em ambos os casos, o transporte foi bem-sucedido e a mensagem não chegou.

Inspecionar a resposta em um destino leva um script dado a resposta do receptor. Retornar falso, ou lançar, e a entrega é marcada como falha — o que significa que é repetida, enfileirada e aparece na contagem de falhas em vez de ser contada silenciosamente como entregue.

É oferecido apenas em destinos que recebem uma resposta. Em um que não pode, é recusado no carregamento em vez de ser deixado nunca executando.

10.10 O que um resultado de entrega significa

ResultadoSignificado
DeliveredO destino aceitou a mensagem. Para MLLP, um acuso de receção positivo foi recebido.
QueuedA entrega falhou e a mensagem será repetida.
FailedA entrega falhou e não será repetida, seja porque a colocação em fila está desativada ou as tentativas estão esgotadas.
FilteredO destino recusou a mensagem pelo seu próprio filtro. Não é um erro.

Esses são registrados por destino por mensagem, então uma mensagem que atingiu três de quatro destinos é registrada como exatamente isso. Não há um "sucesso" de nível de canal, porque não significaria nada.

10.11 Entrega lenta

Um destino que está aceitando mensagens, mas levando muito tempo para isso, é um problema distinto de um que está falhando, e é fácil perder porque todos os resultados são bem-sucedidos.

O tipo de alerta slow-delivery existe para isso. Vale a pena configurá-lo em qualquer coisa onde o acuso de recebimento do remetente aguarde a entrega, porque um destino cujo tempo de resposta aumentou silenciosamente dobrará eventualmente e começará a produzir reenvios — e nesse ponto o sintoma aparece upstream, em um sistema que você pode não administrar.

10.12 Gravar em um banco de dados

type: database executa uma instrução por mensagem com valores vinculados da mensagem.

Placeholders são do próprio driver — $1 para postgres, ? para mysql e sqlite, @p1 para sqlserver — e o Perfuse não reescreve-os. Isso é deliberado: uma camada de tradução que obtivesse um placeholder errado vincularia o nome de um paciente à coluna errada, e o resultado pareceria dados válidos em vez de um erro.

Uma instrução escrita no dialeto errado é recusada quando é salva, nomeando o estilo que o driver deseja. Antes que essa verificação existisse, o erro surgia como syntax error at or near "," do servidor quando uma mensagem chegava, o que nomeia uma instrução que você escreveu e, portanto, o envia procurar um erro de digitação em vez de no dialeto.

destinations:
  - name: warehouse
    type: database
    database:
      driver: postgres
      dsn: ${WAREHOUSE_DSN}
      statement: INSERT INTO messages (mrn, family_name, birth_date) VALUES ($1, $2, $3)
      params:
        - PID-3.1
        - PID-5.1
        - PID-7

Um parâmetro citado é uma constante em vez de um caminho, que é como um canal escreve seu próprio nome ou um código de sistema de origem em uma linha ao lado dos dados da mensagem.

Os valores são sempre vinculados como parâmetros. Uma referência ${...} dentro da instrução é recusada: um nome que contém um apóstrofo quebraria a instrução, e um valor hostil a reescreveria.

10.13 Enviar para um soquete bruto

type: tcp escreve para um soquete com estruturação que você escolhe, o que é o que um dispositivo ou um instrumento de laboratório geralmente deseja. MLLP é uma estruturação entre várias; este destino oferece as outras.

destinations:
  - name: instrument
    type: tcp
    tcp:
      address: instrument.lab:9100
      framing: delimited
      delimiter: \r
      expect_reply: true
      timeout: 30s

A estruturação não tem um valor padrão, deliberadamente. Escrever com a estruturação errada não falha. O extremo distante lê mensagens divididas nos lugares errados, ou aguarda um terminador que nunca chega, e o sintoma aparece no sistema de recebimento em vez de aqui.

framingO que escreve
mllp0x0b antes, 0x1c 0x0d depois. O mesmo enquadramento que um destino MLLP utiliza.
delimitedUm delimiter após cada mensagem, e um start_block opcional antes dela.
fixedRegistos preenchidos ou truncados para record_length.
lengthUm prefixo length_bytes. big_endian e length_includes_header ambos têm duas convenções no mundo e a diferença é silenciosa.
wholeUma mensagem por conexão, fechada para marcar o fim.

Apenas as configurações que a estruturação escolhida usa são aceitas. Um comprimento de registro em um fluxo delimitado é recusado em vez de ignorado, porque uma configuração que é silenciosamente ignorada é uma que alguém acredita estar em vigor.

expect_reply altera o que significa entregue. Sem ele, sucesso significa que os bytes alcançaram o buffer de envio do sistema operacional — que um peer que travou um momento depois nunca leu.

10.14 Amazon S3, SQS e SNS

Um canal pode ler a partir de uma fila SQS ou um prefixo de bucket S3, e entregar para SQS, SNS ou S3. Os cinco são HTTP assinados sem AWS SDK no binário, e os cinco aceitam as mesmas configurações de acesso: region, access_key_id, secret_access_key (escreva ${AWS_SECRET_ACCESS_KEY} para ler a variável de ambiente), um session_token opcional e endpoint para LocalStack, MinIO ou um endpoint de VPC. Em Canais → Novo canal, escolha *Lemos a partir de uma fila Amazon SQS*, *Coletamos objetos a partir de um bucket Amazon S3*, ou os tipos de destino SQS, SNS e S3.

Nada é confirmado para a AWS até que o canal tenha lidado com ele. Uma mensagem SQS é excluída após isso e, caso contrário, reaparece quando seu tempo limite de visibilidade termina, então uma política de reenvio de fila é o que move uma que continua falhando para uma fila de cartas mortas. Um objeto S3 se move para processed/ após isso, ou para error/ se não puder ser lidado, então um arquivo ruim não impede o resto.

Em uma fila FIFO ou tópico, as mensagens são agrupadas por paciente por padrão - SQS mantém a ordem dentro de um grupo e em nenhum outro lugar - e duplicadas por conteúdo, então uma repetição não é entregue duas vezes.

Um arquivo S3 pode ser escrito diretamente para Glacier com storage_class, e como linhas JSON para Amazon Athena com format: ndjson; perfuse athena imprime a tabela. A referência tem todas as configurações.

10.15 AMQP 1.0 e Azure

AMQP 1.0 é o que o Azure Service Bus e os Event Hubs falam, e o RabbitMQ 4, ActiveMQ e Artemis além de seus outros protocolos. Um source amqp recebe de uma fila ou assinatura e aceita cada mensagem apenas uma vez que o canal tenha lidado com ela; uma que não pôde ser lidada é liberada como uma entrega falha, então o broker a reenvia e, após o limite da fila, a coloca em uma fila de cartas mortas. Um destino amqp relata sucesso apenas quando o broker aceita a mensagem. Para Service Bus: addr é <namespace>.servicebus.windows.net:5671 com tls, username o nome da política de acesso compartilhado, password sua chave, e address o nome da fila, ou <topic>/subscriptions/<name> para receber.

Azure Blob Storage: um destino azure_blob escreve um blob por mensagem na camada de acesso escolhida - Hot, Cool, Cold ou Archive - e um source azure_blob pega blobs a partir de um prefixo, movendo-os para processed/ ou error/ como o source S3 faz. Prefira um token SAS limitado ao contêiner em vez da chave da conta.

10.16 MQTT

Uma fonte mqtt subscreve um filtro de tópico (+ corresponde a um nível, # a todos os níveis abaixo) em qualquer broker MQTT 3.1.1: Mosquitto, EMQX, HiveMQ, AWS IoT Core, Azure Event Grid. Com QoS 1, o padrão, cada mensagem é confirmada apenas uma vez que o canal a tenha processado. O MQTT não tem forma de recusar uma mensagem única, por isso uma que não pôde ser processada é deixada sem confirmação e a conexão é refeita; o broker mantém a sessão sob o id do cliente (perfuse-<channel> a menos que client_id especifique o contrário) e a envia novamente, primeiro na fila. QoS 0 é no máximo uma vez: qualquer coisa enviada enquanto o Perfuse estiver desligado é perdida. Um destino mqtt publica e, com QoS 1, relata sucesso quando o broker tem a mensagem.

source:
  type: mqtt
  mqtt:
    addr: broker.hospital.local:8883
    topic: hl7/+/adt
    username: perfuse
    password: ${MQTT_PASSWORD}
    tls: {enabled: true, ca_file: /etc/perfuse/broker-ca.pem}

O AWS IoT Core quer um certificado de cliente: forneça tls.cert_file e tls.key_file.

10.17 IBM MQ

ibm_mq lê e escreve filas IBM MQ por meio da API de mensagens REST do gerenciador de filas (mqweb), que o IBM MQ 9.1.5 e posterior enviam em todas as plataformas, z/OS incluída, então nenhum cliente MQ é instalado ao lado do Perfuse. O usuário precisa do papel MQWebUser e da autoridade de colocar, obter e navegar na fila. Um source navega pela primeira mensagem, a entrega ao canal e a remove por seu id de mensagem apenas uma vez que foi lidada; uma mensagem que falha permanece primeira na fila. Execute um leitor por fila. Um destino coloca mensagens persistentes (a menos que non_persistent), com o id de controle HL7 como o id de correlação.

destinations:
  - name: to-mainframe
    type: ibm_mq
    ibm_mq:
      url: https://mq.hospital.local:9443
      queue_manager: QM1
      queue: HL7.ADT.OUT
      username: perfuse
      password: ${IBM_MQ_PASSWORD}
      tls: {enabled: true, ca_file: /etc/perfuse/mq-ca.pem}

api_version é v3 para MQ 9.3 e posterior (o padrão), v2 para 9.1.5 a 9.2. Um gerenciador de filas com um canal AMQP também pode ser alcançado com o conector amqp.

10.18 Google Cloud Pub/Sub e Cloud Storage

Um source pubsub puxa de uma assinatura e confirma cada mensagem uma vez lidada; uma que falha é devolvida imediatamente (seu prazo de confirmação definido para zero), com o resto de seu lote, então o Pub/Sub a entrega novamente e, após a política de carta morta da assinatura, a coloca em uma fila de cartas mortas. Um destino pubsub publica com o tipo de mensagem HL7 e o id de controle como atributos; order_by: patient define a chave de ordenação a partir de PID-3.1, então uma assinatura com ordenação de mensagens mantém as mensagens de cada paciente em ordem.

Um destino gcs escreve um objeto por mensagem, nomeado como uma chave S3 é, na classe de armazenamento escolhida (STANDARD, NEARLINE, COLDLINE, ARCHIVE). Um source gcs pega objetos a partir de um prefixo e os move para processed/ ou error/ como o source S3 faz.

Ambos se conectam como uma conta de serviço: credentials_file é sua chave JSON. Deixe-o vazio no Google Cloud (uma VM, GKE ou Cloud Run) para usar a conta de serviço anexada lá. endpoint nomeia um emulador (o emulador Pub/Sub, fake-gcs-server), que não requer credenciais.

source:
  type: pubsub
  pubsub:
    project: hospital-integration
    subscription: adt-to-perfuse
    credentials_file: /etc/perfuse/gcp-key.json

10.19 Lendo uma caixa de correio (IMAP e POP3)

Uma fonte email lê uma caixa de correio e converte o que encontra em mensagens: cada anexo (take: attachments, o padrão, restringido por padrões attachment_names), o texto do email (take: body), ou o email completo (take: raw) para um script desmontar. Laboratórios, centros de imagem e pequenas clínicas ainda enviam resultados desta forma.

Cada verificação entra, lê a correspondência não lida mais antiga primeiro e sai. Sobre IMAP, um email é buscado sem ser marcado como lido, entregue ao canal e, apenas uma vez que cada mensagem dele foi aceita, é movido para move_to (Processado), marcado como lido (after_read: flag) ou excluído. Correio que falhou ou que não foi aceito (um remetente fora allowed_senders, nenhum anexo que combine com attachment_names, maior que max_message_size), mova para error_folder (Erro) com o motivo no log. Ambas as pastas são criadas quando faltam. O POP3 não tem pastas ou flags, então exclui: exclusões são comprometidas com o QUIT no final da verificação, então uma sessão que se interrompe exclui nada e um email processado pode ser lido novamente (nunca perdido). Correio POP3 que não é aceito permanece no servidor e é relatado uma vez.

O login é uma senha (${MAIL_PASSWORD}; uma senha de aplicativo para o Gmail) ou OAuth 2.0 sobre SASL XOAUTH2, que o Microsoft 365 exige (ele desativou o login de senha) e o Gmail prefere:

source:
  type: email
  email:
    host: outlook.office365.com        # imap.gmail.com, pop.gmail.com, or your server
    username: results-feed@hospital.example
    oauth:
      provider: microsoft              # microsoft, google or custom (with token_url)
      tenant: hospital.onmicrosoft.com
      client_id: 00000000-0000-0000-0000-000000000000
      client_secret: ${MAIL_CLIENT_SECRET}
    attachment_names: ["*.hl7"]
    allowed_senders: [lab.example, results@partner.example]

Com client_secret e sem refresh_token, é usada a acesso somente do aplicativo do Microsoft 365 (a concessão de credenciais do cliente, escopo https://outlook.office365.com/.default): um administrador registra o aplicativo, concede a ele o acesso IMAP.AccessAsApp e o limita à única caixa de correio com um principal de serviço do Exchange. Com um refresh_token (o consentimento de uma pessoa), é usada a escala delegada IMAP.AccessAsUser.All ou POP.AccessAsUser.All e um token de atualização rotativo é mantido por toda a vida do processo. O Gmail precisa de um refresh_token: o Google não oferece acesso somente do aplicativo a uma caixa de correio.

O allowed_senders aceita endereços e domínios. A linha De um email pode ser forjada, então ele mantém acidentes e emails perdidos, não um atacante; uma fonte que deve ser confiável pertence ao Direct (S/MIME assinado), SFTP ou uma VPN. A security é tls (993 ou 995, o padrão), starttls (143 ou 110) ou none, que é permitida apenas para localhost. As verificações são feitas a pelo menos 10 segundos de intervalo (60 por padrão), porque os serviços de email limitam as contas que verificam mais rápido.

Testado contra o GreenMail 2.1.3 (IMAPS, IMAP, POP3S e POP3: login recusado com uma senha errada, busca sem marcar como lido, MOVE, flag, excluir, um email muito grande recusado antes de ser lido) e contra o IMAP do Gmail com uma senha de aplicativo (criar uma pasta, anexar, buscar, MOVE, excluir). O OAuth foi testado contra um endpoint de token fictício apenas: não contra o Microsoft ou o Google.

10.20 AS2

O AS2 (RFC 4130) é como muitos pagadores, centrais de compensação e fornecedores trocam EDI: um HTTP POST cujo corpo é assinado com o certificado do remetente e criptografado para o receptor, respondido com um recibo (um MDN) que nomeia um resumo do que chegou. O S/MIME é o mesmo código que a mensagens diretas usam. Ambas as extremidades estão no construtor de canal: Parceiros comerciais nos enviam EDI sobre AS2 como fonte, Um parceiro comercial sobre AS2 como destino.

# receive: partners post here
source:
  type: as2
  as2:
    listen: ":4080"            # path /as2 by default
    id: HOSPITAL-AS2           # our AS2 identifier (AS2-To)
    cert_file: as2/ours.crt    # partners encrypt to this
    key_file: as2/ours.key     # and receipts are signed with it
    tls: { enabled: true, cert_file: tls.crt, key_file: tls.key }
    partners:
      - id: PAYER-AS2
        cert_file: as2/payer.crt
dataType: x12
# send
destinations:
  - name: payer
    type: as2
    as2:
      url: https://as2.payer.example/as2
      from: HOSPITAL-AS2
      to: PAYER-AS2
      cert_file: as2/ours.crt
      key_file: as2/ours.key
      partner_cert_file: as2/payer.crt
      file_name: "${control_id}.x12"

Recebendo. Uma mensagem para qualquer outro AS2-To, ou de um remetente não em partners, é recusada com 403 e sem recibo. A mensagem de um parceiro deve ser assinada e criptografada, a menos que a entrada defina allow_unsigned ou allow_unencrypted. A carga útil é descriptografada, sua assinatura verificada contra o certificado do parceiro (parceiros usualmente trocam certificados autoassinados, o que está bem: o certificado é a confiança), e entregue ao canal como o formato da mensagem diz. O parceiro recebe o recibo que pediu: na resposta, ou publicado na URL Receipt-Delivery-Option do parceiro; assinado quando pediu um assinado. Uma mensagem que falha recebe um recibo que nomeia o motivo (decryption-failed, authentication-failed, insufficient-message-security, unexpected-processing-error).

Envio. Cada mensagem é assinada (SHA-256) e encriptada (AES-256-CBC). Com receipt: sync, o padrão, conta como entregue apenas quando o recibo verifica contra partner_cert_file, diz processed, e transporta o mesmo resumo (MIC) como o que foi enviado; qualquer outra coisa é uma entrega falhada e é retentada. receipt: async solicita o recibo em receipt_url, que deve ser uma fonte AS2 neste servidor que lista o parceiro: a mensagem conta como entregue uma vez que o parceiro aceita o pedido, e um recibo que mais tarde discorda é registado como um erro. receipt: none solicita nada. unsigned, unencrypted e unsigned_receipt relaxam cada parte para um acordo que o especifique; username e password adicionam autenticação básica HTTP para portais que a exigem. O tipo de conteúdo segue o formato do canal (application/edi-x12 para X12) a menos que content_type defina um.

Triple DES, AES-128 e AES-192 são lidos, bem como AES-256, desde que os parceiros ainda os enviam, e também é o streaming BER (comprimentos indefinidos) que os gateways Java escrevem.

Compressão (RFC 5402). Uma mensagem comprimida é lida de qualquer forma que tenha sido construída: comprimida antes de ser assinada ou criptografada, ou uma mensagem assinada comprimida por completo. O resumo do recibo segue o RFC: sobre o que foi assinado quando é assinado, sobre o conteúdo não comprimido quando não é. Uma mensagem que expandiria além de dez vezes o max_message_size da fonte é recusada com decompression-failed, então alguns kilobytes não podem reivindicar gigabytes de memória. Um destino comprime com compress: true, antes de assinar e criptografar, como a maioria dos gateways faz; pergunte ao parceiro primeiro.

Uma mensagem enviada duas vezes. Um parceiro que nunca recebeu o nosso recibo envia a mensagem novamente com o mesmo ID de mensagem (RFC 4130 seção 7.5). A origem lembra os IDs de mensagem de cada parceiro por duplicate_window (padrão 720h, 30 dias; pelo menos uma hora) e responde a um reenvio com um recibo processed sem passá-lo novamente. O registo é mantido na base de dados, para que um reinício não o esqueça. Uma mensagem cujo processamento falhou não é lembrada, para que a tentativa de novo do parceiro seja processada. Cópias que chegam ao mesmo momento esperam umas pelas outras e apenas a primeira é passada. Se o registo não puder ser lido, a mensagem é recusada com unexpected-processing-error e o parceiro tenta novamente mais tarde, em vez de arriscar uma segunda cópia. Uma mensagem sem ID de mensagem não pode ser reconhecida e é registada como tal.

A interoperabilidade é testada contra pyas2lib 1.4.3 em ambos os sentidos, com Triple DES e AES-256, comprimido e não, recibo síncrono assinado incluído.

10.21 OpenPGP

Pagadores, centrais de compensação e agências estaduais frequentemente enviam e recebem arquivos apenas sob OpenPGP. Um bloco pgp em uma fonte abre o que chega; um em um destino protege o que deixa. Ambos estão no construtor de canal: Mensagens Open PGP-encriptadas abaixo da fonte, Encriptar com OpenPGP em cada destino.

source:
  type: sftp
  sftp: { host: sftp.payer.example, user: hospital, key_file: keys/id_ed25519, dir: outbound }
  pgp:
    decrypt_with: keys/our-secret.asc      # our secret key, armored or binary
    passphrase: ${PGP_PASSPHRASE}
    verify_with: [keys/payer.asc]          # the senders' public keys
    require_signature: true
destinations:
  - name: claims
    type: sftp
    sftp: { host: sftp.payer.example, user: hospital, key_file: keys/id_ed25519, dir: inbound,
            file_name: "${date}-${control_id}.x12.pgp" }
    pgp:
      encrypt_to: [keys/payer.asc]
      sign_with: keys/our-secret.asc
      passphrase: ${PGP_PASSPHRASE}

Os ficheiros-chave são lidos em relação ao ficheiro do canal e são lidos e desbloqueados quando o canal é carregado: um ficheiro-chave em falta ou uma frase-passe incorrecta pára o canal ali, e não no primeiro ficheiro.

aberto primeiro e, em seguida, dividido em mensagens, por isso um lote encriptado como um ficheiro funciona. Um que não consegue abrir é recusado: uma origem de ficheiro move-o para a sua pasta de erros, um remetente HTTP responde 400 com o motivo. require_signature recusa uma mensagem não assinada por uma das verify_with; allow_unencrypted aceita uma que está apenas assinada; pass_plain deixa uma mensagem que não é PGP de todo passar inalterada, para uma pasta que recebe ambos.

encrypt_to) e assinado (com sign_with), após todos os outros passos. Um ficheiro, destino SFTP, FTP, S3, Azure Blob ou GCS ainda nomeia o ficheiro a partir da mensagem em texto puro, por isso ${control_id} funciona, e qualquer estruturação está dentro da encriptação. armor: true escreve texto .asc em vez de binário; no_compress desativa a compressão; file_name é o nome transportado dentro da mensagem.

As mensagens são escritas com AES-256 no formato RFC 4880 que os receptores mais antigos leem, e o formato RFC 9580 mais recente também é lido. A criptografia é ProtonMail/go-crypto; Perfuse não implementa primitivos. A interoperabilidade é testada contra GnuPG em ambos os sentidos: gpg decripta e verifica o que Perfuse escreve, e Perfuse abre e verifica o que gpg escreve.

10.22 Entrega a outro canal

Um destino de canal entrega a mensagem a outro canal por nome. O canal receptor trata-a como qualquer outra chegada: registra-a, filtra-a, transforma-a e a distribui.

Esta é a forma suportada de construir uma cadeia. Ela é deliberadamente visível — dois canais, dois conjuntos de estatísticas, duas entradas no histórico da mensagem — porque uma cadeia oculta dentro de um canal é uma cadeia que ninguém pode monitorar.

A mensagem é entregue na memória em vez de sobre uma rede, para que não haja estruturação, nenhum reconhecimento e nenhum tempo limite entre os dois.

10.23 O que acontece quando o processo é interrompido

A pergunta que qualquer pessoa que tenha executado um motor de interface pergunta primeiro, e a que raramente é respondida, porque a resposta honesta é geralmente embaraçosa.

Foi respondida matando o processo com SIGKILL a meio de um lote — o que é o que uma falha de energia, uma kill de memória insuficiente e um reset de hipervisor parecem por dentro — e contando o que sobreviveu contra o que havia sido prometido.

A propriedade em teste não é "nada é perdido". Isso não é alcançável e afirmá-lo seria uma mentira. É a promessa mais estreita que um remetente realmente confia: uma mensagem que foi positivamente confirmada é uma mensagem que chegou.

Com ack.when: on_delivery, que é o padrão, cada destino é escrito antes de que a confirmação seja enviada, por isso um AA é uma afirmação sobre o destino em vez de sobre uma fila. Uma mensagem eliminada antes da sua confirmação pode muito bem ser perdida, e isso está corretamente: o remetente nunca foi prometido nada e a enviará novamente.

10.23.1 Confirmando na entrega

Cinco execuções, mortas após 5, 25, 40, 75 e 110 mensagens de 120.

ConfirmadoPresente downstream depoisConfirmado mas faltando
2552550

A promessa mantida em cada ponto de interrupção, e nada foi duplicado. Uma duplicata teria sido aceitável e uma perda não: um A08 reenviado é um incômodo que os receptores absorvem, e um resultado de laboratório que nunca chegou silenciosamente é um evento de segurança do paciente.

10.23.2 Confirmando na receção

on_receipt responde assim que a mensagem é enfileirada, antes que qualquer destino tenha sido escrito. Este capítulo sempre disse que uma mensagem confirmada ainda pode ser perdida dessa forma. Aqui está o tamanho disso.

Morto apósConfirmadoPresente downstreamPerdido
5514
2525124
7575273
1101102108

Essencialmente tudo em voo. A configuração não é um defeito e há feeds onde é a escolha certa, mas deve ser escolhida sabendo que uma falha descarta o que foi confirmado e ainda não foi escrito, e que isso é quase tudo de uma explosão.

Nada recuperado no reinício, porque perfuse run não tem uma loja durável. Um destino que não pode perder mensagens durante uma interrupção precisa de queue.enabled, que precisa da base de dados que perfuse serve fornece — e perfuse run agora recusa esse canal em vez de iniciá-lo sem a fila.

10.23.3 Um remetente que morre na metade de uma mensagem

A falha mais perigosa destas, porque uma mensagem HL7 truncada geralmente ainda é analisada. Os segmentos antes do corte estão completos e bem formados, por isso um receptor não tem forma de saber que PID e PV1 chegaram e os segmentos OBX que transportam os resultados não chegaram.

Um quadro foi aberto, seis décimos de uma mensagem foram enviados, e a conexão foi reiniciada em vez de fechada. A mensagem parcial não foi entregue, o ouvinte sobreviveu, e uma mensagem bem formada enviada imediatamente após foi aceita normalmente, para que o fragmento não tenha sido transportado para a próxima mensagem também.

O registo de conexão agora relata quantos bytes de um quadro inacabado foram abandonados, para cada modo de falha em vez de apenas um fechamento limpo. Anteriormente, um remetente que falhou, um processo morto e um cabo puxado todos registavam messages=0 e nada mais, o que não pode distinguir uma verificação de saúde vazia de um resultado de laboratório jogado fora nove décimos do caminho.

10.23.4 Um disco cheio

A exaustão de espaço é detectada e registada em vez de engolida. Duas coisas sobre isso valem a pena saber.

O remetente não recebe uma rejeição imediata. A entrega é repetida no cronograma usual — um segundo, dois, quatro, oito — e a confirmação negativa chega cerca de quinze segundos depois. Um remetente cujo tempo limite próprio é mais curto do que isso vê uma conexão paralisada em vez de um AE, e concluirá que a rede está em falta em vez do disco.

E um volume que relata zero bytes livres ainda pode aceitar pequenos anexos por um tempo, porque adicionar alguns centenas de bytes a um ficheiro cujo último bloco tem espaço não precisa de nova alocação. A primeira falha de escrita ocorre mais tarde do que o momento em que o disco foi preenchido.

10.23.5 O que não foi testado

Um diretório de destino que perde a permissão de escrita. Não pode ser injetado com chmod: o motor mantém o ficheiro de saída aberto e alterar o modo de um ficheiro não afeta um descritor já aberto contra ele. Testá-lo corretamente precisa que o volume seja remontado somente leitura ou removido por baixo do processo, o que não foi feito. É nomeado aqui em vez de omitido, porque uma lacuna que ninguém menciona lê como uma lacuna que ninguém procurou.

11 Alertas

Nada fora do Perfuse irá dizer que um feed parou. O remetente está sendo confirmado e está satisfeito; o receptor não tem como saber que uma mensagem foi enviada. O alerta é a única coisa que está entre uma interface quebrada e alguém notando semanas depois.

11.1 Os tipos de alertas

TipoDispara quando
error-rateAs falhas excedem uma proporção do tráfego.
queue-depthUma fila tem mais de N mensagens esperando.
queue-ageA mensagem mais antiga na fila é mais antiga do que uma duração.
queue-stuckUma fila não está drenando nada.
no-trafficNada chegou por um período fixo.
below-rhythmO tráfego está bem abaixo do que essa fonte normalmente faz *neste momento da semana*.
channel-downUm canal que deveria estar em execução não está.
script-errorsUm script está falhando.
rows-quarantinedUma fonte de banco de dados está colocando linhas de lado.
slow-deliveryAs entregas estão tendo sucesso, mas estão demorando muito.
contractUma mensagem viola o contrato declarado do canal.
phi-volumeUm canal carrega várias vezes sua taxa usual para a hora.
phi-after-hoursUm canal que só carrega tráfego diurno carrega algum à noite.
phi-new-destinationUm canal entrega para um endereço que nunca enviou antes.
phi-bulk-readsUma pessoa lê mais de N registros de pacientes diferentes dentro de um minuto.

Os últimos quatro assistem ao acesso aos dados do paciente e são descritos abaixo.

11.2 O silêncio é a coisa mais difícil de detectar

Um canal que parou de receber produz nenhum erro. Não há nada para contar. É por isso que no-traffic existe, e por que não é suficiente por si só.

no-traffic é um limiar fixo: alertar se nada chegou durante, digamos, duas horas. Em uma fonte que nunca fica quieta, isso funciona. Em uma fonte de laboratório de uma clínica, é inútil — a fonte está silenciosa todas as noites e todos os fins de semana, então um limiar de duas horas aciona alguém às 1h da manhã todos os dias, e um limiar longo o suficiente para sobreviver ao fim de semana não notará uma falha na terça-feira de manhã até a terça-feira à tarde.

Não há um único número que seja ambos. Isso não é um problema de ajuste; é que a pergunta "esse feed parou" não pode ser respondida por uma constante quando o feed normal varia por um fator de cem ao longo da semana.

11.3 Detecção ciente do ritmo

below-rhythm compara o tráfego atual contra o que esse canal normalmente faz nessa hora desse dia da semana.

Perfuse aprende a semana de cada canal a partir de sua própria história registrada: 168 baldes horários, começando na segunda-feira, para que uma semana de trabalho seja contígua. Para cada balde, ele mantém uma mediana, um baixo e um alto, um piso e quantas observações ele é baseado.

O limiar é uma parte do normal, com valor padrão de 0.8 (80 por cento na consola) — alertar quando o tráfego cai abaixo de quatro quintos do que é normal para esta hora.

11.3.1 Mediana, não média

Um único esvaziamento de fila de quarenta mil mensagens contra um normal de trezentas move uma média o suficiente para que o feed possa ficar completamente silencioso depois sem nunca cair abaixo disso. A mediana não é afetada por uma hora extraordinária, que é exatamente a propriedade necessária.

11.3.2 O piso é um percentil, não o mínimo

Se o ritmo de um canal é confiável o suficiente para alertar é decidido por sua extremidade baixa, não sua extremidade alta. Um alerta de falta dispara quando o tráfego é *baixo*, então apenas a extremidade baixa pode dizer se produzirá falsos positivos. Uma versão anterior disso comparou o alto contra a mediana e errou em ambas as direções ao mesmo tempo: desqualificou um feed perfeitamente estável por um mês após uma fila e aprovou um feed genuinamente errático que oscilava entre duas e novecentas mensagens na mesma hora porque seu alto era apenas três vezes sua mediana.

O piso é o percentil vigésimo, em vez do mínimo, porque o mínimo é arrastado para zero por um único feriado bancário. E o percentil não é interpolado — cada número em um alerta às 2h da manhã deve ser uma contagem que o feed realmente produziu, não uma média de duas contagens que não produziu.

11.3.3 Ele dirá quando não puder dizer

Um canal com nenhuma história é omitido completamente, em vez de ser tratado como um que parou. Um novo canal não deve parecer um canal quebrado.

Onde a história é muito fina ou muito errática para apoiar um julgamento, a regra declina de disparar, em vez de adivinhar. "Eu não posso dizer honestamente" é uma resposta de primeira classe aqui, e é preferida a um alerta que está correto ligeiramente mais frequentemente do que a chance.

Horas ausentes dentro da janela de aprendizado são registradas como zeros reais, não como dados ausentes. Metade do sinal em uma fonte de clínica é *quando está legitimamente quieta*, e tratar essas horas como desconhecidas jogaria isso fora.

11.4 Configurando alertas

A partir da interface, em Alertas, por canal ou em todos eles. Cada regra tem um tipo, um limiar e para onde enviar o alerta. As regras são salvas em alerts.yaml ao lado do banco de dados (ou o arquivo -alerts nomeia) e entram em vigor imediatamente; até a primeira salvar as regras internas se aplicam. O arquivo também pode ser editado manualmente: a alteração é detectada dentro de trinta segundos, e um arquivo que não carrega mais é relatado no log e as regras em vigor são mantidas.

Vale a pena fazer antes que uma fonte vá ao ar, em vez de após o primeiro incidente. O conjunto específico vale a pena ter em qualquer fonte clínica:

  1. below-rhythm — a fonte parou quando não deveria estar quieta.
  2. error-rate — as mensagens estão chegando e falhando.
  3. queue-age — algo está preso, em vez de apenas ocupado.
  4. channel-down — o canal não está funcionando.

O primeiro é o que pega a falha que ninguém mais relatará.

11.5 Assistindo ao acesso aos dados do paciente

Uma violação raramente anuncia a si mesma. Parece um feed carregando mais do que o usual, tráfego às três da manhã em um canal que só funciona durante o horário de expediente, um destino que ninguém configurou, ou uma pessoa abrindo paciente após paciente. O Perfuse assiste a esses quatro, ativados por padrão (serve -watch-access=false desativa), e relata o que vê por meio das regras de alerta acima, então é configurado, reconhecido e entregue como qualquer outro alerta.

Nada é julgado para um canal até que ele tenha transportado 200 mensagens, porque "inusual" não significa nada sem um padrão. O padrão é aprendido com as duas últimas semanas do repositório de mensagens quando o servidor é iniciado, então uma reinicialização não torna todos os canais novos novamente. Qualquer coisa vista é mantida por quinze minutos, então o alerta se limpa sozinho.

Ele apenas observa e relata. Nunca retarda uma mensagem ou recusa uma leitura: essas são heurísticas, e uma fonte de dados interrompida porque uma suposição estava errada é um problema clínico. Cada alerta diz o que foi visto e o que poderia ser inocente, porque a maioria deles será inocente.

Os administradores veem o que o monitor aprendeu na tela de Alertas, em Acesso a dados de paciente em observação: o padrão de cada canal (ainda aprendendo, apenas durante o dia ou dia e noite), quantos destinos ele conhece e tudo o que foi visto nos últimos quinze minutos, incluindo o que está abaixo do limiar de uma regra.

11.6 Para onde os alertas vão

Os alertas podem ser enviados como JSON para um webhook (-alert-webhook: Slack, Teams, Mattermost, PagerDuty, Alertmanager ou qualquer coisa que aceite um POST), enviados como armadilhas SNMPv2 para gerentes SNMP (-snmp-traps, veja SNMP), ou escritos no registo para um coletor pegá-los. Não há entrega de e-mail própria: aponte o webhook para um relé se os alertas devem chegar como e-mail.

Um alerta que é apenas escrito em um log que ninguém lê não está alertando. Se Perfuse for a única coisa que notará uma fonte parada, o alerta tem que alcançar uma pessoa.

12 A Loja de Mensagens

Toda mensagem que o Perfuse recebe é registada, tal como recebida, antes que algo a modifique. O mesmo acontece com o que foi enviado para cada destino e o que lhe aconteceu. A loja é um ficheiro SQLite dado por -db.

12.1 O que é mantido

Por mensagem: os bytes brutos como chegaram, quando chegaram, qual o canal, o tipo de mensagem analisada e o evento de acionamento, e o resultado do filtro.

Por destino por mensagem: os bytes que foram enviados, o resultado, o tempo necessário, e qualquer erro ou confirmação negativa recebida.

Esta é a forma que uma investigação precisa. "O que eles nos enviaram", "o que enviamos a eles" e "o que disseram sobre isso" são três perguntas diferentes e cada uma delas é feita.

12.2 Pesquisa

Por canal, por intervalo de tempo, por resultado, por tipo de mensagem e evento de acionamento, e por valor de campo.

A pesquisa de campo funciona na mensagem analisada, por isso procurar um número de registo encontra-o onde quer que o campo exista na mensagem, em vez de corresponder aos dígitos em qualquer lugar do texto. Uma pesquisa de texto para 12345 em uma mensagem que contém uma quantidade de 12345 encontra uma mensagem que não tem nada a ver com o paciente que está a procurar.

12.3 Repetição e reprocessamento

Porque o original é mantido, uma mensagem pode ser executada novamente com a configuração atual.

Rastrear pega uma mensagem registada e mostra o que o canal faria com ela agora, sem enviar nada. Coberto em depuração.

Reprocessar executa-a novamente, incluindo a entrega. Isso é o que corrige um lote de mensagens que falharam porque um destino estava mal configurado: corrija a configuração, selecione as mensagens afetadas, reprocesse.

Reprocessar entrega novamente. Se as mensagens tiveram um sucesso parcial da primeira vez, o reprocessamento produzirá duplicatas nos destinos que já as tinham. O Perfuse regista quais destinos tiveram sucesso, por isso o reprocessamento pode ser limitado aos que falharam — faça isso em vez de reprocessar tudo, a menos que o sistema receptor deduplique por ID de controlo de mensagem.

12.4 Desatualização

Um rastreo de uma mensagem antiga contra a configuração atual está a responder a uma hipótese: o que *aconteceria* agora. Isso é geralmente o que você quer, mas nem sempre — se estiver a investigar o que deu errado na última terça-feira, o canal pode ter mudado desde então.

O Perfuse detecta isso e diz isso. Um rastreo de uma mensagem que chegou antes do canal ter sido editado pela última vez é marcado como tal, para que a resposta não seja confundida com uma reconstrução do que realmente aconteceu.

12.5 Retenção

A loja cresce. cleanup.periodDays controla por quanto tempo as mensagens são mantidas.

Duas coisas a considerar. As mensagens clínicas podem estar sujeitas a requisitos de retenção que são mais longos do que qualquer coisa que você escolheria por razões operacionais, e a loja não é o sistema de registo — o sistema receptor é. A cópia do Perfuse existe para diagnosticar e reprocessar, e ambas as necessidades diminuem rapidamente após algumas semanas.

A retenção também decide quanto histórico o aprendiz de ritmo tem para trabalhar. Veja alertas: uma janela de retenção mais curta do que algumas semanas deixa-o incapaz de distinguir um domingo tranquilo de uma alimentação interrompida.

12.6 A loja contém dados clínicos

Esta é a parte do Perfuse que contém informações de paciente, e deve ser tratada como tal: em armazenamento encriptado, respaldada como dados clínicos e controlada por acesso. Veja segurança.

As mensagens de teste geradas descritas em testes existem em parte para que esses dados não precisem deixar o ambiente para reproduzir um problema em outro lugar.

13 Depuração

A questão é quase sempre a mesma: esta mensagem chegou, algo deu errado na saída, onde é que ela mudou? O Perfuse responde a esta pergunta reproduzindo uma mensagem gravada através da configuração atual e mostrando cada passo.

Nada é enviado enquanto se faz o rastreio. O canal continua a funcionar inalterado e não é necessário reinstalar.

13.1 Rastrear uma mensagem

Selecione qualquer mensagem gravada e rastreie-a. O resultado mostra, por ordem:

13.2 Passo a passo

A vista passo a passo executa cada transformação por si só e captura a mensagem inteira após ela. Uma barra numerada de passos, colorida pelo que aconteceu, e a mensagem como ela estava em cada ponto.

A mensagem inteira em vez de apenas a alteração, porque a alteração muitas vezes não está onde está o problema — um passo que modificou corretamente o campo para o qual foi destinado, em uma mensagem onde um passo anterior já havia colocado a coisa errada lá, parece perfeitamente correto em isolamento.

13.3 Quatro resultados e a distinção que importa

ResultadoSignificado
changedO passo foi executado e modificou a mensagem.
no-effectO passo foi executado, e a mensagem não foi alterada.
skippedA condição when do passo foi falsa, por isso ele não foi executado.
failedO passo resultou em erro.

no-effect e skipped são relatados separadamente, e este é o ponto de toda a funcionalidade.

De fora, eles são idênticos: a mensagem é a mesma depois de qualquer um deles. Eles significam coisas opostas. skipped significa que a condição funcionou como escrita e esta mensagem não era uma para a qual se aplicava — normalmente correto. no-effect significa que o passo foi executado e não encontrou nada para fazer, o que normalmente significa que ele está direcionado a um campo que não existe.

Um motor que relata ambos como "nada aconteceu" deixa você incapaz de distinguir uma condição funcional de um caminho quebrado, e essa é a falha de transformação mais comum que existe.

Um passo que relata no-effect em cada mensagem é quase sempre um caminho errado. O cabeçalho do passo a passo conta quantos passos não encontraram nada, o que é a forma mais rápida de detectá-lo: um canal com três passos e três resultados no-effect não está transformando nada.

13.4 Testar uma alteração antes de salvá-la

O construtor pode executar uma configuração candidata contra tráfego gravado e relatar o que seria diferente. Esta é a forma mais segura de alterar um canal ao vivo: faça a edição, veja o que ela faz com as últimas centenas de mensagens reais, então salve.

Também é como descobrir que uma alteração que parece obviamente correta afeta mensagens que você não havia pensado — um passo condicionado a um evento de gatilho, em uma fonte de dados que se revela transportar quatro.

13.5 O que o rastreio não pode dizer

Ele executa a configuração atual. Se o canal foi editado desde que a mensagem chegou, o rastreio é hipotético em vez de uma reconstrução, e o Perfuse o marca como tal em vez de deixar a distinção passar silenciosamente.

Ele também não executa o transporte. Um rastreio mostra o que seria enviado, não se o destino o aceitaria — uma mensagem correta e um destino que recusa conexões produzem um rastreio limpo e uma entrega falha. Esses são visíveis no registro de entrega em vez disso.

13.6 Scripts

Um script é um passo opaco no rastreio. O Perfuse pode mostrar o que entrou e o que saiu, e não pode mostrar o que aconteceu entre ou quais campos foram lidos.

Este é o custo concreto de utilizar um script em vez de passos declarativos e é um aspecto a considerar ao fazer a escolha. Consulte transformation.

14 Testes

O conselho padrão para testar uma interface é construir mensagens de amostra que reflitam o seu próprio ambiente — os códigos do seu laboratório, a sua mistura de casos, os hábitos do seu remetente — e remover os dados do paciente manualmente. Isso é lento, e fazer isso de forma incompleta é o resultado normal.

O Perfuse oferece três coisas em vez disso: tráfego gerado que corresponde à forma de uma fonte de dados sem o seu conteúdo, um canal proposto a partir de uma amostra que alguém lhe enviou, e uma comparação com o motor que você está substituindo.

14.1 Tráfego de teste gerado

Se um canal tiver lidado com mensagens, o Perfuse pode produzir mais mensagens semelhantes a elas.

O que é fiel:

O que não é fiel, e isso é afirmado em vez de implícito: coerência clínica. Um paciente gerado tem um número de registro não relacionado, uma string com formato de nome e um diagnóstico sem relação com a observação. Essas mensagens exercitam uma interface. Elas não são um conjunto de testes clínicos e não podem ser usadas para validar a lógica clínica.

14.1.1 Por que não contém dados reais

O argumento é estrutural, em vez de uma afirmação sobre esforço. A única entrada do gerador é o perfil de tráfego do canal, e um perfil contém taxas de preenchimento, formas, comprimentos, contagens de repetições e frequências de segmentos. Ele não contém valores.

A única exceção é campos de tabelas de códigos, e um código não identifica ninguém.

Essa é uma garantia mais forte do que a desidentificação de mensagens reais, que é um processo que pode ser feito de forma incompleta e geralmente é. Aqui não há caminho pelo qual um nome possa alcançar a saída, porque o nome nunca esteve na entrada.

Cada mensagem gerada é analisada antes de ser retornada — um corpus não analisável faria com que alguém procurasse por um bug na interface que na verdade é um bug no gerador — e cada uma é marcada T em MSH-11, com um aplicativo de envio sintético e uma instalação deliberadamente sintética.

Uma mensagem de teste que não é marcada como tal eventualmente será encontrada em um sistema de produção por alguém que não tem como saber que não era real. O T e o remetente sintético não são cosméticos.

14.2 Construir um canal a partir de uma amostra

Cole a mensagem que um laboratório, hospital ou fornecedor enviou por e-mail e o Perfuse propõe um canal para ela. Nada precisa estar em execução primeiro.

Ele lida com o que as pessoas realmente colam: várias mensagens em um bloco, qualquer quebra de linha, enquadramento MLLP que sobreviveu à cópia e a nota de cobertura acima da mensagem. Recusar uma amostra porque chegou com quebras de linha do Windows seria um obstáculo em vez de uma verificação.

14.2.1 Três listas

A proposta vem com o que a amostra mostra, o que foi suposto, e o que a amostra não pode dizer — três listas separadas, ponderadas igualmente na interface.

Elas são separadas porque um leitor que não pode dizer qual é qual tem que verificar tudo ou confiar em tudo, e ambos são piores do que saber onde procurar.

A partir de uma única mensagem, os limites são nomeados especificamente em vez de de forma geral: quais campos são opcionais, quais segmentos se repetem, quais códigos existem além dos que estão aqui, se o remetente já enviou um evento de disparo diferente. Uma advertência geral é algo que as pessoas ignoram.

A confiança é uma palavra — baixa, moderada, razoável — nunca um percentual. Um percentual implica um cálculo, e isso é um julgamento sobre quantas amostras existem.

Os segmentos Z são chamados por nome, porque um segmento local é a coisa que nenhuma especificação menciona e a razão mais comum pela qual um canal construído a partir de um modelo padrão não funciona.

14.2.2 O aviso de separador

Se o separador de campos da amostra não for o usual |, isso aparece primeiro, e a confiança cai para baixa.

A razão é uma falha silenciosa genuína. O HL7 obtém seu separador de campos da própria mensagem, então uma amostra cujos pipes foram substituídos por semelhantes tipográficos — o que um processador de texto faz — analisa perfeitamente em campos que estão todos errados. Nada dá erro em lugar algum.

Recusar uma amostra dessas seria errado, porque um remetente pode legitimamente usar outro separador. Portanto, é sinalizado, o caractere é nomeado e é sugerido solicitar um anexo de texto simples.

14.3 Comparando com o motor antigo

Antes de mover uma fonte de dados ao vivo, a questão é se o Perfuse produz a mesma saída que a coisa que tem sido executada por anos. Nenhuma quantidade de qualidade de design responde a isso. Veja migration.

14.4 Verificando contra a coisa real, em contêineres

Três verificações são executadas contra implementações reais em vez de contra a própria ideia do Perfuse de um protocolo. Elas vivem fora do make check porque precisam de um tempo de execução de contêiner e uma verificação que precisa do Docker é uma verificação que as pessoas param de executar.

scripts/interop-up.sh inicia todos eles e imprime o que cada um desbloqueia.

ContêinerVerificaçõesO que encontrou
Keycloak 26web/e2e-saml/, e fixtures internal/samlUm defeito. A forma canônica que uma assinatura cobre foi computada com prefixos de namespace dropados, então nenhum provedor de identidade real poderia ter assinado alguém
Microsoft EntraTestes e fixtures internal/saml ao vivoDois defeitos, ambos no que rodeia o protocolo. Uma conta foi criada sob o NameID opaco do Entra, porque a lógica de nome legível queria uma reclamação de e-mail e o Entra não envia nenhuma. E uma conta SAML foi registrada como OIDC, porque o armazenamento derivou o protocolo de um emissor que parece idêntico para ambos
HAPI FHIRgo test ./internal/engine/ -run HAPIUm defeito. Uma autoridade de designação não mapeada produziu um sistema de identificador que anuncia um OID e carrega uma palavra, que o HAPI aceitou sem reclamação
ActiveMQgo test ./internal/engine/ -run RealBrokerCorreto, incluindo o caso de framing de byte nulo. Afirmado através da interface de gerenciamento do próprio corretor em vez de através de uma função que retorna nil
nginx, certificados de clientego test ./internal/engine/ -run ClientCertificateCorreto
Orthanc (um PACS real)go test ./internal/engine/ -run RealPACSCorreto. Um C-STORE chega e o nome do paciente, identificador, data de estudo, modalidade e classe SOP todos sobrevivem
PostgreSQLgo test ./internal/engine/ -run RealPostgresCorreto, e ele provocou um melhor erro: uma declaração no lugar dos placeholders do dialeto errado agora é recusada quando salva em vez de se tornar um erro de sintaxe no servidor quando uma mensagem chega
OpenSSH sftp-servergo test ./internal/engine/ -run OpenSSHServerCorreto. Os testes SFTP existentes usam a mesma biblioteca Go em ambos os extremos; o OpenSSH é uma implementação diferente e a que está no extremo oposto de quase todos os feeds reais
Mirth 4.5.2go test ./internal/mirth/ -run RealMirthCorreto agora. O único fixture usado costumava ser escrito à mão e o Mirth não o carregaria; scripts/mirth-author-channel.sh tem o Mirth autor um em vez disso, e o Perfuse o lê

Cada um pula em vez de falhar quando seu contêiner está ausente, então make check passa em uma máquina sem Docker.

Por que isso é separado do resto da suíte. Cada outro teste desses recursos teve ambas as metades escritas aqui: um documento que este código assinou, lido de volta pelo código que o assinou. Isso é um acordo consigo mesmo, e vale menos do que parece.

O canonicalizador SAML é o caso que prova o ponto. Ele carregava mil linhas de testes, cinco delas especificamente sobre canonicalização, e todas elas passaram enquanto nenhum provedor de identidade real poderia ter assinado alguém — a forma canônica que uma assinatura cobre estava sendo computada com prefixos de namespace dropados, e a única maneira de encontrar isso era entregá-lo a um documento que o Perfuse não havia escrito.

Duas das oito verificações encontraram defeitos abertamente, e uma terceira provocou uma melhoria real. Três não encontraram nada de errado. Essa proporção é o argumento para manter todos eles: uma verificação que passa disse algo que você não poderia ter sabido de outra forma, e não havia como saber antecipadamente quais seriam elas.

Um padrão vale a pena nomear, porque apareceu em ambos os defeitos: aceitação não é verificação. O HAPI aceitou o sistema de identificador malformado e o armazenou; o defeito só apareceu ao ler o recurso de volta. Um receptor que tolera algo não é evidência de que está correto, apenas de que esse receptor era leniente.

Duas afirmações capturadas são comprometidas, em internal/saml/testdata/keycloak-assertion.xml e entra-response.xml, com testes sobre ambas — então essa regressão particular é capturada sem um contêiner.

Ambos são necessários em vez de um ser sobra. O Keycloak prefixa sua afirmação e assinatura, o Entra não, e esses são os dois casos opostos na canonicalização — que é exatamente onde o defeito estava. Um teste afirma que cada documento ainda cobre seu próprio caso, porque uma captura de substituição que aconteceu de ser prefixada silenciosamente reduziria a cobertura sem falhar nada. A lição geral não se generaliza tão barato: para qualquer outra coisa, o contêiner é a verificação.

14.5 Diagnosticando um teste que falha uma vez e nunca mais

Um teste que falha em uma execução completa e passa sozinho dezesseis vezes não é um teste instável. É um teste que compartilhou algo com a execução, e a maneira de descobrir o que é medir a coisa compartilhada em vez do teste.

Dois instrumentos existem para isso, e ambos são destinados a serem executados ao lado de uma suíte completa:

./scripts/e2e-watchdog.sh /tmp/watchdog.log     # the HTTP server and the shared session
./scripts/e2e-mllp-probe.py /tmp/mllp.log       # the fixture channel's listener

Cada um descobre as portas da execução do arquivo de estado de configuração e amostra a cada 500 milissegundos até que o servidor saia. Eles registram cada amostra em vez de apenas as falhas, o que os torna úteis: um pico aparece em uma execução onde nada falhou, então uma falha que aparece uma vez em três execuções se torna mensurável em cada uma.

Defina PERFUSE_E2E_KEEP=1 para manter o diretório temporário, que contém o banco de dados como foi deixado e o log do servidor para toda a execução. O log do servidor é geralmente a resposta. Em um caso investigado, ele registrou um canal parando e seu ouvinte reassociando 421 milissegundos depois, e a conexão recusada do probe caiu dentro dessa janela.

Leia a trilha em vez de error-context.md, que esteve vazio em mais de uma ocasião onde a trilha continha a mensagem real.

Copie os artefatos antes de reexecutar qualquer coisa. Uma execução bem-sucedida limpa test-results, então a trilha da falha que você está investigando some no momento em que você tenta reproduzi-la. Uma vez perdida, a pergunta que ela teria respondido não pode ser respondida.

Pare os contêineres de interoperabilidade primeiro. Pare-os antes de uma execução completa do navegador e inicie-os com ./scripts/interop-up.sh posteriormente, se você ainda precisar deles.

Oito contêineres ocupam cerca de 9,8 GB de memória e, em uma máquina sem muito mais do que isso, há muito pouco sobrando para os processos do Chromium, node e a cadeia de ferramentas do Go juntos. O que ele produz não é um erro de falta de memória, mas um renderizador que para de ser agendado: uma trilha registrada mostra um intervalo de 60,2 segundos sem quadros, durante o qual o Playwright esperou que um botão se tornasse "visível, habilitado e estável" e não pôde obter dois quadros de animação consecutivos para comparar. O servidor estava saudável durante todo o tempo, a solicitação mais lenta em toda a execução sendo de 154 milissegundos.

Essa falha se lê como um defeito no teste que aconteceu de estar executando. Vale a pena conhecer a forma dela: todas as solicitações rápidas, a página visualmente congelada, o loop de repetição nunca atingindo uma segunda iteração e todo o processo passando em isolamento.

Apenas uma execução por vez. A suíte compartilha um servidor, uma sessão assinada em web/e2e/.auth/admin.json e um arquivo de estado que nomeia o processo do servidor. Nenhum deles é por execução, então uma segunda execução iniciando enquanto a primeira está em andamento sobrescreve o arquivo de estado e mata o servidor e a sessão da outra execução.

O que isso parece é nada semelhante à causa. Produziu uma sequência de 279 falhas cuja primeira mensagem foi ENOENT: no such file or directory, open './e2e/.auth/admin.json', uma sequência que parou cedo relatando 217 aprovados, e dois testes falhando com bind: address already in use — nenhum dos quais sugere duas execuções em conflito. A suíte agora obtém um bloqueio e se recusa a iniciar, nomeando o processo que o mantém. Um bloqueio deixado por uma execução interrompida é assumido em vez de bloquear para sempre, porque uma medida de segurança que trava a suíte é algo que alguém deleta juntamente com a segurança.

Uma armadilha relacionada, agora corrigida: dois specs nomearam suas portas de escuta diretamente, então um servidor deixado para trás por uma execução interrompida os fez falhar em algo com que não tinham nada a ver. As portas são pedidas ao sistema operacional agora.

Não responda a nada disso com repetições. Um teste que passa na segunda tentativa encontrou uma corrida real e a escondeu, e playwright.config.ts define retries: 0 por esse motivo.

Uma advertência: amostragem a cada 100 milissegundos gerou vinte processos por segundo, esticou uma execução pela metade e falhou dois testes em tempos limite que não tinham nada de errado com eles. Um instrumento que muda o que ele mede produz descobertas sobre si mesmo.

14.6 O que ainda precisa de infraestrutura real

Várias partes do Perfuse são implementadas e nunca foram exercitadas contra a coisa real. Elas são listadas aqui em vez de serem descobertas:

Os recursos deste capítulo e do próximo existem para que você possa reunir suas próprias evidências em vez de aceitar a palavra de alguém.

14.7 Medido contra corpora de conformidade públicos

Uma suíte de testes cujos fixtures foram escritos aqui prova a concordância com si mesmo. Estes são os dados de outras pessoas.

14.7.1 FHIR R4, os exemplos próprios da especificação

Todos os 2.912 arquivos de exemplo publicados com a especificação FHIR R4 — cada exemplo que os autores do padrão escreveram.

ResultadoContagem
Recursos validados com nenhum achado13.723
Recursos relatados como inválidos0
Arquivos recusados como um tipo de recurso não implementado753
Entradas de pacote puladas como um tipo não implementado1.348

Nenhum recurso foi validado incorretamente. Cada falha é uma recusa explícita que nomeia o tipo que não pode ler — 672 ValueSet, 80 ConceptMap e um Parameters. Um validador que passa silenciosamente o que não entende é pior do que um que diz isso.

O corpus encontrou um defeito, que é o motivo para executá-lo. Validar um pacote imprimiu "Validação de pacote a partir de um ficheiro não é suportada ainda" e continuou. Isso era falso em ambas as direções: pacotes cujas entradas aconteceram a ser tipos que o analisador podia manter já estavam sendo validados, e um pacote que era genuinamente inválido produziu a mesma linha, contou nada, e saiu zero — incluindo sob -strict, que existe para que isso possa gatear uma compilação. Quarenta e dois dos próprios pacotes da especificação estavam sendo pulados.

Os conjuntos agora são validados entrada por entrada, com três resultados mantidos separados: uma entrada que está errada falha e nomeia o campo, uma entrada de um tipo que esta compilação não pode ler é contada como pulada e relatada, e um conjunto que transporta nenhum corpo de recurso não é nenhum. O mesmo corpus passou de 2.100 recursos verificados para 13.723.

14.7.2 HL7 v2, o corpus de teste HAPI

Os fixtures de mensagem do HAPI, a implementação de referência Java HL7 v2 — material deliberadamente desconfortável, incluindo payloads uuencoded, delimitadores escapados e grupos repetidos.

59 mensagens, 59 analisadas, nada recusado. Sete tipos de mensagens em um corpus que qualquer sistema único descreveria como uma coisa, que é o ponto perfuse profile existe para fazer.

14.7.3 O que não foi executado

DICOM contra um conjunto de conformidade público, e X12 contra um corpus publicado. Nenhum dos dois foi feito, e nenhum deve ser inferido a partir dos dois acima.

15 Migração do Mirth

Duas coisas são necessárias para substituir um motor de trabalho: os canais têm que ser transferidos, e alguém tem que ser capaz de mostrar que a substituição produz a mesma saída. Perfuse faz o primeiro importando as próprias exportações do Mirth, e o segundo comparando os dois motores em seu próprio tráfego.

Tudo neste capítulo se aplica igualmente ao Open Integration Engine e BridgeLink. Mirth Connect parou de ser de código aberto na versão 4.6 em março de 2025; OIE (hospedado pela Eclipse Foundation) e BridgeLink (Innovar Healthcare) são os forks que continuam a linha de código aberto, e ambos escrevem os mesmos formatos de exportação. O importador é testado contra os três, abaixo.

15.1 Importação de canais

Perfuse lê todas as exportações que esses motores escrevem:

ExportaçãoDo AdministradorO que é transferido
Um canalExportar CanalO canal
Um grupo de canaisExportar GrupoCada canal nele, cada um mantendo o grupo
Modelos de códigoExportar Modelos de CódigoCada biblioteca como um arquivo de script
Uma cópia de segurança do servidorBackup de Configuração, ou GET /api/server/configurationTodos os acima de uma vez

Aponte perfuse translate para qualquer um deles, ou solte um em Administrar → Migrar:

perfuse translate -o ./channels server-backup.xml

Uma biblioteca de modelos de código torna-se lib/<library>.js ao lado dos canais, e cada canal que o Mirth tinha a biblioteca ativada recebe scripts.include: [lib/<library>.js] — assim, um transformador que chama uma função de site, como formatMRN(), ainda a encontra. Um canal para o qual a biblioteca não foi ativada não a inclui, porque os seus scripts não podiam vê-la no Mirth. Os fragmentos de arrastar-e-soltar são deixados de fora: o Mirth apenas os cola num passo à mão, por isso não são código que é executado por si só. No navegador, importar um canal salva as bibliotecas que inclui primeiro.

Um *Channel Writer* nomeia o canal para o qual entrega por id. Num grupo ou backup, o destino está no mesmo documento, pelo que se torna num destino de channel que nomeia esse canal; a partir de uma exportação de um único canal, é relatado para si preencher. Os scripts globais de servidor não têm um equivalente no Perfuse e são relatados em vez de serem eliminados.

O relatório diz, por canal, se traduziu limpo, traduziu com avisos ou não pôde ser lido.

O título é uma fração com seu denominador — "37 de 40 prontos" — porque "37 prontos" não diz nada sobre o que você ainda tem que fazer.

Um canal que não pôde ser lido é um problema diferente de um que não pôde ser traduzido. O primeiro significa que o XML em si não foi parseado e geralmente é uma exportação truncada ou parcial; o segundo significa que o conteúdo do canal tem algo sem um equivalente no Perfuse. A importação separa-os.

15.2 O que traduz e o que precisa de uma decisão

Fontes, destinos, filtros e as etapas de transformador comuns traduzem diretamente. Os conectores que traduzem: TCP/MLLP (e TCP bruto com sua estruturação), HTTP, Arquivo, Banco de Dados, JavaScript, DICOM, Web Service (SOAP), SMTP e Leitor/Escritor de Canal. JMS e o Escritor de Documento não traduzem e são relatados como bloqueadores.

Uma etapa Mapper que define uma variável a coloca no mapa que seu escopo nomeia — channelMap por padrão — exatamente como Mirth faz, então etapas posteriores que a leem com $('name') a encontram.

Transformadores JavaScript não traduzem em geral. Canais Mirth comumente mantêm um código substancial em um transformador, e não há uma conversão automática de JavaScript arbitrário para etapas declarativas. O importador relata esses em vez de tentar uma tradução que possa estar sutilmente errada: um transformador mal traduzido é pior do que um marcado para um humano, porque ele será executado.

Onde um script genuinamente tem que permanecer um script, Perfuse pode executá-lo — veja a chave scripts na referência de canal — ao custo da traça de nível de etapa descrita em depuração.

15.3 O que o importador foi testado

Cinco motores, cada um autorando seus próprios documentos: Mirth 4.5.2, OIE 4.5.2, 4.6.0 e 4.7.0, e BridgeLink 26.9.0. scripts/mirth-engine-corpus.sh compila um pequeno programa contra os jars de cada motor e tem seu próprio serializador que escreve três canais ordinários — uma alimentação MLLP com um mapeador, um script que chama uma biblioteca de modelos de código e um filtro; uma alimentação HTTP para um banco de dados; uma sondagem de arquivo sobre MLLP — mais a biblioteca e um grupo de canais. Ele carrega-os no motor em execução e baixa o backup do servidor do motor. Os resultados são comprometidos em internal/mirth/testdata/engines/, e a suíte de testes segura o importador para cada um deles em cada compilação: cada backup é lido, traduzido, carregado e o canal ADT é executado com duas mensagens para verificar se a biblioteca preenche o número do registro e o filtro descarta o resultado.

As próprias exportações do Perfuse vão no sentido oposto — canais do Perfuse importados para cada motor em execução e verificados para garantir que o motor não os armazene como inválidos. Os cinco aceitam todos os transportes que o Perfuse exporta. O Open Integration Engine 4.7.0 adicionou duas configurações HTTP sem equivalente aqui: um remetente HTTP vinculado a um endereço local escolhido é relatado como um aviso, e um limite de cabeçalho de solicitação do ouvinte HTTP apenas quando está acima do 1 MB que o Perfuse aceita.

A primeira execução contra este corpus encontrou quatro defeitos, todos corrigidos: o tradutor recusou fontes HTTP e de arquivo como "apenas MLLP é suportado" muito tempo depois que o Perfuse tinha ambos; ele leu o endereço de um remetente HTTP de um campo que nenhum dos motores escreve; ele traduziu o tamanho do buffer de soquete do Mirth como um limite de mensagem de 64 KB; e uma variável do Mapeador se tornou uma variável global do JavaScript que $('mrn') nunca viu, então a biblioteca preencheu uma string vazia.

The single-channel fixture that started this was also exported by Mirth 4.5.2, authored by Mirth itself rather than written here. That distinction earned its place: the only fixture in this repository used to be hand-written, and a real Mirth will not load it — the API accepts the POST and then stores the channel as This channel is invalid. Verify all required extensions are loaded correctly, with every destination connector discarded.

Escrever um à mão nunca iria funcionar, e o motivo é digno de ser conhecido se você está produzindo exportações próprias. O serializador do Mirth ignora elementos que não reconhece, então um nome de elemento errado não produz nenhum erro — o conector simplesmente não está lá depois.

scripts/mirth-author-channel.sh constrói um usando as próprias classes de modelo do Mirth e seu próprio serializador, então posta-o em um servidor em execução e falha se o servidor o rejeitar. O importador do Perfuse lê o resultado: nome, transporte de origem e destinos todos sobrevivem.

15.4 Comprovando que corresponde

Esta é a parte que decide se uma migração acontece, e ela precisa de evidências em vez de confiança.

O Perfuse compara sua própria saída contra a do antigo motor, mensagem por mensagem, em seu tráfego. O que ele precisa são pares: a mensagem como ela chegou e a mensagem que o antigo motor produziu a partir dela. Ambas estão no próprio repositório de mensagens do Mirth e podem ser exportadas do navegador de mensagens.

O Perfuse não pode alcançar o Mirth, e este manual não irá fingir o contrário. Uma ferramenta que alegasse verificar uma migração sem nunca ver a saída real do antigo motor estaria verificando nada. Fornecer os pares é a forma honesta do exercício.

15.4.1 Quatro números, não uma taxa de aprovação

ResultadoSignificado
IdênticoByte por byte o mesmo.
Apenas cosméticoDifere em maneiras que não carregam informações — campos vazios finais, um terminador final.
DiferenteO valor de um campo é diferente.
Não executariaO Perfuse não pôde processar a mensagem de forma alguma.

Eles são quatro números porque significam quatro coisas diferentes e colapsá-los esconde os que precisam de uma decisão.

Idêntico significa byte por byte, não equivalente. Um teste mais fraco permitiria diferenças na ordem de segmentos ou separadores finais, e essas são exatamente as que um sistema downstream rigoroso rejeita.

Diferenças cosméticas são contadas separadamente em vez de serem incorporadas à coluna boa. Elas genuinamente não carregam informações, então tratá-las como falhas as enterraria sob milhares de nada — mas elas não são idênticas, e um receptor fazendo sua própria análise rigorosa pode discordar.

"Não executaria" é separado de "diferente" porque geralmente é uma lacuna de configuração que o importador não pôde preencher, e não uma decisão de mapeamento. Se tudo estiver nessa coluna, o veredito diz isso e diz para verificar a configuração antes de ler qualquer outra coisa.

15.4.2 Diferenças são agrupadas por campo

Uma execução de mais de cinquenta mil mensagens que relata quatro mil diferenças não lhe disse nada que você possa agir. A mesma execução que relata que PID-8 difere em cada mensagem porque o antigo motor escreveu Male onde Perfuse escreve M lhe disse exatamente uma coisa para decidir.

Então cada descoberta é um campo, com uma contagem, e diz se a diferença é sistemática — o mesmo par de valores todas as vezes — ou se o conteúdo do campo difere.

Essa distinção é a coisa mais útil no relatório. Um par de valores distintos em quatro mil mensagens é uma única decisão de mapeamento. Quatro mil pares distintos é o conteúdo diferindo, o que é um problema diferente e muito pior, e os dois não devem ler da mesma forma.

Descobertas são ordenadas por quantas mensagens elas afetam, então a maior causa única é a primeira.

15.4.3 O veredito não arredonda

Ele fornece contagens exatas: 49.993 de 50.000, não "mais de 99%". Os sete são o ponto principal de executá-lo.

Está escrito para ser citado em um pedido de alteração, porque é onde o número acaba.

15.5 Uma sequência sugerida

  1. Importe os canais e resolva qualquer coisa relatada como ilegível.
  2. Para cada canal, revise os avisos. A maioria será de scripts.
  3. Exporte alguns milhares de pares de mensagens do Mirth para o canal mais movimentado e execute a comparação.
  4. Trabalhe nos resultados. Os sistemáticos são uma decisão cada.
  5. Execute novamente até que as únicas diferenças sejam as que você decidiu que estão corretas.
  6. Execute o Perfuse em modo de sombra ao lado do Mirth no tráfego ao vivo, entregando em lugar nenhum, e compare novamente durante um período que inclua um fim de semana e um fim de mês.
  7. Corte um canal, não todos.

15.6 O que só executa em um software de um fornecedor

A tela de migração responde a uma segunda pergunta, e vale a pena perguntar antes de ter alguma opinião sobre o Perfuse: quanto da sua lógica de integração só pode ser executada no software que você tem.

Cada canal recebe um veredito de Portabilidade, a partir do mesmo scan que produz as notas de migração. Ele é executado contra uma exportação de canal, então não precisa de nada instalado e não altera nada.

15.6.1 A distinção é o ponto principal

A maioria do Java nos scripts do Mirth não é de bloqueio. SimpleDateFormat, HashMap, Apache Commons — tudo isso trabalhando em torno de um mecanismo de JavaScript de 2009, tudo isso comum, tudo isso com equivalentes diretos. Um canal com três centenas dessas referências é totalmente portátil, e uma ferramenta que relatasse "300 referências Java, você está preso" estaria mentindo para você.

O bloqueio é especificamente as chamadas que precisam do servidor do próprio fornecedor: com.mirth.connect.* e jars do fornecedor. Cinco dessas e você está preso. Quinhentas do outro tipo e você está livre.

Então, o veredito começa com o número que importa e diz na mesma frase que o número maior não é isso. Onde há chamadas do fornecedor, elas são listadas por nome — uma contagem é uma afirmação, e uma lista é algo que o seu próprio engenheiro pode ir e verificar.

Uma terceira categoria é mantida separada: capacidade que existe, mas não a partir de um script. Iniciar um canal a partir do JavaScript não tem equivalente aqui, e há um ponto de extremidade da API que faz exatamente a mesma coisa. Chamá-lo de bloqueio exageraria o resultado.

15.6.2 Chamadas Java que são executadas inalteradas

As classes Java mais comuns são executadas como estão escritas. O Perfuse não tem um tempo de execução Java, portanto, essas são classes JavaScript com os mesmos nomes e métodos, suficientes para a forma como os scripts do canal as usam; importPackage(java.util) e importClass(...) as trazem para o escopo por seus nomes curtos, como no Rhino (os Date, Map, Set, Math, String e Boolean do próprio JavaScript nunca são substituídos: os do Java ainda estão lá pelo nome completo). O relatório de migração conta cada uma dessas chamadas como já suportada.

PacoteClasses
java.utilArrayList, LinkedList, Vector, List, Collection, HashMap, LinkedHashMap, Hashtable, TreeMap, Properties, HashSet, LinkedHashSet, TreeSet, Arrays, Collections, Date, Calendar, GregorianCalendar, UUID, Base64, regex.Pattern (com Matcher), concurrent.ConcurrentHashMap
java.langString, StringBuilder, StringBuffer, Integer, Long, Short, Byte, Double, Float, Boolean, Math, System (tempo e separador de linha apenas)
java.text, java.math, java.net, java.nioSimpleDateFormat e DateFormat (letras de padrão do Mirth), BigDecimal (como um double), URLEncoder, URLDecoder, StandardCharsets
Apache Commonslang3.StringUtils e lang.StringUtils (cerca de sessenta métodos), StringEscapeUtils, codec.binary.Base64

Elas se comportam como o Java onde os scripts dependem disso: Integer.parseInt("x") lança NumberFormatException, String.replaceAll e split aceitam expressões regulares, enquanto replace é literal, mapeia strings de chave por valor, TreeMap e TreeSet iteram em ordem e SimpleDateFormat.parse retorna uma data que getTime() funciona. Um método que um script chama que o equivalente não tem falha naquela linha, nomeando-o; qualquer outra classe Java falha por nome, como antes. BigDecimal é um duplo aqui, portanto, não mantém a aritmética decimal exata do Java: verifique os scripts que usam isso para dinheiro.

15.6.3 Scripts externos são relatados como desconhecidos

Uma etapa que executa um arquivo de script externo referencia um caminho no servidor antigo, e o arquivo não está na exportação. Nada pode ser dito sobre o que ele contém, então é contado como desconhecido em vez de supor um ou outro. Busque esses arquivos antes de concluir qualquer coisa — em ambas as direções.

15.6.4 O próprio bloqueio do Perfuse, declarado na mesma respiração

Esta seção seria desonesta sem isso.

O Perfuse é Apache 2.0, o que é irrevogável para o código já lançado. Você pode bifurcar o que existe hoje e ninguém pode retirar isso. Os canais são arquivos YAML e os scripts são JavaScript comuns, então não há superfície proprietária para chamar — a dependência Java do Mirth é estruturalmente indisponível aqui, o que é o único lugar onde uma limitação é genuinamente uma característica.

O que isso não promete: que uma versão futura permaneça aberta, que um serviço hospedado exista a um preço que você goste, ou que migrar do Perfuse não custe nada. Mover qualquer camada de integração significa retestar todos os canais contra tráfego real. O que você está escolhendo é se os artefatos que você constrói são legíveis e portáteis, e se a saída depende de uma licença que alguém mais controla.

15.6.5 Configurando a etapa 6

One message real traffic Live channel unchanged Candidate the version you are testing Receiver delivers nothing Comparison field by field The candidate sees the same real messages as the live channel and delivers none of them. Only the live channel reaches the receiver. What you read afterwards is where the two disagreed, field by field — not a pass or a fail.

A seção Shadow começa uma comparação. Escolha o canal que está em execução, escolha o candidato para comparar contra a lista e comece.

Três coisas sobre isso valem a pena saber antes de confiar nos números.

O candidato é escolhido a partir de uma lista, não digitado. Uma sombra nomeia um ficheiro de canal e um nome que não resolve torna o canal *ativo* inválido — o Perfuse recusa um canal por completo quando algo que referencia está quebrado. Portanto, um erro de digitação não produz um aviso, mas faz com que o canal em execução desapareça.

A quota é um percentual. Reduza-a apenas em uma fonte de alimentação ocupada e saiba o que custa: a amostragem reduz o trabalho e a confiança na mesma proporção, e a mensagem que teria mostrado a diferença é a incomum.

Campos a ignorar é geralmente necessário. Um canal que carimba um carimbo de data/hora ou um número de sequência difere em cada mensagem única, o que relata uma taxa de diferença de 100% e não diz nada. MSH-7 e MSH-10 são o par comum.

Uma comparação é escrita no ficheiro do canal assim que você o inicia e começa a observar quando o canal é carregado novamente — a tela diz isso em vez de afirmar que já está em execução. Parar uma comparação deixa o canal candidato no lugar, porque o candidato é a coisa destinada a ir ao ar.

A Etapa 6 é a que não pode ser encurtada. As diferenças que importam geralmente estão no tráfego que aparece apenas ocasionalmente — um evento de gatilho raro, um lote de fim de mês, um remetente que se comporta de forma diferente à meia-noite — e uma amostra tirada durante uma tarde não as conterá.

15.7 Voltar pelo outro caminho

Um canal pode ser exportado como um ficheiro de canal Mirth, a partir do navegador: Canais, então Para Mirth no canal desejado.

Isso existe porque a objeção a substituir um motor de trabalho raramente é se o substituto é bom. É o que acontece se a decisão se revelar errada, e uma exportação que volta pelo caminho que veio é a resposta mais barata para isso.

Leia o que o diálogo diz antes de pegar o ficheiro. O formato do Mirth não tem lugar para um filtro Perfuse, uma cadeia de transformação, um contrato ou uma comparação de sombra, então um canal exportado faz menos do que o de onde veio. Os transportes e seus endereços são convertidos; a lógica não. Cada perda é listada por nome antes que o ficheiro seja oferecido, e a mesma lista vai para a descrição do canal para que quem o importa também o veja.

Um canal que o Mirth não pode expressar é recusado em vez de aproximado. Um destino S3 não tem equivalente no Mirth, e um canal que importou limpo enquanto entregava em algum lugar além do balde seria pior do que nenhum ficheiro. A recusa nomeia o destino em falta.

As definições de conector não são escritas a partir da leitura do formato do Mirth. scripts/mirth-dump-connector-templates.sh tem o próprio serializador do Mirth produzir os padrões para cada classe de conector, e o Perfuse substitui valores nesses documentos — recusando qualquer configuração que o modelo não contenha. Isso importa porque de como o Mirth responde a um canal que não pode analisar: não recusa a importação. Ele armazena um canal cuja descrição foi substituída por "Este canal é inválido. Verifique se todas as extensões necessárias estão carregadas corretamente" e cujos destinos foram silenciosamente descartados. Um exportador verificado contra sua própria saída em vez de contra um servidor passa em todos os testes enquanto produz documentos que são descartados, o que é exatamente o que aconteceu aqui antes que as exportações fossem tentadas contra um Mirth em execução.

O que cruza hoje: MLLP e TCP em ambas as direções, HTTP em ambas as direções, leitura e escrita de ficheiros, leitura e escrita de bancos de dados, DICOM em ambas as direções, e destinos SMTP, SOAP e JavaScript. Cada par é verificado importando-se para um Mirth 4.5.2 real e verificando se o servidor não substituiu silenciosamente o canal.

16 CMS-0057 para pagadores

A regra final de interoperabilidade e autorização prévia da CMS (CMS-0057-F) exige que os pagadores afetados — organizações de Medicare Advantage, programas de Medicaid e CHIP estaduais e seus planos de cuidados gerenciados, e emitentes de QHP nas trocas federais — executem quatro APIs FHIR a partir de 1 de janeiro de 2027, e publiquem métricas de autorização prévia em seu site público todos os anos a partir de 2026.

O Perfuse fornece as quatro APIs em seu ponto de extremidade FHIR e as conversões que as preenchem: reclamações adjudicadas como CARIN Blue Button, autorizações prévias como Da Vinci PDex, e as métricas anuais no layout do modelo próprio da CMS. A visão CMS-0057, sob Troca, diz quais das quatro esta instância pode responder e o que cada uma ainda precisa, e faz as três conversões no navegador.

Medicamentos estão fora do escopo em toda parte, como estão nas disposições de autorização prévia da regra: nenhuma reclamação de farmácia, nenhuma formação, e uma linha de métricas que nomeia um medicamento é recusada em vez de contada.

16.1 As quatro APIs

APIO que serveGuiasActivado por
Acesso ao PacienteAs reclamações, dados clínicos e autorizações anteriores de um membro, para um aplicativo que ele escolheCARIN Blue Button 2.2.0, PDex 2.2.0, US Core, SMART App Launch-fhir e um emissor SMART (-smart-issuer)
Acesso ao PrestadorO mesmo para os membros atribuídos a um prestador, em massaPDex 2.2.0, Da Vinci ATR 2.1.0, Bulk Data-fhir-payer-apis e -fhir-bulk-export
Payer-to-PayerO registo de um membro para outro pagador, após correspondênciaHRex 1.2.0 $member-match, PDex 2.2.0-fhir-payer-apis
Autorização PréviaO que uma ordem precisa, a documentação, então o pedido e a decisãoDa Vinci CRD, DTR e PAS 2.2.x (2.2.1, 2.2.0, 2.2.1) e 2.1.0, com tradução X12 278-fhir, gravável, e -crd-rules

A API de Acesso ao Paciente não precisa de nenhuma operação própria: é a leitura e pesquisa comuns do endpoint FHIR, protegida por SMART, com recursos CARIN e PDex no repositório. A pesquisa de ExplanationOfBenefit suporta os parâmetros com nomes CARIN — patient, identifier, type, service-date, billable-period-start, provider, insurer, coverage — e Coverage suporta subscriber-id, identifier e payor.

16.1.1 Duas versões das guias: 2.1.0 e 2.2.x

CMS-0057-F recomenda CRD, DTR e PAS 2.0.1 e 2.1.0. As versões 2.0.1 baseiam-se no US Core 3.1.1, que expirou em 1 de janeiro de 2026, por isso a versão 2.1.0 é a que um sistema de registo eletrônico de saúde provavelmente fala; as mais recentes são CRD 2.2.1, DTR 2.2.0 e PAS 2.2.1. Perfuse responde em ambas. Ele determina qual versão um chamador fala, primeiro a mais específica:

  1. a partir do pedido: extensão CDS Hooks do CRD davinci-crd.requestedVersion ("2.1"), ou a versão em um perfil Da Vinci que um DTR

ou PAS reivindica (profile-pas-request-bundle|2.1.0);

  1. a partir do registro do chamador: davinci_version: "2.1" em um cliente SMART (-smart-clients) ou um cliente CDS (-cds-clients);
  2. a partir do servidor: serve -davinci-version 2.1; o padrão é 2.2.
clients:
  - issuer: https://ehr.example.org
    jwks_url: https://ehr.example.org/.well-known/jwks.json
    davinci_version: "2.1"

Cada resposta é decidida e mantida na forma 2.2.x e reescrita para um chamador 2.1.0 à medida que é enviada, por isso as regras, a fila de revisão, o link X12 278 e as métricas são as mesmas para ambos. A reescrita cobre o que as versões soletram de forma diferente: CRD 2.1.0 não tem indeterminate (Perfuse diz condicional, com o motivo) e não tem categoria em um detalhe de cobertura; DTR 2.1.0 nomeia o pacote PackageBundle e deixa a QuestionnaireResponse para o aplicativo; PAS 2.1.0 $inquire responde com um Bundle, e falta as extensões do revisor e transmissão. A lista completa, e a verificação contra cada exemplo de guia 2.1.0, está em conformance/davinci21. Uma notificação PAS segue -davinci-version, desde que uma assinatura não diz qual versão o seu proprietário lê.

16.2 Requisitos e documentação de cobertura: CRD e DTR

A API de Autorização Prévia é, na prática, três guias Da Vinci juntos. CRD informa o clínico, enquanto a ordem ainda é um rascunho, se ela é coberta, se precisa de autorização prévia e qual documentação é desejada. DTR entrega ao EHR o questionário que reúne essa documentação. PAS envia o pedido e retorna a decisão. O Perfuse serve todos os três como o pagador.

-crd-rules rules.yaml serve CRD sobre CDS Hooks em /cds-services: todos os seis hooks do CRD, order-sign, order-select, order-dispatch, appointment-book, encounter-start e encounter-discharge, cada um com um prefetch para a cobertura ativa do paciente. Os dois hooks de encontro também prefetch o encontro e respondem sobre o encontro em si, correspondendo ao seu tipo e tipo de serviço, assim como appointment-book responde sobre um agendamento. As regras são a política do pagador, mantidas em um arquivo porque mudam sem lançamentos de software:

payer: Springfield Health Plan
rules:
  - description: Home oxygen equipment
    codes: [E0424, E0431]
    covered: covered            # covered, not-covered, conditional
    pa: auth-needed             # no-auth, auth-needed, satisfied, performpa, conditional
    documentation: [clinical]
    questionnaire: https://www.springfield-health-plan.example/fhir/Questionnaire/home-oxygen

Cada pedido recebe uma atualização de systemActions que transporta a extensão de informação de cobertura do CRD - que o EHR armazena no pedido e mais tarde envia com a autorização prévia - e um cartão que o clínico lê. Um pedido cujo código não tem regra é respondido como conditional, nunca assumido como coberto; um pedido sem Cobertura alguma recebe um cartão que o indica. examples/crd/ contém um ficheiro de regras e um questionário correspondente.

Uma regra também pode conter o restante do que CRD permite que um pagador diga:

O que o EHR não pré-carregou, o Perfuse lê do fhirServer do EHR com o token que enviou. Se isso falhar, a resposta é indeterminate com a razão technical do CRD, nunca uma suposição. Uma Cobertura que terminou ou não está ativa é respondida como not-covered, no-active-coverage.

members: fhir no ficheiro de regras resolve a cobertura contra os próprios registos do pagador nesta loja FHIR do servidor (inicie-o com -fhir), os mesmos registos que $member-match lê:

com esse número.

A Descoberta declara davinci-crd.version e uma opção de configuração coverage-info. Quando um cliente desativa a opção, a resposta é vazia. Os JWTs do EHR são verificados como define o CDS Hooks, com iss, aud, exp, iat e jti e sem sub, e um jti repetido é recusado.

As chamadas autenticam com o JWT que um EHR assina para cada chamada, a partir de um emissor nomeado em -cds-clients com sua URL JWKS — que é como o CDS Hooks o descreve — ou com um token de API do Perfuse. A Descoberta é aberta, como exige o CDS Hooks.

DTR: carregue os questionários no endpoint FHIR e POST /fhir/Questionnaire/$questionnaire-package os retorna como pacotes de DTR, com as bibliotecas CQL que eles nomeiam. O pedido pode nomear o questionário ou enviar a ordem e deixar que as informações de cobertura digam qual.

Tentando: Payers → Reivindicações e autenticação → Requisitos de cobertura (CRD) envia uma ordem para as regras deste servidor ou para a URL do serviço CDS de um pagador e exibe os cartões e as informações de cobertura.

16.3 Reclamações como CARIN Blue Button

perfuse cms0057 carinbb emparelha cada reclamação em um 837 com seu pagamento em um 835, pelo número da conta do paciente que o 835 é obrigado a ecoar de volta, e escreve uma transação FHIR para cada: a ExplanationOfBenefit com o Patient, Coverage, Organizations e Practitioners que referencia.

perfuse cms0057 carinbb -system https://fhir.your-plan.org/identifier -network innetwork \
    claims.837 remittance.835

O perfil segue a reclamação: reclamações profissionais (837P) se tornam C4BB-ExplanationOfBenefit-Professional-NonClinician, e institucionais (837I) em paciente ou não, de acordo com o tipo de conta. Cada entrada é um PUT com um id tirado dos identificadores de origem, para que carregar a mesma reclamação duas vezes a atualize em vez de criar uma segunda cópia.

Três coisas não estão em nenhum dos arquivos X12, e cada uma é tratada dizendo que não está lá, em vez de adivinhar:

Diagnósticos são escritos com seu ponto decimal (J02.9, não J029), porque é assim que o sistema de código os publica e um servidor de terminologia perguntado sobre a outra grafia diz que não existe. O identificador de membro de um dependente é o do assinante, que é o que o 837 carrega, e as notas dizem isso. Um NPI cujo dígito de verificação está errado é relatado antes que o US Core o rejeite.

16.4 Autorizações prévias como PDex

perfuse cms0057 priorauth converte uma resposta de reclamação Da Vinci PAS — ou o pacote de resposta PAS que a transporta — em uma explicação de benefício de autorização prévia PDex, que é o que as três APIs de dados servem.

perfuse cms0057 priorauth pas-response.json pas-claim.json

A reclamação PAS é opcional e quase sempre necessária. Uma explicação de benefício deve dizer qual cobertura a decisão foi tomada, e apenas o pedido transporta isso; sem ele, a conversão para e diz isso. A ação de revisão — aprovada, negada, pendente, com seu número de autorização e motivo — se move da extensão PAS para a PDex, e o tipo de serviço X12 mantém seu código sob o URI que a PDex vincula a ele.

16.5 As APIs de Acesso ao Fornecedor e Payer-to-Payer

Com -fhir-payer-apis o endpoint FHIR responde a três operações adicionais:

As exportações aplicam a regra de exclusões ao longo do caminho. As reclamações perdem o pagamento e todos os montantes de compartilhamento de custos e reembolso, e mantêm os serviços, códigos, datas e fornecedores; o perfil CARIN é removido de meta.profile porque o recurso não atende mais a ele. O Payer-to-Payer também deixa de fora as autorizações prévias negadas. Membros que detêm um Consentimento ativo de opt-out de Acesso ao Fornecedor PDex são excluídos de uma exportação de fornecedor, e o log registra quantos. O parâmetro patient só pode restringir os membros do Grupo; nomear qualquer outra pessoa é recusado.

O acesso à exportação de um Grupo é decidido pela autenticação do endpoint. Os escopos SMART especificam quais tipos de recursos um token pode ler, e não qual Grupo, por isso cada prestador de serviços precisa de um token que possa alcançar apenas a sua própria lista de atribuições. Um token de API pode ser limitado a Grupos quando é criado — perfuse token create -label riverside-provider-access -fhir-groups riverside-attributed, ou o campo Limitar a Grupos FHIR em Usuários → Credenciais de máquina — e, no endpoint FHIR, pode ler esses Grupos, executar $davinci-data-export ou $export neles e recuperar o que a exportação produziu, e nada mais. O Grupo de outro prestador de serviços responde não encontrado em vez de proibido, por isso um token não aprende quais outras listas de atribuições existem; todos os outros pedidos, incluindo a correspondência de membros e a pesquisa comum, são recusados. O limite se aplica a tokens de API; um token de um emissor SMART não carrega nenhum limite de Grupo. Quando o SMART está configurado, tokens de API são recusados, a menos que Configurações → FHIR → Aceitar tokens de API Perfuse além de tokens SMART esteja ativado (veja Segurança, *Quem pode chamar o endpoint FHIR*); um token limitado a Grupos de um prestador de serviços precisa disso.

16.6 Um diretório de fornecedores: Plan-Net

CMS-0057 também pede aos pagadores um diretório de fornecedores, e o endpoint FHIR serve um a Da Vinci Plan-Net 1.1.0 sem opção para ativar: carregar os Practitioners, PractitionerRoles, Organizations, OrganizationAffiliations, Locations, HealthcareServices, InsurancePlans e Endpoints, e os aplicativos dos membros podem pesquisá-los. Todo parâmetro de pesquisa Plan-Net é indexado - um papel de rede e serviço, uma área de cobertura de plano, uma organização participante de afiliação, uma organização partof - junto com os includes e cadeias reversas (_has) que as consultas do guia usam, e a CapabilityStatement lista os perfis Plan-Net.

A suíte Plan-Net do Inferno passa em 199 testes. Os 10 que falham são cadeias diretas onde o kit pega seu valor de pesquisa do primeiro Organization que viu em vez de um que os recursos pesquisados se referem; isso é relatado ao kit (sua issue 34), e o servidor responde corretamente a essas consultas quando fornecido um valor que os dados contêm.

16.7 Métricas de autorização prévia

perfuse cms0057 metrics lê um CSV de decisões exportadas do sistema de gestão de utilidade e produz a página pública que o CMS exige, no layout de *Relatório de Métricas de Autorização Prévia — Visão geral e Modelo*.

perfuse cms0057 metrics -year 2025 -org "Springfield Health Plan" -services services.csv \
    decisions.csv > prior-authorization-metrics-2025.html

As colunas são encontradas por cabeçalho: priority, received, decided e decision são necessárias, e request_id, line_of_business, extended, appealed, appeal_decision, service_code e service_description são lidos quando presentes. Um pedido pertence ao ano em que foi decidido; um ainda pendente é listado como excluído, nunca contado. Cada linha que não pode ser lida é relatada com seu número de linha.

A aritmética segue o modelo: para pedidos padrão e agilizados separadamente, a participação aprovada e negada, aprovada e negada dentro do prazo de decisão, aprovada após a extensão do tempo de revisão, e aprovada após recurso — de recursos, não de pedidos — com a média e mediana de tempo de recebimento à decisão. Uma mediana inferior a um dia é escrita em horas em vez de arredondada para "0 dias", o que o modelo pede explicitamente. Pedidos parcialmente aprovados são contados como aprovados, desde que o modelo não tenha categoria para eles, e a página diz quantos havia. Métricas são relatadas por linha de negócios, que é o nível que o CMS exige.

A página é autossuficiente — não há script, nem folha de estilo externa ou fonte — porque é publicada em um site público por quem o mantém, e qualquer coisa que carrega de outro lugar é algo que pode quebrar ou rastrear um visitante. -format csv e -format json dão os mesmos números para outros usos. Sem -services, a página carrega um aviso de que a lista de itens e serviços que requerem autorização prévia está faltando, porque o CMS exige isso na mesma página.

16.8 Medicamentos: o formulário, Benefício de Prescrição em Tempo Real e autorização prévia eletrônica

O CMS-0062-P (proposto em 14 de abril de 2026) traria medicamentos para autorização prévia: os pagadores afetados apoiariam a autorização prévia eletrônica NCPDP SCRIPT, o padrão de formulary e benefício NCPDP e o benefício de prescrição em tempo real NCPDP a partir de 1 de outubro de 2027, decidiriam pedidos de medicamentos dentro de 24 horas (expedido) e 72 horas (padrão), dariam uma razão específica para cada negação e relatariam métricas de medicamentos a partir de 2028. O Medicare Part D já exige a autorização prévia eletrônica SCRIPT. Um arquivo, o formulary, responde a tudo isso:

perfuse serve -fhir -pas -crd-rules payer-rules.yaml -formulary formulary.yaml

examples/formulary/formulary.yaml é um exemplo cujos medicamentos são conceitos RxNorm reais com NDCs RxNorm listados para eles (verificados contra RxNav). Um arquivo nomeia o pagador, seus planos (cada um com o formulary que usa, seus IDs de grupo e suas participações de custo por benefício de farmácia e nível) e seus formularies. Cada medicamento é um SCD ou SBD RxNorm com seu grupo RxNorm (o SCDG ou SBDG que a API de formulary do Drug exige), seus NDCs, um nível, e seus limites: prior_authorization, step_therapy, quantity_limit (uma quantidade em um número de dias rolante, e um máximo diário), not_covered, alternatives (códigos RxNorm, mais preferidos primeiro), notes, e questionnaire, a URL canônica do Questionário FHIR que uma autorização prévia solicita. cost_30_day é o custo do plano de um suprimento de 30 dias, que uma coinsurance é uma porcentagem de; sem ele, uma coinsurance é citada como uma porcentagem, nunca como um valor inventado. Todo o arquivo é verificado quando é carregado, todos os problemas listados de uma vez. Um membro é encontrado pela lista members do arquivo, por grupo, ou através do repositório FHIR: uma Coverage cujo subscriberId é o ID do membro e cuja class do tipo plan é o ID do plano. Payers › Drugs mostra o formulary, preços um medicamento e executa uma autorização prévia de ponta a ponta.

16.8.1 A API de Formulário de Medicamentos Da Vinci US

Publicado em /formulary/fhir como Da Vinci US Drug Formulary 2.1.0: cada plano é um PayerInsurancePlan, cada formulário é um Formulary (ambos InsurancePlan), cada medicamento é um FormularyDrug (MedicationKnowledge) e cada entrada é um FormularyItem (Basic). As pesquisas do guia são servidas (Basic?code=formulary-item&formulary=...&drug-tier=...&pharmacy-benefit-type=...&period=..., subject:MedicationKnowledge.code, InsurancePlan?formulary-coverage=..., coverage-type, MedicationKnowledge?code=...&doseform=...) com _include=Basic:subject, Basic:formulary e InsurancePlan:formulary-coverage. É público, sem credencial, como o CMS exige de um formulário de um pagador: é servido a partir de uma loja própria, na memória, que contém o formulário e nada mais, então não pode acessar o registro de um paciente. É somente leitura. Um medicamento excluído não é publicado, pois a API lista o que um formulário cobre; RTPB e ePA ainda respondem que não está coberto. Verificado com o validador HL7 FHIR contra o pacote 2.1.0 do guia com terminologia verificada: cada recurso gerado a partir da amostra não tem erros.

16.8.2 Benefício de Prescrição em Tempo Real

POST /ncpdp/rtpb recebe um RTPBRequest (NCPDP RTPB v13) com um token de API do papel de operador e responde com um RTPBResponse do formulary: o status de cobertura, o status de formulary, a participação estimada do membro e a do plano, e as restrições de cobertura, com até cinco alternativas cobertas com preços da mesma forma. Códigos de restrição e o status que cada um mapeia seguem as Recomendações de implementação de RTPB públicas da NCPDP: 75 autorização prévia necessária, 608 terapia de etapa, 76 limites do plano excedidos, 7X dias de suprimento acima do limite do plano (um medicamento não disponível por correio, por exemplo), 70 não coberto, todos *cobertos com restrições* (CR) exceto 70 (NC). Um membro com uma autorização prévia aprovada em arquivo recebe CC e AB8, como o guia Surescripts solicita, para que o prescritor não seja enviado para solicitar novamente. Um pedido que não pode ser precificado é NotProcessed com um código de rejeição NCPDP: 52 para um membro não encontrado, E7 e 19 para uma quantidade ou dias de suprimento em falta. O benefício de farmácia é lido do pedido: um preenchimento acima de 34 dias é um suprimento de três meses, e o tipo de farmácia M é encomenda por correio.

16.8.3 Autorização prévia eletrônica (NCPDP SCRIPT)

POST /ncpdp/script recebe PAInitiationRequest, PARequest, PAAppealRequest e PACancelRequest com um token de API do papel de operador, e responde a cada um com sua resposta:

SolicitaçãoResposta
PAInitiationRequestClosed quando nenhuma é necessária: CC nenhuma autorização prévia necessária, FN dentro do limite de quantidade, FM não coberto ou não no formulário, FQ uma aprovação em arquivo, CD nenhum membro encontrado, CG uma já em andamento. Caso contrário, Open, com um ID de caso e o conjunto de perguntas.
PARequestDecidido como uma solicitação PAS: Approved com o número de autorização e período, Denied com o motivo, ou Open em revisão.
PAAppealRequestUm caso negado decidido novamente, com base no motivo em PANote (um recurso sem um é solicitado).
PACancelRequestApproved enquanto o caso está aberto ou em revisão, e a solicitação PAS é cancelada; Denied uma vez que esteja decidida.

O conjunto de perguntas é o Questionário FHIR do medicamento do repositório FHIR, o mesmo que o DTR preenche: um booleano se torna uma escolha sim/não, uma escolha se torna uma escolha, um número se torna numérico, uma data se torna uma data, e qualquer outra coisa se torna texto livre; grupos são achatados em ordem, e enableWhen não é transportado, pois o SCRIPT ramifica por escolha e não por condição. Um medicamento sem questionário é perguntado três perguntas de texto livre: o diagnóstico, o que foi tentado e por que esse medicamento. Um PARequest se torna um pedido de PAS da Vinci: um Claim para o medicamento (RxNorm e NDC), o MedicationRequest que ele solicita, o paciente, prescritor, pagador e cobertura, e as respostas como um QuestionnaireResponse, com quaisquer anexos como DocumentReferences. Em seguida, é decidido como todas as autorizações prévias neste servidor são: o arquivo de regras, um serviço de decisão (-pas-decider-url), ou a fila de revisores, onde é marcado Medicamento e mantido nos prazos do medicamento. Um serviço de decisão vê um pedido de medicamento exatamente como vê um pedido de um cliente PAS de um EHR. Recomendamos o Vaglio, o motor de decisão de código aberto (PolyForm Shield) da BioDream, que tem políticas de medicamento com terapia de etapa; o motor de um pagador se conecta através da mesma -pas-decider-url, e nenhum é necessário para o arquivo de regras e revisores decidirem.

Uma decisão tomada após a solicitação ter sido respondida (de um revisor, de um recurso) é enviada ao prescritor como uma PAResponse não solicitada ou PAAppealResponse, encaminhada para o canal nomeado por -epa-reply-channel, que a entrega à rede. Sem um, ou quando a entrega falha, o caso afirma que o prescritor não foi informado e a tela a envia novamente.

Payers › Medicamentos › Autorização prévia envia as mensagens que o sistema de um prescritor enviaria para o endpoint próprio do servidor (iniciar, responder às perguntas, ver a decisão), lista todos os casos com o que o prescritor foi informado e mostra as figuras de medicamentos que a CMS-0062-P propõe: solicitações aprovadas, negadas e pendentes, recurso e aprovadas ou negadas em recurso, a média e a mediana de horas desde a solicitação até a decisão, e quantas foram decididas com atraso. Medicamentos de benefício médico solicitados através do PAS (um código HCPCS J com um MedicationRequest, ou um item codificado em RxNorm ou NDC) são contados como medicamentos nas figuras do PAS também.

O que isso se baseia, declarado claramente. Os esquemas e guias de implementação da NCPDP são licenciados. Os nomes de elementos e a ordem aqui seguem os guias de acompanhamento públicos da Surescripts ePA e RTPB e seus exemplos, e as recomendações públicas da NCPDP para o RTPB. Dois elementos que o material público nunca mostra são escritos no padrão SCRIPT usado em outros lugares e devem ser verificados contra uma cópia licenciada antes da certificação: Closed/ReasonCode e Denied/DenialReason. Nenhuma mensagem foi verificada contra o XSD da NCPDP ou a certificação de uma rede. O arquivo de Formulário e Benefício da NCPDP não é produzido: seu layout completo está no guia licenciado da NCPDP, e um arquivo parcial seria recusado pela rede que o carrega.

16.9 O que foi verificado e contra o que

As saídas CARIN e PDex foram validadas com o validador FHIR oficial da HL7, carregado com os pacotes publicados (hl7.fhir.us.carin-bb#2.2.0, hl7.fhir.us.davinci-pdex#2.2.0): reivindicações profissionais, de internação e de ambulatório e duas decisões PAS, sem erros. As entradas PDex foram os exemplos próprios do guia PAS em vez de formas escritas aqui para concordar com o conversor. O validador encontrou cinco defeitos na primeira execução — entre eles que o CARIN exige a versão do perfil em meta.profile e a versão do sistema de código de tipo de reivindicação em reivindicações institucionais — e cada um é corrigido e coberto por um teste.

A construção disso encontrou um defeito mais antigo: o repositório FHIR descartou todos os elementos que seu modelo interno não declarou, então uma ExplanationOfBenefit perdeu seus itens, diagnósticos, adjudicação e pagamento no caminho. O repositório agora mantém qualquer coisa que um recurso carregue e um teste carrega uma reivindicação CARIN através do servidor e a lê de volta inteira.

A saída do CRD - a ordem atualizada e a resposta do CDS Hooks contra o modelo lógico próprio do CRD - e a saída do pacote do DTR validam no validador oficial do HL7 contra o CRD 2.2.1 e o DTR 2.2.0 sem erros.

O DTR aqui é o lado do pagador da versão 2.2.0. $questionnaire-package pega os questionários nomeados, aqueles nomeados pelo CRD em uma ordem, ou a id de afirmação de cobertura que o CRD retornou (context, enquanto o mesmo processo está servindo o CRD), e retorna cada um como um pacote de bundle com uma QuestionnaireResponse para preencher, as Bibliotecas que seu CQL precisa e suas dependências. Os conjuntos de valores que suas respostas usam viajam no pacote quando são carregados (PUT /fhir/ValueSet/{id}), e $expand lista seus códigos. $log-questionnaire-errors escreve o que um aplicativo DTR relata para o log do servidor.

Questionários adaptativos: escreva o questionário inteiro uma vez, com a extensão questionnaireAdaptive do SDC e enableWhen nas perguntas que só se aplicam às vezes. O pacote entrega ao aplicativo uma casca vazia, e cada chamada $next-question adiciona a próxima pergunta que se aplica às respostas até agora, até que não haja mais nada a perguntar e a resposta seja marcada como concluída. A ordem e a ramificação são as regras próprias do pagador; perguntas que não se aplicam nunca são mostradas.

Entrar como cliente: os clientes DTR e PAS alcançam o pagador com os Serviços de Backend SMART - um JWT assinado trocado por um token no servidor de autorização do pagador. Aponte o Perfuse para esse servidor com -smart-issuer (e -smart-jwks se o endereço não for resolvido a partir do Perfuse), e passe -smart-backend-services para que o documento de descoberta diga isso. A suíte DTR do Inferno passa por esse caminho com o Keycloak como servidor de autorização.

O Perfuse pode ser esse servidor de autorização em si: serve -fhir -smart-clients clients.yaml emite tokens de Serviços de Backend para os clientes listados em /auth/token, cada um com as chaves públicas que assina suas afirmações e os escopos de sistema que podem ser concedidos, e o endpoint FHIR aceita esses tokens. Não é necessário um servidor de identidade separado para os clientes de máquina para máquina de um pagador.

Com -smart-users users.yaml também, membros e clínicos entram lá para autorizar aplicativos, o que a API de Acesso ao Paciente precisa: o aplicativo envia a pessoa para /auth/authorize, eles entram, um clínico escolhe o paciente e ambos veem o que o aplicativo pede e podem desmarcar qualquer coisa. Um membro é sempre dado apenas seu próprio registro, independentemente do que o aplicativo peça. Cada pessoa no arquivo nomeia o recurso FHIR que é, Patient/… ou Practitioner/…, e um hash de senha de perfuse smart hash; a senha em si nunca é escrita.

As pessoas podem entrar na provedora de identidade própria da organização: -smart-oidc oidc.yaml nomeia (emissor, id do cliente e onde o segredo está), e a página de entrada oferece "Entrar com" ao lado da senha. Cada pessoa é vinculada pelo assunto do provedor, oidc_subject no arquivo de usuários, para que o arquivo ainda decida quem pode autorizar aplicativos e qual recurso FHIR é; uma conta vinculada a ninguém é recusada. Códigos, tokens de atualização e revogações são mantidos no banco de dados, para que uma reinicialização não faça ninguém sair.

Utilizadores → Aplicativos SMART no console lista os aplicativos registados e as pessoas, e adiciona, edita e remove-os. Cada registo é verificado como os ficheiros no início, escritos neles e utilizados de imediato. Um aplicativo confidencial guardado sem um segredo recebe um, mostrado uma vez; uma palavra-passe é definida lá e nunca mostrada novamente. Remover um aplicativo, ou uma pessoa, impede os tokens de acesso já emitidos para ele ou concedidos por eles de imediato, e não quando expiram, e os seus tokens de atualização com eles.

Os escopos podem ser granulares, como o SMART App Launch 2 e o US Core definem: patient/Observation.rs?category=laboratory lê apenas as Observações que a pesquisa encontraria. Uma concessão que é filtrada para um tipo aplica seu filtro a cada pesquisa e a cada leitura desse tipo; uma concessão não filtrada para o tipo, ou para *, levanta-o. Um filtro que não pode ser lido não concede nada em vez de tudo.

16.10 Decidindo pedidos de autorização prévia: PAS

serve -fhir -pas -crd-rules rules.yaml responde ao Da Vinci PAS 2.2.1 em POST /fhir/Claim/$submit e POST /fhir/Claim/$inquire. As decisões provêm do mesmo ficheiro de regras que as respostas do CRD, por isso a ordem em que um clínico é informado de que precisa de autorização é decidida pela regra que o disse:

  - description: Physical therapy
    codes: ["PT"]                       # matched on the item's productOrService, then the code of the order it requests
    system: https://codesystem.x12.org/005010/1365
    covered: covered
    pa: auth-needed
    pa_decision: approve                # approve, deny or pend; empty: not-covered is denied, no-auth approved, the rest pended
    details:
      - {code: allowed-quantity, value: "6"}   # asked for more, it is certified for six (A6, with the authorised detail)
  - description: MRI
    codes: ["62"]
    pa_decision: approve
    pa_alternative: {system: "https://codesystem.x12.org/005010/1365", code: "4"}  # approved as an X-ray instead (an added item)
  - description: Surgery
    codes: ["2"]
    pa: auth-needed                     # pended for a reviewer, asking for:
    questionnaire: https://payer.example.org/Questionnaire/surgery   # a DTR questionnaire
    pa_attachments: ["18776-5"]         # and documents, by LOINC attachment code

Cada item recebe uma ação de revisão X12: A1 certificado, A3 não certificado, A4 pendente, A6 modificado, C cancelado (tipo de certificação 3). Uma linha que não nomeia um serviço não é decidida, mas respondida com um erro (X12 901 AG, corrigir e resubmeter). A resposta ecoa o que uma resposta 278 echoa — números de rastreamento de itens, as datas de serviço solicitadas, as datas do encontro, os identificadores de transmissão com remetente e receptor trocados — e fornece a cada linha o número de referência administrativa próprio do pagador. Um serviço que nenhuma regra nomeia é pendente, nunca aprovado: uma decisão que ninguém registrou é uma decisão para uma pessoa.

Pedidos pendentes esperam por um revisor, que responde com POST /fhir/Claim/$decide:

{"resourceType": "Parameters", "parameter": [
  {"name": "claimResponse", "valueString": "<the ClaimResponse id>"},
  {"name": "decision", "valueCode": "approve"},
  {"name": "reason", "valueString": "Reviewed with the plan of care."},
  {"name": "reviewer", "valueString": "<the reviewer's NPI>"}]}

decision pode também ser modify: certificado, mas não como solicitado, com quantity (valueDecimal, as unidades certificadas) e/ou alternative (valueCoding, o serviço aprovado em vez disso). A resposta então diz A6 Modificado, com o detalhe certificado ou a alternativa como um item adicionado, e um número de autorização. item (valueInteger, repetível) limita a decisão a algumas linhas. A decisão se torna uma nova versão da resposta, marcada como revisada por uma pessoa, e com -fhir-subscriptions é entregue no tópico PAS (PASSubscriptionTopic, filtrado por org-identifier, o identificador da organização solicitante) como o Conjunto de Respostas PAS completo, na mesma transação que o registra. $inquire retorna a resposta atual para cada solicitação que o prestador fez sobre esse membro; uma investigação de outro prestador não encontra nada. $decide precisa de um escopo de escrita; $inquire é uma leitura.

Os pedidos e cada versão de suas respostas são mantidos em pas_requests e pas_responses no banco de dados do servidor.

16.10.1 A fila do revisor

Na consola web, Payers → CMS-0057 → Fila de revisor lista os pedidos pendentes mais próximos do prazo: um pedido acelerado (Claim.priority stat) tem um prazo de 72 horas após a sua chegada, um padrão tem 7 dias. Escolher um deles mostra o membro, o prestador, cada serviço com as unidades solicitadas e o seu estado, o que a resposta solicitou e todos os documentos recebidos para ele, com documentos de texto simples mostrados inline. Um editor registra a decisão lá: aprovar, negar ou modificar (unidades certificadas, ou outro serviço aprovado em vez disso), com um motivo e o NPI do revisor. Uma modificação tem que certificar menos unidades do que foram solicitadas; tantas ou mais é uma aprovação e é recusada como modificação. Um serviço aprovado em vez disso começa no sistema de códigos do solicitado. É a mesma decisão que $decide faz, por isso a assinatura do prestador entrega-a. Ler um pedido e decidir são ambos escritos no registo de auditoria.

Monitor → Painéis da equipe → Autorização prévia mostra, nos últimos 30 dias, quantos pedidos padrão e acelerados foram decididos dentro dos prazos do CMS-0057, decididos tardiamente, ainda à espera no prazo e atrasados agora, com o tempo médio para decidir, e como os serviços solicitados foram respondidos: aprovados, modificados, negados ou ainda pendentes. Estes dois azulejos são lidos a partir dos próprios pedidos, por isso não estão na exportação do Grafana do painel, que o diz na sua descrição.

16.10.2 Recebendo os documentos que um pedido pendente solicita

Uma resposta pendente solicita documentos com uma Tarefa e um CommunicationRequest por documento. Um questionário é solicitado como o PAS o descreve: um CommunicationRequest com o único código LOINC 102089-0, sob o número de rastreamento da linha para a qual é (itemTraceNumber, que o ClaimResponse ecoa; uma linha enviada sem um é atribuída um). Esse número de rastreamento é o contexto DTR: $questionnaire-package com apenas context definido como ele retorna o questionário. O prestador de serviços envia o que foi solicitado com Da Vinci CDex $submit-attachment (POST /fhir/$submit-attachment): o TrackingId é o número de rastreamento da solicitação (o primeiro identificador do ClaimResponse, que também é o da Tarefa), ou um identificador do CommunicationRequest, AttachTo é preauthorization, e MemberId deve ser o membro da solicitação. Cada anexo do DocumentReference ou QuestionnaireResponse é mantido com a solicitação e exibido ao seu revisor; um documento que chega decide nada.

16.10.3 Decidindo em um sistema de gestão de utilização X12

A maioria dos pagadores decide autorizações prévias em um sistema de gestão de utilização (UM) que fala X12 278. Com -pas-278-url, o Perfuse é a interface FHIR daquele sistema: cada $submit é enviado como uma solicitação 278 (005010X217), e cada item é um evento do paciente. Cada solicitação contém o que o PAS nomeia para ele: o tipo de revisão (extension-serviceItemRequestType, UM01: serviços de saúde, admissão ou cuidados especializados), o tipo de certificação (extension-certificationType, UM02), o tipo de serviço, o local de serviço (UM04), o nível de serviço (extension-levelOfServiceCode, UM06: eletivo, urgente ou de emergência; uma prioridade stat substitui a urgente), a data, as datas de admissão e alta de uma revisão de admissão, os diagnósticos, o provedor do serviço que realizará o serviço e o procedimento e a quantidade, como uma linha de serviço profissional (SV1) ou, em uma reclamação institucional, uma linha de serviço hospitalar (SV2). O código de ação e o número de autorização da resposta 278 se tornam a ação de revisão do item: certificado, em parte ou modificado, negado, pendente, cancelado ou não considerado (pendente para um revisor, com os motivos de rejeição). As regras locais não são consultadas.

perfuse serve -fhir -pas -pas-278-url https://um.example/x12/278 -pas-278-receiver ACMEUM \
  -pas-278-token-env UM_TOKEN

Um sistema de UM que pende primeiro e decide mais tarde publica a sua resposta 278 posterior em POST /fhir/Claim/$decide-278; cada evento é associado ao seu pedido pelo número de rastreio que o Perfuse enviou, e decidido como $decide o decidiria. Se o sistema de UM não puder ser alcançado, ou responder com algo que não seja uma resposta 278, cada item é pendente para um revisor e o prestador de serviços é informado apenas disso; o motivo está no registo do servidor.

Consultas que o sistema UM responde

O $inquire de um prestador de serviços deve encontrar uma autorização, independentemente de como foi solicitada: por fax, através do portal do pagador, por telefone ou em uma solicitação de um remetente diferente. O Perfuse apenas armazena as solicitações que passaram por ele; o sistema de gestão de utilização (UM) armazena todas. Portanto, com um sistema de gestão de utilização que responde em tempo real (todos os transportes, exceto sftp), cada $inquire também é enviado para lá como uma consulta de autorização 278 (005010X215: BHT02 28, o membro, o prestador, o número de autorização do insurance.preAuthRef da Reclamação quando disponível, e as datas de eventos do billablePeriod ou as datas de serviço dos itens, caso contrário, um ano antes ou depois de hoje). Cada autorização que a resposta contém e que o Perfuse não tem (combinada com os números de rastreio que ele enviou e os números de autorização que ele já forneceu) é devolvida como um Pacote de Resposta de Consulta de Reclamação adicional: a decisão do sistema de gestão de utilização para cada linha de serviço, o número de autorização e período, e uma nota indicando onde foi encontrada. Nenhuma Reclamação é fabricada para uma autorização que ninguém submeteu em FHIR: seu ClaimResponse.request contém uma razão para a ausência de dados, como o perfil do PAS permite. Uma consulta apenas lê; nada nos próprios registros do Perfuse é alterado. Se o sistema de gestão de utilização estiver inativo ou responder com um TA1 ou 999, o prestador recebe o que o Perfuse armazena, e o status do link indica o motivo. A forma segue as guias de consultas de autorização 278 publicadas pelas UnitedHealthcare, Cigna e Blue Cross Blue Shield de Massachusetts; ainda não foi testada contra um sistema de gestão de utilização real.

Como os 278s chegam ao sistema UM

O guia de conectividade do sistema UM diz como leva 278s, e -pas-278-transport (Configurações, Pagadores, Gestão de Utilização link) segue-o:

TransporteO que é enviadoAutenticação
x12 (padrão)A 278 enviada como application/edi-x12; a resposta é o corpo da respostaUm token de portador, OAuth, Autenticação Básica HTTP, um certificado de cliente
core-soapO envelope CAQH CORE real-time SOAP 1.2 (COREEnvelopeRealTimeRequest, tipo de payload X12_278_Request_005010X217E1_2, ou X12_278_Request_005010X215 para uma consulta): Regra de Conectividade vC2.2.0 com o payload no envelope, que a maioria dos pagadores e CMS esMD executa, ou -pas-278-core-version C4.0.0 com o payload como anexo MTOMvC2.2.0: um nome de usuário e senha (Token de Segurança de Nome de Usuário WS) ou um certificado de cliente. vC4.0.0: um certificado de cliente e um token OAuth
core-mimeO envelope CAQH CORE vC2.2.0 HTTP MIME multipart, o payload como uma parte de arquivoO nome de usuário e a senha do envelope, ou um certificado de cliente
sftpCada 278 colocado em uma pasta no servidor SFTP do sistema de gerenciamento de utilização (-pas-278-sftp, -pas-278-sftp-outbound); suas respostas coletadas de outra (-pas-278-sftp-inbound, todos -pas-278-sftp-every)Uma chave SSH ou senha; a chave do servidor deve estar em -pas-278-sftp-known-hosts

Um certificado de cliente é -pas-278-cert e -pas-278-key; -pas-278-ca confia na autoridade de certificação própria do pagador. O OAuth é -pas-278-oauth-token-url, -pas-278-oauth-client-id e o segredo, obtido com a concessão de credenciais de cliente e mantido até um minuto antes de expirar. Senhas, tokens e segredos nunca são bandeiras: cada um é nomeado por uma variável de ambiente (-pas-278-password-env, -pas-278-token-env, -pas-278-oauth-secret-env, -pas-278-sftp-password-env), ou digitado na pantala de configurações, onde é mantido no arquivo de configurações (legível apenas pela conta do servidor) e nunca mostrado novamente.

UM_PASSWORD=... perfuse serve -fhir -pas -pas-278-transport core-soap \
  -pas-278-url https://um.example/CORE/RealTime -pas-278-receiver ACMEUM \
  -pas-278-user perfuse -pas-278-password-env UM_PASSWORD

Sobre SFTP, cada solicitação é pendente até que sua resposta chegue: a resposta 278 decide os itens, e o Perfuse coloca um 999 aceitando ela na pasta de saída. Um arquivo que não pode ser lido permanece na pasta de entrada para uma pessoa e é oferecido novamente na próxima leitura.

Quando o sistema UM não pode ler uma solicitação

Um sistema UM que não pode ler um 278 responde com um TA1 (o envelope) ou um 999 (a transação) em vez de uma decisão. O Perfuse lê qual e o que diz, pendura cada item ("gestão de utilização não pode ler a solicitação"), e registra. Pagador, CMS-0057, Fila de Revisor mostra o link: o que foi enviado nos últimos sete dias, cada interchange por seu número de controle, e o que aconteceu com ele (respondido; reconhecido, resposta a vir; rejeitado, com o segmento, elemento e código do 999; não alcançado). Cada interchange tem seu próprio número de controle, um a mais que o último, que é o que um TA1 ou 999 nomeia quando responde.

16.10.4 Decidindo com base nas evidências clínicas, com um serviço de decisão

Um ficheiro de regras decide por código de serviço: um código não precisa de autorização, não é coberto ou vai para um revisor. Se este paciente atende aos critérios para ele é uma questão diferente, respondida a partir das condições, respostas do questionário e documentos que o prestador enviou com o pedido. Com -pas-decider-url, cada item que as regras deixam para um revisor é primeiro colocado para um serviço de decisão, como Vaglio, que lê o mesmo pedido de PAS Bundle através do pacote pas publicado pelo Perfuse. Um Vaglio público, em pedidos inventados apenas, é executado ao lado da instância de teste do Perfuse em https://vaglio.perfuse.health:8443 (faça login como demo, senha try-vaglio-demo; ele pode olhar para tudo e mudar nada): cada decisão lá tem a sua prova, uma carta de linguagem simples e um recibo que qualquer pessoa pode verificar.

perfuse serve -fhir -pas -crd-rules payer-rules.yaml -pas-decider-url https://vaglio.example/api/pas/decide \
  -pas-decider-token-env VAGLIO_TOKEN

A URL deve ser https, ou http simples para esta máquina (localhost, 127.0.0.1), porque transporta o registo do paciente e o token. Vaglio em si responde apenas em https; quando usa um certificado da sua própria autoridade, passe essa autoridade com -pas-decider-ca DATA/tls/ca.crt (ou qualquer autoridade interna do pagador que o certificado do serviço venha). O serviço é enviado o pedido Bundle como o prestador o enviou, POST <url>?item=<sequence> (application/fhir+json), e responde {"decision": "approve" | "deny" | "pend", "why": "...", "requested": ["..."]}, ou 404 quando decide nada para esse item, o que deixa a resposta da regra em pé. why é a nota de processo da resposta e é necessária para uma negação, que é pendente de outra forma; requested é dito ao prestador como a informação que um pedido pendente precisa. Um pendente também pode transportar "questionnaire": "<canonical>" e "attachments": ["<LOINC>", ...], que são solicitados na resposta do CDex Task e CommunicationRequests ao lado de qualquer questionário DTR ou anexos que a regra solicite (a regra do questionário vence, desde que uma Tarefa solicite um; um código que não é da forma LOINC é descartado e registado). Uma regra que aprova ou nega é a política de cobertura do pagador e não é enviada para o serviço. Uma falha, um tempo limite ou uma resposta que não é uma das três decisões deixa o item pendente para um revisor, com o motivo no registo do servidor: nada aqui transforma uma falha em uma aprovação. Isso não pode ser combinado com -pas-278-url, onde o sistema de gestão de utilização responde a cada item.

Conselho antes de enviar. Com -crd-advisor-url ao lado de -crd-rules, CRD também pergunta a um serviço de decisão o que um pedido de autorização prévia para cada ordem que precise seria dito como o registo está, e mostra a resposta como um cartão adicional: "Antes de enviar: um pedido para isso precisaria: ...", ou "seria aprovado", com o que ainda é necessário, o questionário que o solicita e o que o aprovaria. Vaglio responde em /api/pas/advise, com o mesmo token e autoridade que acima:

perfuse serve -fhir -pas -crd-rules payer-rules.yaml \
  -crd-advisor-url https://vaglio.example/api/pas/advise -crd-advisor-token-env VAGLIO_TOKEN

CRD envia POST <url> com {"service": {"system": "...", "code": "..."}, "resources": [ ... ]}, os recursos sendo a pré-busca do hook (o paciente primeiro, a cobertura deixada de fora), e lê {"decides": true, "answer": "approve" | "pend" | "deny", "summary": "...", "missing": [...], "questionnaire": "...", "toApprove": [[...]], "policyTitle": "..."}. É um conselho e não muda nada: a informação de cobertura, os outros cartões e a decisão PAS são o que as regras dizem. Ele espera no máximo três segundos, e nenhuma resposta, uma falha ou "decides": false deixa a resposta exatamente como está sem ela. O Perfuse nunca precisa de um serviço de decisão.

O pedido transporta X-PAS-Request-Id, o id pelo qual a resposta é conhecida. Um serviço com seus próprios revisores que pendura um item pode enviar sua decisão posteriormente como qualquer revisor: Claim/$decide com esse id como claimResponse, a sequência do item e a decisão e motivo. A assinatura do provedor entrega como se fosse feita na fila do revisor.

Uma assinatura com conteúdo id-only informa ao provedor qual resposta mudou sem dizer o que é: o foco da notificação é Bundle/<id>. GET /fhir/Bundle/<id> retorna o último Pacote de Resposta do PAS, GET /fhir/Bundle/<id>/_history/<n> a versão que uma notificação enviou, e GET /fhir/ClaimResponse/<id> o ClaimResponse sozinho. Um token vinculado a um paciente é informado de que não existe, como qualquer registro fora do seu paciente.

Verificado com a suíte oficial do Servidor PAS Inferno v2.2.1 (verifique a verificação). Não enviado, embora o PAS marque como deve-suportar: ClaimResponse.adjudication com uma ação de revisão, ClaimResponse.extension:authorizedProvider e ClaimResponse.item.extension:communicatedDiagnosis, porque as extensões que precisam não são permitidas lá pelo seu próprio contexto no PAS 2.2.1 e o validador rejeita uma resposta que as transporta; e request.extension:DataAbsentReason, porque o Perfuse sempre sabe a solicitação. Os 278s enviados a um sistema de gestão de utilização (acima) são verificados contra os próprios exemplos de solicitação do PAS 2.2.1, as amostras de esMD 278 publicadas pela CMS e um verificador 278 escrito a partir de guias de acompanhamento públicos, e cada transporte contra um sistema UM fictício escrito a partir das Regras de Conectividade da CAQH (verifique a verificação); ainda não contra um sistema UM real ou uma câmara de compensação, e não certificado CORE. Não implementado: anexos enviados de volta com CDex.

Um arquivo de regras é verificado contra os invariantes próprios do CRD quando carregado: um questionário precisa de documentação, um serviço que não é coberto não pode precisar de autorização, satisfied pertence a um caso e não a uma regra, e qualquer coisa condicional deve dar um motivo.

Não verificado: as exportações e a correspondência de membros contra a implementação de outro pagador, as métricas contra as figuras publicadas de um pagador, e o CRD contra um cliente CDS Hooks de um EHR real.

16.11 Envio de solicitações de autorização prévia para um pagador (para prestadores de serviços)

Tudo acima responde a solicitações, como um pagador. O lado de um prestador de serviços é o contrário: um aplicativo de registro eletrônico de saúde ou um aplicativo de registro de tratamento constrói um pacote de solicitação Da Vinci PAS, e algo precisa enviá-lo ao pagador, manter a resposta e passá-la adiante. Um destino pas faz isso.

name: prior-auth-out
dataType: raw
source:
  type: http
  http:
    listen: 127.0.0.1:8095
    path: /pas
destinations:
  - name: acme-health
    type: pas
    pas:
      payer: https://pas.acme-health.example/fhir
      bearer_token: ${ACME_PAS_TOKEN}     # or auth: { type: client_credentials, token_url, client_id, client_secret }
      results_to: pas-answers             # optional: a channel that takes each answer back to the EHR

Cada mensagem deve ser um Bundle de solicitação PAS completo em um canal bruto. O Perfuse posta-o inalterado para {payer}/Claim/$submit: o pagador decide sobre o Claim juntamente com o paciente, a cobertura e os recursos de suporte no Bundle, e um Claim reconstruído de um resumo perderia esses. Fora desta máquina, o endereço do pagador deve ser https.

Uma decisão é um pedido entregue, independentemente do seu conteúdo. Uma aprovação, uma recusa e uma pendência são todas registadas e nenhuma é repetida, porque repetir uma recusa submete o mesmo pedido duas vezes. O que falha a entrega, e é repetido, é um pagador que não tomou uma decisão: um estado de erro, um OperationOutcome (o seu texto é o erro) ou um ClaimResponse cujo resultado é error. A decisão é lida item a item a partir dos códigos de ação de revisão do PAS (X12 306: A1 aprovado, A2 parcialmente, A3 recusado, A4 pendente, A6 modificado); uma resposta sem código é listada como "sem código de decisão" em vez de ser considerada como uma aprovação. Uma recusa sem motivo em qualquer lugar é recusada por não cumprir o CMS-0057.

A resposta do pagador é a réplica do destino, então Inspecionar a réplica pode julgá-la, e results_to a entrega a outro canal. Cada solicitação é listada em CMS-0057, Solicitações enviadas aos pagadores: quando foi enviada, o paciente, o serviço, a decisão e a referência do pagador (preAuthRef), que uma investigação posterior nomeia. A lista é mantida em prior-auth.json ao lado do banco de dados (no máximo 10.000 solicitações; as decididas mais antigas vão primeiro, uma pendente nunca vai); e cada locatário vê apenas a sua.

Verificado contra a implementação de referência do pagador Da Vinci PAS da HL7 (imagem do docker hlseven/davinci-prior-auth): uma solicitação enviada por um canal em execução é pendente por ele com sua referência, e a resposta aparece na tela (veja verificação). Ainda não tentado contra um pagador de produção. Não construído: seguir em frente com uma solicitação pendente com $inquire, ou receber a resposta posterior do pagador por assinatura; um canal pode fazer qualquer um desses hoje com um destino http ou fhir.

16.12 Redes Alinhadas com o CMS

O Quadro de Interoperabilidade da CMS (Ecossistema de Tecnologia de Saúde da CMS) pede que as redes de dados de saúde se autodeclaram a 26 critérios e sejam listadas como Redes Alinhadas com a CMS; EHRs, provedores, pagadores e aplicativos se conectam a elas. Os critérios 13 a 16 estão em vigor desde 4 de julho de 2026: APIs FHIR no US Core com um CapabilityStatement completo e Dados em Lote, documentos como anexos FHIR legíveis por humanos, notificações de agendamento e encontro por Assinatura FHIR, e um localizador de registros.

Administrar › Rede Alinhada com a CMS lista cada critério com o que o Perfuse fornece para ele e onde este servidor está, lido do que está ativado aqui:

StatusSignificado
Pronto aquiO Perfuse fornece e está ativado.
Pronto, com uma lacunaEstá ativado e parte do critério está fora dele (nomeado na tela).
Construído, não ativadoO Perfuse fornece; a tela nomeia a configuração ou sinalizador que o ativa.
Sua tarefaA parte da organização: um acordo, uma certificação, publicação no Diretório Nacional de Prestadores.
Não construídoO software faria e o Perfuse não.

O que os quatro em vigor precisam deste servidor:

CritérioNo PerfuseAtivar
13 APIs FHIR, US Core, Dados em MassaO endpoint FHIR com seu CapabilityStatement e $export-fhir, -fhir-bulk-export
14 Documentos como anexos FHIRDocumentReference com Binário e IHE MHD sobre o registro XDS-fhir (MHD também -xds)
15 Notificações de encontro e compromissoAssinaturas baseadas em tópicos (R5 Backport para R4) a partir de feeds ADT e SIU-fhir-subscriptions
16 Localizador de registrosO registro XDS.b, XCA para outras comunidades, PIXm-xds, -xds-home-community

A tela é uma planilha para a autodeclaração, não uma certificação: a CMS revisa as redes que suspeita não atenderem aos critérios, e o texto do próprio quadro é a autoridade. Não construído hoje: consultas de lacunas de qualidade abertas (critério 8), uma consulta de um pagador para dados de encontro de um pedido (9), relatórios de métricas de consulta para o Diretório Nacional de Provedores (19), verificação de provedores contra esse diretório (6), leitura de licenças de motorista móvel ou cartões de seguro digitais (3, 23), e aplicação de uma política de consentimento geral em cada leitura (5). A prova de identidade IAL2 é do serviço de identidade; o Perfuse aceita os tokens daquele que você escolhe.

17 Segurança

O Perfuse lida com dados clínicos. Este capítulo é o que ele faz sobre isso e o que deixa para você.

17.1 Segurança de transporte

O TLS na interface web é configurado com -tls-cert e -tls-key. Sem eles, a interface é HTTP simples, o que é aceitável em um endereço de loopback para uma primeira olhada e em nenhum outro lugar — ele transporta credenciais e conteúdo de mensagem, ambos legíveis no fio.

O TLS nos transportes de canal é por fonte e por destino, sob um bloco tls. As configurações disponíveis estão nas referências fonte e destino.

insecure_skip_verify aceita qualquer certificado. Ele existe porque os sistemas hospitalares rotineiramente apresentam certificados que não verificarão e recusar-se a se conectar significaria recusar-se a integrar. Ele é nomeado para ser conspícuo e usá-lo significa que a conexão é criptografada, mas não autenticada — você tem proteção contra interceptação passiva e nenhuma contra um servidor interposto.

Uma conexão TLS não verificada não é a mesma que uma verificada e a distinção vale a pena registrar em algum lugar onde seus auditores a encontrarão. A solução melhor é quase sempre obter o certificado da extremidade distante e confiá-lo explicitamente em vez de confiar em tudo.

17.2 Autenticação e funções

Os usuários são mantidos no banco de dados. Cada um tem uma das cinco funções e cada função inclui tudo o que está nas funções acima dela:

FunçãoPode
MonitorVerificar se as coisas estão funcionando: status do canal, contagens, mapa de fluxo, alertas, painéis, métricas e profundidade da fila. Sem conteúdo de mensagens, arquivos de canal ou mensagens em fila.
VisualizadorTambém ler mensagens, arquivos de canal, rastros e log de atividade.
OperadorTambém reenviar: reprocessar uma mensagem, reproduzir um canal e tentar novamente entregas em fila.
EditorTambém criar e alterar canais e executar comparações.
AdministradorTambém iniciar e parar canais, limpar filas e gerenciar pessoas, tokens e configurações do servidor.

Um sexto papel, Plataforma, pertence a quem executa um servidor compartilhado: cria inquilinos e define seus limites, e não possui canais próprios.

Monitor é para uma mesa de ajuda ou para uma tela de operações em uma parede: tudo o que é necessário para ver que uma fonte parou, e nada que nomeie um paciente. Visualizador pode ler o conteúdo da mensagem, que é dados clínicos; é um papel de baixa privilégio para *configuração*, não para privacidade. Operador separa a correção de uma entrega falha à noite da alteração do que uma fonte faz: a pessoa que reenvia não precisa ser capaz de reescrever o canal.

17.2.1 Senhas erradas repetidas

Senhas erradas e entradas de passkey com falha são contadas pelo endereço que a conexão vem, e após algumas seguidas, esse endereço espera antes de poder tentar novamente (a resposta é 429, com Retry-After). As contas não são bloqueadas por nome, porque isso permitiria que qualquer pessoa bloqueasse um administrador propositadamente.

O endereço é o próprio da conexão, nunca um que um pedido afirma em X-Forwarded-For, que o remetente escreve. Atrás de um proxy reverso na mesma máquina, o Perfuse usa a última entrada X-Forwarded-For em vez disso, a que o proxy adicionou, por isso cada cliente é ainda contado à parte. Um proxy em outra máquina atinge o Perfuse a partir de um endereço e todos os seus clientes compartilham um contador: limite de taxa de entradas nesse proxy também.

17.2.2 Grupos de canais

Uma pessoa (ou um token de API) pode ser limitada a alguns grupos de canais: então vê e age apenas nos canais cujo group é um deles. É o arranjo de um grupo hospitalar em um servidor, cada equipe de analistas de instalação cuidando de suas próprias fontes e uma equipe central, sem limite, cuidando de todas elas. Rhapsody chama isso de um armário.

O limite se aplica em todos os lugares ao mesmo tempo, porque é aplicado ao pedido em vez de ser lembrado por cada tela: a lista de canais, o painel e o mapa de fluxo, mensagens e sua pesquisa, contagens e gráficos, a fila, alertas, métricas, certificados, contratos e uso de conjunto de códigos. Um canal fora dos grupos da pessoa não existe para eles; pedir por ele pelo nome responde *não encontrado*, então seu nome também não é confirmado. Um canal sem grupo é visto apenas por pessoas sem limite.

Salvar um canal o mantém dentro dos grupos da pessoa: eles não podem criar um canal em outro grupo, ou mover um para fora do seu próprio. O que cada instalação compartilha - tabelas de códigos, bibliotecas de scripts, decisões de autorização prévia - eles podem ler, mas não alterar. Figuras do servidor como um todo (autorização prévia, uso de token, túneis) são mostradas apenas a pessoas sem limite, e também são métricas e alertas sobre o servidor como um todo em vez de um canal.

Um administrador limitado a grupos é o próprio administrador de uma instalação. Eles gerenciam as pessoas e tokens dos seus grupos, iniciam e param os seus canais e limpam as suas filas. Um colega que eles adicionam recebe os grupos deles, a menos que eles especifiquem alguns deles, e eles não podem dar um grupo que não possuem, e nunca veem ou alteram ninguém sem limites. Tudo o mais que um administrador pode fazer altera o servidor inteiro - configurações, entrada, reinicialização, regras de alerta, marca, frota, servidor SMART - e é recusado a eles.

Os grupos são definidos em Utilizadores (e para tokens em Tokens), como uma lista separada por vírgulas. Cada alteração é registada no registo de atividades e entra em vigor na próxima solicitação da pessoa.

Um papel diferente em cada grupo

Uma pessoa pode ter um papel diferente em cada um dos seus grupos: lab=editor, adt em Utilizadores edita os canais do laboratório e tem o papel escolhido ao lado dele - digamos, visualizador - nos canais de admissões. Eles veem os canais de ambos os grupos em todas as telas. Salvar, iniciar ou reenviar um canal em um grupo onde o seu papel é muito baixo é recusado com o papel que eles têm lá; não finge que o canal está faltando, pois eles podem vê-lo. O seu papel no topo da tela é o mais forte que eles têm, o que abre as telas que esse papel usa, e cada ação nessas telas ainda é limitada aos grupos onde eles têm esse papel.

Apenas pessoas limitadas a grupos de canais podem ter um. Alguém que vê todos os canais tem um papel, porque "editor dos canais do laboratório" para uma pessoa sem limites seria editor de tudo o que pertence a nenhum grupo, e das páginas do servidor. Um administrador de instalação pode dar um papel por grupo apenas nos grupos que eles administram, e nunca acima do seu próprio papel lá.

17.3 Quem pode chamar o endpoint FHIR

O endpoint FHIR (serve -fhir) verifica um dos dois tipos de token:

limitado a Grupos FHIR. Este é o padrão quando nenhum servidor de autorização SMART está configurado.

um possui âmbitos, e o endpoint retém cada pedido a eles.

Com o SMART configurado, apenas tokens SMART são aceitos, portanto, cada chamador é mantido dentro dos seus âmbitos. Um token de API tem um papel e não tem âmbitos: um token de visualizador pode ler o registo de cada paciente. Um pagador que ativou o SMART para limitar cada aplicativo ao que foi concedido não deve ter uma forma de entrar que não seja limitada.

Alguns sites precisam de ambos - uma alimentação de reclamações interna que mantém um token de API e não tem um cliente SMART, ao lado de aplicativos de membros que entram através do SMART. Para esses, Configurações → FHIR → Aceitar tokens de API do Perfuse além de tokens SMART (-fhir-api-tokens na inicialização) permite que tokens de API sejam aceitos também. Está desativado por padrão, entra em vigor na próxima solicitação em qualquer direção e alterar isso é escrito no registo de auditoria. Um token é distinguido pela sua forma: um token SMART é um JWT assinado, e um token de API nunca é, portanto, um nunca é verificado como o outro. Onde possível, dê a um sistema como esse um cliente de Serviços de Backend SMART, com apenas os âmbitos do sistema que ele precisa.

17.3.1 Um endpoint FHIR aberto a estranhos

Um servidor de teste público fornece credenciais que podem escrever, porque testar autorização prévia ou assinaturas necessita de escrita. Dois limites impedem que um cliente estrague para todos, ambos sob Definições → FHIR e ambos desativados por predefinição:

O endpoint de um hospital próprio não precisa de nenhum.

17.4 Agentes de IA: o servidor MCP

Com Configurações › Segurança › Agentes de IA (MCP) ativado (ou serve -mcp), o Perfuse serve o Protocolo de Contexto de Modelo em /mcp, para que um agente de IA, como Claude, ChatGPT ou um assistente de IDE, possa perguntar o que está acontecendo. Está desativado por padrão e desativar isso para todos os agentes na próxima chamada.

Um agente se conecta com um token de API de Administrar › Utilizadores › Credenciais de máquina como um token de portador, nunca com uma sessão de navegador de uma pessoa (isso é recusado, portanto, um agente nunca age com o acesso completo de uma pessoa). Uma configuração de cliente parece:

{ "mcpServers": { "perfuse": { "type": "http", "url": "https://perfuse.example/mcp",
    "headers": { "Authorization": "Bearer <token>" } } } }
FerramentaPapelO que faz
server_status, list_channels, queue, alertsmonitorSe as coisas funcionam, sem conteúdo de mensagem
get_channel, search_messages, get_message, find_patient, fhir_searchvisualizadorCanais, mensagens (com conteúdo), mensagens de um paciente em vários formatos, uma pesquisa FHIR
retry_delivery, reprocess_messageoperador, e mcp:writeRepetir uma entrega em fila, enviar uma mensagem através do seu canal novamente
start_channel, stop_channeladministrador, e mcp:writeIniciar ou parar um canal

Cada ferramenta é respondida pela mesma rota ou pesquisa FHIR que a tela de uma pessoa usa, chamada com o token do próprio agente, portanto, o papel do token, os grupos de canais e o inquilino decidem o que ele vê, exatamente como fazem na console; e fhir_search obtém o acesso próprio do token no ponto de extremidade FHIR (que pode recusar tokens de API completamente; veja a seção FHIR acima). Um agente é oferecido apenas as ferramentas que o token pode usar. A leitura é o padrão: uma ferramenta que altera algo também precisa do âmbito mcp:write do token ("Deixe que um agente de IA aja com ele" ao emitir o token), portanto, um token emitido para um agente de relatórios não pode ser convencido a agir por um prompt. As respostas de um token de monitor têm os conteúdos da mensagem removidos, independentemente do que uma rota retorna.

Cada chamada está em Activity como mcp.tool com o nome do token, a ferramenta, seus argumentos e o resultado (ok, refused, invalid, rate-limited ou o status HTTP); mcp.connect registra qual cliente se conectou. Cada token pode fazer 60 chamadas de ferramenta por minuto (Chamadas de ferramenta por minuto de um token); acima disso, uma chamada é respondida com um erro que o agente pode ler, e nada é feito. Um pedido de uma página de navegador em outra origem é recusado, o que o MCP pede a um servidor para parar o rebinding de DNS. O transporte é o Streamable HTTP do MCP, respondido como JSON sem stream de eventos; as versões do protocolo 2025-06-18, 2025-03-26 e 2024-11-05 são aceitas. As mensagens e os recursos FHIR contêm dados do paciente: as respostas de um agente vão para o modelo em que ele é executado, então dê um token a um agente apenas onde esse modelo é permitido vê-los, e dê a ele o papel mais baixo que faz o trabalho.

17.5 Uma conta de demonstração

serve -demo-account demo:PASSWORD cria uma conta partilhada para um servidor de demonstração pública, e a página de início de sessão mostra o seu nome de utilizador e palavra-passe com um botão que inicia sessão com eles. A conta é um visualizador, por isso pode ver tudo e alterar nada. Ao contrário de qualquer outro visualizador, também pode abrir as telas dos administradores (utilizadores, tokens de máquina, definições, proteção de dados, os pares da frota), somente para leitura: uma demonstração é julgada pelas suas telas. Lê-as como um visualizador lê canais, com todas as credenciais mostradas como definidas ou não, nunca o seu valor, e todas as alterações recusadas. Também pode pressionar os testes que não alteram nada e não alcançam nada fora do servidor: um teste de script e o validar e analisar do editor de canal. Não pode alterar a sua palavra-passe ou adicionar uma chave de passe, porque o primeiro visitante a fazer qualquer uma delas bloquearia todos os demais. Cada início a coloca novamente como um visualizador com a palavra-passe publicada. A palavra-passe deve ter pelo menos 12 caracteres, como qualquer outra. Use-a apenas em um servidor que contenha dados de teste: qualquer pessoa que leia a página de início de sessão pode ler todas as mensagens no servidor.

17.6 Auditoria

Alterações de configuração, logins e acesso ao conteúdo de mensagem são registrados com quem, o que e quando.

O log de auditoria está no mesmo banco de dados que as mensagens. Isso é conveniente e é uma limitação: alguém que possa modificar o banco de dados pode modificar o log de auditoria. Se os seus requisitos incluem auditoria com evidência de violação, o log precisa ser enviado para algum lugar apenas para anexos e a saída de log própria do Perfuse é a forma de fazer isso.

17.7 Segredos na configuração

Senhas, códigos e chaves aparecem na configuração do canal, o que significa que elas estão nos arquivos YAML.

Duas consequências. Os ficheiros necessitam de permissões de sistema de ficheiros que refletem o seu conteúdo, e se estiverem em controlo de versão — o que é recomendado — o repositório contém credenciais e deve ser tratado de acordo.

Quando um valor é um segredo, a interface representa-o como um segredo e a API não o devolve uma vez guardado. Isso protege-o contra leitura sobre o ombro de alguém ou vazamento em uma captura de ecrã. Não protege o ficheiro.

17.8 O que está na base de dados

O armazém de mensagens mantém as mensagens tal como recebidas, o que para uma fonte clínica significa dados identificáveis do paciente. Deve estar em armazenamento encriptado, fazer backup como dados clínicos com a retenção que isso implica, e controlar o acesso ao nível do sistema de ficheiros, bem como através dos papéis próprios do Perfuse.

cleanup.periodDays limita por quanto tempo é mantido. Veja a loja de mensagens para a tensão entre isso e ter história suficiente para alertas de ritmo.

17.9 Proteção de dados (GDPR e UK GDPR)

A tela Proteção de dados (Administrar, apenas administradores) responde a pedidos de uma pessoa sob o GDPR e o UK GDPR. Ela não decide nada em nome do controlador: se um pedido deve ser concedido e se uma isenção se aplica é a decisão do controlador, registrada com o pedido.

Descobrir o que é mantido. Uma pessoa é identificada por identificadores: system|value (um número do NHS, um MRN com a sua autoridade de atribuição) ou um número por si só. Com um índice de paciente, esses se alargam a todos os números de todos os registos ligados à mesma pessoa, por isso um pedido que cita um número de hospital encontra os registos arquivados sob os outros. Ver o que é mantido pesquisa então todos os armazenamentos que mantêm dados de paciente:

ArmazémEncontrado por
Mensagenso índice de identidade (Configurações → Dados → Índice de identificadores de paciente); sem ele, as mensagens não podem ser encontradas por identificador
A fila de entregalendo os identificadores de cada mensagem enfileirada
O armazém FHIRos recursos de Paciente que transportam um identificador, e cada recurso cujas referências indexadas apontam para um
Pedidos de autorização préviaos identificadores do paciente do pedido
O índice de pacienteo identificador, ou o EUID

O que ela não pode alcançar, ela diz: traços enviados a um coletor (-trace-endpoint), o registro de auditoria (mantido: é o registro de quem fez o quê, incluindo este pedido), e backups.

Pedidos. Um pedido é registrado com seu tipo (acesso, Artigo 15; portabilidade, Artigo 20; exclusão, Artigo 17; restrição, Artigo 18), quem é dele de acordo com os registros do controlador, os identificadores e uma nota (como a identidade foi confirmada, uma extensão e seu motivo). Ele é devido um mês após o recebimento (Artigo 12(3)); um pedido atrasado é mostrado em vermelho.

Eliminar agora elimina tudo o que for encontrado: mensagens inteiras (registo, corpo, entregas, identificadores, anexos que nenhuma outra mensagem utiliza), entregas enfileiradas (não são enviadas), os recursos FHIR com a sua história, pedidos de autorização anteriores com as respostas, anexos e números de rastreio, e a pessoa no índice do paciente com todos os registos ligados e a sua história (um evento regista que uma eliminação ocorreu, e por quem).

Um pedido fechado mantém apenas os últimos caracteres dos números da pessoa: ele permanece como o registro de uma resposta sem ser outra cópia deles. Cada etapa está no registro de auditoria com os números mascarados.

Retenções legais. Uma retenção nomeia uma pessoa por identificadores, com seu motivo e uma data de término opcional. Enquanto estiver em vigor, uma exclusão é recusada diretamente, e a janela de retenção do repositório de mensagens poupa as mensagens da pessoa (registros e corpos) até que a retenção seja levantada.

Backups e o livro de exclusões. Um backup feito antes de uma exclusão ainda mantém o que foi excluído até expirar. Cada exclusão é escrita em um livro: quando, por quem, aprovado por quem, quanto foi removido de cada repositório e os identificadores da pessoa como hashes SHA-256 salgados em vez de claros. Após restaurar um backup, Aplicar exclusões novamente hash os identificadores que os repositórios restaurados mantêm com cada entrada do sal e exclui todas as pessoas que o livro nomeia. Números curtos podem ser encontrados a partir de seus hashes tentando todos os valores, então o livro é ele mesmo um dado pessoal e é mantido com a própria proteção do banco de dados.

Retenção. A tela lista por quanto tempo cada tipo de registro é mantido aqui e o que o altera: registros e corpos de mensagens por suas janelas de retenção, a fila até ser entregue ou removida, o repositório FHIR, pedidos de autorização anteriores e o índice de paciente até ser excluído (registros clínicos não são excluídos em um cronograma), o registro de auditoria mantido.

Registo de processamento (Artigo 30). Registo de processamento descarrega, em Markdown ou CSV, o que este servidor sabe sobre ele: o controlador, o responsável pela proteção de dados e onde os dados são armazenados (Definições → Dados → Proteção de dados), a retenção de cada tipo de registo e uma atividade de processamento por canal com o que recebe, de onde, para quais destinos e os hosts para os quais envia. Os propósitos, bases legais e categorias de sujeito de dados são deixados para o controlador preencher, e assim o indicam. Uma célula CSV que começa com =, +, - ou @ é escrita com um apóstrofo inicial, para que uma folha de cálculo não a execute.

Onde os dados são armazenados. Onde os dados são armazenados (Definições → Dados → Proteção de dados) afirma, em palavras que um regulador pode verificar, onde o servidor, o seu banco de dados e os seus backups são executados; a tela de Proteção de dados e o registo mostram isso. Um projeto de acordo de processamento de dados para organizações hospedadas pela BioDream está em docs/legal/dpa-template.md; é um projeto para um advogado, não um aconselhamento jurídico.

A API é /api/privacy (resumo), /api/privacy/find, /api/privacy/requests (e /{id}/approve, /{id}/export, /{id}/erase, /{id}/close), /api/privacy/holds, /api/privacy/reapply e /api/privacy/register.

17.10 Inquilinos

Um inquilino é uma fronteira de isolamento: canais, mensagens, usuários e configurações pertencem a um, e nada cruza.

Isso existe para um provedor de serviços que executa feeds para várias práticas. Não o use para separar departamentos dentro de uma organização que precisam ver o tráfego uns dos outros: a isolamento é real e não há visão entre inquilinos. Para isso, use grupos de canais (acima), que dividem as pessoas de uma organização enquanto permitem que uma equipe central veja tudo.

17.10.1 Limites

Um operador de plataforma define os limites de cada inquilino em Tenants, para que um cliente não possa sobrecarregar o restante de um servidor partilhado. Deixe um limite vazio para nenhum.

Nenhum deles perde uma mensagem. Acima da taxa ou do limite de armazenamento, uma mensagem recebida é recusada da mesma forma que um receptor ocupado recusa uma: o MLLP não recebe confirmação (não é uma rejeição, que alguns remetentes consideram como "não reenvie"), o HTTP recebe 429 com Retry-After, o SOAP recebe 503, o DICOM recebe um status retriable e uma fila, bucket ou arquivo é deixado onde estava. O remetente reenvia, como todos os motores de integração e registros eletrônicos de saúde fazem. Nada que já esteja armazenado é excluído para fazer espaço. Um limite aumentado entra em vigor dentro de um minuto, e todas as alterações de limites são registradas no log de atividades.

17.11 Dados de teste

As mensagens geradas descritas em testing existem em parte como um controlo de privacidade. Reproduzir um problema noutro local, enviar um exemplo a um fornecedor ou popular um ambiente de teste são todas coisas que, de outra forma, são feitas com mensagens reais.

A saída do gerador não contém dados de paciente por construção, e não por redação. Prefira-a a mensagens reais manualmente removidas, que é um processo que pode ser feito de forma incompleta e geralmente é.

17.12 Login único

Três mecanismos e contas locais ao lado de todos eles.

OpenID Connect (-oidc), um diretório sobre LDAP (-ldap) e SAML 2.0 (-saml). Cada um é configurado a partir de Administrar → Login e escrito no arquivo que a flag nomeia, para que a tela e o arquivo sejam duas visões de uma coisa em vez de dois lugares para manter em sincronia.

Contas locais estão sempre disponíveis e não podem ser desativadas. Isso é deliberado: um motor de integração local cuja única forma de entrar é um provedor de identidade se torna inacessível exatamente quando o provedor de identidade é inacessível, e uma interface clínica não é um bom lugar para aprender isso. A tela de login informa quantos administradores locais existem antes de encorajá-lo a depender de qualquer outra coisa.

17.12.1 O que um mapeamento de grupo decide

Os três mapeiam grupos do diretório para funções do Perfuse, e alguém em grupos que correspondem a mais de um obtém o mais privilegiado. Isso é a única direção segura para resolver — a alternativa é uma pessoa perder acesso ao qual tem direito porque também está em um grupo menor.

Qualquer um dos seis papéis pode ser concedido: monitor, visualizador, operador, editor, administrador e plataforma.

Um grupo também pode ser limitado a alguns grupos de canais, na segunda caixa da sua linha (channel_groups no arquivo). Uma vez que qualquer grupo nomeie algum, todos os logins definem os grupos de canais de uma pessoa com base nos grupos que concederam sua função: alguém em um grupo que edita os canais do laboratório e em outro que visualiza todos os canais é um editor dos canais do laboratório e nada mais. A função mais forte nunca é combinada com o alcance mais amplo, porque nenhum grupo concede isso. Um grupo com uma caixa vazia fornece todos os canais. Enquanto nenhum grupo nomear algum, o login deixa os grupos de canais como um administrador os definiu em Usuários.

Quando todos os grupos de uma pessoa nomeiam grupos de canais, cada grupo de canais recebe a função mais forte entre os grupos que o nomeiam: com Lab-Interfaces (editor, laboratório) e Clinical-IT (visualizador, laboratório e admissões), a pessoa edita os canais do laboratório e visualiza os canais de admissões, como se tivesse sido definido manualmente. Quando um dos seus grupos fornece todos os canais, não há lista para segurar uma função por grupo, e a regra acima se aplica.

roles:
  editor: [Lab-Interfaces]
  operator: [Night-Desk]
  viewer: [Clinical-IT]
  channel_groups:
    Lab-Interfaces: [lab, pathology]
    Night-Desk: [adt]

Esse é o arquivo OpenID Connect e SAML. O arquivo do diretório mapeia cada grupo para uma função (roles: {Lab-Interfaces: editor}), e channel_groups fica ao lado de roles lá.

Um mapeamento que não concede nada a ninguém é recusado em vez de ser salvo. Uma configuração que autentica pessoas e as rejeita todas parece idêntica a um produto quebrado por fora: a viagem de ida e volta é concluída e todos são recusados sem nada explicar por quê.

Criar uma conta no primeiro acesso está desativado por padrão. Com ele desativado, alguém tem que existir no Perfuse antes de poder acessar, então o diretório decide quem eles são e o Perfuse decide quem é permitido entrar.

17.12.2 SAML, especificamente

As partes dignas de nota antes de configurá-lo:

17.12.3 O que cada provedor envia

O atributo de grupo é onde os acessos dão errado, e os três provedores comuns cada um nomeiam de forma diferente.

ProvedorGeralmente enviaNotas
KeycloakgroupsPrecisa de um mapeador de associação de grupo adicionado ao cliente.
Entra IDum URI de reclamação que termina /claims/groupsEnvia IDs de objeto de grupo, a menos que a aplicação seja configurada para enviar nomes. Mapeie os IDs ou altere o provedor.
Oktao que a aplicação foi configurada para enviarComumente groups, com um filtro decidindo quais são enviados.
ADFSum URI de reclamaçãoAssina a Resposta em vez da Afirmação, que o Perfuse aceita.

Um URI de reclamação pode ser inserido por seu segmento final: digitar groups encontra http://schemas.microsoft.com/ws/2008/06/identity/claims/groups. Um nome que simplesmente termina com a palavra não corresponde — excluded_groups não é groups.

A associação de grupo que chega como um valor separado por vírgulas é tratada como um nome de grupo único e não corresponde a nada. Essa é a leitura correta do padrão, e dividir por vírgulas significaria que um grupo que contém legitimamente um se tornou silenciosamente dois. Se isso é o que o seu provedor envia, altere-o lá.

Testar na tela de acesso verifica tudo o que pode ser verificado sem uma pessoa: as configurações, o certificado e se um pedido de acesso pode ser construído. Ele diz claramente que não pode provar que alguém possa acessar, porque isso precisa de uma afirmação real sobre uma pessoa real e a única maneira de obtê-la é para eles tentarem.

17.13 Contas provisionadas pelo provedor de identidade: SCIM

Com -scim (Definições → Iniciar sessão → Contas automáticas), um fornecedor de identidade como Okta, Microsoft Entra ID ou Google Workspace cria, atualiza e remove contas Perfuse por si mesmo em /scim/v2/Users, por isso uma pessoa que deixa a organização perde acesso quando a sua conta de diretório é desativada, e não quando alguém se lembra. O fornecedor autentica com um token de API que detém o papel de administração, criado em Utilizadores → Credenciais de máquina, enviado como um token bearer.

17.14 O que o Perfuse não faz

Não encripta a base de dados em repouso. Utilize encriptação de sistema de ficheiros ou volume.

Não gere os seus próprios certificados ou os renova. Aponte para ficheiros e gere esses ficheiros com o que já utiliza.

O SAML foi verificado contra dois fornecedores independentes, cada um com um navegador de inscrição real, uma afirmação real e uma sessão real: Keycloak 26 e Microsoft Entra. Dois são mais do que o dobro de um, porque os dois discordam de uma forma que se revelou essencial — o Keycloak escreve a sua afirmação com prefixos de namespace e o Entra escreve os mesmos elementos sem eles, e o único defeito que esta área teve foi na manipulação de prefixos.

Comece por ler os metadados do seu fornecedor. Configurações, depois Início de sessão, depois a aba SAML: forneça a URL dos metadados ou cole o documento, e o endereço de início de sessão e o certificado de assinatura são preenchidos automaticamente. Cada fornecedor de SAML publica um desses — Okta, Entra, AWS IAM Identity Center, Keycloak, ADFS — e é a diferença entre configurar um fornecedor e transcrevê-lo. Fazê-lo manualmente significa encontrar o certificado dentro do XML, remover as quebras de linha do base64 e envolvê-lo em cabeçalhos PEM, onde um único espaço extra produz um erro de assinatura que não diz nada sobre formatação.

O que é devolvido é descrito em vez de descarregado: o assunto de cada certificado, expiração e impressão digital SHA-256, para que possa verificar contra o que o console do seu fornecedor mostra. Um certificado expirado é chamado de expirado em vez de ser deixado como uma data para comparar visualmente. Nada é salvo por leitura — aplicá-lo ao formulário é um clique separado, porque um documento que alguém colou não é ainda uma decisão sobre o que confiar.

Uma URL de metadados é obtida apenas sobre https, e o endereço é verificado contra a mesma política que rege os destinos do canal, por isso isso não pode ser usado para fazer o servidor ler credenciais de instância de nuvem. Redirecionamentos não são seguidos, porque um endereço permitido que redireciona para um bloqueado passaria direto por essa verificação.

Se estiver a configurar o Entra, cinco coisas não corresponderão ao que os exemplos mostram. Ele não envia nenhuma reivindicação de e-mail. O seu NameID é um identificador opaco em vez de um endereço. Ele não envia nenhuma reivindicação de grupos, a menos que o aplicativo esteja explicitamente configurado para emitir uma, por isso um mapeamento de funções escrito contra grupos recusa cada início de sessão. Quando os grupos são emitidos, eles são GUIDs de objeto em vez de nomes, a menos que o seu inquilino sincronize a partir do Active Directory no local. E os nomes das suas reivindicações vivem sob schemas.microsoft.com/identity onde a maioria da documentação mostra schemas.xmlsoap.org. O Perfuse lida com todos os cinco; eles são listados porque os quatro primeiros pareceriam de outra forma como falhas no Perfuse quando são o Entra sendo o Entra.

Essa distinção não é teórica aqui. A primeira afirmação real do Keycloak falhou completamente, porque a forma canônica que a assinatura cobre estava sendo computada com prefixos de namespace removidos. Nenhum fornecedor de identidade real poderia ter assinado alguém, e os cinco testes de canonicalização do pacote passaram em todos — cada um deles assinado e verificado com o mesmo código, por isso provaram apenas que concordava consigo mesmo. Se é o primeiro a apontar um fornecedor diferente para isso, espere encontrar algo, e o log do servidor nomeará a etapa que falhou.

18 Operações

18.1 Implantação

Um binário e dois caminhos: um diretório de ficheiros de canal e um ficheiro de base de dados. Não há servidor de aplicação, não há nível web separado e não há corretor de mensagens necessário.

perfuse serve -channels ./channels -db ./perfuse.db -addr 0.0.0.0:8443 \
  -tls-cert ./cert.pem -tls-key ./key.pem

Execute-o sob o que supervisiona os serviços no host — systemd, launchd, um tempo de execução de contentor. Ele espera ser reiniciado se sair.

18.2 Onde os dados podem ir (residência de dados)

serve -residency (Configurações → Dados → Onde os dados podem ir) nomeia as regiões de nuvem que os dados deste servidor podem ser enviados ou lidos: áreas (eea, uk, ch) e códigos de região (eu-central-1, uksouth, europe-west2), separados por vírgula. eea são as regiões da AWS, Azure e Google Cloud na Área Econômica Europeia (Frankfurt, Irlanda, Paris, Estocolmo, Milão, Espanha; Países Baixos, Alemanha, França, Suécia, Noruega, Itália, Polônia, Espanha; Bélgica, Países Baixos, Alemanha, Itália, França, Finlândia, Espanha, Polônia), uk as regiões no Reino Unido, ch as regiões na Suíça.

Com ele definido, um canal é recusado quando é salvo e quando é carregado, se um conector nomear uma região fora da lista: uma fonte ou destino S3, SQS ou SNS region (ou seu endpoint, quando esse é um hostname da AWS), ou qualquer destino cujo endereço é um hostname da AWS que carrega uma região (sqs.us-east-1.amazonaws.com, uma URL da API Gateway). O servidor se recusa a iniciar com um coletor de rastreamento ou um webhook de alerta em outra região. Um conector apontado para um host que não nomeia nenhuma região (o próprio sistema de um hospital, MinIO na rede do site) não é julgado: o registo de processamento na tela de Proteção de dados lista todos os hosts para os quais cada canal envia, para o controlador verificar. O painel e a tela de Proteção de dados dizem para onde os dados podem ir.

Alojamento na UE e no Reino Unido. deploy/hosted contém OpenTofu (ou Terraform) para um servidor hospedado por organização em Frankfurt, Irlanda ou Londres: o servidor, o seu banco de dados PostgreSQL e backups, um bucket de backup, registos e gravações de sessões de suporte, tudo encriptado com uma chave na Região, nada replicado para outra Região, suporte apenas através do Session Manager e Perfuse executado com -residency. O seu ficheiro README diz o que ele constrói, o que não abrange, o que foi verificado (validado e planeado contra uma conta real; ainda não aplicado) e o que custa ao preço de lista em cada Região.

18.3 Configuração como ficheiros

Os canais são ficheiros, o que significa que podem estar em controlo de versão, revistos antes da implementação e diferençados após um incidente.

Os ficheiros são lidos novamente sem uma reinicialização. Um ficheiro que não é analisado é relatado e a versão carregada anteriormente continua a funcionar, então um erro de sintaxe não pode tirar um feed de funcionamento do ar.

Um canal editado na interface web é escrito de volta para o seu ficheiro. Se esses ficheiros estiverem em controlo de versão, espere commits das alterações de configuração feitas através da interface e não edite manualmente um ficheiro enquanto alguém o tiver aberto no construtor.

18.4 Backup

Duas coisas a fazer backup, e elas têm características diferentes.

O diretório do canal é pequeno, muda raramente e é o que você precisa para reconstruir o serviço. Faça backup como configuração; o controlo de versão é geralmente suficiente.

A base de dados contém mensagens, utilizadores e histórico de auditoria. É grande, muda constantemente e contém dados clínicos — portanto, precisa ser feito backup como dados clínicos, com a retenção e encriptação que isso implica. Perder isso não para o serviço, mas perde a capacidade de investigar qualquer coisa que já tenha acontecido e a história em que o ritmo do aprendizado depende.

18.5 Comportamento de reinício

Ao reiniciar, os canais são carregados e as fontes começam a ouvir. As entregas enfileiradas são retomadas.

A coisa a entender é o que acontece com o trabalho em voo. Sob o reconhecimento padrão on_delivery, uma mensagem que ainda não foi reconhecida não é reconhecida, então o remetente a reenviará — o que é o resultado correto. Sob on_receipt, uma mensagem que foi reconhecida, mas ainda não foi entregue, está na fila e é retomada; se a fila estiver desativada, é perdida. Veja fluxo de mensagens.

18.6 Atualização

Substitua o binário e reinicie. O esquema da base de dados é migrado automaticamente para a frente no início.

As migrações são apenas para a frente. Não há downgrade, então um rollback para um binário anterior após o esquema ter mudado precisa da base de dados anterior. Faça uma cópia antes de atualizar — esta é a única precaução operacional que vale a pena ser disciplinada.

18.7 Monitorização

A alerta interna do Perfuse é abordada em alerta e é o que irá dizer que uma fonte de alimentação parou.

De fora, monitore o processo, o disco em que a base de dados está e se a interface web responde. A base de dados cresce e um disco cheio para a gravação de mensagens, o que é um modo de falha sem outro aviso.

18.7.1 SNMP

Para ferramentas de monitorização que falam SNMP (Nagios, Zabbix, PRTG, SolarWinds, LibreNMS), o Perfuse executa um agente SNMPv2c somente leitura e envia uma armadilha quando um alerta dispara ou se resolve. Defina-o em Definições → Monitorização → SNMP, ou com flags:

perfuse serve -snmp-listen :161 -snmp-community 'long-random-community' -snmp-allow 10.0.5.0/24 \
  -snmp-traps nms.example.org,10.0.5.9:1162

18.7.2 Um inventário de cada interface

-inventory interfaces.md (Configurações → Monitorização → Inventário) escreve um documento Markdown listando cada canal - o seu formato, sempre em execução, o que recebe de e o que envia para - seguido pela descrição própria de cada canal e reescreve-o a cada -inventory-every (um dia por padrão). Destina-se a ser comprometido ao lado dos ficheiros do canal ou entregue a um auditor e lido sem a aplicação em execução.

18.8 Capacidade

O teto de throughput do Perfuse não foi medido em hardware real sob tráfego real, e este manual não imprimirá um número que não possa suportar.

O que pode ser dito: a arquitetura é uma goroutine por conexão com filas por destino, então o throughput escala com destinos em vez de ser serializado por um trabalhador; a gravação de mensagens é uma escrita SQLite por mensagem, o que torna o disco a restrição mais provável; e a loja de mensagens cresce linearmente com o tráfego, então a retenção é a configuração que governa o uso de disco a longo prazo.

Se estiver a dimensionar isto para uma grande fonte de dados, meça-o com o seu próprio tráfego utilizando o corpus de teste gerado descrito em testing. Essa é a resposta honesta, e também é uma resposta melhor do que um número de alguém else's hardware.

18.9 Onde esta instalação ficou presa

A atividade carrega um painel, visível para administradores, mostrando o que o Perfuse recusou fazer — agrupado por mensagem, mais frequente primeiro — e até onde a instalação avançou em direção a um canal de trabalho.

Ele existe porque todas as outras afirmações sobre se este software é fácil de usar vêm das pessoas que o escreveram. Uma recusa não: alguém queria algo, o servidor disse não, e nenhuma das partes estava adivinhando. É a única evidência no produto que não vem da BioDream LLC.

O funil nomeia o passo que ainda não aconteceu em vez de deixar timestamps para comparar. O estado digno de ser observado é as mensagens chegam e nenhuma foi entregue a um destino — um canal pode receber tráfego por semanas e não entregar nada, e de todas as outras telas isso parece estar funcionando.

Nada do que alguém digitou é gravado. A tabela contém a rota da solicitação com identificadores substituídos por {id}, o status e a frase do próprio servidor. Uma mensagem de validação nomeia um campo e uma regra, que é a parte útil; o valor que quebrou a regra é muito frequentemente dados de paciente, e uma tabela desses seria uma responsabilidade pior do que a fricção que mediu.

Duas exclusões deliberadas. Um 5xx é uma falha neste software e já é registrada como tal — misturar os dois enterraria os casos em que alguém não conseguiu descobrir o que digitar sob os casos em que nada que digitassem teria ajudado. E uma sessão expirada produz uma sequência de 401s que não dizem nada sobre usabilidade e afogariam todas as descobertas que o fazem.

Ler o relatório também corta a tabela para as suas últimas cinco mil linhas. Recusas são respostas 4xx, então cresce lentamente, e a leitura é um momento natural para organizar: nenhum temporizador e nada que execute quando ninguém está olhando.

GET /api/friction retorna a mesma coisa para qualquer um que prefira lê-la como JSON.

18.10 Registos

O Perfuse registra para a saída padrão, que é onde um supervisor ou tempo de execução de contêiner o coletará.

Detalhes de nível de mensagem vão para a loja de mensagens em vez do registro, deliberadamente. Uma linha de registro por mensagem em uma fonte de dados ocupada é ruído que esconde as linhas que importam, e a loja é pesquisável de maneiras que um arquivo de registro não é.

O registro carrega o que a loja não pode: inicialização e desligamento, resultados de carga de configuração, alterações de estado de canal e erros que não são atribuíveis a uma mensagem específica.

18.11 Executando duas instâncias

Dois ou mais servidores podem executar como um cluster: quando o servidor que executa uma fonte de alimentação para, outro assume em poucos segundos, e a próxima tentativa do remetente atinge-o. Eles compartilham um banco de dados PostgreSQL em vez de cada um manter um ficheiro SQLite, e concordam entre si, através dele, sobre qual deles executa o quê.

perfuse serve -db 'postgres://perfuse:SECRET@db.hospital.internal/perfuse?sslmode=verify-full' \
  -cluster active-passive -node-name perfuse-01 -node-address https://perfuse-01.hospital.internal:8443 \
  -data /var/lib/perfuse

Inicie cada servidor da mesma forma com o seu próprio nome e endereço. A conta do banco de dados precisa criar tabelas e, uma vez, a extensão citext (ou um administrador executa CREATE EXTENSION citext primeiro). Cada servidor mantém os seus próprios ficheiros em -data: o seu registo, o seu ID de nó e as suas cópias da configuração.

Duas maneiras de compartilhar o trabalho.

Quem executa o quê, e nenhum momento com dois. Cada peça de trabalho é um contrato de arrendamento no banco de dados, renovado a cada quinto de -cluster-lease (15 s por defeito). Um servidor que não consegue renová-lo (ele travou, a sua rede falhou, o banco de dados é inacessível) para esse trabalho por si mesmo uma vez que o seu próprio relógio diz que o contrato de arrendamento está quase feito, com um terço do contrato de arrendamento para sobrar. Outro servidor assume o contrato de arrendamento apenas após o seu próprio relógio ter observado o contador do contrato de arrendamento parado por um contrato de arrendamento completo. Nenhum relógio é comparado com outro, por isso os relógios dos servidores e o do banco de dados não precisam concordar; eles precisam apenas funcionar a uma taxa mais ou menos igual, o que todos os relógios fazem. Entre o antigo titular parar e o novo começar, há uma breve lacuna com ninguém ouvindo, que um remetente vê como uma conexão recusada e retenta; nunca há um momento com dois ouvindo em uma fonte de alimentação ou dois trabalhadores drenando uma fila.

Um servidor que desliga limpa ou um administrador que escolhe Step down no líder, transfere imediatamente em vez de após o arrendamento.

What every server shares. Messages, the delivery queue, accounts and sessions, the audit log, the FHIR store, the terminology tables and the patient index are in the database, so whichever server runs a channel finds the queue the last one left. The channel files, the settings file, the alert rules, single sign-on files, the logo, Direct certificates and saved views are kept the same on every server through the database: each keeps its own copy on its own disk, a change on any server (in the console, by hand, by a git pull) reaches the others within two seconds, and a channel changed on another server restarts with its new file. The same file changed on two servers at once keeps the version that reached the database first, and the other beside it as NAME.conflict-SERVER. Settings that apply only at a restart (the message database, the ports the console listens on) are applied by each server at its next restart, and the log says so. What names something on one machine stays on that server's command line and out of the shared file: the certificate and key (-tls-cert, -tls-key), the SNMP listening address and the server's name in traces. Settings shows them as set on each server.

Iniciar e parar. Iniciar ou parar um canal em qualquer servidor se aplica ao cluster: o servidor que o executa o inicia ou para dentro de um segundo, e a resposta indica qual servidor é esse.

O balanciador de carga à frente. O endereço de um feed deve alcançar o servidor que o executa. Aponte o remetente para um endereço virtual (um balanciador de carga, um IP flutuante, um nome DNS com um TTL curto) e faça com que o balanciador de carga verifique /readyz?channel=NAME, que responde 200 apenas no servidor que executa esse canal, e 503 nos outros. Para a consola, /readyz é 200 em todos os servidores ativos; /readyz?role=leader apenas no líder.

On an AWS Network Load Balancer, use a target group per feed with an HTTPS health check on /readyz?channel=NAME, a 5-second interval and a threshold of 2, and turn cross-zone load balancing on. With it off, the load balancer's node in a zone where no server runs the feed sees only unhealthy targets, sends to all of them anyway, and a sender that resolved to that node waits until the feed comes back to its zone (95 seconds in a test). Set the deregistration delay to 0, since a server that stops running a feed has nothing to drain.

O que foi testado. Dois servidores no PostgreSQL 16, um remetente transmitindo 300 mensagens, reenviando até ser respondido, e o servidor que executava a fonte de dados morto com SIGKILL duas vezes (a primeira, e então a segunda após a primeira voltar). Todas as mensagens respondidas alcançaram o destinatário, em ambas as formas tentadas: entregues antes da confirmação, e enfileiradas no repositório compartilhado enquanto o destinatário recusava (185 mensagens respondidas esperavam na fila no momento da morte; o sobrevivente as entregou todas). A falha sobreveio em 3 a 4 segundos em um contrato de 3 segundos. Um duplicado é possível e foi visto uma vez em 600: uma mensagem que o servidor moribundo entregou e não pôde confirmar, que o remetente reenviou. Os testes do coordenador cobrem uma falha, um servidor cortado do banco de dados enquanto ele é executado, step-down, disseminação, movimentos e configuração compartilhada com conflitos. Eles são executados no CI contra o PostgreSQL com o detector de corrida, com a suíte completa.

O mesmo foi feito então na AWS: dois servidores Linux (ARM) e um Windows Server 2022 em três zonas de disponibilidade, Amazon RDS PostgreSQL 16 sobre TLS com o certificado verificado (sslmode=verify-full), um Balanceador de Carga de Rede interno à frente, e remetentes reenviando até serem respondidos:

TesteMensagensRespondidas mas perdidasDuplicadosTempo máximo que um remetente esperou
Ativo-passivo, o servidor que executava a fonte de dados morto duas vezes (Linux, e então Windows), destinatário recusando no meio2.0000015 s
Um líder Linux cortado do banco de dados (firewall), seu processo deixado em execução3.0000116 s
Um líder Windows cortado do banco de dados3.0000020 s
O líder morto enquanto um servidor tinha seu relógio 2 minutos à frente e outro 90 segundos atrasado2.0000018 s
Ativo-ativo, quatro fontes de dados sobre três servidores, um morto e trazido de volta6.0000224 s

Com o contrato de 15 segundos padrão, um servidor cortado do banco de dados parou sua fonte de dados 10 segundos após sua última renovação, e o próximo servidor a iniciou 6 a 8 segundos após isso: nunca ambos ao mesmo tempo. Os relógios desalinhados não mudaram nada, pois nenhum relógio é comparado com outro.

Ainda não. Um cluster serve uma organização: -cluster com -multi-tenant é recusado. Os ouvintes se movem com seu canal, então o balanceador de carga é o do site para fornecer.

Um servidor sozinho continua a funcionar como sempre, no SQLite, sem cluster algum.

18.12 Mais de um servidor

Um site com duas instâncias tem uma pergunta que nenhuma consola única pode responder: tudo está em execução? Mirth cobra pelo resposta. Esta é a visão da frota.

Uma instância é nomeada como o local onde você olha. Ela pesquisa as outras e mostra todos os canais em todos os servidores em uma tabela, com um resumo em todos eles.

18.12.1 Adicionar um par

Configurações → Frota, ou PUT /api/fleet/peers. Um peer precisa de um nome, uma URL e um token emitido pelo peer em si.

O nome é necessário e não é a URL, porque uma URL não é algo que alguém reconhece às três da manhã.

O token deve ser criado no peer, em Usuários, e deve ter escopo de visualizador. Adicionar um peer sem um é recusado, com essas instruções, em vez de ser aceito e então falhar silenciosamente em cada pesquisa. Ler a saúde de outra instância é o menor privilégio que existe, e é o único que a visão da frota precisa.

18.12.2 Controlar um peer, que está desligado

allow_control permite iniciar e parar os canais desse peer a partir daqui. Ele está desativado por padrão e cada uso é auditado por nome.

Os dois privilégios são deliberadamente separados. Ler a saúde de outro servidor é menor; parar seus canais durante uma transfusão não é, e o segundo nunca deve chegar silenciosamente anexado ao primeiro.

18.12.3 O que o relatório diz

Cada servidor relata o número total de canais, quantos estão em execução, parados ou com erros, a profundidade da fila e a idade da mensagem em espera mais antiga, quantos alertas estão a disparar e se está a drenar para desligar.

A contagem resumida conta os servidores de três maneiras: alcançável, inacessível e indeterminado. O terceiro cobre peers cuja saúde ninguém sabe — ainda não pesquisado, recusando o token, ou executando uma versão que este não pode ler. Ele é mantido separado do inacessível porque "não podemos dizer" não é "ele está inativo", e juntar os dois é como uma página da frota começa a mentir.

Pela mesma razão, o rollup contém knownFrom: quantas instâncias os números do canal e da fila foram efetivamente lidos. Doze canais em execução em uma frota significam algo diferente quando dois de cinco servidores não responderam, e o total sozinho não pode dizer isso.

Um peer inacessível diz por quê em termos que um operador pode agir. Uma conexão recusada é relatada como o host estando ativo, mas sem nada ouvindo naquela porta, o que é um problema diferente de um host que não responde de forma alguma.

18.12.4 Diferença de relógio

O rollup relata a maior diferença entre os relógios dos servidores nele. Vale a pena ter um número próprio: correlacionar um incidente em duas instâncias cujos relógios discordam por quatro minutos produz uma sequência de eventos que não ocorreu.

18.12.5 O que um peer aprende sobre si

Contagens e taxas. O relatório que uma instância fornece a outra não contém identificadores de mensagens, detalhes de nível de canal ou dados de paciente de qualquer tipo.

É isso que impede que uma visão de frota seja uma centralização de dados clínicos: a instância agregadora aprende quantos canais estão em execução e nada sobre o que fluiu por meio deles. Se você quiser as mensagens, você abre a própria console do servidor, onde o registro de auditoria registra que você fez isso.

18.12.6 Um peer apontado para si mesmo

Recusado. Uma instância que faz polling do seu próprio endereço por meio da sua própria pilha HTTP aparece duas vezes na sua própria visão de frota e contabiliza duplamente cada canal que tem.

18.12.7 TLS em redes internas

insecure_skip_verify aceita o certificado de um peer sem verificá-lo. Ele existe porque a infraestrutura hospitalar é executada em autoridades de certificação privadas e recusar-se a funcionar de forma alguma empurraria as pessoas para o HTTP simples, o que é pior. Ele é nomeado para que não possa ser confundido com uma boa ideia.

19 A Linha de Comando

Tudo o que Perfuse faz a um sistema em execução é alcançável a partir da interface web, e isso é deliberado: uma funcionalidade que precisa de um terminal é tratada como um defeito em vez de uma escolha de design. Os comandos aqui são para o trabalho que acontece *em torno* de um sistema em execução — antes de existir, enquanto decide se confia nele, e quando precisa entregar algo a alguém.

Vários deles nunca tocam um servidor. perfuse explain, perfuse profile, perfuse deident e perfuse translate lêem ficheiros e escrevem ficheiros, por isso são úteis num portátil contra um patrimônio que ainda funciona inteiramente com algo mais.

Execute qualquer comando com -h para as suas bandeiras. Este capítulo diz para que serve cada um.

As bandeiras mostradas aqui são ilustrativas, não exaustivas. -h é gerado a partir do código e não pode ficar desatualizado; uma lista copiada para a prosa pode.

19.1 Canais em execução

19.1.1 perfuse serve

Executa a interface web e a API, e por predefinição executa também os canais. Este é o comando que uma instalação utiliza.

Toda opção que aceita é listada em Opções do Servidor, gerada a partir do programa. Recusa-se a servir HTTP simples a qualquer coisa excepto loopback, a menos que se passe -insecure. Isso não é uma configuração de cortesia: tráfego clínico e um cookie de sessão sobre uma conexão de LAN não encriptada é um evento relatável, e a flag existe para que dizer sim seja uma decisão que alguém tomou, em vez de um predefinição herdada. Consulte segurança.

19.1.2 perfuse run

Executa canais a partir de YAML sem interface web e sem base de dados. Útil em um contentor que deve fazer exatamente uma coisa, e útil quando se deseja ver o comportamento de um canal sem que nada mais esteja em execução.

19.1.3 perfuse check

Valida definições de canais e imprime o que elas fazem, sem executá-las. A segunda metade é o ponto: um canal que carrega não é necessariamente o canal que se pretendia, e ler um resumo em inglês simples do que um ficheiro fará apanha um erro que a validação não pode ver.

Sai com um código de saída não zero em caso de falha, por isso pertence a qualquer verificação da sua configuração antes que ela chegue a um servidor. -quiet imprime nada em caso de sucesso, para esse uso.

-allow-metadata-egress permite destinos apontados para endereços de metadados de instâncias em nuvem. Esses endereços contêm as credenciais da própria máquina, por isso um canal que possa ser convencido a enviar para lá é uma fuga de credenciais; a verificação recusa-os a menos que se diga o contrário.

19.1.4 perfuse test

Executa testes escritos contra definições de canais. Um teste envia uma mensagem através do filtro real do canal, transformações reais e scripts reais, na ordem real, com apenas a rede substituída — por isso o que passa aqui é o que o canal faz.

Os testes vivem em *_test.yaml ou *.test.yaml ao lado dos canais. Consulte testes.

19.2 Migrando de outro motor

Estes três são os que se devem executar primeiro, antes de decidir qualquer coisa. Consulte migração.

19.2.1 perfuse explain

Lê exportações do Mirth, Open Integration Engine e BridgeLink — um canal, um grupo de canais ou um backup de servidor completo — e descreve o que cada canal faz e o que bloquearia uma migração. Não altera nada e não precisa de uma instalação do Perfuse, o que a torna o passo mais barato possível: aponte para uma exportação do seu patrimônio e leia o que é retornado.

-strict sai com um código de saída não zero se algo for bloqueado, por isso pode controlar um pipeline. -json emite as mesmas descobertas para uma máquina.

19.2.2 perfuse translate

Converte exportações do Mirth, Open Integration Engine e BridgeLink em ficheiros de canal do Perfuse: um canal, um grupo de canais, uma exportação de biblioteca de modelo de código ou um backup de servidor completo.

perfuse translate -o ./canais server-backup.xml

Bibliotecas de bibliotecas de código são escritas para lib/ ao lado dos canais, e cada canal do Mirth que tinha uma biblioteca ativada inclui-a. Consulte migração.

Nada é silenciosamente descartado. Cada parte de um canal é ou traduzida, transportada como um script que é executado inalterado, ou relatada como necessitando de um ser humano. A terceira categoria é a honesta — um tradutor que produzisse um ficheiro com aparência limpa para cada entrada estaria a esconder as decisões que mais se precisa tomar.

19.2.3 perfuse compare

Executa o mesmo tráfego através de dois motores e relata onde eles discordam, agrupados por campo.

Este é o comando que responde à pergunta "por que devo confiar neste com dados de pacientes", e responde com evidências que você reuniu, em vez de uma afirmação feita aqui. É o passo recomendado antes de fazer a transição e o passo recomendado inicial em qualquer discussão sobre se o Perfuse está pronto.

19.3 Compreender uma fonte de dados

19.3.1 perfil do perfuse

Lê as mensagens e relata o que realmente está nelas: quais campos estão sempre preenchidos, quais nunca estão, os conjuntos de valores reais de campos codificados, contagens de repetições e quais segmentos Z aparecem.

Os valores são relatados apenas para campos cujos valores formam um conjunto de código pequeno, para que um perfil do tráfego real não se torne um arquivo cheio de dados de pacientes.

Salvar um perfil e compará-lo posteriormente é como descobrir que um remetente alterou algo:

perfuse profile -save last-month.json corpus/ perfuse profile -against last-month.json new/

19.3.2 contrato do perfuse

Transforma a saída desse pensamento em algo executável. Um contrato diz como uma fonte de dados deve ser, para que no dia em que ela muda, você seja informado, em vez de descobrir semanas depois por meio de um receptor que falhou — as mensagens ainda são válidas HL7 quando um campo some, então nada mais nota.

perfuse contract promote -o adt.contract.yaml corpus/ perfuse contract check adt.contract.yaml today/

promote gera um ponto de partida, não uma resposta. Leia-o e exclua a maior parte dele: cada linha registra se foi medida ou decidida, o que é o que lhe diz quais linhas manter.

19.4 Produzindo mensagens

19.4.1 perfuse generate

Produz mensagens sintéticas HL7 v2. Tudo é inventado — nomes obviamente fictícios, identificadores sequenciais, endereços inventados — para que a saída seja segura para comprometer, enviar e anexar a um ticket.

Ele pode enviar diretamente para um canal em vez de escrever um arquivo, o que é a forma mais rápida de provar que um ouvinte funciona:

perfuse generate -n 100 -send 127.0.0.1:6661

19.4.2 perfuse deident

Lê mensagens reais e escreve um corpus que mantém sua estrutura, seus códigos e seus intervalos, e nada do que identifica um paciente. Esta é a diferença entre ser capaz de enviar alguém uma reprodução e não.

Não é a mesma ferramenta que perfuse generate e a distinção é importante. Mensagens geradas são inventadas e, portanto, seguras, mas irreais; um corpus desidentificado é *derivado do tráfego real*, então reproduz as peculiaridades que realmente quebram as interfaces.

Duas propriedades dignas de serem compreendidas antes de usá-lo:

-keep-local-segments passa segmentos Z inalterados e é inseguro. Segmentos Z são exatamente onde os sites colocam nomes, notas e texto livre, então manter eles derrota o propósito da ferramenta. Ela existe porque um problema estrutural às vezes está *em* um segmento Z, e então você precisa de um corpus que não deve ser compartilhado.

19.5 Movendo mensagens manualmente

19.5.1 perfuse listen

Aceita HL7 v2 sobre MLLP e o confirma. Um receptor que existe por tanto tempo quanto você precisa, para provar que um remetente pode alcançar esta máquina em todos os aspectos.

19.5.2 perfuse enviar

Envia mensagens HL7 v2 sobre MLLP a partir de ficheiros.

MLLP não tem autenticação e não tem encriptação, em Perfuse ou em qualquer outro lugar. Ambos os comandos estão sujeitos a isso, assim como todas as fontes e destinos MLLP: o acesso é restrito à camada de rede ou não é restrito.

19.6 FHIR

19.6.1 perfuse fhir

Converte HL7 v2 para FHIR, valida FHIR ou o serve, dependendo do subcomando.

O subcomando de validação é útil por si só: irá dizer se um recurso que alguém lhe enviou satisfaz o US Core, que é o perfil contra o qual a regulamentação americana é escrita. Ser capaz de responder a isso sem adotar um motor é o objetivo.

19.6.2 perfuse x12

Converte X12 (ou outros delimitados EDI) para o XML Mirth Connect e Open Integration Engine escrevem para ele, e vice-versa: perfuse x12 xml FILE e perfuse x12 from-xml FILE, entrada padrão quando nenhum arquivo é fornecido. A saída é o que o OIE 4.6 escreve, byte a byte, para que possa ser comparada com o que um servidor Mirth produziu ou foi alimentado por um sistema construído contra ele. Um canal faz o mesmo com x12.arrives_as: xml e um destino x12_as: xml; consulte X12.

19.6.3 perfuse sof

Runs a SQL on FHIR ViewDefinition over FHIR files (the NDJSON of a bulk export, Bundles or JSON arrays; - for stdin) and writes the table: -view FILE (required), -format csv|ndjson|json|parquet (csv by default), -header=false, and -o FILE (required for Parquet). See SQL on FHIR views.

19.6.4 perfuse medida

Avalia uma medida de qualidade com critérios FHIRPath sobre arquivos FHIR (o NDJSON de uma exportação em massa, Bundles ou matrizes JSON; - para stdin) e escreve o MeasureReport. Sinalizadores:

Veja medidas de qualidade digitais.

19.6.5 Flags FHIR em perfuse serve

FlagEfeito
-fhirServir o endpoint FHIR em /fhir. Ativado por predefinição.
-fhir-versionA versão servida. R4 por predefinição.
-fhir-read-onlyRecusar escritas.
-fhir-api-tokensCom SMART configurado, aceitar tokens de API do Perfuse, bem como tokens SMART (desativado por predefinição; também em Configurações → FHIR).
-fhir-bulk-exportAtivar $export. Desativado por predefinição.
-fhir-subscriptionsAtivar assinaturas de tópicos: notificações de encontro e compromisso para endpoints FHIR que os clientes escolhem. Desativado por predefinição; necessita R4 e um endpoint gravável.
-fhir-subscriptions-allow-httpPermitir que as assinaturas entreguem para http simples. Para um receptor de teste, nunca para dados de paciente em uma rede.
-fhir-patient-directory-searchPermitir que um token limitado a um paciente procure o diretório (profissionais de saúde, organizações, localizações), dentro de seus âmbitos. Desativado por predefinição.
-fhir-declaresGuias que este servidor declara em sua declaração de capacidade, separados por vírgulas: um endereço de CapabilityStatement de uma guia, ou Type=profile endereço. Uma declaração para clientes e kits de teste; não muda nada que a loja aceita.

A loja mantém documentos, bem como recursos: um documento, coleção ou Bundle de mensagem colocado em /fhir/Bundle/{id} é mantido inteiro, lido novamente com cada entrada na versão servida e encontrado por type, identifier, timestamp e composition. Uma transação colocado lá é mantida como um registo e não aplicada; um POST para /fhir aplica uma.

As respostas são em JSON, a não ser que o cliente peça XML (Accept: application/fhir+xml, ou _format=xml). O Perfuse lê apenas JSON: um corpo enviado como XML recebe 415. Um Bundle de documento POSTado para /fhir é mantido quando este servidor detém, por identificador, o paciente e o encontro que a Composition nomeia, e recusado com 422 caso contrário. Uma leitura Binária com Accept definido para o seu próprio tipo de conteúdo responde com o conteúdo em si.

19.7 Configuração e operação

19.7.1 perfuse init

Cria o layout do diretório, um canal de exemplo e uma definição de serviço para o sistema operacional em que é executado. Nada existente é substituído, a menos que você passe -force.

perfuse init -dir /opt/perfuse -service systemd

19.7.2 perfuse serviço

Registra Perfuse como um serviço do Windows, remove-o ou relata se está instalado e em execução. Apenas para Windows; no Linux, o equivalente é o arquivo de unidade que perfuse init pode escrever para você. Veja operações.

19.7.3 perfuse token

Emite credenciais para máquinas em vez de pessoas. Um token não expira e não é afetado por alguém sair, o que é necessário para um servidor que pesquisa seu vizinho e o que uma sessão do navegador deliberadamente não é.

perfuse token create -db perfuse.db -label fleet-from-site-a -role viewer perfuse token list -db perfuse.db perfuse token revoke -db perfuse.db -label fleet-from-site-a

Apenas o hash é armazenado, então um token é exibido uma vez quando é criado e não pode ser recuperado posteriormente. Um banco de dados roubado, portanto, não produz um token utilizável. Dê a um token o papel mais baixo que faça o trabalho: uma vista de frota precisa de viewer e nada que apenas leia deve ter algo mais.

-fhir-groups riverside-attributed,riverside-north limita um token a esses Grupos FHIR, para uma exportação de acesso de provedor CMS-0057: no endpoint FHIR, ele pode ler esses Grupos e exportá-los, e nada mais. Consulte CMS-0057 para pagadores.

19.7.4 perfuse athena

Imprime o Amazon Athena CREATE EXTERNAL TABLE para um arquivo S3 escrito com format: ndjson, usando a projeção de partição na parte dt=YYYY-MM-DD da chave, para que nenhum crawler precise ser executado à medida que os dias são adicionados.

perfuse athena -bucket hospital-archive -destination archive

Imprimido em vez de executado, pois a criação de uma tabela requer permissões do Athena e do Glue que este programa não deve possuir.

19.7.5 perfuse sbom

Lista tudo o que está vinculado ao binário, lido a partir da própria compilação e não a partir do go.mod — portanto, descreve o binário à sua frente e não o que alguém pediu uma vez.

-json emite CycloneDX e -spdx emite SPDX tag-value, que é geralmente o que uma revisão de aquisição ou segurança está pedindo. O código do navegador incorporado no binário é incluído, pois um revisor que combina um binário com advisories precisa saber que ele contém uma aplicação React.

19.7.6 perfuse version

Imprime a versão e o commit a partir do qual foi construído. Vale a pena incluir em um ticket: "a versão atual" não é uma versão, e duas máquinas que foram instaladas com uma semana de diferença frequentemente não estão executando a mesma compilação.

20 Opções do Servidor

Toda opção que perfuse serve aceita, gerada a partir do próprio programa, de modo que essa lista não pode nomear uma opção que não existe ou deixar uma de fora. A maioria também é uma configuração na interface web, nomeada na última coluna: um valor salvo lá tem prioridade sobre a flag na próxima inicialização, e a flag permanece como a forma de defini-la a partir de uma definição de serviço. O endereço de escuta, o banco de dados e o diretório do canal permanecem como flags apenas, pois eles indicam onde o servidor encontra o que estaria editando.

Segredos nunca são flags. Uma opção que precisa de uma senha ou token nomeia uma variável de ambiente que a contém.

20.1 Todas as opções

OptionTakesDefaultWhat it doesIn the console
-addrstring127.0.0.1:8080, or 127.0.0.1:8443 with -tls-certaddress to serve the interface on—
-alert-severitystringwarningminimum severity to send to the webhook: warning or criticalSettings › Alerts › Delivery: Only send alerts at least this serious
-alert-webhookstring—POST alerts to this URL as JSON. Works with Slack, Teams, Mattermost, Alertmanager or anything that accepts a webhook. The payload carries channel names, counts and thresholds; never message contentSettings › Alerts › Delivery: Send alerts to this address
-alertsstring—YAML file of alert rules. Default: alerts.yaml beside the database, written when the rules are first saved in the console; until then a conservative default set is used—
-allow-metadata-egresson/off—permit destinations pointed at cloud instance metadata addresses, which hold this machine's credentialsSettings › Security › What may leave: Allow destinations at cloud instance metadata addresses
-cds-clientsstring—the EHRs trusted to call the CDS services with signed JWTs (issuer and jwks_url)Settings › Payers › Prior authorization: EHRs trusted to call the CDS services
-channelsstring./channelsdirectory holding channel files—
-clusterstring—share the work with other servers on the same PostgreSQL -db: active-passive (one runs everything, another takes over when it stops) or active-active (channels spread over all)—
-cluster-leaseduration15show long a crashed server holds its work before another takes it over; renewed five times as often—
-crd-advisor-castring—a PEM file of certificate authorities to trust for -crd-advisor-url beside the system's (Vaglio's is its DATA/tls/ca.crt)Settings › Payers › Decision service: Certificate authorities to trust for the advice service
-crd-advisor-token-envstring—name of an environment variable holding a bearer token for -crd-advisor-url (the token itself is never a flag)Settings › Payers › Decision service: Environment variable holding the advice service's token
-crd-advisor-urlstring—with -crd-rules, ask the decision service at this URL (such as Vaglio's /api/pas/advise) what a prior authorization request for each order needing one would be told as the record stands, shown as one more CRD card; the prefetched record is POSTed to it. No answer, or any failure, leaves the cards as they are without itSettings › Payers › Decision service: Advice before submitting (CRD)
-crd-rulesstring—a Da Vinci CRD rules file: serve coverage requirements over CDS Hooks at /cds-servicesSettings › Payers › Prior authorization: Coverage rules file (Da Vinci CRD)
-dashboardsstring—a file mapping directory groups and roles to the dashboard each opens onSettings › Monitoring › Dashboards: Which dashboard each group opens on (file)
-datastring—directory for this server's own files (settings, alerts, sign-in configuration, the log): default beside -db when it is a file, the current directory when it is a PostgreSQL URL—
-davinci-versionstring2.2the Da Vinci CRD, DTR and PAS release answered when neither a request nor its client's registration says: 2.2 (CRD 2.2.1, DTR 2.2.0, PAS 2.2.1) or 2.1 (2.1.0)—
-dbstring./perfuse.dbdatabase for users, messages and stored resources: a file, or a postgres:// URL for servers that share one store (a cluster)—
-demo-accountstring—for a public demonstration server: username:password of a shared viewer account shown on the sign-in page—
-dicomweb-archivestring—keep imaging objects in this directory and serve them over DICOMweb (QIDO-RS, WADO-RS, WADO-URI, STOW-RS) at /dicomwebSettings › Data › Imaging archive: Keep images in this folder and serve them over DICOMweb
-dicomweb-corsstring—comma-separated browser origins, such as an OHIF viewer's, allowed to call /dicomwebSettings › Data › Imaging archive: Browser origins allowed to call it
-drain-forduration—after SIGTERM, report not-ready for this long before shutting down (for rolling deploys)Settings › Engine › Shutdown: Wait for in-flight messages on shutdown
-ecr-agencystring—play a public health agency for testing eCR: answer case reports at $process-message with a Reportability Response, using the agency YAML file given (name, phone, address, endpoint; optional rctc, reply)Settings › Public health › Case reporting: Act as a test public health agency
-ecr-responseson/off—accept eCR Reportability Responses at the FHIR endpoint's $process-message, storing each as DocumentReference/<id> derived from the eICR it answersSettings › Public health › Case reporting: Receive Reportability Responses
-engineon/offtruerun the channel engine in this process, so the interface can start, stop and monitor channels—
-epa-payer-idstring—this payer's identifier on the prescribing network, the From of every RTPB and ePA response (default: the formulary's payer id)Settings › Payers › Drug formulary: Payer ID on the prescribing network
-epa-reply-channelstring—route ePA decisions made after the request was answered (a reviewer's, an appeal's) to this channel, which delivers them to the prescriber's networkSettings › Payers › Drug formulary: Channel that sends later ePA decisions
-fhiron/offtrueserve a FHIR endpoint at /fhirSettings › FHIR › The FHIR server: Serve a FHIR endpoint at /fhir
-fhir-api-tokenson/off—with SMART configured, accept Perfuse API tokens on the FHIR endpoint as well (unscoped; the console's FHIR settings can switch it)Settings › FHIR › Access: Accept Perfuse API tokens beside SMART tokens
-fhir-bulk-exporton/off—enable $export, which produces a file holding every record the FHIR endpoint servesSettings › FHIR › Bulk data: Bulk Data export ($export)
-fhir-declaresstring—guides this FHIR server declares in its capability statement, comma-separated: a CapabilityStatement address, or Type=profile addressSettings › FHIR › Capability statement: Guides this server declares
-fhir-max-resourcesint—for a public server: refuse new FHIR resources once this many are held (0: no limit)Settings › FHIR › Access: Most resources held
-fhir-member-match-without-consenton/off—let $member-match answer without an active Consent; the Payer-to-Payer API is opt-in, so only for testingSettings › Payers › CMS-0057-F: Answer $member-match without the member's consent
-fhir-openon/off—serve the FHIR endpoint with no authentication at all, exposing every stored recordSettings › FHIR › Access: Let anyone read the FHIR endpoint without signing in
-fhir-patient-directory-searchon/off—let a token limited to one patient search the directory (practitioners, organisations, locations) within its scopesSettings › FHIR › Access: Let a patient's app search the directory
-fhir-payer-apison/off—enable the CMS-0057 payer operations: $member-match (Payer-to-Payer) and Group $davinci-data-export (Provider Access); the Group exports also need -fhir-bulk-exportSettings › Payers › CMS-0057-F: The CMS-0057-F payer APIs
-fhir-read-onlyon/off—refuse writes to the FHIR endpointSettings › FHIR › Access: Refuse writes to the FHIR endpoint
-fhir-subscriptionson/off—enable topic-based subscriptions, which send encounter and appointment notifications to URLs FHIR clients chooseSettings › FHIR › Notifications: FHIR subscriptions (encounter and appointment notifications)
-fhir-subscriptions-allow-httpon/off—let subscriptions deliver to plain-http endpoints; for a test receiver, never for patient data on a networkSettings › FHIR › Notifications: Allow subscriptions to notify plain-HTTP addresses
-fhir-versionstring4.0.1FHIR release to serve: R4, R4B or R5Settings › FHIR › The FHIR server: FHIR version clients see
-fhir-writes-per-minuteint—for a public server: writes one client address may make to the FHIR endpoint a minute (0: no limit)Settings › FHIR › Access: Writes a minute from one client
-fleet-labelstring—how this instance names itself in a fleet view (default: hostname)Settings › Fleet › This server: Name for this server
-formularystring—publish this drug formulary over the Da Vinci US Drug Formulary API at /formulary/fhir and answer NCPDP Real-Time Prescription Benefit and SCRIPT electronic prior authorization from itSettings › Payers › Drug formulary: Drug formulary file
-icd11-client-idstring—a WHO ICD API client: ICD-11 codes not imported are looked up thereSettings › Data › Code systems: WHO ICD API client ID
-icd11-client-secretstring—the WHO ICD API client's secretSettings › Data › Code systems: WHO ICD API client secret
-icd11-releasestring2025-01the ICD-11 MMS release the WHO ICD API is asked aboutSettings › Data › Code systems: ICD-11 release to ask for
-icd11-urlstring—the ICD API's address when it is not the WHO's: the WHO's ICD-API container on your network needs no clientSettings › Data › Code systems: ICD API address
-index-identityon/offtrueindex patient identifiers from message contents so a message can be found by MRN, name or accession in any format; has no effect when -store-payloads is offSettings › Data › What is kept: Index patient identifiers
-insecureon/off—serve over plain HTTP on a non-loopback address (not recommended)—
-inventorystring—write a Markdown inventory of every interface to this file, and keep it currentSettings › Monitoring › Inventory: Write an interface inventory to
-inventory-everyduration24h0m0show often to rewrite the interface inventorySettings › Monitoring › Inventory: Rewrite the inventory every
-json-logson/off—emit structured JSON logsSettings › Monitoring › Logging: Write logs as JSON
-ldapstring—YAML file configuring directory (LDAP) sign-in (default: ldap.yaml beside the database, once saved in the console)—
-log-filestring—append the log, and the first administrator's one-time password, to this file (mode 0600) instead of the console. A Windows service has no console, so there it defaults to perfuse.log beside the database—
-mcpon/off—serve the Model Context Protocol at /mcp, so AI agents with an API token can read status, messages, the queue, alerts and the FHIR store with that token's own accessSettings › Security › AI agents (MCP): Let AI agents connect over MCP
-measure-reporterstringPerfusethe reporting organisation's name on MeasureReports from $evaluate-measure when the request names no reporter—
-metrics-openon/off—serve /metrics to anybody who can reach the port. Only safe where that port is genuinely private: metric labels name your channels, and on a multi-tenant server they name every tenant'sSettings › Security › Metrics: Serve /metrics without a token
-metrics-tokenstring—credential the Prometheus scrape endpoint requires. Give the scraper the same value in bearer_token_file. Without this, only a signed-in operator can read /metricsSettings › Security › Metrics: Token a metrics scraper presents
-mpion/off—keep a patient index (master patient index) in mpi.db beside the database: patient records from every system linked into one enterprise identifier per person, fed by mpi destinations and the PIX v3 identity feed, answering Patient/$match, PIXm, PIX v3 (/pixv3) and PDQ v3 (/pdqv3)Settings › Data › Patient index: Keep a patient index
-multi-tenanton/off—keep each tenant's channels in their own subdirectory of -channels, so one server can run integration for several organisations without them being able to see each other—
-node-addressstring—this server's console URL as the other servers and a load balancer reach it—
-node-namestring—this server's name in the cluster (default: an id kept in -data)—
-oidcstring—YAML file configuring OpenID Connect sign-in (default: oidc.yaml beside the database, once saved in the console)—
-pason/off—serve Da Vinci PAS 2.2.1 and 2.1.0 (Claim/$submit, $inquire, $decide) on the FHIR endpoint; decisions come from -crd-rules, and what no rule decides is pended for a reviewer. With -fhir-subscriptions, the PAS topic delivers each pended request's resultSettings › Payers › Prior authorization: Da Vinci PAS prior authorization server
-pas-278-castring—a PEM file of certificate authorities to trust for the UM system beside the system'sSettings › Payers › Utilization management link: Certificate authorities to trust for the UM system
-pas-278-certstring—a PEM client certificate for X.509 mutual TLS with the UM system (CORE's authentication)Settings › Payers › Utilization management link: Client certificate file
-pas-278-core-receiverstring—the CORE envelope's ReceiverID, as the UM system's connectivity guide gives it (default: -pas-278-receiver)Settings › Payers › Utilization management link: CORE envelope ReceiverID
-pas-278-core-rule-versionstring—what to write in the CORE envelope's CORERuleVersion when the UM system's guide asks for something other than the version itself (CMS esMD's sample says v2.2.0)Settings › Payers › Utilization management link: CORERuleVersion written in the envelope
-pas-278-core-senderstring—the CORE envelope's SenderID, as the UM system's connectivity guide gives it (default: -pas-278-sender)Settings › Payers › Utilization management link: CORE envelope SenderID
-pas-278-core-versionstring2.2.0the CAQH CORE Connectivity Rule the UM system runs, for core-soap and core-mime: 2.2.0 (payload in the envelope) or C4.0.0 (payload as an MTOM attachment; SOAP only)Settings › Payers › Utilization management link: CAQH CORE Connectivity Rule
-pas-278-keystring—the private key (PEM) for -pas-278-certSettings › Payers › Utilization management link: Client certificate key file
-pas-278-oauth-client-idstring—the OAuth client ID for -pas-278-oauth-token-urlSettings › Payers › Utilization management link: OAuth client ID
-pas-278-oauth-scopestring—the scope asked for with the OAuth token, when the UM system wants oneSettings › Payers › Utilization management link: OAuth scope
-pas-278-oauth-secret-envstring—name of an environment variable holding the OAuth client secret (the secret itself is never a flag)Settings › Payers › Utilization management link: Environment variable holding the OAuth client secret
-pas-278-oauth-token-urlstring—an OAuth 2.0 token endpoint: a token got with the client-credentials grant is sent as a bearer token (CORE vC4.0.0's authorization)Settings › Payers › Utilization management link: OAuth token endpoint
-pas-278-password-envstring—name of an environment variable holding the password for -pas-278-user (the password itself is never a flag)Settings › Payers › Utilization management link: Environment variable holding the password
-pas-278-payer-idstring—the UMO's payer ID (NM1*X3) when the request's insurer carries no identifierSettings › Payers › Utilization management link: Payer ID for the 278s
-pas-278-productionon/off—mark the 278s sent as production (ISA15 P) rather than testSettings › Payers › Utilization management link: Mark the 278s as production
-pas-278-receiverstring—ISA08/GS03 receiver ID on the 278s sent to the UM systemSettings › Payers › Utilization management link: Receiver ID on the 278s
-pas-278-senderstringPERFUSEISA06/GS02 sender ID on the 278s sent to the UM systemSettings › Payers › Utilization management link: Sender ID on the 278s
-pas-278-sftpstring—host:port of the UM system's SFTP server, for -pas-278-transport sftpSettings › Payers › Utilization management link: SFTP server
-pas-278-sftp-everyduration1m0show often the SFTP inbound folder is readSettings › Payers › Utilization management link: Read the SFTP inbound folder every
-pas-278-sftp-inboundstring—the SFTP folder the UM system's 278 responses, 999s and TA1s are collected fromSettings › Payers › Utilization management link: SFTP inbound folder
-pas-278-sftp-keystring—an OpenSSH private key file for the SFTP user, instead of a passwordSettings › Payers › Utilization management link: SFTP key file
-pas-278-sftp-known-hostsstring—an OpenSSH known_hosts file holding the SFTP server's key; required, so requests never go to whoever answersSettings › Payers › Utilization management link: SFTP known_hosts file
-pas-278-sftp-outboundstring—the SFTP folder the 278 requests (and the 999s for the answers) are put inSettings › Payers › Utilization management link: SFTP outbound folder
-pas-278-sftp-password-envstring—name of an environment variable holding the SFTP password (the password itself is never a flag)Settings › Payers › Utilization management link: Environment variable holding the SFTP password
-pas-278-sftp-userstring—the SFTP user nameSettings › Payers › Utilization management link: SFTP user
-pas-278-token-envstring—name of an environment variable holding a bearer token for the UM system (the token itself is never a flag)Settings › Payers › Utilization management link: Environment variable holding the token
-pas-278-transportstringx12how the 278s reach the UM system: x12 (POSTed as application/edi-x12), core-soap (a CAQH CORE SOAP envelope), core-mime (CAQH CORE HTTP MIME multipart), or sftp (batch files over -pas-278-sftp, answers collected from its inbound folder)Settings › Payers › Utilization management link: How the 278s travel
-pas-278-urlstring—forward every PAS request to the payer's utilization management system as an X12 278 request sent to this URL (by -pas-278-transport), and answer with its 278 response; later 278 responses go to Claim/$decide-278Settings › Payers › Utilization management link: Send PAS requests on to the UM system at
-pas-278-userstring—user name for the UM system: CORE's UserName (WS-Security UsernameToken in SOAP), or HTTP Basic for x12Settings › Payers › Utilization management link: User name
-pas-decider-castring—a PEM file of certificate authorities to trust for -pas-decider-url beside the system's, such as the payer's own authority or the decision service's (Vaglio's is its DATA/tls/ca.crt)Settings › Payers › Decision service: Certificate authorities to trust for the decision service
-pas-decider-token-envstring—name of an environment variable holding a bearer token for -pas-decider-url (the token itself is never a flag)Settings › Payers › Decision service: Environment variable holding the decision service's token
-pas-decider-urlstring—ask the decision service at this URL (such as Vaglio) to decide each PAS item on the request's clinical evidence, when -crd-rules leave it to a reviewer; the PAS request Bundle is POSTed to it. Cannot be combined with -pas-278-urlSettings › Payers › Decision service: Decision service URL
-passkey-allowed-modelsstring—comma-separated authenticator AAGUIDs that may enrol; requires -passkey-attestation-roots—
-passkey-attestation-rootsstring—a PEM file of authenticator vendor certificates; passkey attestation is verified against these—
-passkey-domainstring—the bare domain passkeys are registered for, such as perfuse.example.org. No scheme, no port, no path. Setting it turns passkeys on; leaving it empty leaves them offSettings › Sign-in › Passkeys: Domain passkeys are bound to
-passkey-namestringPerfusethe name an authenticator shows a person when they register a passkeySettings › Sign-in › Passkeys: Name shown on the device
-passkey-originsstring—comma-separated origins the console is reached at, with scheme and port: https://perfuse.example.org. Defaults to https:// plus the domainSettings › Sign-in › Passkeys: Other origins passkeys are accepted from
-peersstring—YAML file listing other Perfuse instances to show in a fleet viewSettings › Fleet › Fleet: Other Perfuse servers to show (file)
-public-urlstring—the https address patients' phones and other organisations reach this server at, for the SMART Health Links it hosts (default: the listen address)Settings › FHIR › The FHIR server: Address others reach this server at
-rctcstring—eCR trigger codes for the case report preview: a FHIR ValueSet or Bundle of them, such as the eRSDSettings › Public health › Case reporting: Trigger codes file (RCTC or eRSD)
-residencystring—cloud regions this server's data may go to or come from: areas (eea, uk, ch) and region codes (eu-central-1), comma-separated; channels with connectors elsewhere are refusedSettings › Data › Data protection: Where data may go (cloud regions)
-retention-daysint30how long to keep recorded messages; 0 keeps them for ever, which will eventually fill the diskSettings › Data › How long it is kept: Delete records after
-samlstring—YAML file configuring SAML 2.0 sign-in (default: saml.yaml beside the database, once saved in the console)—
-scimon/off—accept SCIM 2.0 provisioning from an identity provider at /scim/v2. Okta, Entra ID and Google Workspace use it to create accounts and, more importantly, to disable them when somebody leavesSettings › Sign-in › Automatic accounts: Let the identity provider manage accounts
-scim-default-rolestringviewerrole for an account the identity provider does not describe. Defaults downward on purpose: an account whose role could not be determined should be able to read and nothing else—
-settingsstring—settings file the web interface may edit (default: perfuse-settings.yaml beside the database)—
-shl-allow-httpon/off—let a received SMART Health Link point at plain HTTP; for testing onlySettings › Public health › Health links: Allow SMART Health Links over plain HTTP
-signing-certstring—certificate for signing documents (defaults to -tls-cert)Settings › Security › Document signing: Certificate for signing documents
-signing-keystring—key for signing documents (defaults to -tls-key)Settings › Security › Document signing: Key for signing documents
-smart-audiencestring—the audience a SMART token must be issued for, normally the FHIR base URLSettings › SMART › Authorization: Audience tokens must name
-smart-authorizestring—the authorization endpoint to advertise to SMART appsSettings › SMART › Authorization: Authorization endpoint
-smart-backend-serviceson/off—advertise that the SMART authorization server issues backend-services (client_credentials, signed JWT) tokensSettings › SMART › Built-in server: Backend Services (system-to-system tokens)
-smart-clientsstring—run Perfuse's own SMART authorization server at /auth for the apps registered in this YAML fileSettings › SMART › Built-in server: Registered apps file (turns on the built-in server)
-smart-issuerstring—accept SMART on FHIR access tokens from this authorization serverSettings › SMART › Authorization: Accept SMART access tokens from this authorization server
-smart-jwksstring—where to fetch the SMART issuer's signing keys, when not from its published metadata (split DNS, a private address)Settings › SMART › Authorization: Key set file
-smart-jwks-uristring—the authorization server's public key set URL, advertised to SMART apps (needed to claim OpenID Connect sign-in)Settings › SMART › Authorization: Key set address
-smart-keystringsmart-signing.keythe built-in authorization server's RSA signing key (PEM, mode 0600), created if missingSettings › SMART › Built-in server: Signing key file
-smart-oidcstring—with -smart-users, let people sign in at this OpenID Connect provider (YAML: issuer, client_id, client_secret_file or client_secret_env, label); each is linked by oidc_subjectSettings › SMART › Built-in server: Sign people in through the OpenID Connect provider
-smart-tokenstring—the token endpoint to advertise to SMART appsSettings › SMART › Authorization: Token endpoint
-smart-usersstring—with -smart-clients, the people who may sign in to authorize apps (YAML: username, password_hash, fhir_user)Settings › SMART › Built-in server: People who sign in to authorize apps (file)
-snmp-allowstring—comma-separated networks or addresses the SNMP agent answers, such as 10.0.5.0/24; required with -snmp-listenSettings › Monitoring › SNMP: Networks that may ask
-snmp-base-oidstring1.3.6.1.4.1.8072.9999.9999.16, Net-SNMP's experimental spacewhere Perfuse's values sit, under your enterprise numberSettings › Monitoring › SNMP: Base OID
-snmp-communitystring—the SNMPv2c community (a password sent in clear: at least 6 characters, not public or private)Settings › Monitoring › SNMP: SNMP community
-snmp-contactstring—sysContact the SNMP agent reportsSettings › Monitoring › SNMP: Contact (sysContact)
-snmp-listenstring—answer SNMPv2c GET/GETNEXT/GETBULK on this UDP address, such as :161 (off when empty). Read-only: channel states, counts and queue depthsSettings › Monitoring › SNMP: Answer SNMP on this address
-snmp-locationstring—sysLocation the SNMP agent reportsSettings › Monitoring › SNMP: Location (sysLocation)
-snmp-trapsstring—comma-separated managers (host or host:port, default port 162) that receive an SNMPv2 trap when an alert fires or resolvesSettings › Monitoring › SNMP: Send traps to
-store-messageson/offtruerecord every message handled, which is what makes the message browser workSettings › Data › What is kept: Keep a record of each message
-store-payloadson/offtruestore message contents as well as their outcomes; turn this off where PHI must not be held at restSettings › Data › What is kept: Keep message contents
-tls-certstring—TLS certificate fileSettings › Security › Encryption: TLS certificate file
-tls-keystring—TLS private key fileSettings › Security › Encryption: TLS private key file
-trace-endpointstring—OTLP/HTTP base URL to export message traces to, for example http://localhost:4318Settings › Monitoring › Tracing: Send traces to
-trace-instancestring—name for this instance in traces; defaults to the hostname, which is what distinguishes replicasSettings › Monitoring › Tracing: This instance's name in traces
-trace-samplefloat1fraction of traces to record, 0 to 1—
-tsa-urlstring—RFC 3161 time-stamping authority for DSDR signatures on claims attachmentsSettings › Security › Document signing: Time-stamping authority
-vpnstring—partner VPN tunnels to report on the Connections dashboard (YAML: AWS Site-to-Site VPN, Azure VPN Gateway or strongSwan, and both sides' settings); see examples/vpn.yamlSettings › Monitoring › Connections: VPN tunnels to watch (file)
-watch-accesson/offtruewatch traffic and reads of patient data for what a breach looks like (bursts, night traffic, new destinations, bulk reads) and raise alerts—
-xdsstring—keep clinical documents here as an IHE XDS.b registry and repository with this repository uniqueId (an OID), answering ITI-41, ITI-42, ITI-18 and ITI-43 at /xds/repository and /xds/registrySettings › Data › Document sharing (IHE XDS): Keep documents here as an XDS registry and repository
-xds-home-communitystring—this community's home community id (urn:oid:...), so /xca/gateway answers XCA ITI-38 and ITI-39 for itSettings › Data › Document sharing (IHE XDS): Home community id, for XCA

21 Referência de Canal

Toda chave que pode aparecer no nível superior de um ficheiro de canal. Estas são extraídas da fonte, por isso este capítulo não pode descrever uma opção que não existe ou omitir uma que existe.

21.1 Canal

Canal é um fluxo de mensagens configurado: somewhere as mensagens chegam, um filtro opcional e um ou mais lugares para onde elas vão.

Definido como Channel em internal/config.

ChaveTipoObrigatórioPredefinição
nametextosim—
descriptiontextonão—
grouptextonão—
attachmentsAnexos (um bloco, omitir para não incluir)não—
delimitedDelimitado (um bloco, omitir para não incluir)não—
tableslista de textonão—
contractContractRef (um bloco, omitir para não incluir)não—
enabledverdadeiro ou falso (um bloco, omitir para não incluir)não—
dataTypeDataTypenãohl7
hl7v3HL7v3Options (um bloco, omitir para não incluir)não—
x12X12Options (um bloco, omitir para não incluir)não—
ncpdpNCPDPOptions (um bloco, omitir para não incluir)não—
edifactEDIFACTOptions (um bloco, omitir para não incluir)não—
scriptScriptOptions (um bloco, omitir para não incluir)não—
dicomDICOMOptions (um bloco, omitir para não incluir)não—
sourceFontesim—
filtertextonão—
transformationslista de transform.Stepnão—
scriptsScripts (um bloco, omitir para não incluir)não—
shadowShadow (um bloco, omitir para não incluir)não—
destinationslista de Destinosim—

21.1.1 nome

O nome identifica o canal nos registos e métricas.

Obrigatório e único.

21.1.2 grupo

O grupo é o que este canal faz parte, para organizar uma lista que cresceu demais para ler.

Cosmético em cinco canais e estrutural em duzentos: os canais de um site dividem-se pelo sistema com que falam, ou pela equipa que os possui, e uma lista plana de duzentos nomes é inutilizável, por mais boa que seja a restante interface.

Uma string simples em vez de um objeto de grupo com o seu próprio ficheiro, porque um grupo não tem comportamento. No momento em que tem um ficheiro, adquire configurações, e configurações em um grupo significam que o comportamento de um canal depende de algo que não está escrito no canal - o que é a propriedade que torna a configuração do Mirth difícil de raciocinar.

21.1.3 anexos

Anexos move grandes cargas úteis para fora da mensagem e as coloca de volta antes da entrega.

Opt-in por canal: uma alimentação de mensagens ADT simples não tem nada a extrair e não deve pagar pela maquinaria.

21.1.4 delimitado

Delimitado configura um canal delimitado.

Apenas significativo quando o tipo de dados é delimitado.

21.1.5 tabelas

Tabelas nomina ficheiros de tabelas de mapeamento compartilhadas que uma transformação pode referenciar por nome.

Compartilhadas porque o domínio tax é em grande parte re-derivar um mapeamento que alguém já derivou: os códigos de sexo e classes de paciente de um site são traduzidos identicamente em todos os canais que os tocam, e uma tabela dentro de um canal é uma tabela que apenas esse canal pode usar.

21.1.6 ativado

Ativado é verdadeiro por predefinição.

Um canal desativado é carregado e validado, mas não iniciado, por isso um ficheiro que está temporariamente desativado ainda é verificado pelo CI.

21.1.7 tipo de dados

O tipo de dados é o formato das mensagens que este canal recebe.

O valor padrão é hl7, por isso todos os canais escritos antes da existência deste continuam funcionando.

21.1.8 x12

X12 contém as configurações que só têm significado em um canal X12.

Defini-lo em qualquer outro tipo é recusado em vez de ignorado.

21.1.9 script

O script configura um canal NCPDP SCRIPT.

As etapas vivem aqui em vez de nas transformações de nível superior para a mesma razão que todos os outros formatos não v2: os tipos de etapas diferem por formato, então uma chave significaria coisas diferentes dependendo do tipo de dados.

21.1.10 dicom

A configuração de imagem configura as etapas de transformação nomeadas de um canal DICOM.

Imagem nomeada em vez de DICOM porque Origem e Destino já têm um campo DICOM e três campos com o mesmo nome em níveis diferentes é como alguém define o errado. A chave yaml é dicom, que é o que uma pessoa que escreve o arquivo espera, e o nome Go é o que impede um erro no local da chamada.

21.1.11 filtro

O filtro é uma expressão que deve ser válida para que uma mensagem seja encaminhada.

Uma mensagem que não corresponde ainda é reconhecida: o remetente não fez nada de errado, simplesmente não estamos interessados.

21.1.12 transformações

As transformações são alterações declarativas aplicadas às mensagens aceitas, em ordem, antes de qualquer script ser executado.

Esta é a camada destinada a realizar o trabalho comum: cada etapa é validada quando o arquivo é carregado, aparece em uma diferença e pode ser revisada por alguém que não lê JavaScript.

21.1.13 scripts

Os scripts contêm JavaScript para os casos em que as etapas declarativas não podem ser expressas e é onde os scripts de um canal Mirth são inseridos sem alterações.

Um canal com um script é marcado como tal na interface, porque seu comportamento não pode ser estabelecido apenas lendo a configuração.

21.1.14 sombra

A sombra executa uma versão candidata deste canal ao lado e relata onde eles diferem.

Nada do que ela faz pode alcançar um receptor.

22 Referência de Origem

Toda a forma como um canal pode receber mensagens e cada chave que cada um aceita. Um canal tem exatamente uma origem.

22.1 Origem AMQP

A Origem AMQP recebe de uma fila ou assinatura.

Uma mensagem é aceita apenas após o canal tê-la processado. Uma que não pôde ser processada é liberada como uma entrega falha, para que o broker a redelivery e - no Service Bus, após o limite de entrega máximo da fila - a coloque em letras mortas.

Definido como AMQPSource em internal/config.

ChaveTipoObrigatórioPadrão
prefetchnúmero inteironão10
reconnectduração, como 30s ou 5mnão5s

22.1.1 prefetch

Prefetch é o número de mensagens que o broker pode enviar antecipadamente.

O valor padrão é 10. Elas ainda são processadas uma a uma, em ordem.

22.1.2 reconnect

Reconnect é o tempo de espera após uma conexão perdida.

Defaults to 5s.

22.2 Origem AS2

A Origem AS2 recebe AS2 (RFC 4130): EDI publicado sobre HTTP, assinado e criptografado com S/MIME, respondido com um recibo (um MDN) que contém um resumo do que chegou.

A carga útil é o que o canal processa; X12 e EDIFACT são os usuais.

Definido como AS2Source em internal/config.

ChaveTipoObrigatórioPadrão
listentextosim—
pathtextonão—
tlstlsconf.Settings (um bloco, omitir para deixar de fora)não—
idtextosim—
cert_filetextosim—
key_filetextosim—
partnerslista de AS2Partnersim—
max_message_sizenúmero inteironão—
duplicate_windowduração, como 30s ou 5mnão—

22.2.1 path

Path é o caminho da URL que os parceiros publicam.

Default /as2.

22.2.2 tls

TLS serve HTTPS.

A maioria dos parceiros exige isso em seu acordo, além do S/MIME.

22.2.3 id

ID é o nosso identificador AS2, que os parceiros enviam em AS2-To.

Uma mensagem para qualquer outro é recusada.

22.2.4 parceiros

Os parceiros são quem pode enviar aqui.

Uma mensagem de qualquer outra pessoa é recusada.

22.2.5 janela_de_duplicados

DuplicateWindow é o tempo durante o qual o ID de mensagem de um parceiro é lembrado, para que uma mensagem enviada novamente (o parceiro nunca recebeu nosso recibo e tentou novamente) seja respondida com um recibo e não seja transmitida duas vezes (RFC 4130 seção 7.5).

Default 30 days.

22.3 Origem do Azure Blob

AzureBlobSource recolhe blobs de um prefixo de contêiner.

Definido como AzureBlobSource em internal/config.

ChaveTipoObrigatórioPadrão
prefixtextosim—
suffixtextonão—
after_readtextonão—
move_totextonãoprocessado/
error_prefixtextonãoerro/
poll_intervalduração, como 30s ou 5mnão30s
max_object_sizenúmero inteironão16 MiB
framedverdadeiro ou falsonão—

22.3.1 mover_para

MoveTo é onde um blob tratado se move.

Padrão é processado/.

22.3.2 prefixo_de_erro

ErrorPrefix é onde um blob que não pode ser tratado se move, para que não bloqueie o restante.

Padrão é erro/.

22.3.3 intervalo_de_poll

PollInterval entre listagens.

Defaults to 30s.

22.3.4 tamanho_máximo_de_objeto

MaxObjectSize recusa um blob maior, que é deixado onde está.

Padrão é 16 MiB.

22.4 Origem do Corretor

BrokerSource lê mensagens de um corretor de mensagens.

Leitor JMS do Mirth, alcançado via STOMP porque JMS é uma API Java em vez de um protocolo. Veja internal/stomp para saber por que STOMP e não OpenWire.

Definido como BrokerSource em internal/config.

ChaveTipoObrigatórioPadrão
addrtextosim—
destinationtextosim—
logintextonão—
passcodetextonão—
hosttextonãoo host do endereço
selectortextonão—
subscription_idtextonãoo nome do canal
heartbeatduração, como 30s ou 5mnãotrinta segundos
reconnectduração, como 30s ou 5mnãocinco segundos
timeoutduração, como 30s ou 5mnãotrinta segundos
tlstlsconf.Settings (um bloco, omitir para não utilizar)não—

22.4.1 addr

Addr é o host e porta do broker.

Obrigatório. 61613 é a porta STOMP usual.

22.4.2 destino

Destino é a fila ou tópico a ler.

Required.

Os brokers soletram estes de forma diferente - /queue/nome no ActiveMQ, um nome simples no RabbitMQ - por isso é passado sem alterações em vez de ser montado aqui. Adivinhar significaria trabalhar contra um broker e ler silenciosamente nada em outro.

22.4.3 iniciar sessão

Iniciar sessão e Código de Acesso autenticam.

A maioria dos brokers recusa uma conexão anônima.

22.4.4 código de acesso

Iniciar sessão e Código de Acesso autenticam.

A maioria dos brokers recusa uma conexão anônima.

22.4.5 host

Host é o host virtual.

O valor padrão é o host do endereço.

22.4.6 seletor

Seletor filtra mensagens no broker.

Um seletor JMS, passado sem interpretação. A filtragem no broker em vez de aqui significa que as mensagens que este canal não deseja nunca cruzam a rede - o que, em uma fila compartilhada, é a diferença entre ler cem mensagens por dia e cem mil.

22.4.7 id_de_assinatura

ID de Assinatura nomeia a assinatura.

O valor padrão é o nome do canal.

Nomeado em vez de gerado, porque uma assinatura durável é identificada por ele: um gerado criaria uma nova assinatura em cada inicialização e deixaria as antigas acumulando mensagens que ninguém lê.

22.4.8 sinal de vida

Sinal de vida mantém a conexão ativa.

O valor padrão é trinta segundos.

Ativado por padrão aqui, ao contrário do padrão próprio do cliente, porque uma fonte mantém uma conexão aberta por semanas. Sem sinais de vida, uma conexão através de um firewall que silenciosamente dropou a rota parece perfeitamente saudável deste lado e as mensagens simplesmente param de chegar, sem nada registrado.

22.4.9 reconnect

Reconectar é quanto tempo esperar antes de reconectar após uma falha.

O valor padrão é cinco segundos.

22.4.10 tempo de expiração

Limites de tempo de expiração ao conectar.

O valor padrão é trinta segundos.

22.5 Fonte de Consulta DICOM

DICOMQuerySource consulta um arquivo com C-FIND e emite uma mensagem por novo estudo.

Mirth não tem um conector equivalente. O seu suporte DICOM é um ouvinte e um remetente - pode receber imagens enviadas para ele e enviá-las, e é tudo. Pedir a um arquivo o que ele contém foi solicitado nos fóruns desde 2015.

O que o torna valioso não é a consulta, é a automação: uma pré-busca que é executada às três da manhã, uma reconciliação que nota que o arquivo está faltando um estudo que o RIS diz existir, uma lista de trabalho construída com base no que foi realmente digitalizado em vez do que foi pedido. Esses são trabalhos que os sites atualmente fazem com um script agendado fora do motor, o que significa que eles são invisíveis para ele - sem repetições, sem alertas, sem histórico de mensagens.

Definido como DICOMQuerySource em internal/config.

ChaveTipoObrigatórioPadrão
addresstextosim—
called_aetextosim—
calling_aetextonão—
leveltextonãoESTUDO
patient_rootverdadeiro ou falsonão—
matchmapeamento de texto para textonão—
returnlista de textonão—
intervalduração, como 30s ou 5msim—
windowduração, como 30s ou 5mnão—
overlapduração, como 30s ou 5mnãouma hora
limitnúmero inteironão500
timeoutduração, como 30s ou 5mnãodois minutos
tlstlsconf.Settings (um bloco, omitir para deixar de lado)não—
emit_on_first_pollverdadeiro ou falsonãofalso

22.5.1 endereço

O endereço é o host e a porta do arquivo.

Required.

Nomeado para corresponder ao destino DICOM em vez de abreviado. Os dois foram "endereço" e "addr" por uma tarde, o que é o tipo de inconsistência que alguém escrevendo um arquivo de canal à mão erra uma vez e então desconfia de todo o formato.

22.5.2 called_ae

CalledAE é o título AE do arquivo.

Obrigatório na prática: a maioria dos arquivos recusa uma associação endereçada a qualquer outra coisa, e essa recusa lê como uma interrupção em vez de um erro de configuração.

22.5.3 calling_ae

CallingAE é o título AE que Perfuse apresenta.

Os arquivos comumente usam-no para controle de acesso.

22.5.4 nível

O nível é o nível de consulta: PACIENTE, ESTUDO, SÉRIE ou IMAGEM.

Padrão é ESTUDO.

ESTUDO é o padrão porque é o que quase todas as consultas úteis desejam e porque as alternativas surpreendem as pessoas: nível de IMAGEM contra um grande CT retorna uma resposta por fatia, o que é centenas por estudo.

22.5.5 correspondência

As correspondências são as chaves de consulta.

Um valor filtra; um valor vazio pede que o campo seja retornado.

As chaves são nomeadas em vez de numeradas - "PatientID" em vez de "0010,0020" - porque um arquivo de canal é lido por pessoas, e um número de tag em um arquivo de configuração é uma pesquisa que cada leitor tem que realizar.

22.5.6 retornar

Retornar são campos para trazer de volta sem filtrar neles.

Separado de Combinação com um valor vazio, mesmo que eles codifiquem identicamente, porque a intenção difere e um leitor pode ver quais chaves estão restringindo a pesquisa e quais estão sendo coletadas.

22.5.7 intervalo

Intervalo é com que frequência sondar.

Required.

22.5.8 janela

Janela é até onde cada sondagem olha, como uma data de estudo.

Zero desativa completamente o filtro de data.

Uma janela é o que mantém isso limitado. Sem uma, cada sondagem pede ao arquivo tudo o que ele já possuiu e, em seguida, descarta o que já foi visto antes - o que funciona em um arquivo de teste e é antisocial contra um arquivo real que contém milhões de estudos.

22.5.9 sobreposição

Sobreposição reconsulta este período já sondado.

Padrão é de uma hora.

Necessário, em vez de cauteloso. Um estudo pode ser registrado com a data de ontem, o nosso relógio e o do arquivo não precisam concordar, e uma fronteira de sondagem que se alinha exatamente com uma chegada perde-o. A sobreposição repergunta, e o controle de já visto impede a duplicata - então o custo da sobreposição é uma consulta ligeiramente maior e o custo de não sobrepor é um estudo perdido em silêncio.

22.5.10 limite

Limite limita as combinações aceitas de uma sondagem.

Defaults to 500.

Um limite em vez de nenhum limite porque uma chave de combinação mal digitada transforma isso em "me dê tudo", e o primeiro sintoma disso contra um arquivo real é o administrador do arquivo perguntar quem está martelando-o.

22.5.11 tempo de expiração

Tempo limite limita uma sondagem.

Padrão é de dois minutos.

22.5.12 emitir_na_primeira_sondagem

EmitirNaPrimeiraSondagem envia mensagens para tudo o que a primeira sondagem encontra.

Padrão é falso.

Falso importa. Apontar isso para um arquivo que já contém um milhão de estudos e fazê-lo emitir uma mensagem para cada um não é uma execução útil inicial, e é o tipo de erro que é notado a jusante em vez de aqui. A primeira sondagem registra o que existe e emite nada; a segunda sondagem em diante relata o que é novo.

22.6 Fonte DICOM

FonteDICOM recebe objetos de imagem como um provedor de serviço de classe C-STORE.

O que um hospital aponta uma modalidade ou um PACS. Mirth chama isso de Ouvinte DICOM e faz apenas C-STORE, então isso é paridade em vez de um subconjunto.

Definido como DICOMSource em internal/config.

ChaveTipoObrigatórioPadrão
listentextosim—
ae_titletextonão—
allowed_calling_aelista de textonão—
sop_classeslista de textonão—
transfer_syntaxeslista de textonão—
max_object_bytesnúmero inteironão—
idle_timeoutduração, como 30s ou 5mnão—
tlstlsconf.Settings (um bloco, omitir para não incluir)não—

22.6.1 listen

Listen é o endereço para servir.

Obrigatório. 104 é a porta DICOM registrada; 11112 é a alternativa comum onde a ligação a uma porta privilegiada não é possível.

22.6.2 ae_title

AETitle é como este endpoint se chama.

Fortemente recomendado em vez de obrigatório e advertido quando ausente. O controle de acesso de um endpoint DICOM é frequentemente apenas o título AE, então um endpoint que aceita qualquer título aceita qualquer coisa que possa alcançá-lo.

22.6.3 allowed_calling_ae

AllowedCallingAE lista os títulos AE permitidos para se conectar.

Vazio aceita qualquer chamador.

Este é o controle de acesso que o DICOM realmente tem. Um PACS é frequentemente configurado para aceitar um título de chamada nomeado e rejeitar tudo o mais, e esta extremidade não tinha equivalente: o título chamado foi verificado - que é o nome que o chamador discou, então qualquer pessoa pode enviá-lo corretamente - enquanto quem estava chamando foi registrado no log e ignorado em seguida.

Vazio ainda aceita qualquer coisa, porque uma modalidade que ninguém lista é o estado normal de uma instalação inicial e recusar por padrão quebraria todos os deploys no dia um. Em vez disso, ele avisa e o aviso nomeia os títulos que se conectaram para que alguém possa preencher isso com base no que realmente chegou.

22.6.4 sop_classes

SOPClasses restringe os tipos de objeto a aceitar.

Vazio aceita qualquer.

Vazio é um padrão razoável aqui porque este motor relata objetos em vez de interpretá-los, então recusar uma classe desconhecida recusaria imagens válidas sem benefício.

22.6.5 transfer_syntaxes

TransferSyntaxes restringe as codificações a aceitar, em ordem de preferência.

Vazio aceita os três não comprimidos.

22.6.6 max_object_bytes

MaxObjectBytes define um limite para um objeto recebido.

Zero aplica um padrão.

22.6.7 idle_timeout

IdleTimeout fecha uma associação que ficou silenciosa.

Zero significa nunca, o que é geralmente correto - uma modalidade mantém uma associação aberta entre estudos.

22.6.8 tls

O TLS criptografa as associações de entrada e pode exigir um certificado de cliente.

Vale a pena afirmar claramente: o Mirth precisa da sua extensão de Gerenciador de SSL pago para isso, e as bifurcações da comunidade não podem enviá-lo de forma alguma. O DICOM carrega nomes de pacientes em seus metadados, então este é um dos lugares onde ser uma reescrita em vez de uma bifurcação é uma vantagem real em vez de estilística.

22.7 Fonte Mweb DICO

DICOMwebSource aceita solicitações STOW-RS.

Definido como DICOMwebSource em internal/config.

ChaveTipoObrigatórioPadrão
listentextosim—
pathtextonão/dicom-web
tokentextonão—
usernametextonão—
passwordtextonão—
max_object_bytesnúmero inteironão—
tlstlsconf.Settings (um bloco, omitir para deixar de lado)não—

22.7.1 listen

Listen é o endereço para servir.

Required.

22.7.2 path

O caminho é a raiz do serviço.

Os objetos são aceitos em Path/estudos e Path/estudos/{uid}. O padrão é /dicom-web, que é o que o Orthanc e o dcm4chee usam, então um remetente configurado para qualquer um deles precisa apenas alterar o host.

22.7.3 token

O token, quando definido, é necessário como um token de portador.

O nome de usuário e a senha exigem autenticação básica HTTP.

22.7.4 nome de usuário

O token, quando definido, é necessário como um token de portador.

O nome de usuário e a senha exigem autenticação básica HTTP.

22.7.5 senha

O token, quando definido, é necessário como um token de portador.

O nome de usuário e a senha exigem autenticação básica HTTP.

22.8 Fonte de Banco de Dados

DatabaseSource lê linhas de um banco de dados e transforma cada uma delas em uma mensagem.

Esta é a forma como muitas interfaces hospitalares começam. Um sistema de departamento não tem capacidade HL7, então alguém escreve linhas em uma tabela de preparação e o motor de interface faz o poll. É sem glamour e está em todos os lugares.

Também é a forma mais comum de um canal Mirth parar, e o motivo é quase sempre a mesma forma: uma linha que não pode ser processada é lida, falha e é lida novamente, para sempre, porque nada a marcou. O canal parece estar vivo. A fila parece vazia. Nada se move, e cada mensagem atrás da linha ruim espera por uma linha que nunca terá sucesso.

A maior parte do design aqui é sobre isso.

Definido como DatabaseSource em internal/config.

ChaveTipoObrigatórioPadrão
drivertextosim—
dsntextosim—
querytextosim—
after_querytextonão—
key_columntextonão—
templatetextonão—
columntextonão—
poll_intervalduração, como 30s ou 5mnão—
batch_sizenúmero inteironão100
max_attemptsnúmero inteironão3
query_timeoutduração, como 30s ou 5mnão30s

22.8.1 driver

O driver nomeia o banco de dados.

See SupportedDrivers.

22.8.2 dsn

DSN é a string de conexão.

Prefira uma referência de variável de ambiente sobre um literal, porque normalmente contém uma palavra-passe e os canais são projetados para viver no git.

22.8.3 consulta

A consulta seleciona as linhas que estão à espera de serem enviadas.

Required.

Deve ser um SELECT. Uma sondagem que executa escritas silenciosamente seria executada em um cronograma sem registro do que foi alterado.

22.8.4 após_consulta

AfterQuery marca uma linha como processada e é executada com a chave da linha vinculada a ela.

Strongly recommended.

Sem isso, cada sondagem relê cada linha que a consulta ainda corresponde, por isso a consulta em si precisa excluir linhas processadas de alguma outra forma. Se nenhum dos dois for verdadeiro, o canal reenvia as mesmas linhas para sempre, o que é uma tempestade de duplicados em vez de uma paralisação e é, em última análise, pior.

22.8.5 coluna_chave

KeyColumn identifica uma linha para AfterQuery, quarentena e deduplicação.

Obrigatório quando AfterQuery estiver definido.

22.8.6 modelo

O modelo constrói uma mensagem a partir de uma linha.

Ou este ou Coluna é obrigatório.

As referências de coluna usam ${nome_coluna}. Colunas ausentes são um erro no carregamento em vez de uma cadeia vazia em uma mensagem clínica.

22.8.7 tamanho_lote

BatchSize limita as linhas tomadas por sondagem.

Defaults to 100.

Limitado porque uma primeira sondagem ilimitada contra uma tabela que alguém tem preenchido por um ano leria tudo em memória e, em seguida, enviaria tudo, o que é como uma migração inunda um receptor ao vivo.

22.8.8 tentativas_máximas

MaxAttempts é o número de vezes que uma linha única pode falhar antes de ser colocada em quarentena e a sondagem continuar.

Defaults to 3.

Esta é a configuração que impede a paralisação. Retentar para sempre não é resiliência; é uma linha ruim que impede um feed de hospital.

22.8.9 tempo_limite_consulta

QueryTimeout limita uma única sondagem.

Defaults to 30s.

22.9 Fonte Direta

DirectSource recebe correio direto que o HISP entrega: um ouvinte SMTP para o correio deste endereço.

Cada mensagem é decifrada, sua assinatura verificada contra os âncoras e seu signatário contra From, e seu conteúdo passado: um pacote XDM de documentos, caso contrário, cada anexo, caso contrário, o texto.

Definido como DirectSource em internal/config.

ChaveTipoObrigatórioPadrão
listentextonão—
tls_certtextonão—
tls_keytextonão—
max_bytesnúmero inteironão—
smtp_hosttextonão—
usernametextonão—
passwordtextonão—
imapDirectIMAP (um bloco, omitir para deixar de fora)não—
xdrDirectXDR (um bloco, omitir para deixar de fora)não—

22.9.1 smtp_host

SMTPHost, Username e Password são o servidor de envio do HISP, usado para enviar uma notificação de entrega "processada" (MDN) ao remetente uma vez que a mensagem tenha sido recebida.

Sem ele, nenhuma notificação é enviada.

22.9.2 nome de usuário

SMTPHost, Username e Password são o servidor de envio do HISP, usado para enviar uma notificação de entrega "processada" (MDN) ao remetente uma vez que a mensagem tenha sido recebida.

Sem ele, nenhuma notificação é enviada.

22.9.3 senha

SMTPHost, Username e Password são o servidor de envio do HISP, usado para enviar uma notificação de entrega "processada" (MDN) ao remetente uma vez que a mensagem tenha sido recebida.

Sem ele, nenhuma notificação é enviada.

22.10 Fonte de E-mail

EmailSource lê e-mails de uma caixa de correio e transforma anexos, corpos ou mensagens inteiras em mensagens.

Definido como EmailSource em internal/config.

ChaveTipoObrigatórioPadrão
protocoltextonão—
hosttextosim—
portnúmero inteironão—
securitytextonão—
tlstlsconf.Settings (um bloco, omitir para não incluir)não—
usernametextosim—
passwordtextonão—
oauthEmailOAuth (um bloco, omitir para não incluir)não—
mailboxtextonão—
taketextonão—
attachment_nameslista de textonão—
allowed_senderslista de textonão—
after_readtextonão—
move_totextonão—
error_foldertextonão—
poll_intervalduração, como 30s ou 5mnão—
max_message_sizenúmero inteironão—

22.10.1 senha

A senha pode ser ${ENV}; para o Gmail, uma senha de aplicativo.

Ignorado com oauth.

22.10.2 attachment_names

AttachmentNames limita quais anexos são recebidos, por padrão de nome de arquivo (*.hl7).

Vazio recebe todos os anexos.

22.10.3 allowed_senders

AllowedSenders limita cujos e-mails são lidos: endereços e domínios.

O cabeçalho From pode ser forjado, então isso mantém acidentes e e-mails casuais fora, não um atacante.

22.10.4 mover_para

MoveTo é a pasta para a qual os e-mails processados são movidos; Processed por padrão.

Criado quando faltante.

22.11 Fonte FTP

FTPSource coleta arquivos de um servidor FTP ou FTPS.

Por que o FTP ainda está aqui

Já se passaram trinta anos desde a sua substituição recomendada e muitos sistemas hospitalares ainda exportam para ele: aparelhos cujo firmware nunca será atualizado, sistemas de faturamento cujo fornecedor cobra por uma alteração. Recusar-se a falar com ele não faz com que esses sistemas desapareçam, significa que o motor de integração não pode ser usado.

FTPS é o padrão. É o mesmo protocolo com TLS, a maioria dos servidores sobreviventes o suporta e é uma conversa muito mais fácil com a equipe de segurança do que o FTP simples.

Definido como FTPSource em internal/config.

ChaveTipoObrigatórioPadrão
hosttextosim—
usertextonão—
passwordtextonão—
securityftpconn.Securitynãoexplícito
insecure_skip_verifyverdadeiro ou falsonão—
roottextonão—
timeoutduração, como 30s ou 5mnãotrinta segundos

22.11.1 host

O Host é o servidor, com uma porta opcional.

A porta 21 é assumida.

22.11.2 usuário

O usuário e a senha autenticam.

Ambos podem ser omitidos para um servidor anônimo.

O FTP anônimo ainda é como alguns feeds de referência pública são publicados, então um usuário vazio é uma configuração legítima em vez de uma omissão e não é recusado. Em um servidor que espera credenciais, omiti-las produz uma falha de login no momento da conexão, que é relatada contra o canal em vez de ser repetida silenciosamente.

22.11.3 senha

O usuário e a senha autenticam.

Ambos podem ser omitidos para um servidor anônimo.

O FTP anônimo ainda é como alguns feeds de referência pública são publicados, então um usuário vazio é uma configuração legítima em vez de uma omissão e não é recusado. Em um servidor que espera credenciais, omiti-las produz uma falha de login no momento da conexão, que é relatada contra o canal em vez de ser repetida silenciosamente.

22.11.4 segurança

A segurança é explícita, implícita ou nenhuma.

O padrão é explícito, que é FTPS negociado com AUTH TLS na porta comum. "nenhuma" é FTP plano e precisa ser solicitado por nome.

22.11.5 raiz

A raiz é o diretório em relação ao qual todos os caminhos são relativos, e contra o qual a contenção é aplicada.

O servidor não tem noção disso: um servidor FTP aceitará felizmente ../.. como um caminho. Então, é isso que impede que um move_to escreva em qualquer lugar que a conta possa alcançar.

22.11.6 tempo de expiração

O tempo limite limita uma operação, não toda a pesquisa.

O valor padrão é trinta segundos.

Por operação, porque uma pesquisa que lista um diretório e busca vinte arquivos realiza vinte e uma operações, e um orçamento único para todas elas abortaria uma transferência perfeitamente saudável de um arquivo grande.

22.12 Fonte de Arquivo

A Fonte de Arquivo lê arquivos de um diretório que este servidor pode ver.

O conector que um site tenta primeiro

Um analisador escreve resultados em uma pasta. Um sistema de faturamento solta um lote à noite. A radiologia exporta relatórios para um diretório que alguém montou anos atrás. Nenhum deles envolve um protocolo, e um motor de integração que não possa ler uma pasta falha em sua avaliação na primeira tarde.

Definido como FileSource em internal/config.

ChaveTipoObrigatórioPredefinido
roottextosim—
follow_symlinksverdadeiro ou falsonão—

22.12.1 raiz

A raiz limita todos os caminhos que esta fonte toca.

Required.

Separado do Dir para que move_to e error_dir possam ser relativos e ainda estar contidos. Dado apenas o Dir, um error_dir de "../falha" estaria fora de qualquer coisa que a fonte tivesse sido concedida, e recusá-lo seria arbitrário porque não haveria nada para recusá-lo.

22.13 Fonte GCS

A Fonte GCSSource pega objetos de um prefixo de bucket, como as fontes s3 e azure_blob fazem.

Definido como GCSSource em internal/config.

ChaveTipoObrigatórioPadrão
prefixtextosim—
suffixtextonão—
after_readtextonão—
move_totextonãoprocessado/
error_prefixtextonãoerro/
poll_intervalduração, como 30s ou 5mnão30s
max_object_sizenúmero inteironão16 MiB
framedverdadeiro ou falsonão—

22.13.1 mover_para

MoveTo é onde um objeto tratado vai quando after_read é move.

Padrão é processado/.

22.13.2 prefixo_de_erro

ErrorPrefix é onde um objeto que não pôde ser tratado vai.

Padrão é erro/.

22.13.3 intervalo_de_poll

PollInterval é a frequência com que o prefixo é listado.

Defaults to 30s.

22.13.4 tamanho_máximo_de_objeto

MaxObjectSize deixa objetos maiores onde estão.

Padrão é 16 MiB.

22.14 Fonte HTTP

HTTPSource aceita mensagens sobre HTTP.

Um ouvinte em vez de um poller: algo publica uma mensagem e recebe um acuso de recibo de volta, que é como a metade moderna do hospital se integra quando MLLP não está disponível para ele.

Definido como HTTPSource em internal/config.

ChaveTipoObrigatórioPadrão
listentextosim—
pathtextonão"/"
tlstlsconf.Settings (um bloco, omitir para deixar de fora)não—
tokentextonão—
max_message_sizenúmero inteironão—
read_timeoutduração, como 30s ou 5mnão—
ackAcknão—

22.14.1 listen

Listen é o endereço para servir.

Required.

22.14.2 path

Path é o caminho de URL para aceitar mensagens.

Defaults to "/".

22.14.3 token

Token, quando definido, é necessário em um cabeçalho Authorization: Bearer.

Não há padrão e não há toggle de modo anônimo: um ponto de extremidade HTTP em uma rede de hospital sem autenticação é uma decisão que tem que ser visível no arquivo, então deixar isso vazio é relatado como um aviso ao carregar.

22.14.4 max_message_size

MaxMessageSize limita o corpo de entrada.

Zero aplica um padrão.

22.15 Fonte IBMMQ

IBMMQSource lê uma fila.

Definido como IBMMQSource em internal/config.

ChaveTipoObrigatórioPadrão
poll_intervalduração, como 30s ou 5mnão2s

22.15.1 intervalo_de_poll

PollInterval é a espera quando a fila está vazia, ou após uma mensagem que não pôde ser tratada.

Defaults to 2s.

22.16 Fonte Java Script

JavaScriptSource configura uma fonte que executa um script em um temporizador e alimenta as mensagens retornadas no canal.

Este é o equivalente ao leitor de JavaScript do Mirth.

O script é executado em uma máquina virtual goja com a mesma caixa de areia que os scripts de transformador: msg não está disponível (não há mensagem de entrada ainda), mas globalMap, configurationMap, logger e DateUtil estão presentes. O script deve retornar uma string (uma mensagem) ou um array de strings (muitas). Retornar nada ou um array vazio significa que a pesquisa produziu nenhuma mensagem, o que é normal.

Definido como JavaScriptSource em internal/config.

ChaveTipoObrigatórioPadrão
scripttextosim—
poll_intervalduração, como 30s ou 5mnão—
timeoutduração, como 30s ou 5mnão—

22.16.1 intervalo_de_poll

PollInterval é a frequência com que o script é executado.

Zero significa 5 segundos.

22.16.2 tempo de expiração

Timeout limita a execução de um script.

Zero significa 30 segundos.

22.17 Fonte Kafka

KafkaSource lê mensagens de um tópico Kafka.

Definido como KafkaSource em internal/config.

ChaveTipoObrigatórioPadrão
brokerslista de textosim—
topicslista de textosim—
grouptextosim—
from_beginningverdadeiro ou falsonão—
commit_after_deliveryverdadeiro ou falso (um bloco, omitir para deixar de fora)não—
max_message_sizenúmero inteironãoo limite do canal
session_timeoutduração, como 30s ou 5mnãoquarenta e cinco segundos
timeoutduração, como 30s ou 5mnãotrinta segundos
saslKafkaSASL (um bloco, omitir para deixar de fora)não—
tlstlsconf.Settings (um bloco, omitir para deixar de fora)não—

22.17.1 corretoras

Corretoras é a lista de servidores de inicialização.

Required.

Uma lista em vez de um endereço, porque um corretor de inicialização único é um ponto de falha único para iniciar: o cluster sobrevive à perda dele e este canal não.

22.17.2 tópicos

Tópicos são os tópicos a serem lidos.

Pelo menos um é necessário.

22.17.3 grupo

Grupo é o grupo de consumidores.

Required.

Nomeado em vez de gerado, e necessário em vez de padrão, porque é o que lembra até onde este canal leu. Um grupo gerado começaria do início - ou do fim, perdendo tudo - em cada reinicialização, e deixaria o grupo antigo para trás segurando offsets comprometidos que ninguém lê. Exigir isso faz com que a pessoa nomeie a coisa que deve permanecer a mesma em todas as reinicializações.

22.17.4 from_beginning

FromBeginning lê o tópico desde o seu início quando o grupo não tem um offset comprometido.

Desligado por padrão, para que um novo canal apontado para um tópico com dois anos de história não reproduza dois anos de eventos de paciente em um sistema ao vivo no dia em que é ativado. A primeira pessoa a atingir isso estaria fazendo em produção, porque é onde o tópico com a história está.

22.17.5 commit_after_delivery

CommitAfterDelivery compromete o offset apenas uma vez que a mensagem foi tratada.

Ligado por padrão, e o motivo é a diferença entre perder uma mensagem e vê-la duas vezes. Comprometer na leitura significa que uma falha entre o comprometimento e a entrega perde a mensagem silenciosamente, e nada em lugar algum registra que ela existiu. Comprometer após significa que uma falha na mesma janela redelivera, o que é visível e que os receptores HL7 são construídos para tolerar - uma duplicata A08 é uma nuisance e um resultado de laboratório perdido é um evento de segurança do paciente.

22.17.6 max_message_size

MaxMessageSize limita um registro.

Padrão para o limite do canal.

22.17.7 tempo_limite_de_sessão

SessionTimeout é o tempo que o coordenador do grupo espera antes de assumir que este consumidor desapareceu e reatribuir suas partições.

O valor padrão é de quarenta e cinco segundos.

22.17.8 tempo de expiração

Limites de tempo de conexão e solicitações de metadados.

O valor padrão é trinta segundos.

22.18 Origem MQTT

MQTTSource subscreve um filtro de tópico.

Definido como MQTTSource em internal/config.

ChaveTipoObrigatórioPredefinido
topictextosim—
reconnectduração, como 30s ou 5mnão5s

22.18.1 reconnect

Reconexão é a espera após uma conexão perdida, ou após uma mensagem que não pôde ser tratada.

Defaults to 5s.

22.19 Origem Pub Sub

PubSubSource puxa de uma assinatura Pub/Sub.

Definido como PubSubSource em internal/config.

ChaveTipoObrigatórioPredefinido
subscriptiontextosim—
max_messagesnúmero inteironão10
reconnectduração, como 30s ou 5mnão5s

22.19.1 max_mensagens

MaxMensagens é quantas são puxadas de uma vez.

Elas ainda são tratadas uma a uma, em ordem. O valor padrão é 10.

22.19.2 reconnect

Reconexão é a espera após um erro.

Defaults to 5s.

22.20 Origem S3

S3Source pega objetos de um bucket.

Definido como S3Source em internal/config.

ChaveTipoObrigatórioPadrão
buckettextosim—
path_styleverdadeiro ou falsonão—
prefixtextonão—
suffixtextonão—
after_readtextonão—
move_totextonãoprocessado/
error_prefixtextonãoerro/
poll_intervalduração, como 30s ou 5mnão30s
max_object_sizenúmero inteironão16 MiB
framedverdadeiro ou falsonão—

22.20.1 prefixo

Prefixo limita quais objetos são lidos, por exemplo, inbound/.

Leituras vazias lêem o bucket inteiro, o que é recusado com após_leitura: mover a menos que mover_para esteja fora dele - caso contrário, os objetos movidos seriam lidos novamente.

22.20.2 após_leitura

AfterRead é mover (o padrão) ou apagar.

Não há deixar: um balde não tem um ficheiro que um polidor possa lembrar de ter visto através de uma reinicialização, por isso deixar objetos significa ler todos novamente a cada vez que o Perfuse é iniciado.

22.20.3 mover_para

MoveTo é o prefixo que um objeto tratado se move para.

Padrão é processado/.

22.20.4 prefixo_de_erro

ErrorPrefix é onde um objeto que não pôde ser tratado se move, para que um ficheiro ruim não bloqueie o resto.

Padrão é erro/.

22.20.5 intervalo_de_poll

PollInterval entre listagens.

Defaults to 30s.

22.20.6 tamanho_máximo_de_objeto

MaxObjectSize recusa qualquer coisa maior.

Padrão é 16 MiB.

22.20.7 emoldurado

Framed lê várias mensagens emolduradas MLLP de um objeto.

Caso contrário, um objeto é uma mensagem.

22.21 Origem SFTP

SFTPSource recolhe mensagens de um diretório em um servidor SFTP.

Extremamente comum e raramente discutido. Um laboratório ou um sistema de radiologia escreve um ficheiro a cada poucos minutos, um servidor SFTP o mantém e algo tem que vir e pegá-lo. Metade das fontes descritas como "enviamos HL7" são isso.

A parte que vale a pena cuidar não é a transferência. É que um ficheiro sendo escrito e um ficheiro terminado de ser escrito parecem idênticos sobre SFTP, por isso uma pesquisa que é mesmo ligeiramente muito ansiosa recolhe metade de uma mensagem. Isso produz uma mensagem HL7 truncada, mas frequentemente analisável, que é o pior resultado disponível: é aceita, confirmada, armazenada e entregue, e a metade faltante nunca é mencionada novamente.

Definido como SFTPSource em internal/config.

ChaveTipoObrigatórioPadrão
hosttextosim22
usertextosim—
passwordtextonão—
key_filetextonão—
key_passphrasetextonão—
known_hosts_filetextonão—
insecure_skip_host_key_checkverdadeiro ou falsonão—
dirtextosim—
patterntextonãotudo
poll_intervalduração, como 30s ou 5mnão—
after_readtextonão—
move_totextonão—
error_dirtextonão—
stable_forduração, como 30s ou 5mnão5s
framedverdadeiro ou falsonão—
max_file_sizenúmero inteironão64MB
timeoutduração, como 30s ou 5mnão60s

22.21.1 host

O Host é o servidor, com uma porta opcional.

Defaults to 22.

22.21.2 senha

Senha autentica com uma senha.

Prefer KeyFile.

22.21.3 key_file

KeyFile é uma chave privada.

A melhor escolha, e a que as equipes de segurança do hospital pedem.

22.21.4 known_hosts_file

KnownHostsFile verifica a identidade do servidor.

Obrigatório, a menos que InsecureSkipHostKeyCheck esteja definido. Sem ele, não há nada para distinguir o servidor real de qualquer coisa que responda nesse endereço, e as credenciais são entregues antes que alguém perceba.

22.21.5 insecure_skip_host_key_check

InsecureSkipHostKeyCheck aceita qualquer chave de host.

Existe porque recusar diretamente envia as pessoas para um script de shell com StrictHostKeyChecking=no, o que é pior em todos os aspectos, incluindo auditoria. Ele avisa em voz alta e nunca é o padrão.

22.21.6 padrão

O padrão selecciona ficheiros por globo.

Por predefinição, selecciona tudo.

22.21.7 mover_para

MoveTo é o diretório remoto para onde os ficheiros são movidos após leitura.

Obrigatório quando AfterRead é "mover".

22.21.8 estável_during

StableFor é o tempo durante o qual o tamanho e a data de modificação de um ficheiro devem permanecer inalterados antes de ser lido.

Defaults to 5s.

Esta é a definição que impede a recolha de metade de uma mensagem. Zero significa ler o que está lá, o que funciona até que um ficheiro seja suficientemente grande ou uma rede seja suficientemente lenta para que a escrita demore mais tempo do que um poll.

22.21.9 emoldurado

Framed indica que o ficheiro contém mensagens emolduradas pelo MLLP.

Quando é falso, o ficheiro é dividido nas fronteiras MSH.

22.21.10 tamanho_máximo_de_ficheiro

MaxFileSize recusa um ficheiro maior do que este número de bytes.

Por predefinição, 64MB.

22.21.11 tempo de expiração

O tempo limite define uma ligação única.

Defaults to 60s.

22.22 Origem SMB

SMBSource recolhe ficheiros de uma partilha de ficheiros do Windows.

Definido como SMBSource em internal/config.

ChaveTipoObrigatórioPredefinido
hosttextosim—
sharetextosim—
usertextonão—
passwordtextonão—
domaintextonão—
roottextonão—
timeoutduração, como 30s ou 5mnãotrinta segundos

22.22.1 host

O Host é o servidor, com uma porta opcional.

A porta 445 é assumida.

22.22.2 partilha

Partilha é o nome da partilha apenas: o "data" em \\\server\data.

Um caminho aqui é recusado em vez de ser cortado.

22.22.3 usuário

Utilizador e Palavra-passe são a conta do Windows.

Obrigatório na prática.

Uma partilha acessível sem credenciais é rara o suficiente num domínio para que um utilizador vazio aqui seja muito mais provável ser um erro do que uma partilha convidada - mas é aceite, porque recusá-la bloquearia a única disposição em que é correcta. Quando a conta pertence a um domínio, defina também o Domínio: autenticar uma conta de domínio sem ele falha de uma forma que parece uma palavra-passe incorrecta.

22.22.4 senha

Utilizador e Palavra-passe são a conta do Windows.

Obrigatório na prática.

Uma partilha acessível sem credenciais é rara o suficiente num domínio para que um utilizador vazio aqui seja muito mais provável ser um erro do que uma partilha convidada - mas é aceite, porque recusá-la bloquearia a única disposição em que é correcta. Quando a conta pertence a um domínio, defina também o Domínio: autenticar uma conta de domínio sem ele falha de uma forma que parece uma palavra-passe incorrecta.

22.22.5 domínio

O domínio é o domínio ou grupo de trabalho do Windows.

Vazio é geralmente correto para uma conta local.

22.22.6 tempo de expiração

Timeout limita uma operação.

O valor padrão é trinta segundos.

Vale a pena aumentar quando uma compartilhamento é alcançado através de um link de site. Uma operação SMB contra um servidor distante é mais lenta do que a mesma operação localmente, o suficiente para que um ajuste padrão para uma LAN produza timeouts que parecem que o compartilhamento está indisponível.

22.23 Origem SOAP

SOAPSource aceita mensagens embrulhadas em um envelope SOAP.

O contraparte da destino SOAP, e a direção mais rara: a maioria da integração hospitalar tem Perfuse chamando um serviço em vez de ser um. Ele existe porque o Web Service Listener do Mirth existe, e um site cujo sistema de envio só fala SOAP não pode migrar sem ele.

Deliberadamente não é um quadro de serviços web geral. Ele aceita um envelope, tira a mensagem dele e responde com um envelope. Não há WS-Security, não há MTOM, não há WS-Addressing e não há ligações geradas - as mesmas omissões que o destino, pelo mesmo motivo: uma meia-implementação de WS-Security é pior do que nenhuma.

Definido como SOAPSource em internal/config.

ChaveTipoObrigatórioPadrão
listentextosim—
profiletextonão—
pathtextonão"/"
versiontextonão1
elementtextonão—
base64verdadeiro ou falsonão—
response_elementtextonão"AckResponse"
response_namespacetextonão—
wsdltextonão—
tlstlsconf.Settings (um bloco, omitir para deixar de fora)não—
tokentextonão—
usernametextonão—
passwordtextonão—
max_message_sizenúmero inteironão—
read_timeoutduração, como 30s ou 5mnão—
ackAcknão—
fault_on_nakverdadeiro ou falsonão—

22.23.1 listen

Listen é o endereço para servir.

Required.

22.23.2 perfil

O nome do perfil nomeia um serviço padrão que este endpoint implementa.

Vazio aceita qualquer envelope como configurado abaixo.

"cdc-iis" responde como um registro de imunização faz, na interface da CDC (urn:cdc:iisb:2011): connectivityTest é ecoado, submitSingleMessage's hl7Message é a mensagem e o reconhecimento do canal vai de volta em resposta, o WSDL é servido em ?wsdl, e username e password, quando definidos, são verificados contra os que estão no corpo (onde o WSDL os coloca) em vez de contra autenticação HTTP. Para um teste de registro, ou para um site que recebe submissões do jeito que os registros fazem.

22.23.3 path

Caminho é o caminho da URL para aceitar envelopes.

Defaults to "/".

22.23.4 versão

A versão é a versão SOAP para responder em, "1.1" ou "1.2".

Defaults to 1.1.

As solicitações são aceitas em ambas as versões, independentemente, porque um remetente que obtém isso errado é comum e rejeitá-lo não ensina nada a ninguém. A configuração controla a resposta, onde obter errado significa que o remetente não pode ler a resposta.

22.23.5 elemento

O elemento nomeia o elemento dentro do corpo SOAP que contém a mensagem.

Vazio significa o texto completo do corpo.

Nomeado em vez de adivinhado porque um corpo pode transportar vários elementos - uma mensagem ao lado de um identificador de remetente e um carimbo de data/hora - e pegar o corpo completo entregaria ao motor um fragmento XML onde se esperava HL7.

22.23.6 base64

Base64 decodifica o conteúdo do elemento antes de tratá-lo como uma mensagem.

Comum em serviços reais, porque HL7 transporta retornos de carragem e os chamadores que não pensaram nisso acabam com XML que os danifica. Se o conteúdo decodifica como base64, mas não foi destinado a ser, o resultado não é uma mensagem e o motor diz isso - o que é por que isso é explícito em vez de farejado.

22.23.7 elemento_de_resposta

ResponseElement nomeia o elemento que envolve o acuso de recebimento na resposta.

O valor padrão é "AckResponse".

22.23.8 wsdl

WSDL é um arquivo servido no caminho de escuta com ?wsdl.

Vazio significa que nenhum é servido.

Um arquivo em vez de algo gerado. Um WSDL gerado descreveria o que este endpoint aceita, o que quase nunca é o que o sistema de envio foi construído para - e um WSDL que está quase certo custa mais tempo do que nenhum WSDL, porque parece autoritativo.

22.23.9 nome de usuário

Nome de usuário e Senha, quando definidos, exigem autenticação básica HTTP.

Oferecido ao lado de um token porque os chamadores SOAP esperam amplamente a autenticação básica, e um site cujo sistema de envio não pode ser alterado precisa da opção que já tem.

22.23.10 senha

Nome de usuário e Senha, quando definidos, exigem autenticação básica HTTP.

Oferecido ao lado de um token porque os chamadores SOAP esperam amplamente a autenticação básica, e um site cujo sistema de envio não pode ser alterado precisa da opção que já tem.

22.23.11 max_message_size

MaxMessageSize limita o corpo de entrada.

Zero aplica um padrão.

22.23.12 fault_on_nak

FaultOnNak responde a um acuso de recebimento negativo com uma falha SOAP em vez de uma resposta normal que carrega o NAK.

Desligado por padrão, o que é o padrão correto e vale a pena explicar. HL7 já tem uma maneira de dizer "Eu recebi isso e o rejeitei", e isso é um NAK - uma troca bem-sucedida que relata uma mensagem rejeitada. Transformar a mesma coisa em uma falha de transporte informa ao remetente que sua solicitação estava malformada, o que não era, e muitos clientes respondem tentando novamente para sempre.

Ele existe porque alguns chamadores só olham o status HTTP e tratariam uma rejeição como sucesso.

22.24 Fonte SQS

SQSSource lê de uma fila SQS.

Uma mensagem é excluída apenas após o canal ter lidado com ela - entregue, ou filtrada, ou falhada de uma maneira que o canal registra. Até então, ela permanece na fila, invisível por visibility_timeout, e volta se Perfuse parar. Então, uma mensagem nunca é perdida; o preço é que uma pode chegar duas vezes, o que SQS em si já permite.

Definido como SQSSource em internal/config.

ChaveTipoObrigatórioPadrão
queue_urltextosim—
wait_secondsnúmero inteironão20: uma fila vazia custa um pedido a cada vinte segundos
max_messagesnúmero inteironão10
visibility_timeoutduração, como 30s ou 5mnãoa configuração própria da fila

22.24.1 visibility_timeout

VisibilityTimeout é quanto tempo uma mensagem recebida permanece oculta enquanto é processada.

O valor padrão é a configuração própria da fila.

22.25 Fonte Serial

SerialSource lê mensagens de uma porta serial.

Por que um conector serial em 2026

Porque o equipamento ainda está lá. Um analisador de gases sanguíneos comprado em 2009 com um sensor funcionando e uma soquete de 25 pinos, um monitor de cabeceira, uma balança em uma unidade de diálise, uma máquina de anestesia mais antiga. Nenhum deles terá um porta Ethernet, vários deles custam seis algarismos, e a alternativa para lê-los é alguém digitando resultados em um formulário.

O Mirth tem um conector serial. O Perfuse não tinha nada e um site com um desses não tinha rota de entrada.

Framing é compartilhado com o conector TCP

Os enquadramentos são os mesmos, independentemente de onde vêm os bytes: um analisador que fala STX/ETX sobre um soquete fala STX/ETX sobre um cabo. Portanto, reutiliza o bloco de enquadramento TCP em vez de definir o seu próprio, o que também significa que um dispositivo movido de um cabo serial para um adaptador serial-Ethernet mantém a sua configuração de enquadramento.

O que é diferente sobre uma linha serial

Não há conexão. Um soquete informa quando o peer se foi; um cabo não. Um cabo desconectado, um dispositivo desligado e um dispositivo com nada a dizer são indistinguíveis - todos os três são silêncio. É por isso que o quiet_after existe: sem algo para dizer "esta linha está em silêncio por mais tempo do que deveria", uma fonte morta parece exatamente como uma noite tranquila.

Definido como SerialSource em internal/config.

ChaveTipoObrigatórioPadrão
porttextosim—
baudnúmero inteirosim—
data_bitsnúmero inteironão8
paritytextonãonone
stop_bitstextonão1
flow_controltextonãonone
max_message_sizenúmero inteironão—
quiet_afterduração, como 30s ou 5mnão—
replytextonão—
reply_texttextonão—
reopen_afterduração, como 30s ou 5mnão—

22.25.1 baud

Baud é a velocidade.

Obrigatório, porque adivinhar produz bytes em vez de um erro.

Uma taxa de baud errada não falha. Ela entrega lixo plausível: bytes de enquadramento aparecem aleatoriamente, corridas ocasionais decodificam como caracteres imprimíveis e um analisador leniente aceita parte disso. Não há padrão deliberadamente.

22.25.2 parity

Parity é none, odd, even, mark ou space.

Padrão é none.

22.25.3 stop_bits

StopBits é 1, 1,5 ou 2, escrito como "1", "1,5" ou "2".

Defaults to 1.

22.25.4 flow_control

FlowControl é none, hardware ou software.

Padrão é none.

Vale a pena configurar corretamente em vez de deixar. Com controle de fluxo de hardware esperado e não configurado, um dispositivo para de enviar parte de uma mensagem longa e o resultado é uma mensagem truncada em vez de uma falha.

22.25.5 quiet_after

QuietAfter registra um aviso quando nada foi recebido por esse tempo.

A única maneira de notar uma fonte serial morta. Um cabo desconectado e uma noite tranquila são o mesmo silêncio, então alguém tem que dizer quanto tempo é muito tempo para este dispositivo específico.

22.25.6 reopen_after

ReopenAfter é quanto tempo esperar antes de reabrir uma porta que falhou.

Um adaptador serial USB desconectado e reconectado volta como o mesmo caminho de dispositivo, mas um novo identificador do kernel, então o antigo retorna erros para sempre. Reabrir é a única recuperação e fazer isso em um loop apertado preenche o log.

22.26 Origem

A Origem é onde um canal recebe mensagens.

Definido como Source em internal/config.

ChaveTipoObrigatórioPadrão
typeSourceTypesim—
listentextosim—
max_message_sizenúmero inteironão—
idle_timeoutduração, como 30s ou 5mnão—
max_connectionsnúmero inteironão—
tlstlsconf.Settings (um bloco, omitir para não usar)não—
httpHTTPSource (um bloco, omitir para não usar)não—
soapSOAPSource (um bloco, omitir para não usar)não—
dicomwebDICOMwebSource (um bloco, omitir para não usar)não—
directDirectSource (um bloco, omitir para não usar)não—
dicomDICOMSource (um bloco, omitir para não usar)não—
fileFileSource (um bloco, omitir para não usar)não—
tcpTCPSource (um bloco, omitir para não usar)não—
ftpFTPSource (um bloco, omitir para não usar)não—
smbSMBSource (um bloco, omitir para não usar)não—
webdavWebDAVSource (um bloco, omitir para não usar)não—
serialSerialSource (um bloco, omitir para não usar)não—
dicom_queryDICOMQuerySource (um bloco, omitir para não usar)não—
brokerBrokerSource (um bloco, omitir para não usar)não—
kafkaKafkaSource (um bloco, omitir para não usar)não—
sqsSQSSource (um bloco, omitir para não usar)não—
s3S3Source (um bloco, omitir para não usar)não—
amqpAMQPSource (um bloco, omitir para não usar)não—
azure_blobAzureBlobSource (um bloco, omitir para não usar)não—
emailEmailSource (um bloco, omitir para não usar)não—
as2AS2Source (um bloco, omitir para não usar)não—
pgpPGPReceive (um bloco, omitir para não usar)não—
mqttMQTTSource (um bloco, omitir para não usar)não—
ibm_mqIBMMQSource (um bloco, omitir para não usar)não—
pubsubPubSubSource (um bloco, omitir para não usar)não—
gcsGCSSource (um bloco, omitir para não usar)não—
databaseDatabaseSource (um bloco, omitir para não usar)não—
sftpSFTPSource (um bloco, omitir para não usar)não—
javascriptJavaScriptSource (um bloco, omitir para não usar)não—
ackAcknão—

22.26.1 tipo

O tipo é o transporte.

Apenas mllp é implementado.

22.26.2 max_message_size

MaxMessageSize limita uma mensagem de entrada.

Zero usa o padrão do transporte.

22.26.3 idle_timeout

IdleTimeout fecha uma conexão que esteve silenciosa por esse tempo.

Zero significa nunca, o que geralmente está correto: uma fonte de hospital mantém uma conexão aberta por meses e fica silenciosa à noite.

22.26.4 max_conexões

MaxConnections limita as conexões concorrentes.

Zero significa ilimitado.

22.27 Origem TCP

TCPSource ouve em um soquete para mensagens que não são necessariamente HL7.

Por que isso é separado de uma origem mllp

MLLP é um enquadramento e Perfuse sempre o falou. Uma grande quantidade de equipamentos não o faz: um analisador de laboratório, uma balança, um monitor de cabeceira, um sistema de faturamento mais antigo. Cada um tende a ter sua própria convenção, e o conector TCP do Mirth cobre todos eles, então um site com uma fonte de soquete que não era HL7 não podia usar Perfuse em absoluto.

Definido como TCPSource em internal/config.

ChaveTipoObrigatórioPadrão
listentextosim—
max_message_sizenúmero inteironão—
idle_timeoutduração, como 30s ou 5mnão—
max_connectionsnúmero inteironão—
replytextonão—
reply_texttextonão—
tlstlsconf.Settings (um bloco, omitir para não usar)não—

22.27.1 idle_timeout

IdleTimeout fecha uma conexão que esteve silenciosa por esse tempo.

Zero significa nunca, o que geralmente está correto: uma fonte de dispositivo mantém uma conexão aberta por meses e fica silenciosa à noite.

22.27.2 max_conexões

MaxConnections limita as conexões concorrentes.

Zero significa ilimitado.

22.27.3 resposta

Resposta é o que enviar de volta após cada mensagem: nada, ack ou uma string fixa.

A maioria das fontes brutas espera nada. Algumas esperam um byte ACK único. Um dispositivo que espera uma resposta e não a recebe geralmente reprisa a mesma mensagem para sempre, então isso vale a pena ser explícito.

22.28 Origem Web DAV

O WebDAVSource recolhe ficheiros de uma coleção WebDAV.

Onde isto surge: sistemas de gestão de documentos, SharePoint, Nextcloud e portais de fornecedores que expõem uma pasta de destino sobre HTTPS porque é a única porta de saída que os firewalls dos seus clientes permitem.

Definido como WebDAVSource em internal/config.

ChaveTipoObrigatórioPadrão
urltextosim—
usertextonão—
passwordtextonão—
insecure_skip_verifyverdadeiro ou falsonão—
timeoutduração, como 30s ou 5mnãosessenta segundos

22.28.1 usuário

O Utilizador e a Palavra-passe autenticam com autenticação básica HTTP.

A autenticação básica envia a palavra-passe num cabeçalho que só é protegido pelo TLS, por isso estes pertencem a uma URL https. Sobre http, são legíveis por qualquer coisa no caminho e nenhum aviso do servidor o dirá.

22.28.2 senha

O Utilizador e a Palavra-passe autenticam com autenticação básica HTTP.

A autenticação básica envia a palavra-passe num cabeçalho que só é protegido pelo TLS, por isso estes pertencem a uma URL https. Sobre http, são legíveis por qualquer coisa no caminho e nenhum aviso do servidor o dirá.

22.28.3 tempo de expiração

O Tempo Limite limita uma solicitação.

O valor predefinido é de sessenta segundos.

Mais longo do que os valores predefinidos do FTP e do SMB propositadamente. Uma lista de coleção WebDAV é um único PROPFIND que o servidor pode demorar muito tempo a montar para um diretório grande, e não há resultado parcial para recorrer.

23 Referência de Destino

Toda a forma como um canal pode enviar mensagens, e cada chave que cada um aceita. Um canal pode ter qualquer número de destinos, e são independentes: um a falhar não impede os outros.

23.1 Destino AMQP

O AMQPDestination envia para uma fila ou tópico, e relata sucesso apenas uma vez que o corretor tenha aceite a mensagem.

Definido como AMQPDestination em internal/config.

ChaveTipoObrigatórioPredefinição
content_typetextonãoo tipo de dados do canal

23.1.1 content_type

O ContentType é enviado com cada mensagem.

O valor predefinido é o tipo de dados do canal.

23.2 Destino AS2

O AS2Destination envia cada mensagem como AS2: assinada com a nossa chave, encriptada para o certificado do parceiro, publicada para a URL do parceiro, e, por predefinição, entregue apenas uma vez que o recibo assinado do parceiro nomeie o mesmo resumo.

Definido como AS2Destination em internal/config.

ChaveTipoObrigatórioPadrão
urltextosim—
fromtextosim—
totextosim—
cert_filetextonão—
key_filetextonão—
partner_cert_filetextonão—
unsignedverdadeiro ou falsonão—
unencryptedverdadeiro ou falsonão—
compressverdadeiro ou falsonão—
receipttextonão—
unsigned_receiptverdadeiro ou falsonão—
receipt_urltextonão—
content_typetextonão—
file_nametextonão—
subjecttextonão—
usernametextonão—
passwordtextonão—
tlstlsconf.Settings (um bloco, omitir para deixar de fora)não—

23.2.1 compress

O Compress comprime a carga útil (zlib, RFC 5402) antes de assinar e encriptar.

Todo o receptor AS2 que anuncia a versão 1.1 ou posterior lê-o; pergunte ao parceiro antes de o ativar.

23.2.2 recibo_não_assinado

UnsignedReceipt pede um recibo que não é assinado.

Desligado: um assinado é pedido e um não assinado é recusado.

23.2.3 content_type

ContentType é o tipo MIME da carga útil.

Padrão pelo tipo de dados do canal: application/edi-x12, application/edifact, application/hl7-v2, caso contrário application/octet-stream.

23.3 Destino do Azure Blob

AzureBlobDestination escreve cada mensagem como um blob em blocos.

Definido como AzureBlobDestination em internal/config.

ChaveTipoObrigatórioPadrão
blobtextonão${date}/${channel}/${control_id}
tiertextonão—
content_typetextonão—

23.3.1 blob

Blob nomeia cada blob, com os espaços reservados do destino S3.

Padrão é ${date}/${channel}/${control_id}.hl7.

23.3.2 tier

Tier é Hot, Cool, Cold ou Archive.

Archive está offline: ler um blob novamente significa reidratá-lo, o que leva horas.

23.4 Destino do Broker

BrokerDestination publica mensagens para um corretor de mensagens.

Escritor JMS do Mirth.

Definido como BrokerDestination em internal/config.

ChaveTipoObrigatórioPadrão
addrtextosim—
destinationtextosim—
logintextonão—
passcodetextonão—
hosttextonãoo host do endereço
content_typetextonãotext/plain para HL7
headersmapeamento de texto para textonão—
persistentverdadeiro ou falso (um bloco, omitir para deixar de fora)nãoverdadeiro
timeoutduração, como 30s ou 5mnão—
tlstlsconf.Settings (um bloco, omitir para deixar de fora)não—

23.4.1 addr

Addr é o host e porta do broker.

Required.

23.4.2 destino

Destino é a fila ou tópico para publicar.

Required.

23.4.3 iniciar sessão

Iniciar sessão e Código de Acesso autenticam.

A maioria dos brokers recusa uma conexão anônima.

23.4.4 código de acesso

Iniciar sessão e Código de Acesso autenticam.

A maioria dos brokers recusa uma conexão anônima.

23.4.5 host

Host é o host virtual.

O valor padrão é o host do endereço.

Vale a pena definir explicitamente em um corretor que hospeda vários hosts virtuais, onde o padrão coloca a publicação naquele que responde ao nome do servidor - uma fila que existe, aceita a mensagem e é lida por ninguém.

23.4.6 content_type

O ContentType é enviado com cada mensagem.

Padrão é text/plain para HL7.

23.4.7 headers

Cabeçalhos são enviados com cada mensagem.

Configuração apenas, nunca conteúdo de mensagem. Um cabeçalho tirado de um campo colocaria um identificador de paciente em metadados de broker que são registrados, indexados e visíveis para todos os outros aplicativos na fila.

23.4.8 persistente

Persistente pede ao broker para sobreviver a uma reinicialização.

Padrão é true.

True porque uma mensagem não persistente é perdida quando o broker é reiniciado, e isso não é um padrão razoável para dados clínicos. False existe para uma fonte de alimentação genuinamente transitória - um pulso de monitoramento - e tem que ser escolhida.

23.5 Destino CDA

CDADestination configura um destino CDA: ele pega o documento clínico transportado dentro de uma mensagem HL7 v2, converte-o e escreve ou publica o resultado.

Isso existe porque um documento quase nunca chega sozinho. Ele chega codificado em base64 dentro de um MDM^T02, e todos os motores que tratam essa mensagem como um bloco opaco deixam o documento ilegível. Possuir ambos os lados disso é o objetivo.

Definido como CDADestination em internal/config.

ChaveTipoObrigatórioPadrão
urltextonão—
dirtextonão—
writetextonão—
versiontextonãoR5
identifier_systemsmapeamento de texto para textonão—
require_agreementverdadeiro ou falsonão—
on_no_documenttextonão—
headersmapeamento de texto para textonão—
bearer_tokentextonão—

23.5.1 url

URL é um servidor FHIR para publicar o pacote convertido.

Deixe-o vazio para escrever em Dir em vez disso. Um dos dois é obrigatório.

23.5.2 dir

Dir escreve a saída em arquivos em vez de publicá-la.

Útil para uma zona de aterrissagem que outro processo pega, e para ver o que a conversão produz antes de apontá-la para um servidor ao vivo.

23.5.3 write

Write seleciona o que é escrito ou publicado:

fhir o conjunto de transações convertidas (padrão) documente os bytes do documento original, inalterados ambos, com o documento ao lado do conjunto transferir um resumo de Transições de Cuidados PACIO: um documento FHIR R4 para o local para onde o paciente vai em seguida (uma casa de repouso, uma unidade de reabilitação, cuidados domiciliários), publicado em url/Bundle ou escrito em dir

"documento" vale a pena ter por si só: um local que deseja seus CDAs em disco para uma equipe de registros não precisa da conversão FHIR em tudo.

23.5.4 sistemas_de_identificadores

IdentifierSystems mapeia uma raiz OID do documento para um URI, para que um MRN se torne nomeado.

Um CDA identifica pessoas por OID e FHIR por URI, e nada pode derivar um do outro.

23.5.5 requer_acordo

RequireAgreement recusa um documento cuja narrativa e entradas codificadas contradizem um ao outro.

Desativado por predefinição, e deliberadamente assim. A verificação é valiosa, mas é um julgamento sobre um documento que alguém mais autorou, e um canal que silenciosamente descarta documentos clínicos reais porque o gerador de C-CDA do remetente é descuidado é pior do que um que os passa com um aviso. Um site que examinou seus próprios resultados e decidiu que quer o portão pode ativá-lo.

23.5.6 on_no_document

OnNoDocument decide o que acontece quando a mensagem não transporta nenhum documento clínico:

pular entregar nada e relatar sucesso (predefinição) falhar tratar como uma falha de entrega

A predefinição é pular, porque um canal que transporta uma alimentação mista de ADT e MDM falharia em cada admissão. Um canal dedicado a documentos deve definir falhar, desde que uma mensagem de documento sem documento é um problema real no remetente.

23.5.7 bearer_token

BearerToken é enviado como um cabeçalho de Autorização.

Prefira uma referência de variável de ambiente sobre um literal em um arquivo que vai para o git.

23.6 Destino do Canal

ChannelDestination encaminha para outro canal no mesmo servidor.

Definido como ChannelDestination em internal/config.

ChaveTipoObrigatórioPredefinido
nametextosim—

23.7 Destino DICOM

DICOMDestination envia objetos de imagem como um usuário da classe de serviço C-STORE.

Mirth chama isso de Remetente DICOM.

Definido como DICOMDestination em internal/config.

ChaveTipoObrigatórioPadrão
addresstextosim—
called_aetextonão—
calling_aetextonão—
transfer_syntaxeslista de textonão—
timeoutduração, como 30s ou 5mnão—
tlstlsconf.Settings (um bloco, omitir para não incluir)não—

23.7.1 endereço

Endereço é o host remoto e porta.

Required.

23.7.2 called_ae

CalledAE é como o remoto se chama, e CallingAE é como este fim se chama.

Ambos importam. Sites configuram um PACS para aceitar um título de chamada específico e rejeitar tudo o mais, então uma falha de correspondência é a razão mais comum para uma primeira conexão falhar - e a falha parece um problema de rede.

23.7.3 calling_ae

CalledAE é como o remoto se chama, e CallingAE é como este fim se chama.

Ambos importam. Sites configuram um PACS para aceitar um título de chamada específico e rejeitar tudo o mais, então uma falha de correspondência é a razão mais comum para uma primeira conexão falhar - e a falha parece um problema de rede.

23.7.4 transfer_syntaxes

TransferSyntaxes restringe o que oferecer, na ordem de preferência.

Vazio oferece a codificação própria do objeto e, em seguida, implicit VR little endian como fallback.

23.7.5 tempo de expiração

Tempo limite limita uma operação de armazenamento.

Zero aplica um padrão.

23.8 Destino Mweb DICOM

DICOMwebDestination armazena cada objeto com STOW-RS.

Definido como DICOMwebDestination em internal/config.

ChaveTipoObrigatórioPadrão
urltextosim—
tokentextonão—
usernametextonão—
passwordtextonão—
headersmapeamento de texto para textonão—
tlstlsconf.Settings (um bloco, omitir para deixar de fora)não—
timeoutduração, como 30s ou 5mnão—

23.9 Destino de Banco de Dados

DatabaseDestination escreve cada mensagem em um banco de dados.

Definido como DatabaseDestination em internal/config.

ChaveTipoObrigatórioPadrão
drivertextosim—
dsntextosim—
statementtextosim—
paramslista de textonão—
timeoutduração, como 30s ou 5mnão30s
max_open_connsnúmero inteironão4

23.9.1 driver

O driver nomeia o banco de dados.

See SupportedDrivers.

23.9.2 instrução

A instrução é executada uma vez por mensagem, com os parâmetros vinculados a ela em ordem.

Os espaços reservados são próprios do driver: $1 para postgres, ? para mysql e sqlite, @p1 para sqlserver. O Perfuse não reescreve-os, porque uma camada de tradução que obtivesse um espaço reservado errado vincularia o nome de um paciente à coluna errada e o resultado pareceria dados válidos.

23.9.3 parâmetros

Os parâmetros são caminhos HL7 ou expressões ${...}, vinculados à instrução em ordem.

Os valores são sempre vinculados como parâmetros e nunca interpolados no SQL. Isso não é apenas sobre injeção: O'Brien é um nome comum, e uma consulta concatenada quebra na apostrofe.

23.9.4 tempo de expiração

O timeout limita uma instrução única.

Defaults to 30s.

23.9.5 max_open_conns

MaxOpenConns limita o pool.

Defaults to 4.

23.10 Destino

O destino é um local para onde um canal envia mensagens.

Definido como Destination em internal/config.

ChaveTipoObrigatórioPadrão
nametextosim—
typeDestinationTypesim—
enabledverdadeiro ou falso (um bloco, omitir para deixar de fora)não—
filtertextonão—
addresstextonão—
dirtextonão—
file_nametextonão—
temp_suffixtextonão"
appendverdadeiro ou falsonão—
retain_hoursnúmero inteironão—
tlstlsconf.Settings (um bloco, omitir para deixar de fora)não—
fhirFHIRDestination (um bloco, omitir para deixar de fora)não—
cdaCDADestination (um bloco, omitir para deixar de fora)não—
httpHTTPDestination (um bloco, omitir para deixar de fora)não—
databaseDatabaseDestination (um bloco, omitir para deixar de fora)não—
sftpSFTPDestination (um bloco, omitir para deixar de fora)não—
tcpTCPDest (um bloco, omitir para deixar de fora)não—
smtpSMTPDestination (um bloco, omitir para deixar de fora)não—
channelChannelDestination (um bloco, omitir para deixar de fora)não—
s3S3Destination (um bloco, omitir para deixar de fora)não—
ftpFTPDestination (um bloco, omitir para deixar de fora)não—
documentDocumentDestination (um bloco, omitir para deixar de fora)não—
soapSOAPDestination (um bloco, omitir para deixar de fora)não—
dicomwebDICOMwebDestination (um bloco, omitir para deixar de fora)não—
xdsXDSDestination (um bloco, omitir para deixar de fora)não—
directDirectDestination (um bloco, omitir para deixar de fora)não—
as2AS2Destination (um bloco, omitir para deixar de fora)não—
mpiMPIDestination (um bloco, omitir para deixar de fora)não—
tefcaTEFCADestination (um bloco, omitir para deixar de fora)não—
pasPASDestination (um bloco, omitir para deixar de fora)não—
x12_astextonão—
dicomDICOMDestination (um bloco, omitir para deixar de fora)não—
javascriptJavaScriptDestination (um bloco, omitir para deixar de fora)não—
brokerBrokerDestination (um bloco, omitir para deixar de fora)não—
kafkaKafkaDestination (um bloco, omitir para deixar de fora)não—
sqsSQSDestination (um bloco, omitir para deixar de fora)não—
snsSNSDestination (um bloco, omitir para deixar de fora)não—
amqpAMQPDestination (um bloco, omitir para deixar de fora)não—
azure_blobAzureBlobDestination (um bloco, omitir para deixar de fora)não—
mqttMQTTDestination (um bloco, omitir para deixar de fora)não—
ibm_mqIBMMQDestination (um bloco, omitir para deixar de fora)não—
pubsubPubSubDestination (um bloco, omitir para deixar de fora)não—
gcsGCSDestination (um bloco, omitir para deixar de fora)não—
elrELRDestination (um bloco, omitir para deixar de fora)não—
pgpPGPSend (um bloco, omitir para deixar de fora)não—
response_transformertextonão—
timeoutduração, como 30s ou 5mnão—
retryRetrynão—
queueQueueConfig (um bloco, omitir para deixar de fora)não—

23.10.1 nome

O nome identifica o destino nos logs e métricas.

Obrigatório dentro de um canal.

23.10.2 file_name

Nome do arquivo, para um destino de arquivo, cria um arquivo por mensagem (${timestamp}, ${date}, ${control_id}, ${message_type}, ${destination}).

Vazio mantém o padrão: um arquivo por dia e tipo de mensagem, anexado a.

23.10.3 temp_suffix

TempSuffix é o nome que um arquivo por mensagem carrega enquanto está sendo escrito, removido por um rename uma vez que está completo, para que o que coleta os arquivos nunca leia metade de um.

Padrão é ".part".

23.10.4 retain_hours

RetainHours exclui arquivos no Dir mais antigos do que isso.

Zero os mantém para sempre.

23.10.5 x12_as

X12As é um xml para um destino em um canal X12 que recebe a troca como o XML Mirth Connect e Open Integration Engine escrevem para X12, para um receptor construído contra o que o Mirth enviou.

Vazio ou x12 envia X12.

23.10.6 elr

ELR torna este um destino de relatório de laboratório de saúde pública: cada resultado de laboratório (ORU^R01) é reformatado em uma mensagem ELR 2.5.1 que contém apenas os pedidos com um resultado relatável, e é isso que é entregue; uma mensagem com nada relatável não é enviada.

Aplica-se a destinos que entregam uma mensagem HL7 v2 como está (mllp, http, arquivo, sftp e o resto), em um canal hl7.

23.10.7 response_transformer

ResponseTransformer inspeciona o que o receptor disse em resposta e pode marcar a entrega como falha.

Ele existe porque "isso chegou" é frequentemente uma pergunta que o transporte não pode responder: um receptor MLLP retorna um aceno de aplicativo cujo significado está em seu texto, e um receptor HTTP retorna 200 com um documento de erro. Em ambos os casos, o transporte foi bem-sucedido e a mensagem não chegou.

Apenas significativo em um destino que recebe uma resposta. Em um que não pode, é recusado no carregamento em vez de deixado nunca executando.

23.10.8 fila

A fila torna a entrega durável: uma mensagem que não pode ser entregue agora é mantida no disco e repetida até que possa ser.

Desativado por padrão.

23.11 Destino Direto

O DirectDestination envia cada mensagem como Direct: assinada com este endereço, encriptada para o certificado de cada destinatário e submetida ao HISP por SMTP.

Definido como DirectDestination em internal/config.

ChaveTipoObrigatórioPadrão
tolista de textosim—
subjecttextonão—
texttextonão—
attach_nametextonão—
xdmverdadeiro ou falsonão—
xdm_source_idtextonão—
recipient_certs_dirtextonão—
dnstextonão—
ldaptextonão—
smtp_hosttextosim—
usernametextonão—
passwordtextonão—
request_mdnverdadeiro ou falsonão—
timeoutduração, como 30s ou 5mnão—

23.11.1 para

Os destinatários são os endereços Direct.

As referências de campo são substituídas, então um destinatário pode vir da mensagem.

23.11.2 recipient_certs_dir

O RecipientCertsDir contém certificados de destinatários (PEM, um arquivo por endereço ou domínio, address.pem ou domain.pem) encontrados antecipadamente; vazio lê o livro de endereços Direct do servidor (a tela Direct).

Os destinatários que não estão lá são procurados no DNS (registros CERT). O Direct não envia para um destinatário cujo certificado não possa ser encontrado.

23.11.3 ldap

O LDAP é o diretório onde o certificado de um destinatário é procurado quando o DNS não tem nenhum (host:porta, porta 389): o segundo modo pelo qual o guia de descoberta de certificado Direct permite.

Vazio encontra o diretório do domínio do destinatário pelo seu registro SRV DNS (_ldap._tcp), como diz o guia; "desligado" nunca pede um diretório.

23.12 Destino de Documento

O DocumentDestination renderiza cada mensagem em um documento.

Definido como DocumentDestination em internal/config.

ChaveTipoObrigatórioPadrão
dirtextosim—
formatDocumentFormatnãopdf
templatetextosim—
titletextonão—
file_nametextonão—
font_sizenúmeronão10
landscapeverdadeiro ou falsonão—
temp_suffixtextonão"
timeoutduração, como 30s ou 5mnão30s

23.12.1 formato

O formato é pdf ou texto.

Padrão é pdf.

23.12.2 modelo

O modelo é o corpo do documento, com referências de estilo ${PID-5.1} para caminhos de mensagem.

Obrigatório. Não há um padrão sensato: um documento sem modelo seria ou a mensagem bruta, que ninguém quer imprimir, ou vazio.

23.12.3 tamanho da fonte

Tamanho da fonte em pontos.

Padrão é 10, que cabe 80 caracteres em A4.

23.12.4 temp_suffix

O sufixo temporário é anexado enquanto escreve e removido por um rename.

Padrão é ".part".

A mesma cortesia como qualquer outro destino de ficheiro, e aqui é mais importante: um watcher de impressão que recolhe um PDF meio escrito produz uma página em branco, e ninguém investiga uma página em branco.

23.12.5 tempo de expiração

O limite de tempo define uma escrita.

Defaults to 30s.

23.13 Destino ECR

ECRDestination configura a notificação de casos eletrónica.

Definido como ECRDestination em internal/config.

ChaveTipoObrigatórioPredefinição
rctctextonão—
sourcetextosim—
facilityECRFacilitysim—

23.13.1 rctc

RCTC é um FHIR ValueSet, ou um Bundle deles, como o eRSD, que contém os códigos de acionamento.

Sem ele, o Perfuse usa o seu exemplo de amostra curto incorporado, que é para testes: as agências esperam o RCTC.

23.14 Destino ELR

ELRDestination configura a notificação de laboratório eletrónica.

Definido como ELRDestination em internal/config.

ChaveTipoObrigatórioPredefinição
configtextosim—
rctctextonão—

23.14.1 config

Config é o ficheiro ELR perfuse elr -config que lê: as aplicações e instalações de envio e receção por OID, o modo de processamento e o que preenche as lacunas que um feed de laboratório deixa (instalação de encomenda, laboratório que executa, autoridades de atribuição).

Um caminho relativo é lido a partir do diretório do ficheiro do canal.

23.14.2 rctc

RCTC é um FHIR ValueSet, ou um Bundle deles, como o eRSD, que contém os códigos de acionamento.

Sem ele, o Perfuse usa o seu exemplo de amostra curto incorporado, que é para testes: as agências esperam o RCTC. Relativo ao ficheiro do canal, como Config.

23.15 Destino FHIR

FHIRDestination configura a conversão para FHIR e entrega a um servidor FHIR.

Definido como FHIRDestination em internal/config.

ChaveTipoObrigatórioPadrão
urltextosim—
versiontextonãoR5
timezonetextonão—
default_identifier_systemtextonão—
identifier_systemsmapeamento de texto para textonão—
claim_us_coreverdadeiro ou falsonão—
validate_before_sendverdadeiro ou falso (um bloco, omitir para deixar de fora)nãoverdadeiro: enviar um recurso que um servidor rejeitará desperdiça um orçamento de repetição e esconde o problema real atrás de um erro de transporte
reject_on_warningverdadeiro ou falsonão—
headersmapeamento de texto para textonão—
bearer_tokentextonão—
authFHIRAuth (um bloco, omitir para deixar de fora)não—
ecrECRDestination (um bloco, omitir para deixar de fora)não—
bundle_scripttextonão—

23.15.1 url

A URL é a URL base do servidor FHIR, por exemplo "https://fhir.example.org/fhir".

O bundle é publicado diretamente nela.

23.15.2 versão

A versão é a versão do FHIR a produzir: R4, R4B ou R5. O valor predefinido é R5, a versão mais recente publicada.

Um deployment que fala com um EHR quase sempre quer R4 e deve dizê-lo, porque baixar silenciosamente esconderia uma decisão real de interoperabilidade.

23.15.3 fuso horário

O fuso horário é aplicado às marcações de tempo HL7 v2 que não possuem offset. O v2 permite um tempo local nu e o FHIR não, por isso algo tem que fornecer um.

Quando não definido, o offset que o remetente colocou em MSH-7 é usado, pois o v2 presume que um tempo nu é o tempo local do remetente; uma mensagem cujo MSH-7 não possui offset cai de volta para UTC.

23.15.4 sistema_de_identificador_padrão

DefaultIdentifierSystem fornece namespaces para identificadores cuja autoridade de atribuição não possui um URI configurado.

Sem um sistema, um MRN é ambíguo entre instalações.

23.15.5 reivindicação_us_core

ClaimUSCore adiciona o perfil US Core 9.0.0 a cada recurso produzido que foi verificado contra ele e está em conformidade.

Um recurso que não atende às expectativas é enviado sem a reivindicação, com uma nota explicando por quê.

23.15.6 validar_antes_de_enviar

ValidateBeforeSend recusa postar um pacote que falha na validação.

Padrão é verdadeiro: enviar um recurso que um servidor irá rejeitar desperdiça um orçamento de repetição e esconde o problema real atrás de um erro de transporte.

23.15.7 rejeitar_em_aviso

RejectOnWarning também recusa em avisos, como um identificador US Core ausente.

Desligado por padrão, porque um aviso é um julgamento sobre a conformidade do perfil em vez de sobre validade.

23.15.8 bearer_token

BearerToken é enviado como um cabeçalho de Autorização.

Prefira uma referência de variável de ambiente, ${NAME}, sobre um literal em um arquivo que vai para o git.

23.15.9 ecr

ECR torna este um destino de relatório de caso de saúde pública.

Cada mensagem é verificada para códigos de gatilho; uma que possui algum é enviada como um eCR 2.1 eICR, embrulhado em uma mensagem eCR, para a URL '$process-message', e uma sem nenhum não é enviada.

23.15.10 script de bundle

O BundleScript é JavaScript executado em cada Bundle convertido antes de ser validado e enviado: bundle é o Bundle como um objeto, editado no local.

É como um site adiciona o que seus próprios sistemas sabem e a mensagem v2 não diz - o código IKNR ou ODS de sua organização, um nível de contato de um perfil nacional - sem que o conversor adivinhe. Um script que lança uma exceção falha a mensagem, como qualquer outro transformador. Não é executado para relatórios de caso (ecr).

23.16 Destino FTP

FTPDestination carrega um arquivo por mensagem.

Definido como FTPDestination em internal/config.

ChaveTipoObrigatórioPadrão
hosttextosim21
usertextonão—
passwordtextonão—
securityFTPSecuritynãoexplícito em vez de nenhum
insecure_skip_verifyverdadeiro ou falsonão—
allow_clear_passwordverdadeiro ou falsonão—
dirtextosim—
file_nametextonão—
temp_suffixtextonão"
framedverdadeiro ou falsonão—
timeoutduração, como 30s ou 5mnão60s

23.16.1 host

O Host é o servidor, com uma porta opcional.

Padrão é 21, ou 990 para TLS implícito.

23.16.2 usuário

O usuário e a senha autenticam.

Um usuário vazio significa anônimo.

23.16.3 senha

O usuário e a senha autenticam.

Um usuário vazio significa anônimo.

23.16.4 segurança

Segurança selecciona TLS: explícito, implícito ou nenhum.

Por predefinição, selecciona explícito em vez de nenhum, porque predefinir para FTP simples faria a escolha insegura a mais silenciosa, e um site que genuinamente não tem TLS deve ter que escrevê-lo.

23.16.5 insecure_skip_verify

InsecureSkipVerify aceita qualquer certificado.

Necessário com mais frequência do que alguém gostaria: estes servidores frequentemente têm um certificado auto-assinado gerado há anos que ninguém pode reemitir. Nomeado separadamente para que a escolha seja deliberada e visível no ficheiro, em vez de escondida dentro de um modo "segurança: relaxada".

23.16.6 allow_clear_password

AllowClearPassword permite uma palavra-passe sobre FTP simples.

Recusado por predefinição, porque isso envia uma credencial através da rede em texto simples em cada entrega. Alguns analisadores genuinamente não têm TLS, por isso tem que ser possível - mas tem que ser escrito, para que seja uma decisão que alguém tomou, em vez de uma predefinição que herdou. O nome é deliberadamente desconfortável para digitar.

23.16.7 temp_suffix

TempSuffix é anexado enquanto o ficheiro está a ser escrito e removido por um rename uma vez que está completo.

Padrão é ".part".

Quem recolhe estes ficheiros é normalmente um trabalho agendado que pega no que encontra, e sem o rename, eventualmente pega metade de uma mensagem.

23.16.8 tempo de expiração

Timeout limita uma transferência.

Defaults to 60s.

23.17 Destino GCS

GCSDestination escreve cada mensagem como um objecto.

Definido como GCSDestination em internal/config.

ChaveTipoObrigatórioPredefinição
objecttextonão${date}/${channel}/${control_id}
storage_classtextonão—
content_typetextonão—

23.17.1 object

Object é o nome do objecto, com os mesmos espaços reservados que uma chave s3.

Padrão é ${date}/${channel}/${control_id}.hl7.

23.18 Destino HTTP

HTTPDestination envia mensagens para um ponto final HTTP.

A coisa mais comum que um canal Mirth faz que Perfuse não pode, e o bloqueador mais comum que o tradutor relata. A maioria dos usos é sem glamour: envie a mensagem para uma API interna, envie-a para um serviço web que embrulha um sistema legado, envie-a para algo que alguém escreveu em uma tarde.

Definido como HTTPDestination em internal/config.

ChaveTipoObrigatórioPredefinição
urltextosim—
methodtextonão—
content_typetextonão—
headersmapeamento de texto para textonão—
bearer_tokentextonão—
usernametextonão—
passwordtextonão—
tlstlsconf.Settings (um bloco, omitir para deixar de fora)não—
success_statuslista de número inteironãoqualquer 2xx
fail_on_bodylista de textonão—
follow_redirectsverdadeiro ou falsonão—

23.18.1 url

URL é onde enviar.

Required.

23.18.2 método

Método predefinido para POST.

O PUT é permitido para um endpoint que o deseje.

O GET e o DELETE são recusados: isso envia um corpo de mensagem e um transporte que silenciosamente descartou a mensagem devido a uma escolha de método seria uma maneira muito silenciosa de perder dados.

23.18.3 content_type

O ContentType padrão é application/hl7-v2+er7, que é o tipo registrado para uma mensagem HL7 v2 delimitada por pipe.

Muitos endpoints desejam text/plain em vez disso.

23.18.4 bearer_token

BearerToken é enviado como um cabeçalho de Autorização.

Prefira uma referência de variável de ambiente sobre um literal em um arquivo que vai para o git.

23.18.5 success_status

SuccessStatus lista os códigos de status que contam como entregues.

Padrão para qualquer 2xx.

Configurável porque os endpoints discordam sobre como parece o sucesso: alguns respondem 200 com um erro no corpo e alguns respondem 202 para uma fila que aceitou a mensagem.

23.18.6 fail_on_body

FailOnBody trata uma resposta contendo qualquer uma dessas strings como uma falha, independentemente do código de status.

Isso existe porque um endpoint que responde 200 com "ERROR: paciente não encontrado" no corpo é comum e tratá-lo como entregue significa que a mensagem some e ninguém sabe.

23.18.7 follow_redirects

FollowRedirects permite que o pedido seja redirecionado.

Desligado por padrão: um redirecionamento em uma escrita republicaria dados clínicos em algum lugar que a configuração nunca nomeou.

23.19 Destino IBMMQ

IBMMQDestination coloca cada mensagem em uma fila.

Definido como IBMMQDestination em internal/config.

ChaveTipoObrigatórioPadrão
non_persistenttrue ou falsenão—

23.19.1 non_persistent

NonPersistent envia mensagens que não sobrevivem a uma reinicialização do gerenciador de filas.

Desativado por padrão.

23.20 Destino JavaScript

JavaScriptDestination executa um script em vez de enviar para algum lugar.

O JavaScript Writer do Mirth, e é usado muito mais do que sua posição em uma lista de recursos sugere. É a saída de emergência: quando um site precisa se comunicar com algo que nenhum conector cobre, ou aplicar lógica que nenhuma transformação expressa, eles escrevem um JavaScript Writer. Uma migração que não pode executar esses não pode mover os canais que os têm, o que em uma instalação madura do Mirth é uma grande fração.

Deliberadamente não é um host de script geral. O script obtém a mensagem e os mesmos ajudantes que um transformador obtém; o que ele não obtém é uma maneira de alcançar o sistema de arquivos ou a rede, porque isso é o que os outros destinos são para e um script que abre seu próprio soquete é invisível para cada retry, fila e métrica no motor.

Definido como JavaScriptDestination em internal/config.

ChaveTipoObrigatórioPadrão
scripttextosim—
timeoutduração, como 30s ou 5mnão—
success_on_undefinedverdadeiro ou falso (um bloco, omitir para deixar de fora)nãoverdadeiro

23.20.1 script

O script é o código a ser executado.

Required.

23.20.2 tempo de expiração

O timeout limita uma execução.

Zero aplica um padrão.

Limitado porque um script de destino está no caminho de entrega: um loop infinito em um não apenas falha uma mensagem, mas também bloqueia a fila atrás dele.

23.20.3 success_on_undefined

SuccessOnUndefined trata um script que não retorna nada como sucesso.

Padrão é true.

Verdadeiro é o padrão correto e vale a pena explicar. Os escritores de JavaScript do Mirth fazem seu trabalho e não retornam nada, então exigir um retorno explícito quebraria todos eles na importação. Definir como falso é para um site que deseja que um script seja explícito sobre se funcionou.

23.21 Destino Kafka

KafkaDestination publica mensagens em um tópico Kafka.

Definido como KafkaDestination em internal/config.

ChaveTipoObrigatórioPadrão
brokerslista de textosim—
topictextosim—
keytextonão—
ackstextonãoall
compressiontextonãosnappy
headersmapeamento de texto para textonão—
timeoutduração, como 30s ou 5mnãotrinta segundos
saslKafkaSASL (um bloco, omitir para deixar de fora)não—
tlstlsconf.Settings (um bloco, omitir para deixar de fora)não—

23.21.1 corretoras

Corretoras é a lista de servidores de inicialização.

Required.

23.21.2 tópico

O tópico é onde publicar.

Required.

23.21.3 chave

A chave é um modelo para a chave do registro, que decide a partição.

Este é o campo que torna o Kafka seguro para uma alimentação clínica, e vale a pena ser preciso sobre por quê. O Kafka garante a ordem dentro de uma partição e em nenhum outro lugar. Registros com a mesma chave sempre aterrissam na mesma partição, então chavear no identificador do paciente mantém os eventos desse paciente em ordem, enquanto permite que pacientes diferentes sejam processados em paralelo.

Sem uma chave, não há garantia. Medido contra um corretor real, trinta registros não chaveados foram para uma partição em vez de se espalharem: o cliente mantém um lote junto e escolhe uma nova partição entre lotes. Então, a ordem é mantida por acidente e quebra em uma fronteira que ninguém pode ver, o que é pior do que quebrar consistentemente - uma alta A03 lida antes de sua admissão A01, intermitentemente, sob carga.

Um caminho HL7, avaliado contra a mensagem de saída: PID-3.1 chaveia pelo paciente.

23.21.4 acks

Acks é quantos corretores devem confirmar uma gravação: "all", "leader" ou "none".

Padrão para todos, que é a única configuração que sobrevive a uma falha do corretor entre a gravação e a replicação. "none" é disparar-e-esquecer e perderá mensagens; ele existe porque alguém que move telemetria não clínica pode legitimamente querê-lo, e recusá-lo diretamente significaria que eles escreveram seu próprio produtor.

23.21.5 compressão

A compressão é "none", "gzip", "snappy", "lz4" ou "zstd".

Padrão para snappy.

Ativado por padrão porque o HL7 é um texto altamente compressível e o fio é normalmente a restrição. Snappy em vez de zstd como padrão: é o mais barato em CPU, e um conector no caminho de entrega não deve ser a coisa que saturará um núcleo.

23.21.6 headers

Os cabeçalhos são cabeçalhos de registo para definir.

Os valores são modelos avaliados por mensagem.

23.21.7 tempo de expiração

O tempo limite define uma publicação.

O valor padrão é trinta segundos.

23.22 Destino MPI

O MPIDestination regista cada mensagem do paciente neste índice de pacientes do servidor: um PID HL7 v2 (um merge A40 merge), ou um Paciente FHIR em um canal bruto.

O índice decide quais registos são a mesma pessoa; consulte a tela do índice de pacientes.

Definido como MPIDestination em internal/config.

ChaveTipoObrigatórioPredefinido
authoritiesmapeamento de texto para textonão—
id_typetextonão—
ssn_systemtextonão—
no_mergeverdadeiro ou falsonão—

23.22.1 autoridades

As autoridades mapeiam o espaço de nome da autoridade de atribuição (PID-3.4.1) para o seu sistema de identificador, para remetentes que não fornecem um identificador universal.

Os não mapeados tornam-se urn:perfuse:aa:<namespace>.

23.22.2 id_type

O IDType é o tipo de identificador (PID-3.5) do número do registo.

Default MR.

23.22.3 ssn_system

O SSNSystem nomeia o PID-19 como um identificador.

Default http://hl7.org/fhir/sid/us-ssn.

23.23 Destino MQTT

O MQTTDestination publica para um tópico.

Definido como MQTTDestination em internal/config.

ChaveTipoObrigatórioPredefinido
topictextosim—
retainverdadeiro ou falsonão—

23.23.1 tópico

O tópico é publicado.

Ele não pode conter caracteres curinga.

23.24 Destino PAS

O destino PASDestination submete cada mensagem, um pacote de solicitação Da Vinci PAS, ao Claim/$submit de um pagador, para um prestador de serviços cujos sistemas constroem a solicitação (um EHR, DTR) e precisam enviá-la, gravar a decisão e transmitir a resposta.

Definido como PASDestination em internal/config.

ChaveTipoObrigatórioPadrão
payertextosim—
bearer_tokentextonão—
authFHIRAuth (um bloco, omitir para não incluir)não—
results_totextonão—

23.24.1 bearer_token

BearerToken é um token estático, ${ENV} permitido.

Autenticação é OAuth client credentials em vez disso, ou Azure, como um destino FHIR.

23.24.2 autenticação

BearerToken é um token estático, ${ENV} permitido.

Autenticação é OAuth client credentials em vez disso, ou Azure, como um destino FHIR.

23.25 Destino Pub Sub

O PubSubDestination publica para um tópico Pub/Sub.

Definido como PubSubDestination em internal/config.

ChaveTipoObrigatórioPredefinido
topictextosim—
order_bytextonão—

23.26 Destino S3

S3Destination escreve cada mensagem como um objeto.

Definido como S3Destination em internal/config.

ChaveTipoObrigatórioPadrão
buckettextosim—
regiontextosim—
keytextonãoum caminho com partições de data mais o ID de controle
access_key_idtextonão—
secret_access_keytextonão—
session_tokentextonão—
endpointtextonão—
path_styleverdadeiro ou falsonão—
server_side_encryptiontextonão—
content_typetextonãoapplication/hl7-v2 para HL7 e texto/plano caso contrário
framedverdadeiro ou falsonão—
timeoutduração, como 30s ou 5mnão60s
storage_classtextonão—
formattextonão—

23.26.1 chave

A chave modela a chave do objeto, usando os mesmos espaços reservados ${date}, ${timestamp}, ${control_id}, ${message_type} e ${channel} que os destinos de arquivo e SFTP.

Padrão é um caminho com partições de data mais o ID de controle.

Particionamento de data por padrão porque a alternativa - todos os objetos em um prefixo plano - torna o bucket lento para listar e impossível de gerenciar por idade, e ninguém descobre isso até que haja quatro milhões de objetos nele.

23.26.2 access_key_id

AccessKeyID e SecretAccessKey autenticam.

Qualquer um deles pode nomear uma variável de ambiente em vez de conter o valor, usando a forma ${NAME}.

23.26.3 secret_access_key

AccessKeyID e SecretAccessKey autenticam.

Qualquer um deles pode nomear uma variável de ambiente em vez de conter o valor, usando a forma ${NAME}.

23.26.4 path_style

PathStyle endereça o bucket como um caminho em vez de um subdomínio.

A maioria dos armazenamentos compatíveis com S3 precisa disso.

23.26.5 content_type

ContentType rotula o objeto.

Padrão é application/hl7-v2 para HL7 e texto/plano caso contrário.

23.26.6 tempo de expiração

Timeout limita uma upload.

Defaults to 60s.

23.26.7 storage_class

StorageClass é a classe de armazenamento S3 que cada objeto é escrito com: STANDARD_IA, INTELLIGENT_TIERING, GLACIER_IR, GLACIER, DEEP_ARCHIVE e assim por diante.

Essa é a forma como um arquivo vai direto para o Glacier - o S3 não tem uma API separada do Glacier para chamar.

23.26.8 formato

Formato é hl7 (padrão: cada objeto é a mensagem) ou ndjson: cada objeto é uma linha JSON com a mensagem e os campos dignos de consulta, sob chaves com partições de data, para que o Amazon Athena possa consultar o arquivo.

Veja perfuse athena.

23.27 Destino SFTP

SFTPDestination escreve cada mensagem em um arquivo em um servidor SFTP.

Definido como SFTPDestination em internal/config.

ChaveTipoObrigatórioPadrão
hosttextosim22
usertextosim—
passwordtextonão—
key_filetextonão—
key_passphrasetextonão—
known_hosts_filetextonão—
insecure_skip_host_key_checkverdadeiro ou falsonão—
dirtextosim—
file_nametextonãoum carimbo de data/hora mais o ID de controle
temp_suffixtextonão"
framedverdadeiro ou falsonão—
appendverdadeiro ou falsonão—
timeoutduração, como 30s ou 5mnão60s

23.27.1 host

O Host é o servidor, com uma porta opcional.

Defaults to 22.

23.27.2 senha

Senha autentica com uma senha.

Prefer KeyFile.

23.27.3 file_name

FileName define o nome.

O padrão é um carimbo de data/hora mais o ID de controle.

23.27.4 temp_suffix

TempSuffix é anexado enquanto um arquivo está sendo escrito e removido por um rename uma vez que esteja completo.

Padrão é ".part".

A mesma cortesia que este conector precisa no caminho de entrada. Quem coleta esses arquivos tem o mesmo problema, e um rename dentro de um diretório é atômico em todos os servidores dignos de uso.

23.27.5 tempo de expiração

O tempo limite define uma ligação única.

Defaults to 60s.

23.28 Destino SMTP

SMTPDestination configura a entrega por e-mail.

Definido como SMTPDestination em internal/config.

ChaveTipoObrigatórioPadrão
hosttextosim—
fromtextosim—
tolista de textosim—
cclista de textonão—
bcclista de textonão—
subjecttextonão—
bodytextonão—
attachverdadeiro ou falsonão—
attach_nametextonãoo ID de controle com um
usernametextonão—
passwordtextonão—
starttlsverdadeiro ou falso (um bloco, omitir para deixar de fora)não—
insecure_skip_verifyverdadeiro ou falsonão—
timeoutduração, como 30s ou 5mnão—

23.28.1 host

Host é o servidor de e-mail, com uma porta opcional.

A porta 587 é assumida, que é a porta de envio com STARTTLS - a porta que um servidor moderno espera de um cliente. A porta 25 é servidor-para-servidor e geralmente é bloqueada ou não autenticada.

23.28.2 de

De é o remetente do envelope.

Obrigatório, porque uma mensagem sem remetente é descartada silenciosamente por uma grande parte da infraestrutura de e-mail, o que a torna a falha mais difícil de diagnosticar.

23.28.3 para

Para, CC e BCC são destinatários.

Pelo menos um Para é obrigatório.

23.28.4 cc

Para, CC e BCC são destinatários.

Pelo menos um Para é obrigatório.

23.28.5 bcc

Para, CC e BCC são destinatários.

Pelo menos um Para é obrigatório.

23.28.6 corpo

Corpo é o texto da mensagem.

As referências de campo são substituídas, como no Assunto. Quando está vazio, a mensagem em si é o corpo.

23.28.7 attach_name

AttachName nomeia o anexo.

O padrão é o ID de controle com um sufixo .hl7.

23.28.8 nome de usuário

Nome de usuário e Senha autenticam no servidor.

Ambos ou nenhum.

23.28.9 senha

Nome de usuário e Senha autenticam no servidor.

Ambos ou nenhum.

23.28.10 starttls

O StartTLS atualiza a conexão antes da autenticação.

Ele é ativado por padrão e desativá-lo com um nome de usuário definido é recusado em vez de permitido: enviar uma senha sobre uma conexão não criptografada não é uma compensação digna de ser oferecida.

23.28.11 insecure_skip_verify

InsecureSkipVerify aceita qualquer certificado.

Nomeado sem ambiguidade porque é isso que ele faz.

23.29 Destino SNS

SNSDestination publica cada mensagem para um tópico SNS.

Definido como SNSDestination em internal/config.

ChaveTipoObrigatórioPadrão
topic_arntextosim—
subjecttextonão—
group_bytextonão—

23.29.1 assunto

O assunto é enviado com assinaturas de e-mail.

Opcional; ${message_type} e ${control_id} são preenchidos.

23.30 Destino SOAP

SOAPDestination publica uma solicitação SOAP por mensagem.

Definido como SOAPDestination em internal/config.

ChaveTipoObrigatórioPadrão
urltextosim—
profiletextonão—
facility_idtextonão—
warnings_are_errorsverdadeiro ou falsonão—
actiontextonão—
versiontextonão1
bodytextosim—
headertextonão—
headersmapeamento de texto para textonão—
usernametextonão—
passwordtextonão—
tlstlsconf.Settings (um bloco, omitir para deixar de fora)não—
fault_is_successlista de textonão—
timeoutduração, como 30s ou 5mnão30s

23.30.1 perfil

O nome do perfil nomeia um serviço padrão cujo envelope o Perfuse constrói sozinho.

Vazio é uma chamada SOAP simples com o corpo escrito neste arquivo.

"cdc-iis" é a interface do registro de imunização do CDC (urn:cdc:iisb:2011), que todos os registros estaduais dos EUA usam: a mensagem vai em submitSingleMessage, o nome de usuário e a senha vão no corpo como o WSDL diz (não como autenticação HTTP), SOAP 1.2 por padrão e o registro de HL7 decide se a mensagem foi entregue. Um registro responde a uma rejeição de disparo com HTTP 200 e um AR dentro, então sem isso uma rejeição lê como um sucesso.

23.30.2 facility_id

FacilityID é o facilityID do cdc-iis, o identificador do registro para a organização que envia.

Opcional no WSDL; alguns registros exigem isso.

23.30.3 warnings_are_errors

WarningsAreErrors, para cdc-iis, trata um reconhecimento AE que contém apenas avisos como uma falha.

Desativado por padrão: os registros enviam AE para "aceito com avisos" e a gravidade ERR diz se algo foi perdido.

23.30.4 acção

A Acção é o SOAPAction.

Requerido pela maioria dos serviços 1.1.

23.30.5 corpo

Corpo é o XML que vai dentro do envelope, com referências de estilo ${PID-5.1} a caminhos de mensagens.

Obrigatório, a menos que um perfil o construa. Não há um valor padrão útil: os nomes dos elementos vêm do esquema próprio do serviço e nenhum mecanismo pode adivinhá-los.

23.30.6 cabeçalho

Cabeçalho é o XML para o elemento Cabeçalho do envelope.

Omitido por completo quando vazio, porque alguns serviços rejeitam um vazio.

23.30.7 fault_is_success

FaultIsSuccess lista códigos de falha que contam como entregues.

Necessário com mais frequência do que deveria ser. Um serviço que responde a uma reenvio com "já submetido" está dizendo que a mensagem chegou, e sem isso um site tem que escrever um transformador de resposta para dizer isso - ou pior, assiste a uma fila de repetição para sempre contra um receptor que já tem a mensagem.

23.30.8 tempo de expiração

Timeout limita uma chamada.

Defaults to 30s.

23.31 Destino SQS

SQSDestination envia cada mensagem para uma fila SQS.

Definido como SQSDestination em internal/config.

ChaveTipoObrigatórioPadrão
queue_urltextosim—
group_bytextonão—

23.31.1 queue_url

QueueURL nomeia a fila.

Uma que termina .fifo é uma fila FIFO e é agrupada e deduplicada.

23.32 Destino TCP

TCPDest envia mensagens para um soquete com estruturação configurável.

Definido como TCPDest em internal/config.

ChaveTipoObrigatórioPadrão
addresstextosim—
max_message_sizenúmero inteironão—
timeoutduração, como 30s ou 5mnão—
expect_replyverdadeiro ou falsonão—
keep_aliveverdadeiro ou falsonão—
tlstlsconf.Settings (um bloco, omitir para deixar de fora)não—

23.32.1 expect_reply

ExpectReply aguarda bytes de volta antes de relatar sucesso.

Desativado por predefinição, e vale a pena considerar. Com ele desativado, "entregue" significa que os bytes alcançaram o buffer de envio do sistema operacional, que um peer que travou um momento depois nunca leu. Com ele ativado, um peer que nunca responde faz com que todas as mensagens expirem.

23.32.2 keep_alive

KeepAlive mantém uma conexão aberta entre mensagens em vez de discar por mensagem.

A maioria dos dispositivos endpoints espera isso; alguns recusam uma segunda mensagem na mesma conexão. Desativado por predefinição porque uma conexão por mensagem é o comportamento que funciona em todos os lugares, ao custo de um aperto de mão cada vez.

23.33 Destino TEFCA

O destino TEFCADestination solicita ao parceiro FHIR facilitado pela TEFCA os registros de cada paciente da mensagem.

Quem é este servidor na rede, seu certificado e o parceiro são configurações do servidor (Configurações, TEFCA), pois pertencem à organização e ao seu acordo com um QHIN. O que um canal decide é quando solicitar e por quê: o propósito de uso é parte do canal, não de quem está conectado, então cada consulta que uma fonte de dados faz declara o mesmo motivo e o registro de auditoria pode ser lido contra ele.

Definido como TEFCADestination em internal/config.

ChaveTipoObrigatórioPadrão
purposetextosim—
results_totextonão—

23.33.1 propósito

O propósito é o propósito de uso: tratamento, pagamento, operações, saúde_pública ou acesso_individual.

Ele deve ser um dos participantes declarados.

23.33.2 resultados_para

ResultadosPara nomeia um canal neste servidor que recebe cada Bundle que o parceiro retorna, como uma mensagem própria.

Vazio mantém o Bundle como resposta apenas deste destino, para que um transformador de resposta possa lê-lo.

23.34 Destino XDS

XDSDestination publica cada documento clínico em um repositório de documentos XDS.b da IHE com ITI-41 Fornecer e Registrar.

Os metadados são lidos do documento CDA (paciente, título, tipo, tempo, autor, confidencialidade, idioma) e completados a partir dessas configurações, que dizem o que o documento não pode: quem o está enviando, que tipo de instalação e prática ele veio, e qual dos identificadores do paciente é o domínio de afinidade.

Definido como XDSDestination em internal/config.

ChaveTipoObrigatórioPadrão
urltextosim—
source_idtextosim—
patient_domaintextonão—
facility_typeXDSCodesim—
practice_settingXDSCodesim—
classXDSCode (um bloco, omitir para deixar de fora)não—
content_typeXDSCode (um bloco, omitir para deixar de fora)não—
tokentextonão—
usernametextonão—
passwordtextonão—
headersmapeamento de texto para textonão—
tlstlsconf.Settings (um bloco, omitir para deixar de fora)não—
timeoutduração, como 30s ou 5mnão—
direct_fromtextonão—
direct_tolista de textonão—

23.34.1 patient_domain

PatientDomain é a autoridade OID de atribuição do domínio de afinidade: o identificador do paciente com essa raiz é o que é registrado.

Sem ele, um documento cujo paciente tem um identificador envia esse identificador, e um com vários é recusado.

23.34.2 token

Token ou Nome de Usuário/Senha autenticam; Cabeçalhos são adicionados a cada solicitação.

A maioria dos domínios de afinidade usa TLS mútuo (tls) em vez disso.

23.34.3 nome de usuário

Token ou Nome de Usuário/Senha autenticam; Cabeçalhos são adicionados a cada solicitação.

A maioria dos domínios de afinidade usa TLS mútuo (tls) em vez disso.

23.34.4 senha

Token ou Nome de Usuário/Senha autenticam; Cabeçalhos são adicionados a cada solicitação.

A maioria dos domínios de afinidade usa TLS mútuo (tls) em vez disso.

23.34.5 headers

Token ou Nome de Usuário/Senha autenticam; Cabeçalhos são adicionados a cada solicitação.

A maioria dos domínios de afinidade usa TLS mútuo (tls) em vez disso.

23.34.6 tls

Token ou Nome de Usuário/Senha autenticam; Cabeçalhos são adicionados a cada solicitação.

A maioria dos domínios de afinidade usa TLS mútuo (tls) em vez disso.

23.34.7 direct_from

DirectFrom e DirectTo fazem a submissão XDR como o transporte Direct: um bloco de endereçamento Direct que nomeia o endereço Direct do remetente e o dos destinatários, e os destinatários no destinatário pretendido da submissão.

Um HISP que recebe XDR entrega como correio Direct, ou para o endpoint XDR próprio do destinatário.

23.34.8 direct_to

DirectFrom e DirectTo fazem a submissão XDR como o transporte Direct: um bloco de endereçamento Direct que nomeia o endereço Direct do remetente e o dos destinatários, e os destinatários no destinatário pretendido da submissão.

Um HISP que recebe XDR entrega como correio Direct, ou para o endpoint XDR próprio do destinatário.

24 Referência de Formato

Opções que governam como as mensagens são analisadas e escritas, para os formatos que precisam de mais do que um nome.

24.1 Anexos

Anexos configura a movimentação de grandes payloads para fora de uma mensagem.

Uma mensagem que transporta um relatório digitalizado ou um PDF é comum em fluxos de trabalho de documentos, e a carga é rotineiramente centenas de vezes maior do que a mensagem ao seu redor. Deixada inline, significa que o armazenamento cresce à taxa dos documentos em vez do tráfego, uma mensagem enfileirada para cinco destinos é copiada cinco vezes, e a interface transmite megabytes para mostrar o nome de um paciente a alguém.

Mirth chama esses de manipuladores de anexos. Isso é o equivalente, e é opt-in por canal porque uma alimentação de mensagens ADT simples não tem nada a extrair e não deve pagar pela maquinaria.

Definido como Attachments em internal/config.

ChaveTipoObrigatórioPredefinição
extractlista de attach.Regrasim—
reassembleverdadeiro ou falso (um bloco, omitir para deixar de fora)nãoverdadeiro

24.1.1 reassemble

Reassemble coloca as cargas de volta antes da entrega.

Padrão é true.

O predefinição é ativado porque um receptor que espera um documento deve receber um documento; uma mensagem que contém um token literal seria arquivada como um relatório e ninguém descobriria até que alguém abrisse o registro.

Desativá-lo é para o caso em que o objetivo do canal é remover documentos - encaminhar metadados para um sistema que não tem utilidade para a imagem, onde enviá-la seria uma questão de privacidade em vez de largura de banda.

24.2 Delimitado

Delimitado configura um canal delimitado.

Tipo de dados Delimitado do Mirth: CSV, separado por tabulações e a longa lista de formatos que um analisador de laboratório ou um serviço de burocracia emite.

Definido como Delimited em internal/config.

ChaveTipoObrigatórioPadrão
delimitertextonão—
quotetextonãoaspas duplas
commenttextonão—
has_headerverdadeiro ou falsonão—
columnslista de textonão—
trim_spaceverdadeiro ou falsonão—
relaxedverdadeiro ou falsonão—
splitverdadeiro ou falso (um bloco, omitir para deixar de fora)nãoverdadeiro
keep_blank_linesverdadeiro ou falsonão—
filtertextonão—
transformationslista de etapas.Stepnão—

24.2.1 delimitador

O delimitador separa colunas, como um caractere ou um nome.

Um nome é aceito porque uma tabulação não pode ser escrita em um arquivo YAML de forma inequívoca, e um arquivo de configuração que contém um caractere invisível é ilegível para quem o abrir em seguida.

24.2.2 aspas

As aspas envolvem valores que contêm o delimitador.

Padrão é aspas duplas; "nenhum" desativa-o.

24.2.3 divisão

A divisão torna cada linha sua própria mensagem.

Padrão é true.

Essa é a decisão que define um canal delimitado e merece ser dita em voz alta. Um arquivo de cinco mil resultados é ou uma mensagem ou cinco mil. Uma mensagem significa um reconhecimento, uma entrada no navegador e uma falha que afeta todo o arquivo. Cinco mil significa que cada linha é filtrada, transformada, entregue e reenviada por conta própria, e uma linha ruim não impede as demais.

A divisão é o padrão porque o tratamento por linha é o que quase todos os sites desejam e porque a alternativa é descoberta tarde: um canal que parecia bom nos testes com um arquivo de três linhas falha em uma transferência noturna inteira devido a uma linha malformada.

24.2.4 manter_linhas_em_branco

ManterLinhasEmBranco impede que linhas em branco sejam puladas.

Pular é o padrão, porque todo arquivo termina com uma quebra de linha e um registro de campos vazios não é um registro. Isso existe para o formato raro em que uma linha em branco é significativa.

24.2.5 filtro

O filtro decide quais mensagens continuam, escrito contra nomes de coluna.

Aqui, em vez de no canal, porque o filtro de nível de canal compila caminhos HL7. Duas configurações nomeadas filtro seriam confusas, mas uma configuração que significa coisas diferentes dependendo do tipo de dados é pior: um canal delimitado que compila silenciosamente seu filtro como HL7 não corresponderia a nada e droparia tudo, o que é a falha que a recusa de nível superior existe para prevenir.

24.2.6 transformações

As transformações são as etapas declarativas, abordando colunas em vez de campos HL7.

Separado das transformações do canal pelo mesmo motivo do Filtro, e é o arranjo que X12 e NCPDP já usam.

24.3 Opções HL7v3

Opções HL7v3 são as configurações que se aplicam apenas a um canal HL7 v3.

Definido como HL7v3Options em internal/config.

ChaveTipoObrigatórioPadrão
filtertextonão—
acknowledgeverdadeiro ou falso (um bloco, omitir para deixar de fora)não—
sender_devicetextonão—
sender_oidtextonão—
transformationslista de etapas hl7v3.Stepnão—

24.3.1 filtro

O filtro exclui mensagens, utilizando caminhos v3.

É um campo próprio, em vez do filtro comum do canal, porque os dois são linguagens diferentes contra modelos de mensagem diferentes. Compartilhar o campo significaria que um filtro v2 nunca corresponderia silenciosamente a um canal v3, ou um filtro v3 falharia ao analisar como v2 - e o segundo é apenas melhor porque falha ruidosamente.

Um canal que define ambos é recusado na carga, desde que um deles teria que ser ignorado e não há uma maneira honesta de escolher.

24.3.2 confirmar

Confirmar envia um reconhecimento MCCI_IN000002UV01 de volta.

Ligado por padrão, ao contrário do X12. Uma interação v3 sobre um transporte síncrono espera um reconhecimento - o aplicativo de envio geralmente está esperando por um - e um remetente que recebe nada geralmente irá repetir, o que é como um paciente é registrado três vezes.

Um ponteiro para que "não definido" e "definido como falso" sejam diferentes: o padrão é ligado, e alguém que o desligue deve ter dito isso.

24.3.3 dispositivo_remessor

DispositivoRemetente é o identificador de dispositivo que colocamos em um reconhecimento.

Obrigatório ao confirmar. Um reconhecimento v3 nomeia o dispositivo de onde vem, e um receptor que não reconhece o nosso pode descartá-lo - o que parece exatamente como não enviá-lo.

24.3.4 transformações

Transformações alteram o conteúdo de um documento v3.

É um campo próprio, em vez das transformações comuns do canal, pelo mesmo motivo que o filtro é: são vocabulários diferentes contra modelos de mensagem diferentes. As etapas v2 abordam segmentos e campos, que um documento v3 não tem, então compartilhar o campo significaria que uma etapa faria silenciosamente nada.

Os nomes das etapas correspondem aos v2 sempre que o significado corresponde, então alguém que tenha escrito um canal pode escrever o outro. O que é diferente é o que v3 precisa e v2 não pode expressar - principalmente que remover um valor tem três significados distintos, então limpar, nulificar e remover são três etapas em vez de uma.

24.4 Estruturação TCP

EstruturaçãoTCP é como as fronteiras de mensagem são encontradas em um soquete bruto.

Compartilhado pela origem TCP e pelo destino TCP, e pela origem serial, porque as estruturações são as mesmas, independentemente de onde os bytes vêm. Um analisador de laboratório que fala STX/ETX sobre um soquete fala STX/ETX sobre um cabo serial também.

Definido como TCPFraming em internal/config.

ChaveTipoObrigatórioPadrão
framingtextosim—
delimitertextonão—
start_blocktextonão—
keep_delimiterverdadeiro ou falsonão—
record_lengthnúmero inteironão—
trim_paddingverdadeiro ou falso (um bloco, omitir para deixar de fora)não—
length_bytesnúmero inteironão—
big_endianverdadeiro ou falsonão—
length_includes_headerverdadeiro ou falsonão—

24.4.1 estruturação

Estruturação é mllp, delimitada, fixa, comprimento ou inteira.

Obrigatório, sem padrão. Ler um fluxo com a estruturação errada produz mensagens que parecem plausíveis em vez de um erro, então adivinhar é pior do que perguntar.

24.4.2 bloco_inicial

BlocoInicial opcionalmente começa uma mensagem.

Bytes antes dele são descartados como ruído de uma conexão parcial.

24.4.3 manter_delimitador

KeepDelimiter inclui o delimitador na mensagem.

Desativado por padrão: é um quadro, não conteúdo.

24.4.4 trim_padding

TrimPadding remove espaços e NULs finais de um registro fixo.

Ativado por padrão.

24.5 Opções X12

X12Options são as configurações que se aplicam apenas a um canal X12.

Definido como X12Options em internal/config.

ChaveTipoObrigatórioPadrão
envelopeEnvelopePolicynãoexigir
splitverdadeiro ou falsonão—
acknowledgetextonão—
ack_sender_idtextonão—
ack_sender_qualifiertextonão—
arrives_astextonão—
transformationslista de x12.Stepnão—

24.5.1 envelope

Envelope diz o que fazer quando as contagens autodeclaradas não correspondem ao que está presente.

Padrão é exigir.

24.5.2 divisão

Split envia uma mensagem por conjunto de transações em vez de uma por arquivo.

Desativado por padrão. Um único 837 pode transportar centenas de reclamações, então ativá-lo multiplica tudo downstream - contagens de mensagens, confirmações, linhas, limiares de alerta - e isso deve ser uma decisão que alguém tomou em vez de um padrão que herdou.

24.5.3 confirmar

Acknowledge diz qual confirmação enviar de volta: 999, 997, ta1 ou nenhuma.

Qual é uma propriedade da relação de parceiro comercial e não da mensagem, então precisa ser configurada. Um 999 substitui um 997 para transações HIPAA, mas muitos parceiros - especialmente conexões de pagadores mais antigos - estão configurados para esperar um 997 e tratarão um 999 como um arquivo não reconhecido. Enviar o errado é pior do que não enviar nada, porque responde a uma pergunta que ninguém fez e deixa a real aberta.

Vazio significa nenhuma, que é o padrão seguro: um parceiro que não está esperando uma confirmação e a recebe pode tratá-la como uma troca não solicitada.

24.5.4 ack_sender_id

AckSenderID e AckSenderQualifier são nossos próprios identificadores de interchange, tornando-se ISA06 e ISA05 de qualquer confirmação.

Obrigatório sempre que Acknowledge estiver definido e recusado na carga caso contrário. Esses devem ser os valores que o parceiro comercial configurou para nós e não há como adivinhá-los: uma troca cujo ISA06 o parceiro não reconhece é descartada antes que alguém a leia, então um valor errado produz silêncio que parece exatamente como não enviar nada - e alguém passa uma semana procurando no lugar errado.

24.5.5 ack_sender_qualifier

AckSenderID e AckSenderQualifier são nossos próprios identificadores de interchange, tornando-se ISA06 e ISA05 de qualquer confirmação.

Obrigatório sempre que Acknowledge estiver definido e recusado na carga caso contrário. Esses devem ser os valores que o parceiro comercial configurou para nós e não há como adivinhá-los: uma troca cujo ISA06 o parceiro não reconhece é descartada antes que alguém a leia, então um valor errado produz silêncio que parece exatamente como não enviar nada - e alguém passa uma semana procurando no lugar errado.

24.5.6 chega_como

ChegaComo é xml quando a fonte entrega a troca como o XML que o Mirth Connect e o Open Integration Engine escrevem para X12 (uma raiz X12Transaction, elementos nomeados CLM.05.1), como um motor que está sendo migrado de, ou um sistema construído contra um, o envia.

Ele é revertido para X12 antes que qualquer outra coisa aconteça. Vazio ou x12 é X12.

24.5.7 transformações

Transformações são alterações declarativas aplicadas a trocas aceitas.

Separado das transformações de nível de canal pelas mesmas razões pelas quais as de v3 são: essas abordam campos HL7 por meio de um analisador que lê segmento-campo-subcomponente, e o X12 não tem subcomponente, trata segmentos repetidos como ordinários em vez de excepcionais e é escrito CLM01 pelas pessoas que o configuram. Um analisador compartilhado teria que aceitar ambas as notações e seria então ambíguo em ambas.

Os nomes dos passos são os mesmos usados pelos passos HL7 e v3, então o que um autor já aprendeu é aplicável.

25 Referência de Comportamento

Confirmação, enfileiramento, repetição, sondagem, configurações de script e sombra. Estas se aplicam independentemente do transporte utilizado por um canal.

25.1 Conexão AMQP

AMQPConnection é onde e como se conectar.

Definido como AMQPConnection em internal/config.

ChaveTipoObrigatórioPadrão
addrtextosim—
addresstextosim—
usernametextonão—
passwordtextonão—
hostnametextonãoo host de addr
tlstlsconf.Settings (um bloco, omitir para deixar de fora)não—
timeoutduração, como 30s ou 5mnão30s

25.1.1 nome de usuário

Nome de usuário e senha autenticam com SASL PLAIN; ambos vazios significam ANÔNIMO.

Para Service Bus, o nome da política e a chave.

25.1.2 senha

Nome de usuário e senha autenticam com SASL PLAIN; ambos vazios significam ANÔNIMO.

Para Service Bus, o nome da política e a chave.

25.1.3 nome do host

O nome do host é enviado ao corretor, que o Service Bus roteia.

Padrão para o host de addr.

25.1.4 tls

TLS criptografa a conexão.

Obrigatório para Service Bus e Event Hubs.

25.1.5 tempo de expiração

Limites de tempo para conectar e cada espera pelo corretor.

Defaults to 30s.

25.2 Parceiro AS2

AS2Partner é um parceiro comercial que uma fonte AS2 aceita mensagens de.

Definido como AS2Partner em internal/config.

ChaveTipoObrigatórioPadrão
idtextosim—
cert_filetextosim—
allow_unsignedverdadeiro ou falsonão—
allow_unencryptedverdadeiro ou falsonão—

25.2.1 cert_file

CertFile é o certificado do parceiro (PEM), para suas assinaturas.

Muitas vezes autoassinado: parceiros AS2 trocam certificados diretamente em vez de através de uma autoridade.

25.2.2 allow_unsigned

AllowUnsigned e AllowUnencrypted aceitam uma mensagem deste parceiro que não está assinada ou não está criptografada.

Desligado: tal mensagem é recusada com um recibo que explica o motivo.

25.2.3 allow_unencrypted

AllowUnsigned e AllowUnencrypted aceitam uma mensagem deste parceiro que não está assinada ou não está criptografada.

Desligado: tal mensagem é recusada com um recibo que explica o motivo.

25.3 Acesso AWS

O acesso AWS é como um conector alcança a AWS: a região para a qual ele assina, as chaves e um endpoint opcional de substituição.

As credenciais podem ser literais ou referências ${ENV_VAR}, que é como elas devem ser fornecidas. Não há uma cadeia de credenciais de instância de metadados, deliberadamente: consulte internal/awsv4.

Definido como AWSAccess em internal/config.

ChaveTipoObrigatórioPadrão
regiontextosim—
access_key_idtextonão—
secret_access_keytextonão—
session_tokentextonão—
endpointtextonão—

25.3.1 secret_access_key

A SecretAccessKey é o segredo, literal ou ${AWS_SECRET_ACCESS_KEY}.

Prefira a referência: este arquivo vai para o controle de versão.

25.3.2 session_token

O SessionToken é apenas para credenciais temporárias.

Elas expiram, e o conector para de funcionar quando elas expiram.

25.4 Ack

Ack configura a geração de confirmação.

Definido como Ack em internal/config.

ChaveTipoObrigatórioPadrão
whenAckWhennão—
applicationtextonão—
facilitytextonão—
include_trigger_eventverdadeiro ou falsonão—

25.4.1 incluir_evento_de_disparo

IncludeTriggerEvent envia ACK^A01 em vez de ACK.

Alguns receptores exigem isso, enquanto outros o rejeitam, por isso é explícito.

25.5 Acesso ao Blob do Azure

O AzureBlobAccess é a conta, o contêiner e a credencial.

Definido como AzureBlobAccess em internal/config.

ChaveTipoObrigatórioPadrão
accounttextosim—
containertextosim—
keytextonão—
sastextonão—
endpointtextonão—

25.5.1 chave

A chave é a chave da conta, ou ${AZURE_STORAGE_KEY}.

Defina-a ou sas.

25.5.2 sas

O SAS é uma cadeia de consulta de assinatura de acesso compartilhado, ou uma referência ${...}.

Preferido: pode ser limitado a este contêiner.

25.6 Referência de Contrato

ContractRef aponta um canal para o seu contrato.

Definido como ContractRef em internal/config.

ChaveTipoObrigatórioPadrão
filetextosim—
check_everytextonão15 minutos
overnúmero inteironão500

25.6.1 check_every

CheckEvery é a frequência com que re-verificar, como uma duração.

Padrão é 15 minutos.

Efetivamente limitado ao intervalo de avaliação de alerta, que é de 30 segundos por padrão, porque a verificação é executada a partir desse loop em vez de um temporizador próprio - então um contrato que solicita 3s obtém 30s. Isso é deliberado: um temporizador é mais fácil de entender do que dois, e mantém o resultado do contrato em sincronia com a leitura a que está anexado. Vale a pena saber antes que alguém defina um intervalo curto e conclua que está quebrado.

Não por mensagem. Construir um perfil significa ler o tráfego recente e fazer isso em cada mensagem faria com que o débito de um canal dependesse da quantidade de histórico que tem - o que é o tipo de característica de desempenho que só aparece em produção, seis meses depois.

25.6.2 over

Over é o número de mensagens recentes a serem perfiladas.

Defaults to 500.

Um recuento em vez de uma janela de tempo, porque uma fonte de alimentação silenciosa e uma ocupada precisam da mesma quantidade de evidências para justificar uma taxa, e uma janela de tempo fornece quantidades muito diferentes.

25.7 Opções DICOM

DICOMOptions configura um canal de imagem.

Por que os passos são nomeados em vez de caminhos

Todo o outro formato obtém um escritor de caminho. DICOM deliberadamente não o faz, e o motivo é os dados de pixel: um objeto é binário, um escritor de tag geral pode definir qualquer tag para qualquer byte, e um erro lá não produz uma mensagem rejeitada - produz uma imagem que abre e está errada. Um radiologista que lê um estudo não tem como saber.

Então, as quatro coisas que os sites realmente precisam são ações nomeadas com efeitos limitados: desidentificar, reescrever um título AE, remover tags privadas, definir a instituição. Cada uma sabe quais tags ela toca, e nenhuma pode alcançar os dados de pixel.

Por que este bloco existe agora

internal/dicom carregou steps.go e transform.go por um tempo - as quatro ações, dicom.Apply e testes. Nada as referenciou. Quinhentas linhas sem um chamador, que a própria seção 7 da fila nomeia: uma implementação sem um chamador é indistinguível de um recurso que não existe. Este bloco e a chamada do mecanismo são o fio, não o recurso.

Definido como DICOMOptions em internal/config.

ChaveTipoObrigatórioPadrão
transformationslista de dicom.Stepnão—

25.8 Endereço Direto

DirectAddress é um endereço Direct que este servidor mantém: seu certificado e chave, e os âncoras que confia.

O mesmo bloco é usado para enviar (assinar como este endereço) e para receber (decifrar para ele).

Definido como DirectAddress em internal/config.

ChaveTipoObrigatórioPadrão
addresstextosim—
cert_filetextosim—
key_filetextosim—
anchors_filetextosim—

25.8.1 cert_file

CertFile e KeyFile são o certificado da morada (PEM, com a sua cadeia após ele) e a chave privada (PEM).

O HISP ou a sua autoridade de registo emite-os; eles são a identidade da morada.

25.8.2 key_file

CertFile e KeyFile são o certificado da morada (PEM, com a sua cadeia após ele) e a chave privada (PEM).

O HISP ou a sua autoridade de registo emite-os; eles são a identidade da morada.

25.8.3 anchors_file

AnchorsFile são as âncoras de confiança (PEM): as autoridades de certificação cujos remetentes e destinatários esta morada confia, como o pacote DirectTrust.

Uma mensagem assinada por qualquer outra coisa é recusada.

25.9 Direct IMAP

O DirectIMAP é a caixa de correio HISP que uma fonte Direct lê.

Definido como DirectIMAP em internal/config.

ChaveTipoObrigatórioPadrão
hosttextosim—
portnúmero inteironão—
securitytextonão—
usernametextosim—
passwordtextonão—
mailboxtextonão—
after_readtextonão—
move_totextonão—
error_foldertextonão—
poll_intervalduração, como 30s ou 5mnão—
tlstlsconf.Settings (um bloco, omitir para não incluir)não—

25.9.1 mover_para

MoveTo é a pasta para a qual as mensagens movem; Processed por predefinição.

Criado quando faltante.

25.9.2 tls

O TLS confia num ficheiro CA (ou no próprio certificado do HISP) e nomeia o servidor esperado nele, para um HISP cujo certificado IMAP não é de uma autoridade pública.

O certificado é sempre verificado.

25.10 Direct XDR

O DirectXDR é o endpoint que uma fonte Direct recebe XDR.

Definido como DirectXDR em internal/config.

ChaveTipoObrigatórioPadrão
listentextosim—
tls_certtextonão—
tls_keytextonão—
client_ca_filetextonão—

25.11 Instalação ECR

ECRFacility é a organização que envia relatórios de casos.

Definido como ECRFacility em internal/config.

ChaveTipoObrigatórioPadrão
nametextosim—
npitextonão—
phonetextosim—
linetextonão—
citytextosim—
statetextosim—
postal_codetextonão—

25.12 Opções EDIFACT

EDIFACTOptions são as configurações que apenas se aplicam a um canal EDIFACT.

Definido como EDIFACTOptions em internal/config.

ChaveTipoObrigatórioPadrão
envelopetextonão—
splitverdadeiro ou falsonão—
acknowledgetextonão—

25.12.1 confirmar

Acknowledge responde a um remetente que publica sobre HTTP com um CONTRL na resposta: aceite (ação 7) quando a troca foi lida e entregue, rejeitado (4) caso contrário.

Default none.

25.13 OAuth de E-mail

EmailOAuth assina com OAuth 2.0 (SASL XOAUTH2), que o Microsoft 365 e o Gmail exigem no lugar de uma senha.

Definido como EmailOAuth em internal/config.

ChaveTipoObrigatórioPadrão
providertextosim—
tenanttextonão—
token_urltextonão—
client_idtextosim—
client_secrettextonão—
refresh_tokentextonão—
scopetextonão—

25.13.1 client_secret

ClientSecret pode ser ${ENV}.

Sem refresh_token, ele seleciona a subvenção de credenciais de cliente apenas de aplicativos da Microsoft.

25.13.2 refresh_token

RefreshToken pode ser ${ENV}: uma caixa de correio que uma pessoa consentiu.

Obrigatório para o Gmail.

25.14 Autenticação FHIR

FHIRAuth é como um destino FHIR autentica um serviço FHIR hospedado.

Três pré-configurações, porque os serviços hospedados são onde um token de portador colado em um arquivo deixa de funcionar dentro de uma hora:

Os tokens são buscados quando necessário e reutilizados até um minuto antes de expirarem.

Definido como FHIRAuth em internal/config.

ChaveTipoObrigatórioPadrão
typetextosim—
regiontextonão—
access_key_idtextonão—
secret_access_keytextonão—
session_tokentextonão—
tenant_idtextonão—
token_urltextonão—
client_idtextonão—
client_secrettextonão—
scopetextonão—

25.14.1 região

A região é a região da AWS.

Lida a partir de uma URL do HealthLake quando não for fornecida.

25.14.2 url_do_token

TokenURL é o ponto de extremidade de token OAuth, para client_credentials.

Para azure, é derivado do locatário.

25.14.3 id_do_cliente

ClientID e ClientSecret identificam o aplicativo.

O segredo pode ser uma referência ${ENV}, que é como deve ser fornecido.

25.14.4 client_secret

ClientID e ClientSecret identificam o aplicativo.

O segredo pode ser uma referência ${ENV}, que é como deve ser fornecido.

25.14.5 âmbito

O âmbito é solicitado com o token.

Para azure, é padrão a URL do serviço FHIR seguida de /.default, que é sua audiência.

25.15 Poll de Arquivo

FilePoll é a parte de uma fonte de coleta de arquivos que não tem nada a ver com o transporte.

Compartilhado pelas fontes locais, FTP, SMB e WebDAV, e pelo SFTP. Cada uma dessas configurações existe porque de uma forma como os arquivos dão errado, em vez de uma forma como os transportes diferem, o que é por que elas pertencem juntas: um site que trabalhou a configuração certa para o seu analisador não deve ter que trabalhar novamente quando o analisador se move para uma compartilhamento.

Definido como FilePoll em internal/config.

ChaveTipoObrigatórioPadrão
dirtextosim—
patterntextonão—
poll_intervalduração, como 30s ou 5mnão—
after_readtextonão—
move_totextonão—
error_dirtextonão—
stable_forduração, como 30s ou 5mnão—
max_file_sizenúmero inteironão—
framedverdadeiro ou falsonão—
rawverdadeiro ou falsonão—
batch_sizenúmero inteironão—
sort_bytextonãonome

25.15.1 padrão

O padrão selecciona ficheiros por globo.

Vazio significa todos os arquivos.

25.15.2 directório_de_erro

ErrorDir é onde um ficheiro que não pôde ser processado vai.

Separado de MoveTo deliberadamente. Um directório que contém apenas falhas é algo que alguém pode observar, e misturar falhas no arquivo significa que a única forma de encontrá-las é ler cada ficheiro.

25.15.3 bruto

Raw trata o ficheiro inteiro como uma mensagem, independentemente do conteúdo.

A definição que torna este conector útil para algo além do HL7. Sem ele, um lote CSV, um ficheiro de reclamação X12 ou um PDF é dividido em linhas que começam com MSH e produz nada, e o erro diz que o ficheiro não é HL7 - verdadeiro, mas não é o ponto, uma vez que o ficheiro nunca foi destinado a ser.

25.15.4 tamanho_lote

BatchSize define o número máximo de ficheiros que uma pesquisa pode ler.

Zero significa sem limite.

Existe para a primeira pesquisa após uma interrupção. Um directório que contém quarenta mil ficheiros que se acumularam durante a noite será lido em uma única passagem, o que mantém o loop de pesquisa ocupado durante o tempo que leva e faz com que o canal pareça travado. Ler um número limitado de ficheiros por pesquisa mantém o canal responsivo e a fila esvaziando visivelmente.

25.15.5 ordenar_por

SortBy ordena os ficheiros dentro de uma pesquisa: nome, modificado ou nenhum.

Padrão é nome. A ordem é mais importante do que parece: um fluxo ADT onde as atualizações A08 chegam antes da admissão A01 produz pacientes que ainda não existem. A ordem da lista de directórios é arbitrária na maioria dos sistemas de ficheiros, por isso deixá-la não ordenada significa que a ordem muda entre pesquisas sem motivo aparente.

25.16 Acesso GCP

GCPAccess é como autenticar no Google Cloud.

Definido como GCPAccess em internal/config.

ChaveTipoObrigatórioPadrão
projecttextonão—
credentials_filetextonão—
endpointtextonão—

25.16.1 ficheiro_de_credenciais

CredentialsFile é uma chave JSON de uma conta de serviço.

Vazio usa a conta de serviço anexada à VM, pod GKE ou serviço Cloud Run que Perfuse executa (o servidor de metadados), a menos que Endpoint nomeie um emulador.

25.17 Acesso GCS

GCSAccess é um bucket de armazenamento em nuvem.

Definido como GCSAccess em internal/config.

ChaveTipoObrigatórioPadrão
buckettextosim—

25.18 Conexão IBMMQ

IBMMQConnection é uma fila alcançada através da API REST de mensagens do gerente de filas.

Definido como IBMMQConnection em internal/config.

ChaveTipoObrigatórioPadrão
urltextosim—
queue_managertextosim—
queuetextosim—
usernametextonão—
passwordtextonão—
tlstlsconf.Settings (um bloco, omitir para não incluir)não—
api_versiontextonão—
timeoutduração, como 30s ou 5mnão30s

25.18.1 nome de usuário

Nome de usuário e senha são um usuário mqweb com o papel MQWebUser; a senha pode ser ${ENV}.

Deixe ambos vazios quando um certificado de cliente (tls.cert_file) autentica.

25.18.2 senha

Nome de usuário e senha são um usuário mqweb com o papel MQWebUser; a senha pode ser ${ENV}.

Deixe ambos vazios quando um certificado de cliente (tls.cert_file) autentica.

25.18.3 tempo de expiração

Timeout limita cada solicitação.

Defaults to 30s.

25.19 Kafka SASL

KafkaSASL autentica em um cluster Kafka.

Definido como KafkaSASL em internal/config.

ChaveTipoObrigatórioPadrão
mechanismtextosim—
usernametextosim—
passwordtextosim—

25.19.1 mecanismo

O mecanismo é "plain", "scram-sha-256" ou "scram-sha-512".

PLAIN envia a senha legível no fio, então pertence com TLS. SCRAM não, é por isso que vale a pena nomear a diferença aqui em vez de tratar os três como intercambiáveis.

25.19.2 senha

Senha é a senha SASL.

Suporta referências ${ENV} como todos os outros segredos aqui, então uma credencial de cluster não precisa ser escrita no arquivo do canal.

25.20 Conexão MQTT

MQTTConnection é como alcançar um broker MQTT 3.1.1: Mosquitto, EMQX, HiveMQ, AWS IoT Core, Azure Event Grid.

Definido como MQTTConnection em internal/config.

ChaveTipoObrigatórioPadrão
addrtextosim—
client_idtextonão—
usernametextonão—
passwordtextonão—
tlstlsconf.Settings (um bloco, omitir para não incluir)não—
qosnúmero inteiro (um bloco, omitir para não incluir)não—
timeoutduração, como 30s ou 5mnão30s

25.20.1 id_do_cliente

ClientID nomeia a sessão.

Uma fonte mantém suas mensagens em reconexões apenas sob um client id fixo; ele é padrão para perfuse-<channel>.

25.20.2 nome de usuário

Nome de usuário e senha autenticam; qualquer um deles pode estar vazio.

A senha pode ser ${ENV}.

25.20.3 senha

Nome de usuário e senha autenticam; qualquer um deles pode estar vazio.

A senha pode ser ${ENV}.

25.20.4 tempo de expiração

Limites de tempo para conectar e cada espera pelo corretor.

Defaults to 30s.

25.21 Opções NCPDP

NCPDPOptions são as configurações que se aplicam apenas a um canal de reclamação de farmácia.

Definido como NCPDPOptions em internal/config.

ChaveTipoObrigatórioPadrão
transformationslista de ncpdp.Stepnão—

25.21.1 transformações

As transformações são alterações declarativas aplicadas a cada transmissão antes da entrega.

O mesmo vocabulário que todos os outros formatos - definir, copiar, limpar, mapear, substituir, cortar, caso, cada um com uma condição opcional - porque o mecanismo de etapas em internal/steps é genérico. O que difere é a notação: um caminho é escrito D1 ou 07-D7, usando os identificadores de campo de dois caracteres do próprio padrão.

25.22 Receber PGP

PGPReceive abre o que uma fonte recebe com OpenPGP: descriptografado com nossa chave secreta e sua assinatura verificada contra as chaves públicas dos remetentes.

Definido como PGPReceive em internal/config.

ChaveTipoObrigatórioPadrão
decrypt_withtextonão—
passphrasetextonão—
verify_withlista de textonão—
require_signatureverdadeiro ou falsonão—
allow_unencryptedverdadeiro ou falsonão—
pass_plainverdadeiro ou falsonão—

25.22.1 descriptografar_com

DecryptWith é o arquivo de chave secreta nossa.

Obrigatório, a menos que permitir_descriptografado esteja ativado e as mensagens sejam apenas assinadas.

25.22.2 frase_de_acesso

A frase de acesso desbloqueia o DecryptWith quando ele está protegido.

Preferir uma referência de variável de ambiente, ${NOME}.

25.22.3 verificar_com

VerifyWith são os arquivos de chave pública dos remetentes.

Uma assinatura de qualquer um deles é verificada e registrada.

25.22.4 passar_plano

PassPlain permite que uma mensagem que não é PGP seja passada inalterada, para uma pasta que recebe ambos.

Desativado: tal mensagem é recusada, então um remetente que esqueceu de criptografar é informado.

25.23 Enviar PGP

PGPSend protege o que um destino entrega com OpenPGP: criptografado para a chave pública do receptor, assinado com a nossa, ou ambos.

Pagadores, centrais de compensação e agências estaduais frequentemente recebem arquivos sobre SFTP apenas desta forma.

Definido como PGPSend em internal/config.

ChaveTipoObrigatórioPadrão
encrypt_tolista de textonão—
sign_withtextonão—
passphrasetextonão—
armorverdadeiro ou falsonão—
no_compressverdadeiro ou falsonão—
file_nametextonão—

25.23.1 criptografar_para

EncryptTo são os ficheiros de chave pública dos destinatários (blindados ou binários).

A mensagem é legível por qualquer um deles. Vazio: a mensagem é apenas assinada.

25.23.2 sign_with

SignWith é o nosso ficheiro de chave secreta, para assinar cada mensagem.

Vazio: apenas encriptado.

25.23.3 frase_de_acesso

A frase-passe desbloqueia SignWith quando está protegida.

Preferir uma referência de variável de ambiente, ${NOME}.

25.24 Configuração de Fila

QueueConfig ativa a fila durável para um destino.

Sem ele, um destino que está desligado por dois minutos perde tudo o que foi enviado durante esses dois minutos: as tentativas ocorrem na memória e quando elas se esgotam a mensagem é registada como falha e perdida. Com ele, a mensagem está no disco e mantém o seu lugar até que o destinatário retorne.

Está desligado por predefinição, o que é uma escolha deliberada em vez de cautela. Uma fila altera o que um acuso de recibo significa e altera o comportamento de ordenação durante uma interrupção, e ambas as coisas são coisas que um operador deve optar por saber em vez de descobrir.

Definido como QueueConfig em internal/config.

ChaveTipoObrigatórioPredefinição
enabledverdadeiro ou falsonão—
max_attemptsnúmero inteironão—
backoffduração, como 30s ou 5mnão—
max_backoffduração, como 30s ou 5mnão—
max_depthnúmero inteironão—
retain_hoursnúmero inteironão—

25.24.1 tentativas_máximas

MaxAttempts é o número de vezes que a fila tenta antes de marcar uma mensagem como falha e passar para a próxima.

Zero significa continuar tentando indefinidamente, o que é legítimo para uma fonte que não pode perder nada, mas deve ser escolhido em vez de herdado.

25.24.2 max_backoff

MaxBackoff limita o atraso crescente.

O predefinido é um minuto em vez de algo maior porque um destinatário que retorna após uma interrupção breve deve ser encontrado rapidamente: um teto de uma hora transforma um problema de dois minutos em uma hora de atraso.

25.24.3 max_depth

MaxDepth recusa novas mensagens uma vez que este número esteja à espera, para que um destinatário que tenha estado desligado por uma semana não possa encher o disco.

Zero significa sem limite.

Quando o limite é atingido, a mensagem é falha em vez de ser enfileirada, e o remetente é informado disso — o que é a resposta honesta, porque não estamos mais prometendo entregá-la.

25.24.4 retain_hours

RetainHours é o tempo durante o qual os itens entregues e abandonados são mantidos antes de serem purgados.

Eles são mantidos para que alguém que esteja a observar uma fila de atrasos possa vê-la a acontecer, e para que uma mensagem abandonada possa ser encontrada posteriormente.

25.25 Tentativa

Tentativa controla a reentrega após uma falha.

Definido como Retry em internal/config.

ChaveTipoObrigatórioPadrão
attemptsnúmero inteironão—
backoffduração, como 30s ou 5mnão—
max_backoffduração, como 30s ou 5mnão—

25.25.1 tentativas

Tentativas é o número total de tentativas, incluindo a primeira.

Zero significa o padrão.

25.25.2 backoff

Backoff é o tempo de espera antes da segunda tentativa.

Ele dobra a cada vez, até MaxBackoff.

25.26 Opções de Script

ScriptOptions configura um canal NCPDP SCRIPT.

Por que o SCRIPT obtém um bloco quando seu filtro é de nível superior

O filtro do canal para cada tipo de dados é a chave de filtro de nível superior, porque internal/expr é genérico sobre o tipo de mensagem: uma chave, compilada contra a árvore ou a reivindicação que o canal transporta. As etapas não podem ser organizadas dessa maneira. Uma etapa v2 endereça um segmento e um campo, uma etapa X12 endereça um elemento de largura fixa, e os tipos são diferentes, então uma chave yaml teria que conter qualquer um que o tipo de dados implicasse - o que é um campo que significa coisas diferentes dependendo de outro campo, e o modo de falha é uma etapa que silenciosamente não faz nada.

Então, isso segue hl7v3, x12, ncpdp e delimitado: as etapas vivem no bloco do formato, e a chave de transformações de nível superior é recusada em um canal SCRIPT em vez de ser aceita e ignorada.

Definido como ScriptOptions em internal/config.

ChaveTipoObrigatórioPadrão
transformationslista de hl7v3.Stepnão—

25.26.1 transformações

Transformações são as etapas declarativas, que endereçam a prescrição como uma árvore XML.

hl7v3.Step em vez de um tipo próprio, e isso não é preguiça. Uma prescrição e um documento v3 são ambos XML, a gramática do caminho é a mesma, e internal/eprescribe já empresta hl7v3.Path para seu filtro com um comentário dizendo isso - v3 e CDA já o usam, e uma terceira cópia seria um terceiro conjunto de respostas para o que //a/b[2]@c significa.

As etapas que transportam um significado exclusivo do v3 são recusadas no carregamento em vez de estarem silenciosamente disponíveis. nullflavor é o único: ele escreve o atributo v3 que declara por que um valor está ausente, o que uma prescrição não tem equivalente, e uma etapa que o escrevesse produziria um documento que o receptor não entenderia.

25.27 Scripts

Scripts contém o JavaScript anexado a um canal.

Definido como Scripts em internal/config.

ChaveTipoObrigatórioPadrão
filtertextonão—
transformertextonão—
preprocessortextonão—
deploytextonão—
undeploytextonão—
postprocessortextonão—
languagetextonão—
timeoutduração, como 30s ou 5mnão—
includelista de textonão—
file_rootslista de textonão—
allowlista de textonão—

25.27.1 filtro

Filtro é executado após o filtro de expressão, se houver, e deve retornar um booleano.

Um script de filtro Mirth cai aqui inalterado.

25.27.2 transformador

Transformador é executado após as etapas declarativas e pode modificar a mensagem.

Um script de transformador Mirth cai aqui inalterado.

25.27.3 pré-processador

O pré-processador é executado antes de a mensagem ser analisada, lê o texto como "mensagem" e devolve o texto para análise.

Um pré-processador Mirth é inserido aqui inalterado.

Este é o único local onde uma mensagem que não é analisada pode ser reparada. Os sites usam-no para um caractere isolado de um gateway serial, um terminador de segmento que chegou como uma quebra de linha, ou um fornecedor que preenche um campo com algo ilegal para a sua posição. Sem ele, o Perfuse rejeita o tráfego que o Mirth aceita hoje.

25.27.4 implementar

A implementação é executada uma vez quando o canal é iniciado, antes de aceitar qualquer coisa.

Este é o local onde os sites aquecem uma cache de pesquisa ou verificam se algo em que dependem está acessível. Ele é executado antes de a origem ser vinculada, então um script de implementação que falha impede que o canal seja iniciado, em vez de permitir que ele aceite mensagens que não consegue lidar.

25.27.5 desimplementar

A desimplementação é executada uma vez quando o canal é interrompido.

Depois de a origem ter parado de aceitar e após as mensagens em voo terem terminado, então ele vê um canal que está genuinamente ocioso. Sua falha não pode impedir uma interrupção: um canal que não pudesse ser desligado porque um script de limpeza jogou uma exceção seria pior do que um que registrou e fechou.

25.27.6 pós-processador

O pós-processador é executado após a mensagem ter sido tratada e não pode alterá-la.

A mensagem e o que aconteceu com ela são visíveis, então ele pode notificar, contar ou registrar. Ele não pode alterar o que foi enviado: no momento em que ele é executado, o envio já ocorreu, e um script que parecesse alterar uma mensagem entregue estaria mentindo sobre isso.

25.27.7 linguagem

A linguagem é a linguagem de script em que esses scripts são escritos: javascript ou lua.

Por que uma configuração para o bloco inteiro em vez de uma por script

Os scripts de um canal compartilham o mapa do canal e o mapa do conector, e são lidos juntos por quem os mantém. Um filtro em Lua ao lado de um transformador em JavaScript significaria duas linguagens em uma revisão, compartilhando o estado por meio de um mapa cujos valores teriam que significar a mesma coisa em ambos. Os sites que desejam isso podem dividir o canal.

Por que o padrão é javascript

Cada script escrito antes que essa configuração existisse é JavaScript e não diz nada sobre sua linguagem. Fazer com que lua seja o padrão silenciosamente reinterpretaria todos eles; exigir o campo os recusaria. Nenhum dos dois é aceitável para uma configuração adicionada posteriormente.

25.27.8 tempo de expiração

O tempo limite delimita cada script.

Zero significa cinco segundos.

Há deliberadamente não há como desabilitá-lo. O Mirth permite que um transformador faça um loop infinito, o que impede o canal, e uma interface que para de aceitar admissões devido a um erro de digitação não é algo a ser oferecido como opção.

25.27.9 incluir

Incluir nomes arquivos de fonte de script compartilhada disponibilizados para cada script neste canal, em qualquer linguagem que scripts.linguagem nomeie.

Este é o modelo de código do Mirth. Um site com quarenta canais geralmente tem uma biblioteca que cada canal chama, e sem ele uma migração significa copiar essa biblioteca para quarenta arquivos - quarenta lugares para corrigir da próxima vez que ela mudar.

Os caminhos são relativos ao ficheiro do canal, por isso uma biblioteca ao lado dos canais viaja com eles. É uma lista porque a alternativa é um ficheiro enorme, e as bibliotecas tendem a dividir-se por assunto.

Os ficheiros têm de estar no idioma do canal. Isto foi apenas JavaScript durante algum tempo, e não por recusa: um canal Lua lia os ficheiros, recusava um ficheiro em falta e, em seguida, o tempo de execução não instalava nada, por isso todas as chamadas para a biblioteca falhavam na primeira mensagem com um global nulo - o erro exato que a recusa acima existe para evitar. Ambas as linguagens instalaram agora, e uma biblioteca que não analisa é recusada no carregamento, nomeando o ficheiro.

25.27.10 file_roots

FileRoots são os diretórios que FileUtil pode ler e escrever.

Requerido sempre que "file" é permitido. Conceder acesso a ficheiros sem nomear diretórios costumava significar todo o sistema de ficheiros: um script podia ler a base de dados do próprio Perfuse, que contém hashes de palavras-passe, a palavra-passe da conta de serviço LDAP e o segredo do cliente OIDC. Criar um canal precisa apenas da função de editor, por isso a escalada foi concluída no momento em que um administrador a iniciou.

25.27.11 allow

Allow concede capacidades que um script seria recusado de outra forma: "file", "database", "route".

Mirth concede todos estes a cada script; exigir que sejam nomeados significa que um transformador não pode começar a ler silenciosamente o sistema de ficheiros após uma cópia-colar.

25.28 Sombra

Shadow executa uma versão candidata de um canal ao lado do canal ativo e relata onde diferem.

Esta é a resposta à pergunta que torna o trabalho de interface assustador: como você sabe que uma alteração é segura? Não lendo-a. Uma transformação é um programa que opera em mensagens cuja variedade ninguém catalogou, e o caso que quebra é sempre o que ninguém pensou - o paciente com dois identificadores, o resultado com um campo de unidades vazio, o A08 que chega antes do seu A01.

Um teste de canal prova os casos que alguém pensou. O modo Shadow prova os casos que realmente chegam, contra tráfego real, antes que a alteração carregue algum deles.

Duas propriedades o tornam seguro, e ambas são estruturais em vez de configuráveis:

Definido como Shadow em internal/config.

ChaveTipoRequeridoPadrão
channeltextosim—
samplenúmeronão1
comparelista de textonão—
ignorelista de textonão—
max_differencesnúmero inteironão100
timeoutduração, como 30s ou 5mnão5s

25.28.1 channel

Canal é o caminho para o ficheiro do canal candidato.

Um ficheiro separado em vez de um bloco inline, propositadamente: o candidato pretende tornar-se o canal ativo, por isso deve ser o artefato que é revisado, comprometido e promovido, e não um fragmento que precisa ser extraído.

25.28.2 sample

Sample é a fração de mensagens para sombra, de 0 a 1. Padrão é 1.

Vale a pena reduzir apenas em uma fonte de alimentação ocupada, e vale a pena entender antes de fazê-lo: a amostragem reduz o custo e reduz a confiança na mesma proporção, e a mensagem que mostraria a diferença é a incomum.

25.28.3 compare

Compare limita a comparação a esses caminhos de campo.

Comparar vazio compara tudo.

25.28.4 ignore

Ignorar exclui caminhos de campo da comparação.

Necessário na prática, porque um canal que carimba um carimbo de data/hora ou um número de sequência difere em cada mensagem única e relatariam uma taxa de diferença de 100%, enquanto não informa nada.

25.28.5 max_differences

MaxDifferences limita quantas mensagens divergentes são mantidas para inspeção.

Defaults to 100.

25.28.6 tempo de expiração

Timeout limita uma execução de sombra.

Defaults to 5s.

Separado do timeout próprio do canal e mais curto. Um candidato com um script em fuga não deve acumular goroutines atrás do tráfego ao vivo.

25.29 Código XDS

XDSCode é um valor codificado nas configurações de destino: código, esquema de codificação (um OID) e exibição.

Definido como XDSCode em internal/config.

ChaveTipoObrigatórioPredefinido
codetextosim—
schemetextosim—
displaytextonão—

26 Como Cada Componente Funciona

Perfuse é construído a partir de pequenos pacotes, cada um com um trabalho. Este capítulo é a própria conta de cada um sobre o que ele faz e por que foi construído dessa forma, tirado da fonte. Onde uma decisão tem um motivo que não é óbvio, o motivo está aqui em vez de em uma mensagem de commit que ninguém encontrará.

26.1 fhir

Pacote fhir implementa recursos FHIR, serialização e validação.

O tratamento de versão é a primeira decisão de design, porque "FHIR" sozinho não identifica um formato de fio. R5 é a versão publicada mais recente e é o padrão aqui. R4 é o que a base instalada e a regulamentação dos EUA consomem na prática, então é totalmente suportado em vez de ser tratado como legado. R6 está em votação no momento da escrita e não é implementado deliberadamente: enviar uma suposição sobre uma especificação não publicada seria pior do que não suportá-la.

O modelo de recurso é R5-formado. Onde R4 difere, a diferença é aplicada durante a serialização, em vez de manter dois conjuntos paralelos de structs, que é como um código-fonte acaba com duas definições ligeiramente divergentes de Paciente.

Source: github.com/biodream-llc/perfuse/fhir

26.2 principal

O comando xmlordergen escreve a ordem de elementos FHIR XML necessários, a partir de um pacote de definições de estrutura.

go run ./fhir/xmlordergen hl7.fhir.r4.core-4.0.1.tgz | gzip -9 -n > fhir/xmlorder_r4.txt.gz

Os objetos JSON podem manter seus membros em qualquer ordem; o XML não pode: cada elemento deve vir na ordem em que sua definição é listada. Cada linha de saída é um caminho e seus filhos nessa ordem, cada filho com como encontrar seus próprios filhos: "@Path" (um elemento definido inline, uma espinha dorsal), "#Path" (o mesmo que outro elemento), ou seus tipos.

Source: github.com/biodream-llc/perfuse/fhir/xmlordergen

26.3 hl7

Pacote hl7 lê mensagens HL7 versão 2.

Ele não tem dependências fora da biblioteca padrão e um teste garante isso. Ele não faz E/S de rede, não escreve arquivos e não inicia goroutines, então é seguro usá-lo de qualquer lugar.

Reading a message

msg, err := hl7.Parse(raw) se err != nil { return err } mrn := msg.MustGet("PID-3.1") nome := msg.MustGet("PID-5.1") msgType, evento, _ := msg.Type() // "ADT", "A01"

Caminhos são a notação que as pessoas já usam quando falam sobre HL7: segmento, campo, então componente e subcomponente opcionais, como em PID-5.1 ou OBX-5.2.3. Repetições são endereçadas com colchetes, como em PID-3[2].1.

Get retorna um erro para um caminho que não consegue analisar; MustGet retorna a string vazia em vez disso. Ambos são seguros em segmentos e campos ausentes, porque uma alimentação real está cheia de ambos e um analisador que entra em pânico em dados ausentes é inútil para o trabalho. Ausência não é um erro — uma mensagem que simplesmente não transporta PID-8 produz "" em vez de uma falha.

Ausente e vazio

HL7 distingue um campo que não foi enviado de um enviado deliberadamente vazio, e clinicamente esses podem significar coisas diferentes - "nenhuma alergia registrada" não é "nenhuma alergia conhecida". Value.Exists relata a diferença onde os chamadores precisam, enquanto String achatiza ambos para "" para o caso comum.

Copiando, e a única maneira de errar

A cópia analisa as suas entradas, por isso a Mensagem devolvida permanece válida, independentemente de como o chamador reutiliza o seu buffer. Isso custa cerca de 3% e uma alocação por mensagem.

ComZeroCopy salta a cópia e mantém uma referência ao slice do chamador em vez disso. É mais rápido e torna a Mensagem insegura para uso após o slice ser reescrito. Ler em um buffer reutilizado é a forma normal e eficiente de ler de uma rede em Go, por isso a armadilha captura o código cuidadoso e o sintoma é valores de campo silenciosamente errados em vez de um erro - os dados de um paciente sob o nome de outro paciente. Use-o para entrada imutável ou que sobreviva à Mensagem e não de outra forma.

Acknowledgements

AckFor constrói um ACK ou NAK para uma mensagem, incluindo para uma que falhou ao analisar, que é o caso que mais importa: um remetente precisa de uma resposta, mesmo quando o que enviou não foi uma mensagem. Veja AckOptions.

O que este pacote não faz

Ele não escreve ou modifica mensagens. Não tem conhecimento da estrutura da mensagem além dos segmentos, por isso não dirá que um PV1 pertence a um grupo de visita específico. Não valida contra as tabelas de uma versão. Essas são omissões deliberadas, em vez de negligências: este é um indexador para tráfego real, que é frequentemente não conformado com o padrão e ainda precisa ser encaminhado.

Source: github.com/biodream-llc/perfuse/hl7

26.4 admitir

Pacote admit limita a quantidade de trabalho em execução ao mesmo tempo.

O motor gera uma goroutine por destino por mensagem. As goroutines são baratas; o que elas mantêm não é. Cada entrega de saída mantém um soquete no extremo distante e um descritor de arquivo aqui e os mantém por todo o orçamento de repetição - com os padrões, cinco tentativas com um tempo limite de trinta segundos mais quinze segundos de retrocesso, então quase três minutos. Alguns centenas de remetentes contra um receptor que parou de responder é, portanto, alguns centenas de descritores mantidos por minutos e o processo é esgotado.

Esgotar é a falha que vale a pena prevenir, porque não é exibida onde aconteceu. É exibida como "muitos arquivos abertos" em algum lugar não relacionado: o banco de dados não pode abrir o seu jornal, a interface para de aceitar, um log não pode ser escrito. O motor parece quebrado em três lugares de uma vez e a causa é um sistema de parceiro que parou de responder.

Dois limites, e o segundo é mais importante do que o primeiro:

Um total, para que o processo fique dentro do seu orçamento de descritor.

Um limite por destino, para que um receptor não possa consumir o total. Sem ele, um parceiro preso derruba todos os outros canais, o que é pior do que não ter limite algum: o raio de ação aumenta de um interface para todos eles.

Source: github.com/biodream-llc/perfuse/internal/admit

26.5 alertas

Pacote alertas observa as métricas e diz quando algo está errado.

O ponto é que ninguém deve ter que olhar para o painel. "Transações com falha permanecem enfileiradas sem investigação oportuna" é uma falha operacional documentada nesta classe de software, e o motivo é sempre o mesmo: as informações estavam em uma tela que ninguém estava na frente às quatro da manhã.

Três decisões dão forma a ele.

Um alerta deve limpar a si mesmo. Uma notificação que dispara e nunca se resolve treina as pessoas para ignorar as notificações. Cada regra aqui é avaliada contra o estado atual, então um receptor que volta fecha o alerta que abriu.

Os alertas são desacelerados por duração, não por contagem. "Taxa de erro acima de 5% agora" dispara em uma mensagem infeliz durante uma hora tranquila. "Acima de 5% por dois minutos" não. Cada regra leva uma duração For e nada dispara até que a condição tenha sido mantida por tanto tempo.

O que é enviado não contém dados de paciente. Um alerta contém um nome de canal, um nome de destino, um número e um limiar. Esses vêm da configuração e da contagem. Um webhook vai para uma sala de bate-papo, uma sala de bate-papo tem um histórico, e um histórico não é um lugar onde um identificador de paciente deve acabar.

Source: github.com/biodream-llc/perfuse/internal/alerts

26.6 amqp

Pacote amqp é um cliente AMQP 1.0: uma conexão, uma sessão, links de envio e recebimento, liquidados após o receptor dizer assim.

AMQP 1.0 é o que o Azure Service Bus e os Event Hubs falam, o que o RabbitMQ 4 fala nativamente e o que o ActiveMQ e o Artemis falam além do STOMP. Escrito aqui pelo mesmo motivo que o cliente STOMP e o assinante AWS: uma biblioteca de cliente completa seria a maior parte da lista de dependências do binário para quatro performativos que importam.

O que ele faz: SASL PLAIN ou ANONYMOUS (Service Bus aceita um nome de chave de acesso compartilhado e chave como PLAIN), TLS, abrir/iniciar/anexar, fluxo baseado em crédito, uma transferência dividida em quadros quando excede o tamanho máximo de quadro do peer e disposições - aceitas, liberadas, rejeitadas. O remetente aguarda a disposição do corretor antes de relatar o sucesso, então "enviado" significa que o corretor assumiu a custódia. Quadros vazios mantêm a conexão viva dentro do tempo limite de ociosidade do peer, que o Service Bus impõe.

O que ele não faz: transações, várias sessões, recuperação de link e anotações de mensagem além de lê-las.

Source: github.com/biodream-llc/perfuse/internal/amqp

26.7 analisar

O pacote analyze transforma um canal Mirth analisado em algo que um humano pode utilizar: uma descrição simples do que o canal faz e uma lista honesta do que não sobreviverá a uma migração.

A regra de design aqui é que uma descoberta deve ser específica o suficiente para ser utilizada. "Este canal usa JavaScript" não é uma descoberta. "O destino 1 chama java.util.Date, que não tem equivalente fora da JVM" é.

Source: github.com/biodream-llc/perfuse/internal/analyze

26.8 api

O pacote api serve a interface HTTP utilizada pelo frontend web.

A restrição de design importante: os canais são lidos e escritos em arquivos no disco. A API é um editor para esses arquivos, não um sistema de armazenamento diferente que acontece a exportar YAML. Um canal criado no navegador e um escrito à mão são o mesmo artifact, o que torna "exportar para compartilhar" trivial e mantém o git como o histórico de registro.

Source: github.com/biodream-llc/perfuse/internal/api

26.9 as2

O pacote as2 é Applicability Statement 2 (RFC 4130): EDI sobre HTTP, assinado e criptografado com S/MIME, com um recibo assinado (um MDN) que nomeia um resumo do que chegou.

Os pagadores e parceiros comerciais o utilizam para X12 e EDIFACT.

O S/MIME é internal/cms, o mesmo código que a mensagens diretas usa. O que está aqui é próprio do AS2: seus cabeçalhos, a verificação de integridade da mensagem (MIC) e o recibo.

Source: github.com/biodream-llc/perfuse/internal/as2

26.10 attach

O pacote attach move grandes cargas de um mensagem e as coloca de volta.

Uma mensagem HL7 que transporta um relatório digitalizado ou um PDF é comum em fluxos de documentos, e a carga é rotineiramente centenas de vezes maior do que a mensagem ao seu redor. Armazenar isso inline significa que o repositório de mensagens cresce à taxa dos documentos em vez do tráfego, uma mensagem enfileirada para cinco destinos é copiada cinco vezes, e a interface tem que transmitir megabytes para mostrar o nome de um paciente a alguém.

Então, a carga é extraída, armazenada uma vez por conteúdo e substituída na mensagem com um token. O Mirth chama esses manipuladores de anexos e é uma funcionalidade de migração documentada, o que é por que o formato do token aqui é projetado para ser reconhecível em vez de inteligente.

O que este pacote não decide

Ele não faz armazenamento e não faz E/S. A extração produz a mensagem reescrita e as cargas; um Armazenamento em algum lugar decide para onde elas vão. Essa separação é o que torna a extração testável sem um banco de dados, e também é o que deixa a mesma lógica executar no playground WASM onde não há banco de dados.

Source: github.com/biodream-llc/perfuse/internal/attach

26.11 authlimit

O pacote authlimit limita as tentativas de autenticação falhas por endereço de origem.

Ele existe porque dois ouvintes precisavam da mesma coisa e um deles não tinha nada. O servidor FHIR recebeu um limitador quando recebeu autenticação; o login da console não tinha nenhum, e uma medição mostrou vinte tentativas de senha por segundo sustentadas contra a conta do administrador sem atraso e sem bloqueio. A essa taxa, uma senha fraca some durante a noite e a única trilha é um log cheio de avisos idênticos.

Deliberadamente não é um limitador de taxa de uso geral. Ele limita as falhas, não as solicitações: um cliente legítimo ocupado nunca é afetado, e a única coisa que se acumula é o erro.

Source: github.com/biodream-llc/perfuse/internal/authlimit

26.12 awsmsg

O pacote awsmsg se comunica com Amazon SQS e SNS com a biblioteca padrão e o signatário compartilhado Signature Version 4.

O mesmo argumento que s3put: o SDK da AWS dobraria o tamanho da lista de materiais para quatro chamadas de API. O SQS usa seu protocolo JSON (AWS JSON 1.0, X-Amz-Target AmazonSQS.<Action>), que a AWS documenta como o atual; o SNS usa seu protocolo de consulta, que é o único que ele tem. Ambos funcionam contra LocalStack e pontos de extremidade de VPC por meio de uma substituição de ponto de extremidade.

Source: github.com/biodream-llc/perfuse/internal/awsmsg

26.13 awsv4

O pacote awsv4 assina solicitações para a AWS com Signature Version 4, usando apenas a biblioteca padrão.

Ele começou dentro do s3put. O SQS, SNS e a leitura do S3 precisam da mesma assinatura com um nome de serviço diferente e com uma string de consulta, e uma segunda cópia do código de assinatura seria um segundo local para o único bug que importa - uma falha de assinatura lê exatamente como credenciais erradas. Então, ele vive aqui, verificado contra os vetores de teste publicados da AWS, e todos os conectores da AWS o utilizam.

As credenciais são chaves estáticas ou variáveis de ambiente padrão. Não há uma cadeia de credenciais de instância de metadados por deliberado: isso significa chamadas IMDS, cache e atualização, que é onde uma implementação pequena deixa de ser pequena, e o Perfuse recusa endereços de metadados como destinos por padrão.

Source: github.com/biodream-llc/perfuse/internal/awsv4

26.14 azblob

O pacote azblob lê e escreve o Armazenamento de Blobs do Azure com a biblioteca padrão: autorização Shared Key ou SAS sobre chamadas HTTP simples.

O mesmo raciocínio que o s3put: o SDK do Azure é grande e as operações que um motor de integração precisa são cinco - put, get, list, delete e definição do nível de acesso. A assinatura Shared Key é especificada exatamente ("Authorize with Shared Key", Azure Storage REST), e o Azurite, emulador da Microsoft, verifica da mesma forma que o serviço.

Source: github.com/biodream-llc/perfuse/internal/azblob

26.15 branding

O pacote branding armazena o logotipo e o nome do produto de um cliente para que uma instalação possa se apresentar como seu próprio produto em vez de como Perfuse.

Por que o logotipo não é uma configuração

Tudo o mais que um operador pode alterar é um escalar no arquivo de configurações. Um logotipo é alguns centenas de kilobytes de binário, e colocá-lo lá significaria base64 em um arquivo YAML que uma pessoa deve ser capaz de ler e editar manualmente. Ele vive ao lado desse arquivo em vez disso, e apenas sua presença é visível através da superfície de configurações.

A parte que importa: uma imagem carregada é entrada não confiável

Um logotipo é carregado por um administrador e, em seguida, servido a todos os navegadores que carregam a console, incluindo na página de entrada antes que alguém tenha autenticado. Isso o torna o pedaço de conteúdo fornecido pelo atacante mais amplamente distribuído no produto, então ele é tratado de acordo:

Source: github.com/biodream-llc/perfuse/internal/branding

26.16 cda

O pacote cda lê documentos clínicos.

O design começa de como esses documentos realmente viajam, que não é como arquivos. Um resumo de alta deixa um EHR dentro de uma mensagem HL7 v2 MDM^T02, com o documento inteiro codificado em base64 em OBX-5 e descrito por um segmento TXA. Isso é milhares de mensagens por dia em um hospital de tamanho médio, e é por isso que este pacote fica ao lado de um analisador HL7 v2 em vez de em uma ferramenta de documento: a metade v2 já está aqui, então o pipeline de "uma mensagem chegou" a "um FHIR DocumentReference existe" é curto.

Três coisas estão deliberadamente em escopo e uma está deliberadamente fora.

Em escopo: ler um documento e dizer o que ele contém em termos simples; verificar que a narrativa legível por humanos e as entradas codificadas concordam; e converter para FHIR. A verificação da narrativa é a incomum. Cada seção C-CDA carrega as mesmas informações duas vezes, uma vez como texto para um clínico e uma vez como códigos para uma máquina, e elas devem coincidir. Na prática, elas frequentemente não coincidem, e nada verifica - nem as ferramentas de certificação, nem os motores. Quando o texto diz que um paciente é alérgico à penicilina e a entrada codificada diz algo diferente, um dos dois leitores age com base na informação errada. É um defeito de segurança do paciente que é mecanicamente detectável, então é detectado aqui.

Fora de escopo: gerar C-CDA conformante. Escrever um significa satisfazer várias centenas de regras de modelo e um Schematron, e produzir documentos que são 95% certos falharia na certificação de maneiras que são miseráveis para depurar. Ler, verificar e converter é a maior parte do valor por uma fração do risco.

Source: github.com/biodream-llc/perfuse/internal/cda

26.17 channeltest

O pacote channeltest executa testes contra uma definição de canal.

Um canal é um programa. Ele filtra, reescreve e roteia mensagens clínicas, e é editado sob pressão por pessoas que não podem tentá-lo contra a produção. A ausência de uma maneira de testá-lo é o único maior motivo pelo qual o trabalho de interface é assustador, e "Eu mudei o transformador e nada parecia diferente no navegador de mensagens" não é um teste.

A decisão central é que um teste executa a mensagem pelo caminho de transformação real — o mesmo filtro, as mesmas etapas declarativas, o mesmo mecanismo de script, na mesma ordem — com apenas o transporte substituído. Um teste que exercitasse uma reimplementação passaria enquanto o canal falhava, o que é pior do que não ter um teste em absoluto porque ativamente engana.

Source: github.com/biodream-llc/perfuse/internal/channeltest

26.18 chanscope

O pacote chanscope estreita leituras e gravações em um contexto para alguns canais.

Depende do contexto em vez de ser um parâmetro de cada consulta porque existem dezenas de consultas em todo o repositório de mensagens e na fila de entrega, e o limite é uma propriedade de quem está fazendo a pergunta, não da pergunta em si. A API define isso uma vez por solicitação para uma pessoa limitada a alguns grupos de canais; cada contagem, lista, gráfico, pesquisa e ação de fila concorda com as outras, para que ninguém seja informado de um total de quarenta falhas e mostre quatro.

Source: github.com/biodream-llc/perfuse/internal/chanscope

26.19 aglomerado

O pacote aglomerado permite que vários servidores Perfuse compartilhem um armazenamento PostgreSQL e decidam, entre eles, qual executa o que.

O problema que resolve

Um servidor é um único ponto de falha: quando ele para, todas as interfaces param. Dois servidores em um banco de dados resolvem isso apenas se nunca executarem o mesmo canal, porque dois ouvintes MLLP em uma fonte se alternam com o remetente, dois trabalhadores de fila entregam a mesma mensagem duas vezes, e dois pollers DICOM relatam o mesmo estudo.

How

Um lease é uma linha que nomeia quem detém algo, com um contador que seu detentor move a cada renovação, a cada poucos segundos. Nenhum relógio é comparado com outro: um detentor que não pode renovar (quebrou, foi cortado do banco de dados) para o que o lease cobre uma vez que seu próprio relógio diz que o lease está quase feito, e outro servidor o assume apenas após seu próprio relógio ter observado o contador parar por todo o lease. Cada um mede um intervalo em seu próprio relógio, então os relógios dos servidores e do banco de dados não precisam concordar; eles precisam apenas funcionar a uma taxa aproximadamente igual. Um relógio que pula (uma máquina virtual ressincronizando, um administrador definindo a hora) não muda nada: a primeira versão usava o relógio do banco de dados para expiração, e um teste encontrou um banco de dados cujo relógio pulou treze segundos e entregou cada lease a um novo servidor enquanto os antigos ainda os executavam.

Entre o detentor parar e o próximo começar, há uma pequena lacuna com ninguém executando, o que custa a um remetente alguns segundos de conexões recusadas, e nunca um momento com dois.

Two modes:

Cada lease carrega uma época, contada sempre que seu detentor muda, que nomeia uma detenção na história.

Source: github.com/biodream-llc/perfuse/internal/cluster

26.20 cms

O pacote cms é a Cryptographic Message Syntax (RFC 5652) como S/MIME e Direct secure messaging a usam: SignedData (assinar uma mensagem, verificar uma e dizer quem a assinou) e EnvelopedData (criptografar uma mensagem para os certificados dos destinatários, descriptografar uma com nossa chave).

Apenas o que a Direct Applicability Statement e seu Implementation Guide exigem: RSA com SHA-256 (SHA-1 aceito apenas para leitura, desde que HISPs mais antigos ainda o enviam), transporte de chave RSA com PKCS#1 v1.5 ou OAEP, e AES-128 ou AES-256 no modo CBC. A criptografia é a biblioteca padrão; este pacote é o ASN.1 em torno dela.

Source: github.com/biodream-llc/perfuse/internal/cms

26.21 cms0057

O pacote cms0057 contém as partes do lado pagador da regra final de interoperabilidade e autorização prévia da CMS (CMS-0057-F) que são sobre dados em vez de transporte: reclamações adjudicadas como recursos CARIN Blue Button ExplanationOfBenefit, autorizações prévias como recursos Da Vinci PDex ExplanationOfBenefit, correspondência de membros HRex para a API Payer-to-Payer, a lista de membros por trás da API Provider Access e as métricas de autorização prévia que um pagador deve publicar todos os anos.

Os endpoints FHIR que servem a esses recursos vivem em fhirserver; este pacote decide o que entra neles.

Medicamentos estão fora do escopo em toda parte, como estão nas disposições de autorização prévia da regra: nenhuma ExplanationOfBenefit de farmácia, nenhuma formulary, nenhuma NCPDP.

Source: github.com/biodream-llc/perfuse/internal/cms0057

26.22 codeset

O pacote codeset contém tabelas de mapeamento que sobrevivem ao canal que primeiro as necessitou.

O imposto de domínio é em grande parte rederivar um mapeamento que alguém já derivou. Os códigos de sexo de um site, classes de paciente, status de pedido e identificadores de instalação são traduzidos da mesma maneira em todos os canais que os tocam, e hoje cada uma dessas traduções é uma tabela separada dentro de um canal separado. Quarenta canais significam quarenta cópias e quarenta lugares para corrigir da próxima vez que o sistema receptor muda.

Então uma tabela se torna um objeto nomeado referenciado por nome. Isso é óbvio e é a metade menor do valor.

A metade que ninguém constrói

A metade maior é a proveniência. A maior parte do que torna uma interface difícil de manter não é o mapeamento - é que ninguém sabe *por quê*. "Removemos zeros à esquerda porque a coluna MRN do laboratório é numérica" é conhecimento que existe na cabeça de uma pessoa e deixa o prédio quando ela se aposenta, e o mapeamento que resta se torna algo que ninguém ousa mudar e ninguém ousa excluir.

Então cada tabela registra quem decidiu e quando, cada entrada pode registrar sua própria razão, e ambos sobrevivem ao arquivo que vai para o controle de versão. Um mapeamento com uma razão pode ser discutido. Um mapeamento sem uma razão se torna superstição.

Por que o arquivo é separado do canal

Porque é partilhado. Uma tabela dentro de um canal é uma tabela que apenas esse canal pode utilizar, o que é o problema. E uma tabela partilhada precisa da sua própria história: "quem alterou o mapeamento de sexo e quando" é uma pergunta sobre a tabela, não sobre o canal que foi editado nesse dia.

Source: github.com/biodream-llc/perfuse/internal/codeset

26.23 conformidade

O pacote de conformidade implementa o fluxo de notificação de eventos ADT do CMS exigido pelo 42 CFR 482.24(d) desde maio de 2021.

Os hospitais devem notificar eletronicamente os prestadores de cuidados estabelecidos de um paciente — cuidados primários, especialistas, instalações de cuidados pós-agudos — quando o paciente é admitido, liberado ou transferido. A regulamentação existe porque os pacientes caem pelas brechas durante as transições: um médico de cuidados primários que não sabe sobre uma liberação não pode agendar o acompanhamento que impede uma readmissão.

Este pacote fornece a maquinaria para: - Rastrear quais prestadores são estabelecidos para cada paciente. - Encaminhar eventos ADT para os prestadores corretos com a prioridade correta. - Registrar cada notificação enviada, com status de entrega, para auditorias do CMS. - Gerar relatórios de conformidade que mostram taxas de notificação e falhas.

A segurança de thread é necessária em toda parte porque as mensagens ADT chegam concorrentemente de vários canais e o pipeline de notificação é executado em paralelo.

Source: github.com/biodream-llc/perfuse/internal/compliance

26.24 config

O pacote de configuração carrega definições de canal de arquivos.

A configuração vive em arquivos em vez de um banco de dados, o que é a principal coisa que o Perfuse faz de forma diferente do Mirth. O Mirth mantém os canais no seu próprio banco de dados, o que é por que o controle de versão é um produto separado, por que promover um canal de teste para produção é difícil e por que ninguém pode responder "o que mudou na última terça-feira" sem uma chamada de suporte. Os arquivos dão git, diffs, revisão, CI e promoção de ambiente sem máquinas extras.

A validação é deliberadamente estrita e ocorre no carregamento: campos desconhecidos são um erro, expressões de filtro são compiladas, endereços são verificados. Um canal que não pode ser entendido deve recusar-se a iniciar em vez de executar de uma forma que ninguém pretendia.

Source: github.com/biodream-llc/perfuse/internal/config

26.25 contrato

O pacote contrato transforma o que uma fonte de dados parece em o que uma fonte de dados deve parecer.

Um perfil responde "o que estou recebendo". Isso é útil uma vez. O problema caro é o dia em que muda: uma atualização do fornecedor deixa cair um campo, um novo código aparece, um segmento começa a se repetir. Nenhum desses é um erro — as mensagens ainda são válidas HL7 e todos os motores do mundo as aceitam — então nada nota até que um receptor caia, geralmente semanas depois, e a investigação comece do lado errado.

Um contrato é o perfil escrito como uma expectativa e então verificado. É um teste de contrato, que é uma ideia resolvida no software em geral e quase completamente ausente da integração de saúde.

Por que a unidade é uma taxa e não uma mensagem

O design óbvio é verificar cada mensagem e reclamar quando uma falha. Isso produz um sistema que ninguém pode usar. As fontes de dados reais contêm uma proporção de mensagens genuinamente estranhas — uma mensagem de teste do fornecedor, um paciente sem sexo registrado, uma entrada manual — e alertar sobre cada uma delas treina as pessoas para ignorar os alertas, no ponto em que o recurso é pior do que nada porque consumiu a atenção que precisava.

Então, uma expectativa é sobre uma proporção sobre uma janela: "PID-3 é populado em pelo menos 99% das mensagens". Uma mensagem estranha nunca dispara. Cinco por cento das mensagens que perdem o número do prontuário médico disparam.

Um contrato descreve o que chega, não o que sai

Essa é a distinção que as pessoas erram primeiro, incluindo eu enquanto testava a integração. O Perfuse armazena a mensagem como ela chegou — isso é deliberado, porque a mensagem armazenada é uma evidência do que um remetente enviou — então um contrato é verificado contra a fonte de dados de entrada e não contra a saída das transformações do canal.

Isso é o padrão correto por uma grande margem: a coisa que muda sem aviso é o sistema de envio, e o ponto de um contrato é notar. Mas significa que uma expectativa escrita sobre um valor mapeado ("após o mapeamento, apenas os códigos do laboratório devem permanecer") falhará imediatamente e de forma confusa, porque os códigos que nomeia nunca aparecem no tráfego que está sendo perfilado. Qualquer coisa sobre o que sai pertence a um teste de canal, que executa as transformações reais.

Por que uma violação nomeia a tolerância que quebrou

"PID-3 falhou" não diz nada a alguém. "PID-3 foi populado em 94,2% das últimas 500 mensagens; o contrato exige 99%" diz a eles o quão ruim é, o quão confiante ser e se vale a pena acordar alguém. Os números são a mensagem.

Source: github.com/biodream-llc/perfuse/internal/contract

26.26 crd

O pacote crd é um serviço de descoberta de requisitos de cobertura da Da Vinci (CRD 2.2.1): o lado do pagador da conversa CDS Hooks que diz a um clínico, enquanto a ordem ainda é um rascunho, se é coberta, se precisa de autorização prévia e quais documentações o pagador irá querer.

A API de Autorização Prévia do CMS-0057 é, na prática, três guias da Da Vinci juntas: CRD para dizer o que é necessário, DTR para reunir e PAS para enviar. O Perfuse tinha PAS. Este é o primeiro dos outros dois; o pacote $questionnaire do DTR está no endpoint FHIR.

As decisões de cobertura vêm de um ficheiro de regras, porque são a política do pagador e mudam sem lançamentos de software: um código (ou uma lista de códigos) e o que se aplica a ele - coberto ou não, autorização prévia necessária ou não, documentação e o questionário DTR que a recolhe. Um pedido que não corresponde a nenhuma regra é respondido como "condicional" e "indeterminado", o que é o que o CRD diz para retornar quando o serviço não pode decidir - nunca um palpite de que está coberto.

As respostas seguem o guia: uma ação de sistema que atualiza cada pedido com a extensão de informações de cobertura, que o EHR armazena no pedido e mais tarde envia com a autorização prévia; e um cartão por pedido, para que um clínico o veja.

Source: github.com/biodream-llc/perfuse/internal/crd

26.27 painéis de controle

O pacote de painéis de controle define os painéis de controle que o Perfuse fornece para cada tipo de pessoa que o observa, e como uma pessoa é atribuída a um: pelo seu papel, por um grupo de diretório que o ficheiro de painéis de controle mapeia, ou pela vista que salvou.

Os painéis de controle são compostos por azulejos, e os azulejos mostram apenas agregados - contagens, taxas, tempos, estados. Nenhum mostra uma mensagem, um paciente ou um identificador, para que um painel de controle possa ser atribuído a um gestor de departamento ou colocado em uma tela de parede sem ampliar quem vê os dados do paciente. Um azulejo que precisa de dados que o Perfuse ainda não registra não é falsificado: o painel de controle o lista em "Planejado".

A flexibilidade total é trabalho do Grafana, não deste pacote. Cada azulejo que tem uma métrica por trás dele é exportado como um painel do Grafana sobre o /metrics do Perfuse, para que um site que queira mais do que uma configuração leve possa levá-lo para lá.

Source: github.com/biodream-llc/perfuse/internal/dashboards

26.28 davinci

O pacote davinci especifica qual versão das diretrizes de autorização prévia da Da Vinci (CRD, DTR, PAS) um cliente fala.

O Perfuse responde em duas versões: 2.2 (CRD 2.2.1, DTR 2.2.0, PAS 2.2.1), a mais recente, e 2.1 (CRD, DTR e PAS 2.1.0), a versão recomendada pela lista de pontos do CMS-0057-F uma vez que a base do US Core 3.1.1 das versões 2.0.1 expirou. As duas versões diferem nos formatos que um cliente lê por nome - os parâmetros do pacote de questionário do DTR (PackageBundle na versão 2.1, packagebundle na versão 2.2), a resposta do $inquire do PAS (um Bundle na versão 2.1, um Parâmetros deles na versão 2.2), extensões que existem em apenas uma delas - portanto, uma resposta não pode atender a ambas, e o servidor precisa saber com qual está se comunicando.

Isso é informado, mais específico primeiro: pelo próprio pedido (davinci-crd.requestedVersion da CRD; a versão de um perfil que a entrada afirma, perfil|2.1.0), então pelo registro do cliente (davinci_version em um cliente SMART ou CDS), e finalmente pela configuração própria do servidor (serve -davinci-version), que é definida como a mais recente por padrão.

Source: github.com/biodream-llc/perfuse/internal/davinci

26.29 dbtime

O pacote dbtime formata carimbos de data e hora para que a ordenação deles como texto os ordene como tempo.

Cada loja no Perfuse mantém carimbos de data e hora como TEXT no SQLite e confia na comparação de strings para ordenação e para consultas de intervalo: ORDER BY received_at DESC, WHERE expires_at < ?, WHERE at >= ?. Isso é um projeto razoável - mantém um banco de dados que alguém pode ler com o shell sqlite3 - mas só funciona se a forma de texto for de largura fixa.

O time.RFC3339Nano não é. A sua documentação diz que remove zeros finais do campo de segundos, para que o mesmo relógio produza strings de comprimentos diferentes:

20:56:33.12345Z <- 123450 microsegundos, zero final removido 20:56:33.123456Z <- 123456 microsegundos

Comparados como texto, o primeiro é *maior*, porque após o prefixo compartilhado "12345" ele tem 'Z' onde o segundo tem '6', e 'Z' é classificado acima de qualquer dígito. Portanto, o instante anterior é classificado posteriormente. Aproximadamente um par adjacente em dez é afetado, o que é por que isso se apresentou como uma falha de teste intermitente em vez de como um recurso obviamente quebrado.

O que ele realmente quebrou: o registro de auditoria e o navegador de mensagens ambos ordenam por um carimbo de data e hora e podem, portanto, listar entradas do mesmo segundo na ordem errada. Um rastro de auditoria é um artefato de conformidade e um navegador de mensagens é como alguém reconstrói o que aconteceu, para que em ambos os casos a ordem é o ponto.

O layout abaixo usa .000000000 em vez de .999999999. Ambos imprimem nanossegundos; a diferença é que os zeros são significativos no primeiro e removidos no segundo.

Source: github.com/biodream-llc/perfuse/internal/dbtime

26.30 delimitado

O pacote delimited analisa registros separados e divididos por caracteres configurados.

Este é o tipo de dados Delimited do Mirth: CSV, separado por tabulações, separado por pipes, arquivos de colunas fixas e a longa cauda de formatos que um analisador de laboratório ou um serviço de burocracia emite porque alguém o escreveu em 1994 e ele funciona.

Deliberadamente não é uma biblioteca CSV geral. O que importa aqui é o que uma alimentação de saúde faz que um CSV bem formado não faz: uma linha de cabeçalho que pode ou não estar presente, uma linha vazia final que não deve se tornar um registro vazio, colunas referenciadas por nome para que uma transformação não quebre quando um fornecedor insere uma, e a capacidade de tratar um arquivo inteiro como uma mensagem ou cada linha como sua própria.

A última dessas é a decisão que molda tudo o mais. Um arquivo de cinco mil resultados é ou uma mensagem ou cinco mil, e as duas não são intercambiáveis: uma mensagem significa um reconhecimento e uma falha para o arquivo inteiro, e cinco mil significa que cada linha pode ser filtrada, transformada e repetida por si só.

Source: github.com/biodream-llc/perfuse/internal/delimited

26.31 dicom

O pacote dicom lê conjuntos de dados DICOM.

O DICOM é onde a radiologia vive, e um motor de integração hospitalar que não pode falar isso é excluído da imagem inteira. O Mirth tem um ouvinte e remetente DICOM, então isso é um bloqueador de migração para qualquer site que faça trabalho de modalidade.

Escopo, declarado claramente

Este pacote analisa conjuntos de dados: as informações de metadados do arquivo, os elementos, a sintaxe de transferência e os valores que importam para roteamento e identificação. Ele não decodifica dados de pixel e nunca fará isso enquanto este pacote estiver preocupado - um motor de integração move imagens, não as exibe, e um decodificador é um grande corpo de trabalho específico de formato cujo único propósito aqui seria fazer o binário maior.

Ler metadados sem tocar pixels também é o que o torna rápido no tráfego que importa: uma tomografia computadorizada de tórax é centenas de megabytes de pixels atrás de dois quilobytes de informações que qualquer pessoa roteia.

Por que as representações de valor são tratadas explicitamente

Um elemento DICOM transporta um valor de representação de duas letras que indica como ler o seu valor, e as regras diferem por VR de maneiras que não podem ser adivinhadas: alguns têm um comprimento de dois bytes e alguns quatro, alguns são preenchidos com um espaço e alguns com um nulo, e strings numéricas podem conter vários valores separados por barras. Obter um errado não produz um erro, produz um valor errado com aparência plausível - um nome de paciente lido do meio de uma data, ou um identificador de estudo deslocado por um byte.

Source: github.com/biodream-llc/perfuse/internal/dicom

26.32 dicomweb

O pacote dicomweb fala DICOMweb (DICOM PS3.18): QIDO-RS para pesquisar, WADO-RS e WADO-URI para recuperar, STOW-RS para armazenar, sobre HTTP.

É como os visualizadores, serviços de IA e arquivos de nuvem alcançam a imagem agora: OHIF, Google Cloud Healthcare, Azure Health Data Services, AWS HealthImaging, interfaces DICOMweb do Orthanc e do dcm4chee. Um motor de integração que só fala o protocolo de rede de 1993 (DIMSE: C-STORE, C-FIND) pode alimentar um PACS, mas não um navegador.

O pacote tem quatro partes: um leitor de conjunto de dados que percorre todo o objeto, incluindo sequências, e sabe onde os dados de pixel estão sem carregá-los; o modelo DICOM JSON (PS3.18 F.2); multipart/related, que é como o DICOMweb move vários objetos em uma solicitação; e um arquivo com um índice, que é o que QIDO e WADO respondem.

Source: github.com/biodream-llc/perfuse/internal/dicomweb

26.33 direct

O pacote direct é a mensagens seguras Direct como um sistema de borda: uma mensagem para um endereço Direct é assinada com o certificado deste endereço e criptografada para o certificado do destinatário, como S/MIME, e enviada a um HISP por SMTP; uma mensagem recebida do HISP (por SMTP ou coletada sobre IMAP) é decifrada e sua assinatura verificada contra os âncoras de confiança antes que qualquer coisa a leia.

Ele segue a Declaração de Aplicabilidade do Projeto Direct para Transporte de Saúde Seguro 1.2 e a especificação XDM (IHE ITI TF-1 Anexo 15) para documentos com metadados. Ele não é um HISP: a credenciação do HISP, sua política de certificado e seu diretório permanecem com o HISP.

Source: github.com/biodream-llc/perfuse/internal/direct

26.34 drug

O pacote drug lida com os códigos e quantidades que identificam um medicamento.

Dividido a partir dos padrões de farmácia que os transportam, porque o mesmo código de droga aparece em uma reclamação NCPDP, uma prescrição SCRIPT, um segmento HL7 RXE e um FHIR MedicationRequest, e uma conversão que vive em um desses lugares é uma conversão que os outros três fazem sem.

Source: github.com/biodream-llc/perfuse/internal/drug

26.35 dsdr

O pacote dsdr assina e verifica documentos CDA como a Guia de Implementação do HL7 para CDA Release 2: Assinaturas Digitais e Delegação de Direitos, Release 1 (outubro de 2014) descreve - o padrão de assinatura eletrônica que o HIPAA adota para anexos de reclamações em CMS-0053-F, 45 CFR 162.2002(e), com conformidade a partir de 26 de maio de 2028.

O que a guia pede e onde é feito aqui:

Onde a guia é silenciosa, as escolhas feitas são nomeadas: ela não fornece um namespace para seus próprios elementos (digitalSignature, authorizedSigner, SignaturePurpose), então eles são colocados em urn:hl7-org:sdtc; e o propósito também é declarado como uma indicação de tipo de compromisso XAdES com o OID ASTM, que as ferramentas XAdES lêem e o próprio elemento da guia não.

A delegação de direitos (um signatário delegado com uma afirmação SAML) não é produzida; uma assinatura que carrega um é relatada como tal.

Source: github.com/biodream-llc/perfuse/internal/dsdr

26.36 e4x

O pacote e4x faz com que o JavaScript do Mirth Connect execute sem alterações.

Os scripts do Mirth são escritos para Rhino, que implementa E4X: o XML é um tipo nativo com sua própria sintaxe. O mecanismo aqui é o goja, que não o faz, e a lacuna não é apenas uma questão de tempo de execução.

Três peças do E4X são *sintaxe*, então o analisador do goja rejeita o arquivo inteiramente antes que qualquer modelo de objeto possa ajudar: para cada (var seg em msg..OBX) { } // para-cada, e o operador descendente var z = <ZZZ><ZZZ.1>valor</ZZZ.1></ZZZ>; // um literal XML var id = node.@root; // uma referência de atributo

Este arquivo reescreve esses em ECMAScript ordinário que o goja analisa, deixando a semântica para o objeto de tempo de execução em xml.go. Tudo o mais sobre E4X - acesso a propriedades por nome de elemento, indexação de repetições, atribuição, toString - já é sintaxe de JavaScript válida e não precisa de reescrita.

A reescrita é feita com um lexer real em vez de expressões regulares, porque a alternativa corrompe scripts que funcionam. Um padrão para o operador descendente encontra um dentro de "http://example.org", um padrão para literais XML encontra um em "a < b && c > d", e um script que silenciosamente muda o significado é muito pior do que um que se recusa a carregar.

Source: github.com/biodream-llc/perfuse/internal/e4x

26.37 edifact

O pacote edifact lê e escreve intercâmbios UN/EDIFACT (ISO 9735): a string de serviço UNA, o envelope de intercâmbio UNB/UNZ, grupos funcionais UNG/UNE opcionais e mensagens UNH/UNT, com o caractere de liberação e, para a versão de sintaxe 4, o separador de repetição.

Verifica os contadores e referências do envelope, endereça elementos de dados para filtros, divide uma troca em uma por mensagem e constrói um reconhecimento CONTRL.

Lê qualquer tipo de mensagem (ORDERS, INVOIC, IFTSTA, MEDRPT...); não contém os diretórios que especificam quais segmentos um tipo de mensagem pode conter, por isso verifica a estrutura, não o conteúdo.

Source: github.com/biodream-llc/perfuse/internal/edifact

26.38 saída

O pacote de saída decide se este motor pode se conectar para fora para um endereço.

Existe porque um destino pode ser apontado para qualquer lugar, e uma combinação o transforma em uma forma de ler a rede interna: um destino SOAP com um transformador de resposta retorna a resposta do receptor para um script, para que um editor possa criar um canal que recupere uma URL interna e escreva o corpo em um log ou mensagem.

Demonstrado em vez de teorizado: um destino SOAP direcionado a um servidor HTTP local colocou o corpo da resposta do servidor em uma linha de log do canal.

A resposta proporcional não é proibir conexões de saída - entregar mensagens para pontos de extremidade configurados é o propósito completo do software, e um editor é destinado a configurá-los. É recusar os endereços específicos que nunca são um destino de mensagem e sempre são um repositório de credenciais.

Source: github.com/biodream-llc/perfuse/internal/egress

26.39 motor

O pacote motor executa canais configurados.

Um canal é uma fonte, um filtro e um conjunto de destinos. O trabalho do tempo de execução é ser honesto sobre o que aconteceu com cada mensagem: um reconhecimento deve significar o que a configuração diz que significa, uma mensagem filtrada deve ser distinguível de uma que foi entregue, e uma mensagem que não pôde ser entregue em nenhum lugar não deve ser relatada como aceita.

Source: github.com/biodream-llc/perfuse/internal/engine

26.40 epa

O pacote epa é a autorização eletrônica de prescrição do NCPDP SCRIPT, do lado do pagador: PAInitiationRequest, PARequest, PAAppealRequest e PACancelRequest de entrada, e suas respostas de saída.

A proposta CMS-0062-P sugere que os pagadores afetados o suportem a partir de 1 de outubro de 2027, e o Medicare Part D já o exige. Um pedido é decidido da mesma forma que toda autorização de prescrição anterior neste servidor: torna-se um pedido de PAS da Da Vinci (um Reivindicação, o MedicationRequest e as respostas do prescritor como uma QuestionnaireResponse) e vai para o mesmo arquivo de regras, serviço de decisão e fila de revisão. O formulário diz quais medicamentos precisam de um e quais perguntas fazer, a partir do mesmo Questionário FHIR que a Da Vinci DTR preenche.

Os esquemas do NCPDP são licenciados. Os nomes de elementos e a ordem aqui seguem o guia de acompanhamento público do Surescripts e seus exemplos; dois elementos que o material público nunca mostra (o motivo dentro de Closed e dentro de Denied) seguem o padrão SCRIPT usado em outros lugares e são nomeados no manual para que um pagador possa verificá-los contra sua própria cópia do esquema.

Source: github.com/biodream-llc/perfuse/internal/epa

26.41 eprescrever

O pacote eprescrever lê e escreve o NCPDP SCRIPT, o padrão pelo qual as prescrições viajam.

Nomeado pelo que faz em vez de pelo padrão, porque internal/script já é o mecanismo JavaScript e dois pacotes chamados script em uma árvore é um erro esperando para ser feito em uma linha de importação.

O SCRIPT é XML, ao contrário do Padrão de Telecomunicação que transporta a reivindicação resultante. Um prescritor envia um NEWRX para uma farmácia; a farmácia envia de volta RXFILL para dizer o que aconteceu, REFREQ para pedir um reabastecimento, ou RXCHG para pedir uma alteração. Cada um desses é uma mensagem aqui.

Onde está o perigo

Dois campos em uma prescrição são perigosos quando mal lidos em vez de quando faltam.

Substituições é o primeiro. Um zero significa que a substituição é permitida e um significa dispensar como escrito. Lê de trás para frente para alguém que espera uma bandeira onde um significa sim, e errar dispensa um genérico onde o prescritor exigiu a marca - ou se recusa a substituir o que foi permitido, que é o mesmo erro que custa ao paciente dinheiro em vez.

A contagem de reabastecimento é a segunda. Uma prescrição de controle II pode não ser reabastecida de forma alguma, e um sistema que transporta uma contagem de reabastecimento de um modelo não controlado produz uma prescrição com aparência válida que uma farmácia deve recusar.

O que não foi verificado

A estrutura da mensagem segue os nomes de elementos do SCRIPT publicados. Nenhuma mensagem deste pacote foi enviada por uma rede de roteamento real, como o Surescripts, e a certificação por um é um processo comercial em vez de técnico. Isso analisa e constrói o formato; não afirma a certificação.

Source: github.com/biodream-llc/perfuse/internal/eprescribe

26.42 equivalente

O pacote equiv prova que dois motores concordam, ou diz exatamente onde não concordam.

Esta é a resposta à única pergunta que realmente bloqueia uma migração. Uma equipe de interface não recusa um novo motor porque falta recursos; eles recusam porque não podem ter certeza de que fará a mesma coisa com o tráfego que já têm, e estar errado significa que os resultados dos exames param de alcançar os médicos. Nenhuma comparação de recursos responde a isso. A evidência sim.

O uso pretendido é uma execução paralela. Ambos os motores recebem as mesmas mensagens de produção; o titular continua entregando e o Perfuse entrega para ninguém, o que é o que os canais de sombra já são. Após duas semanas, as saídas são comparadas aqui, e a conversa muda de "confie nisso" para "aqui estão as três mensagens de quatrocentas mil onde discordamos, e por quê".

Agrupamento é o recurso completo

Uma comparação ingênua de 400.000 mensagens produz 400.000 descobertas e é fechada sem leitura. Quase todas as diferenças reais têm uma causa: um formato de data, um código de instalação, uma etapa de transformação que ninguém transportou. Portanto, as diferenças são agrupadas por causa - o caminho na mensagem e o tipo de diferença - e relatadas uma vez com uma contagem. Três mil diferenças de uma causa são uma descoberta, não três mil. Essa decisão única é o que torna o relatório legível, e um relatório legível é a diferença entre uma migração que prossegue e uma que estagna.

Valores são retidos por padrão

O tráfego real é dados de paciente, então um relatório de comparação é um local onde o PHI pode vazar para um ticket, um e-mail ou uma apresentação. Por padrão, este relatório relata caminhos, tipos e contagens - nunca valores. Isso é suficiente para encontrar a causa: "MSH-7 difere em 3.000 de 3.000 mensagens" diz a um analista que é o formato de data sem mostrar uma data.

Os valores podem ser habilitados deliberadamente, porque eventualmente alguém precisa vê-los, e fingir o contrário apenas os empurraria para uma ferramenta pior. É um opt-in explícito e o relatório diz em sua face que contém conteúdo de mensagem.

Source: github.com/biodream-llc/perfuse/internal/equiv

26.43 expr

A ligação HL7 v2.

Esta é a lógica que costumava viver inline em eval.go. Ela é inalterada em comportamento - deliberadamente, porque o filtro v2 é o que todos os canais HL7 executam e o objetivo da gramática genérica era adicionar formatos, não alterar este.

Source: github.com/biodream-llc/perfuse/internal/expr

26.44 fdlimit

O pacote fdlimit descobre quantos descritores de arquivo este processo pode abrir e aumenta o limite se puder.

Isso existe por causa da forma da falha que impede. Cada conexão de entrada é um descritor, e também é cada entrega de saída em voo. Um receptor que parou de responder segura um descritor para todo o orçamento de repetição - com os padrões, cinco tentativas com um tempo limite de trinta segundos mais quinze segundos de retrocesso, então quase três minutos. Algumas centenas de conexões contra um receptor preso são, portanto, algumas centenas de descritores segurados por minutos.

Ficar sem descritores não produz um erro limpo no local que ficou sem. Produz "muitos arquivos abertos" em outro lugar completamente: o banco de dados não pode abrir seu diário, a interface web para de aceitar, um arquivo de log não pode ser escrito. O motor parece ter quebrado em três lugares não relacionados ao mesmo tempo, e a causa real é um sistema de parceiro que ficou quieto. Essa é a chamada de suporte que este pacote existe para evitar.

Duas coisas acontecem na inicialização. O limite suave é aumentado para o limite rígido, o que geralmente remove o problema diretamente - o padrão suave é frequentemente algumas centenas, enquanto o limite rígido é dezenas de milhares. Em seguida, o que está disponível é relatado, para que o motor possa limitar sua própria concorrência dentro dele, em vez de descobrir batendo.

Source: github.com/biodream-llc/perfuse/internal/fdlimit

26.45 fhirpath

O pacote fhirpath avalia FHIRPath (HL7 FHIRPath N1, 2.0.0) sobre recursos FHIR mantidos como JSON decodificado.

Ele não tem um modelo FHIR: o tipo de um elemento é conhecido quando o JSON FHIR diz (um sufixo de elemento de escolha, como valueQuantity, um resourceType de recurso) ou inferido do valor JSON de outra forma. Isso cobre o que SQL em visualizações FHIR e medidas de qualidade livres de CQL precisam; navegação que depende do modelo (o tipo de um primitivo quando não é uma escolha) é respondida a partir da forma do valor.

Source: github.com/biodream-llc/perfuse/internal/fhirpath

26.46 fhirserver

O pacote fhirserver implementa um servidor FHIR REST.

Isso existe porque o fim útil de um mapeador v2-para-FHIR é algum lugar para colocar o resultado. Ser capaz de converter uma mensagem é uma demonstração; ser capaz de convertê-la, armazená-la e, em seguida, encontrar o paciente novamente por identificador é um produto.

É um servidor FHIR real nas partes que importam para isso: uma declaração de capacidade, criar, ler, atualizar, excluir, pesquisar nos parâmetros que as pessoas realmente usam e pacotes de transação aplicados atomicamente. Não é um servidor FHIR completo - sem histórico, sem pesquisa encadeada, sem _include - e diz isso em sua própria declaração de capacidade, em vez de deixar que um cliente descubra as lacunas.

Source: github.com/biodream-llc/perfuse/internal/fhirserver

26.47 formulário

O pacote formulary é um formulário de drogas de um pagador: quais drogas cada plano cobre, em qual nível e com quais limites (autorização prévia, terapia de etapa, limites de quantidade) e o que o membro paga.

Um ficheiro é a única fonte para tudo o que responde a uma pergunta sobre um medicamento: a API Da Vinci US Drug Formulary (publicada a partir dela como FHIR), respostas de benefícios de prescrição em tempo real da NCPDP e autorização eletrónica prévia da NCPDP SCRIPT (se um medicamento precisa de uma e quais perguntas fazer). Um formulário que vivesse em três lugares responderia à mesma pergunta de três maneiras.

Source: github.com/biodream-llc/perfuse/internal/formulary

26.48 estruturação

O enquadramento do pacote lê e escreve mensagens em um fluxo de bytes que não é MLLP.

Por que isso existe separadamente do mllp

MLLP é um enquadramento: 0x0B antes, 0x1C 0x0D depois. É o que o HL7 v2 usa sobre TCP e o Perfuse sempre o falou.

Muito equipamento não o faz. Um analisador de laboratório, uma balança, um monitor de cabeceira, um sistema de faturamento mais antigo - cada um tende a ter sua própria convenção, e as convenções são todas variações simples das mesmas três ideias: um delimitador em algum lugar, um comprimento de registro fixo ou um comprimento escrito antes da carga útil.

O conector TCP do Mirth cobre isso e o Perfuse não tinha nada, então um site com uma alimentação de soquete que não era HL7 não podia usá-lo de forma alguma.

O erro que este pacote foi escrito para evitar

Ler de um fluxo e adivinhar onde uma mensagem termina é o problema todo. Adivinhar curto e uma mensagem é cortada ao meio; adivinhar longo e duas mensagens chegam como uma. Ambos produzem saída que geralmente parece plausível, o que é pior do que um erro, então todos os modos aqui são explícitos sobre o que termina uma mensagem e nenhum deles recorre a outro.

Uma mensagem sem enquadramento algum é uma configuração legítima - alguns dispositivos abrem uma conexão, enviam uma mensagem e fecham - mas não pode ser combinada com nada mais e não pode ser usada em uma conexão que permanece aberta, então é nomeada e validada em vez de ser tratada como um padrão.

Source: github.com/biodream-llc/perfuse/internal/framing

26.49 ftpconn

O pacote ftpconn carrega arquivos via FTP e FTPS usando apenas a biblioteca padrão.

FTP é antigo, tagarela e não é um bom protocolo. Ele também ainda é como um grande número de sistemas hospitalares aceitam arquivos, geralmente porque o extremo oposto é um analisador de laboratório ou um serviço de burocracia cujo software não foi tocado desde que funcionou. Recusar-se a apoiá-lo não torna esses sistemas modernos; torna o Perfuse inutilizável nesses locais.

Implementado aqui em vez de ser tomado como uma dependência pelo mesmo motivo que o S3: a lista de materiais de oito dependências é um argumento real com quem revisa o software antes de um hospital o instalar. O canal de controle do FTP é texto orientado a linha sobre TCP, então isso é algumas centenas de linhas de net e crypto/tls.

O que é suportado e o que é recusado

Modo passivo apenas. O modo ativo exige que o servidor abra uma conexão de volta ao cliente, o que todos os firewalls hospitalares construídos este século bloqueiam, e oferecê-lo significaria que as pessoas o configuram e então depuram um firewall.

FTPS explícito (AUTH TLS) é suportado e é o padrão quando o TLS é solicitado. FTPS implícito na porta 990 também é suportado porque alguns analisadores só falam isso.

FTP simples é suportado e avisa. Ele envia a senha em texto claro e um local que precisa usá-lo deve ser informado uma vez em vez de ser deixado para descobrir a partir de uma captura de pacote.

Source: github.com/biodream-llc/perfuse/internal/ftpconn

26.50 gcp

O pacote gcp fala com o Google Cloud Pub/Sub e o Cloud Storage por meio de suas APIs REST, com o OAuth 2.0 do Google feito aqui: uma chave de conta de serviço assina um JWT (RS256, crypto/rsa) que é trocado por um token de acesso, ou, no próprio Google Cloud, o servidor de metadados entrega um.

Nenhuma SDK do Google.

Emuladores (o emulador Pub/Sub, fake-gcs-server) não levam credenciais: defina o Endpoint e deixe as credenciais vazias.

Source: github.com/biodream-llc/perfuse/internal/gcp

26.51 gerar

O pacote gerar cria mensagens sintéticas HL7 v2.

Dois usos. Alguém que está tentando o Perfuse precisa de tráfego para olhar, e um teste de canal precisa de um fixture que seja realista o suficiente para exercitar a coisa que está sendo testada. Um gerador é uma extensão paga no Mirth, o que lhe diz que as pessoas querem um.

Tudo aqui é inventado. Os nomes vêm de uma lista fixa de nomes obviamente fictícios, os identificadores são sequenciais dentro de uma execução e os endereços são inventados. Isso não é uma declaração, é o design: um gerador que produzisse nomes reais plausíveis eventualmente colocaria um em um fixture de teste, um relatório de bug e então um repositório.

O realismo é gasto onde é necessário para testar e em nenhum outro lugar. Os carimbos de data e hora têm deslocamentos, os campos repetidos realmente se repetem, um nome às vezes tem uma inicial do meio e às vezes não, e aproximadamente uma mensagem em doze é deliberadamente desconfortável: um campo opcional em falta, um separador incomum mas legal, um componente vazio. Alimentar um canal com nada além de mensagens perfeitamente formadas não diz muito.

Source: github.com/biodream-llc/perfuse/internal/generate

26.52 hl7dict

O pacote hl7dict nomeia os campos dos segmentos HL7 v2.

Isso existe para uma tela: um visualizador de mensagens que pode dizer que PID-5.1 é o nome de família do paciente em vez de deixar que você conte os carets. Quem já depurou uma interface fez essa contagem manualmente, e é a fonte mais comum de erros de deslocamento que colocam um valor no campo errado.

Não é o padrão completo. O HL7 v2 tem centenas de segmentos e milhares de campos, e os que estão aqui são os que aparecem no tráfego ADT, ORU, ORM e SIU. Um campo desconhecido é relatado como desconhecido em vez de ser adivinhado.

Source: github.com/biodream-llc/perfuse/internal/hl7dict

26.53 hl7v3

O pacote hl7v3 lê mensagens HL7 versão 3.

A versão 3 é uma coisa diferente da versão 2 com o mesmo nome. A versão 2 é um fluxo de segmentos delimitados por pipe, cujo significado é posicional; a versão 3 é XML gerada a partir de um modelo de informação de referência, onde o significado é transportado por nomes de elementos e por um pequeno conjunto de tipos de dados que se repetem em todos os lugares. Quase nada é transferido entre os dois além do vocabulário clínico.

Na prática, a v3 chega em uma de duas formas. Ou é um documento CDA, que é derivado da v3 e tratado pelo pacote cda, ou é uma transação IHE - PIX e PDQ v3, em particular, que é como muitos hospitais resolvem identificadores de pacientes entre sistemas. Este pacote é direcionado ao segundo.

Por que os tipos de dados vêm primeiro

A coisa mais consequente sobre a v3 é que um elemento pode estar presente e explicitamente nulo, com um motivo declarado. Uma data de nascimento com nullFlavor="ASKU" significa que o paciente foi perguntado e se recusou a responder. Uma que carrega nullFlavor="NAV" significa que o valor existe, mas não está disponível no momento, então perguntar novamente mais tarde pode funcionar. Uma que simplesmente está ausente significa que ninguém registrou nada.

Colapsar esses em uma string vazia é o erro que este pacote é projetado para prevenir. Não é uma perda cosmética: um sistema downstream que recebe uma data de nascimento vazia onde a fonte disse "paciente se recusou" geralmente a tratará como dados em falta para ser perseguido, e uma correspondência demográfica que deveria ter sido deixada sem resolução é resolvida por um humano adivinhando. Então, cada tipo de dados aqui distingue ausente, nulo-com-motivo e presente.

Source: github.com/biodream-llc/perfuse/internal/hl7v3

26.54 hl7xml

O pacote hl7xml converte mensagens HL7 v2 para e a partir do formato XML que o Mirth Connect usa, e volta para o codificação ER7.

A forma não é uma escolha de design. Os scripts do Mirth são escritos contra a saída do seu próprio serializador ER7-XML, então contêm expressões como

msg['PID']['PID.5']['PID.5.1'].toString()

e a promessa de que um script existente é executado inalterado é mantida apenas se a árvore que ele percorre tiver exatamente os mesmos nomes de elementos, aninhamento e comportamento de repetição. Portanto, cada decisão abaixo é "o que o Mirth faz", e não "o que seria mais organizado".

Os dois que mais importam:

Cada campo é envolto em elementos de componentes numerados, mesmo quando o campo tem apenas um componente, então PID-5 com o valor "Doe" ainda produz <PID.5><PID.5.1>Doe</PID.5.1></PID.5>. Os scripts indexam diretamente para .1 constantemente e uma árvore que colocasse o texto no elemento do campo quebraria quase todos eles.

MSH mantém os números de campos HL7 padrão, onde MSH-1 é o separador de campos e MSH-9 é o tipo de mensagem. O analisador em internal/hl7 indexa MSH com um deslocamento porque o separador ocupa uma posição que nenhum delimitador divide, e esse deslocamento para aqui: um script que diz MSH.9 significa o tipo de mensagem.

Source: github.com/biodream-llc/perfuse/internal/hl7xml

26.55 ibmmq

O pacote ibmmq envia para e lê de filas IBM MQ por meio da API de mensagens REST do gerenciador de filas (mqweb), que o IBM MQ 9.1.5 e posterior enviam em todas as plataformas, incluindo z/OS.

Ele não precisa de uma biblioteca de cliente MQ: o protocolo MQI nativo é da IBM e não documentado, e a API REST é a forma suportada de alcançar o MQ sem uma. (O IBM MQ também fala AMQP 1.0 em um canal AMQP; o conector amqp do Perfuse cobre essa rota.)

A leitura é pelo menos uma vez: a primeira mensagem é visualizada, entregue ao chamador e removida por seu ID de mensagem apenas uma vez que o chamador a tenha tratado. Uma mensagem que não pôde ser tratada permanece na fila, primeiro na linha.

Source: github.com/biodream-llc/perfuse/internal/ibmmq

26.56 identidade

Encontrar uma mensagem pelo que você sabe sobre ela, independentemente do formato em que ela chegou.

A pesquisa de conteúdo existente corresponde a metadados, oferece uma correspondência de subcadeia contra a carga útil e pode avaliar uma expressão de filtro - mas a expressão é avaliada apenas contra o HL7 v2, e cada expressão requer conhecimento do caminho. Portanto, encontrar o tráfego de um paciente significava saber que a identidade reside em PID-3 em uma admissão HL7 v2, em Patient.identifier em um recurso FHIR, em (0010,0020) em uma instância DICOM e em NM109 de um loop NM1*IL em uma reclamação 837. Quatro formatos, quatro vocabulários, e durante um incidente a mensagem que está sendo procurada pode estar em qualquer um deles.

Este pacote mapeia um pequeno conjunto de conceitos - quem a mensagem é sobre, qual visita, qual estudo, qual reclamação - para o local onde cada formato os mantém, para que uma pesquisa possa ser feita por "MRN 12345" em vez de por um caminho. Os conceitos são deliberadamente poucos: são as coisas que as pessoas realmente têm em mãos quando precisam encontrar uma mensagem, que é um número de uma ligação telefônica ou um nome de uma reclamação.

Por que a extração acontece uma vez, no momento do registro

A alternativa é analisar as cargas úteis no momento da consulta, o que é o que a pesquisa de expressão faz. Isso funciona e é honesto sobre ser uma varredura limitada, mas não pode responder "todas as mensagens sobre este paciente em quatro feeds e dois meses" sem ler cada linha. Extrair uma vez para uma tabela indexada transforma isso em uma pesquisa de índice.

Esta é uma escalada de privacidade, e é opcional

Os nomes e identificadores de pacientes atualmente estão dentro de uma coluna de carga útil opaca. Indexá-los os torna pesquisáveis, o que é o objetivo, e também os torna enumeráveis, o que é uma mudança real na exposição: um banco de dados que só podia ser pesquisado agora pode ser perguntado "liste todos os pacientes". Essa é uma decisão para o site, não para este pacote, então a extração é comutável e cada pesquisa através dela é registrada no log de auditoria de PHI.

Source: github.com/biodream-llc/perfuse/internal/identity

26.57 iis

O pacote iis fala o transporte que todos os registros de imunização dos EUA compartilham: o serviço web SOAP do CDC.

Em 2011, um painel de especialistas convocado pelo CDC e pela American Immunization Registry Association escolheu uma interface SOAP para enviar mensagens HL7 v2 para Sistemas de Informação de Imunização, e os registros adotaram isso. O WSDL é pequeno - duas operações, connectivityTest e submitSingleMessage - e a mensagem HL7 (um VXU para relatar uma vacinação, um QBP^Q11 para perguntar sobre o histórico de um paciente) viaja como texto escapado dentro do corpo SOAP. A resposta vem de volta da mesma forma: um ACK, ou um RSP^K11 que carrega o histórico e o prognóstico.

O destino SOAP genérico poderia ser configurado para fazer isso, mas cada site teria que digitar o mesmo envelope, obter o namespace correto, colocar as credenciais no corpo em vez de na autenticação HTTP e, em seguida, ler a confirmação HL7 da resposta para aprender se o registro manteve o registro. Um registro responde a uma vacinação rejeitada com HTTP 200 e um AR; tratar o 200 como sucesso é como as vacinações silenciosamente falham em ser relatadas. Então, este pacote faz o envelope do CDC e julga a confirmação, uma vez.

O que ele não faz: as credenciais de usuário e senha do WSDL são as credenciais de aplicativo do registro e são enviadas como o WSDL diz, no corpo. O TLS mútuo, onde um registro o exige, é a configuração de TLS do destino, como para qualquer chamada HTTPS. Nada aqui é específico de um estado; onde os estados diferem (ID de instalação necessário ou não, SOAP 1.1 aceito ou não, avisos enviados como AE), as configurações do destino dizem isso.

Source: github.com/biodream-llc/perfuse/internal/iis

26.58 kafka

Kafka, como um cliente em vez de algo para substituir.

Um sistema de saúde que tem uma espinha dorsal de eventos tem uma espinha dorsal de Kafka, e os sistemas construídos na última década publicam nela em vez de em um corretor JMS. Então, este conector existe para tornar o Perfuse a borda consciente de saúde de uma plataforma de eventos de outra pessoa: ele lê mensagens clínicas de tópicos e publica-as em tópicos, e deliberadamente não tenta ser uma plataforma de processamento de fluxo. Janelamento, junções, processamento de fluxo e registros de esquema são o ecossistema do Kafka e permanecem lá.

Por que uma dependência, quando STOMP e MLLP foram escritos à mão

A regra declarada neste repositório é que uma dependência deve comprar capacidade em vez de conveniência, e deve ser puro Go para que um binário estático ainda faça a compilação cruzada para todos os alvos. franz-go é puro Go e não carrega cgo, o que foi verificado contra todos os seis alvos.

O protocolo do Kafka não é o STOMP. STOMP é um protocolo de texto que se encaixa em algumas centenas de linhas. Kafka é um protocolo binário versionado em torno de setenta tipos de solicitação, e a parte que mais importa aqui - grupos de consumidores - é um protocolo de coordenação distribuída com fases de junção, sincronização, batimento cardíaco e compromisso de deslocamento e uma dança de reequilíbrio entre elas. Obter isso sutilmente errado não produz uma falha óbvia: produz uma partição que ninguém está lendo, ou dois consumidores lendo a mesma partição. Em uma alimentação clínica, essas são um resultado de laboratório perdido e uma ordem duplicada. Isso é capacidade, e não vale a pena fazer à mão para economizar uma dependência.

Source: github.com/biodream-llc/perfuse/internal/kafka

26.59 ldap

O pacote ldap fala o suficiente LDAP para autenticar uma pessoa e ler seus grupos.

Os hospitais executam quase universalmente o Active Directory, e o AD fala LDAP. O OpenID Connect é a melhor resposta quando é alcançável - veja internal/oidc, e a nota lá sobre o Mirth não ter um único sinal de entrada a qualquer preço - mas um motor de integração muitas vezes se encontra em uma VLAN isolada onde um navegador não pode alcançar um provedor de identidade. É para isso que isso serve.

BER feito à mão em vez de uma dependência, pelo mesmo motivo que o DICOM e o STOMP: a codificação é pequena, e o que chega a essa socket decide se alguém entra em um sistema que move dados de pacientes.

A codificação/asn1 na biblioteca padrão não é usável aqui. Ela visa o DER e rejeita as tags contextuais e a marcação implícita que o LDAP usa em toda parte, então as partes que importam precisariam ser feitas à mão de qualquer forma.

Source: github.com/biodream-llc/perfuse/internal/ldap

26.60 caixa de correio

O pacote caixa de correio lê e-mails de servidores IMAP4rev1 (RFC 3501) e POP3 (RFC 1939), fazendo login com uma senha ou com OAuth 2.0 (SASL XOAUTH2, como o Microsoft 365 e o Gmail exigem), e divide as mensagens (RFC 5322 e MIME) para que um anexo ou o corpo do texto possa se tornar uma mensagem em um canal.

Apenas o que uma fonte de entrada precisa: selecione uma caixa de correio, encontre e-mails não lidos, pegue-os inteiros, então mova, marque ou exclua. Apenas a biblioteca padrão; o TLS é crypto/tls.

Source: github.com/biodream-llc/perfuse/internal/mailbox

26.61 mapeador

O pacote mapeador sugere mapeamentos de campos entre sistemas com pontuações de confiança.

Este é um motor de mapeamento inteligente baseado em regras. Sem LLM, sem chamadas de rede, sem dependências externas. Ele é executado offline no mesmo binário e nunca envia dados de pacientes para qualquer lugar.

O motor combina múltiplos sinais - correspondência de strings difusas em nomes de campos, reconhecimento de padrões de identificadores de saúde, pesquisas de sistemas de código e dados de aceitação históricos - em uma única pontuação de confiança por sugestão. Quando a confiança está abaixo de um limiar configurável, o mapeador se abstém em vez de adivinhar errado, porque um mapeamento errado na saúde pode encaminhar dados para o campo errado e isso é um defeito de segurança do paciente.

A abstenção é a decisão de design central. Um sistema que sempre produz uma resposta treina os usuários a parar de verificar, e a única vez que ele está errado ninguém nota até que um resultado de laboratório aterrisse em um campo de notas. Um sistema que diz "Eu não sei" força uma decisão humana exatamente quando a decisão humana é necessária.

Source: github.com/biodream-llc/perfuse/internal/mapper

26.62 medida

O pacote medida avalia Medidas FHIR (medidas de qualidade digitais) cujos critérios de população são FHIRPath, e escreve o resultado como um Relatório de Medida FHIR: resumo, individual ou lista de assuntos, com estratificadores e uma pontuação de proporção.

Cada critério é avaliado uma vez por paciente, com o foco em um Bundle do registro do paciente (seu compartimento) e essas variáveis: %assunto (o Paciente), %períodoInício e %períodoFim (o período de medição, como DataTimes) e %"Período de Medição" (o mesmo que um Período). Critérios em CQL são recusados com o motivo: o Perfuse não tem um motor CQL.

Source: github.com/biodream-llc/perfuse/internal/measure

26.63 métricas

O pacote métricas coleta o que o motor está fazendo e mantém o suficiente da história para desenhá-lo.

Um motor de interface é observado, não apenas executado. Quando uma enfermaria diz que os resultados pararam de chegar há vinte minutos, a pergunta é o que mudou há vinte minutos, e isso não pode ser respondido pelos contadores atuais sozinhos. Então, isso mantém séries em vez de totais, na memória, em uma resolução fixa.

Três decisões dão forma a ele.

A latência é mantida como um histograma em vez de uma média. Um tempo de entrega médio é quase inútil neste domínio: o número que importa é se os poucos por cento mais lentos de mensagens são lentos o suficiente para violar um compromisso de prazo, e uma média esconde exatamente isso. Os buckets são exponenciais e fixos no momento da compilação, então registrar uma duração é uma comparação e um incremento sem alocação.

As séries são buffers de anel limitados, dimensionados quando o coletor é feito. Nada aqui cresce sem limites, porque um motor de interface é executado por meses de cada vez e um sistema de métricas que precisa ser reiniciado é pior do que nenhum.

A cardinalidade é limitada. Um valor de rótulo tirado de dados de mensagem - um aplicativo de envio, por exemplo - pode tomar milhares de valores se alguém configurar mal uma fonte, e rótulos ilimitados são a forma padrão como o monitoramento derruba a coisa que monitora. Além do limite, os valores entram em um bucket "outro" e o próprio limite é relatado.

Source: github.com/biodream-llc/perfuse/internal/metrics

26.64 mirth

Análise Java para canais Mirth importados.

Por que isso existe

O Mirth executa o Rhino na JVM, então um script Mirth pode chamar qualquer Java no classpath, incluindo as próprias classes do servidor Mirth. O Perfuse executa o goja e não tem um tempo de execução Java. Ele recusa essas chamadas com um erro que nomeia a classe - mas essa recusa acontece quando o script é executado, o que para um conector de fonte significa quando a primeira mensagem real chega.

Então, uma migração costumava ser: a importação tem sucesso silenciosamente, o canal é implantado e a primeira mensagem vinda da rede falha. Uma migração que parece limpa e quebra na primeira carga de tráfego é pior do que uma que recusa na porta, porque a pessoa que fez isso já disse aos seus colegas que deu certo.

Isto encontra essas chamadas no momento da importação e diz o que fazer sobre cada uma delas.

Por que quatro vereditos e não dois

"Usa Java" é um pedaço de informação e o errado, porque o Java que um canal Mirth real usa cai em grupos com quantidades completamente diferentes de trabalho anexado. Aproximadamente metade do que os sites realmente escrevem é SimpleDateFormat e HashMap, que o JavaScript faz de forma nativa. Alguma parte disso é a API de script documentada do Mirth, que o Perfuse já implementa com os mesmos nomes. Um pouco disso quer iniciar e parar canais, o que o Perfuse pode fazer sobre sua API REST, mas não expõe aos scripts. E alguma parte disso é um jar de fornecedor que nunca vai executar aqui.

Relatar esses como um número único não diz nada a um migrador sobre se sua tarde ou seu trimestre está em jogo.

Source: github.com/biodream-llc/perfuse/internal/mirth

26.65 mirthlive

O pacote mirthlive encontra os motores Mirth em execução que os testes de interoperabilidade se comunicam.

O Mirth Connect parou de ser de código aberto na versão 4.6 (março de 2025). Os sites que o deixam vão para um de três lugares: Mirth 4.5.2, a última versão de código aberto, que eles continuam executando; o Open Integration Engine, o fork hospedado pelo Eclipse; ou BridgeLink, o fork da Innovar, que numera suas versões por ano (26.9.0). Um canal que o Perfuse exporta tem que ser carregado em todos eles, e um canal que qualquer um deles exporta tem que ser importado aqui, então todos os testes ao vivo são executados uma vez por motor que responde.

Os motores são encontrados por solicitação, não configurados: ./scripts/interop-up.sh os inicia em portas fixas, e um motor que não está em execução é relatado como ignorado em vez de passar silenciosamente. PERFUSE_MIRTH_ENGINES substitui a lista, como pares nome=url separados por vírgulas.

Apenas os testes importam isso. Ele vive fora de um arquivo _test.go porque dois pacotes o compartilham.

Source: github.com/biodream-llc/perfuse/internal/mirth/mirthlive

26.66 mpi

O pacote mpi é um índice de paciente mestre: ele pega registros de paciente de todos os sistemas de origem (cada um identificado por sua autoridade de designação e número), decide quais pertencem à mesma pessoa e dá a cada pessoa um identificador de empresa (EUID).

Certas correspondências se ligam por conta própria; as incertas esperam em uma fila de revisão para que uma pessoa decida; cada ligação, desligação, mesclagem e decisão é registrada com quem a fez.

A correspondência é determinística primeiro (um identificador de um sistema que o site confia ser único por pessoa, como um identificador nacional ou um número de empresa) e probabilística de outra forma: pesos Fellegi-Sunter sobre nome, data de nascimento, sexo, código postal, telefone e endereço, com Jaro-Winkler para nomes. Ele não decide nada clínico: ele diz quais registros são a mesma pessoa, com suas razões, para que uma pessoa possa confirmar quando não tem certeza.

Source: github.com/biodream-llc/perfuse/internal/mpi

26.67 mqtt

O pacote mqtt é um cliente MQTT 3.1.1: conectar (com TLS, um nome de usuário e senha, ou um certificado de cliente), publicar em QoS 0 ou 1, assinar e confirmar cada mensagem QoS 1 recebida apenas uma vez que o chamador diz que foi tratada.

Escrito contra o padrão OASIS MQTT 3.1.1 em vez de importado, como os outros protocolos de fio do Perfuse. 3.1.1 é a versão que todos os brokers falam: Mosquitto, EMQX, HiveMQ, VerneMQ, plugin MQTT do RabbitMQ, canal de telemetria do IBM MQ, AWS IoT Core e Azure Event Grid.

Entrega: uma mensagem recebida em QoS 1 é confirmada (PUBACK) apenas quando Ack é chamado. Um chamador que não pode tratar uma mensagem fecha a conexão em vez disso; com uma sessão persistente (CleanSession false) o broker envia novamente, marcada como duplicada, quando o cliente se reconecta. O MQTT 3.1.1 não tem confirmação negativa, então essa é a única maneira de pedir uma mensagem novamente.

Source: github.com/biodream-llc/perfuse/internal/mqtt

26.68 msgstore

Encontrar uma mensagem armazenada pelo que alguém sabe sobre ela.

A pesquisa que uma pessoa realmente precisa é "aqui está um número de uma chamada de telefone, mostre-me todas as mensagens sobre ele". Antes disso, significava ou uma correspondência de substring sobre payloads, que é grep e lento, ou uma expressão de filtro, que requer saber que a identidade vive em PID-3 no HL7 v2 e em algum outro lugar inteiramente nos outros três formatos no mesmo servidor.

A identidade é extraída uma vez quando a mensagem é registrada e indexada, então isso é uma pesquisa em vez de uma varredura. O custo é pago no caminho de gravação, uma vez por mensagem, em vez de em cada pesquisa.

Source: github.com/biodream-llc/perfuse/internal/msgstore

26.69 natid

O pacote natid conhece os identificadores nacionais de paciente e pessoa do Reino Unido e da Europa: seus formatos, seus dígitos de verificação, o sistema de identificador que as diretrizes FHIR de cada país nomeiam, e quanto de um pode ser mostrado.

Ele existe para o índice de paciente. Um número nacional é a evidência mais forte de que dois registros são uma pessoa, e também a mais fácil de errar: um dígito digitado duas vezes dá um número que pertence a outra pessoa, e uma fonte envia o número NHS sob um OID enquanto outra o envia sob sua URL FHIR. Então, todos os identificadores que o índice armazena passam por aqui: seu dígito de verificação é testado (um errado nunca é usado para vincular), seu espaçamento é removido e seu sistema é escrito de uma maneira.

O que é verificado e o que não é é dito por esquema. Os algoritmos são públicos; as URIs do sistema de identificador são as do próprio país onde uma diretriz FHIR nacional nomeia uma (SystemVerified), e um padrão documentado de outra forma, que um site altera para seu valor nacional em Configurações → Índice de paciente. Nada aqui decide nada clínico.

Source: github.com/biodream-llc/perfuse/internal/natid

26.70 ncpdp

Escrever um campo numa transmissão NCPDP.

Por que uma escrita recusa um caminho ambíguo

A leitura retorna todos os valores que um caminho aborda, porque um filtro que pergunta se há algum conflito de DUR deve ver todos eles. Uma escrita não pode funcionar dessa maneira. Se D7 aborda os códigos de produto de duas reclamações em uma transmissão, definir D7 não tem um único significado: escrever ambos mudaria um medicamento que ninguém pediu, e escrever o primeiro silenciosamente deixaria o segundo.

Portanto, uma escrita recusa um caminho que aborda mais de um campo, e o erro nomeia a forma qualificada que seria inequívoca. Essa é a mesma lógica que dá às etapas de transformação nenhuma ação de remoção: onde a resposta honesta é que a configuração é ambígua, dizer isso é melhor do que escolher um.

Source: github.com/biodream-llc/perfuse/internal/ncpdp

26.71 oidc

O pacote oidc verifica identidades OpenID Connect.

Escrito contra a biblioteca padrão, em vez de uma dependência JWT. A autenticação é o lugar onde uma dependência não auditada é menos aceitável, a verificação de assinatura para os algoritmos que importam é cerca de cem linhas de crypto/rsa e crypto/ecdsa, e o Perfuse já carrega o suficiente para que adicionar mais precise de um motivo em vez de um hábito.

O escopo é deliberadamente estreito: verificar que um provedor de identidade atestou uma pessoa e relatar o que ele disse sobre elas. Tudo o mais - o que elas podem fazer, quanto tempo a sessão dura - permanece com o Perfuse, porque um provedor de identidade sabe quem alguém é e não o que elas são permitidas fazer em um motor de integração.

Source: github.com/biodream-llc/perfuse/internal/oidc

26.72 parity

O pacote parity compara o que o Perfuse produz contra o que o motor que está sendo substituído produziu.

Por que isso existe

O Perfuse pode importar um canal Mirth e pode rastrear o que ele faria com uma mensagem. Nenhum desses responde à pergunta que alguém realmente tem antes de mover uma fonte de alimentação ao vivo, que é: isso produzirá a mesma saída que a coisa que tem sido executada por seis anos?

Nenhuma quantidade de qualidade de design responde a isso. A única resposta honesta é a evidência, e a evidência tem que vir da própria saída do motor antigo no tráfego do site.

Por que os pares têm que ser fornecidos

Isso não pode alcançar o Mirth, e fingir que sim seria o pior tipo de recurso. O que ele precisa são pares: uma mensagem como ela chegou, e a mensagem que o motor antigo produziu a partir dela. Ambos estão no próprio repositório de mensagens do Mirth e podem ser exportados do navegador de mensagens do Mirth, que é uma coisa que um administrador já sabe como fazer.

Essa restrição é declarada em vez de ocultada. Uma ferramenta que alegasse verificar uma migração sem nunca ver a saída do motor antigo estaria verificando nada.

Por que as diferenças são agrupadas em vez de listadas

Uma execução de cinquenta mil mensagens que relata quatro mil diferenças não disse a alguém nada que possa agir. A mesma execução relatando que PID-8 difere em cada mensagem porque o motor antigo mapeou M para Masculino disse a eles exatamente uma coisa para decidir.

Portanto, os resultados são agrupados por campo, com uma contagem, um exemplo e os pares de valores distintos vistos. Uma decisão por resultado é a unidade que alguém pode trabalhar.

Source: github.com/biodream-llc/perfuse/internal/parity

26.73 pas278

O pacote pas278 mapeia entre a autorização prévia Da Vinci e a transação X12 278.

Por que isso existe

O CMS-0057-F exige que os pagadores exponham uma API de autorização prévia FHIR até 1 de janeiro de 2027. Isso não substitui o X12 278, e nunca iria: o sistema de gestão de utilização de um pagador decide autorizações e fala 278. Portanto, um pagador que atende à regra está traduzindo FHIR para 278 e vice-versa, e um provedor que envia 278 hoje enviará FHIR amanhã para os mesmos pagadores que ainda aceitam ambos.

Essa tradução é a coisa que vale a pena possuir. Um motor que mantém ambos os modelos e não pode converter entre eles deixa a parte mais difícil do trabalho - e a parte onde os erros são caros - para quem está integrando.

As regras que este pacote segue, declaradas em vez de implícitas

Escritas para o mesmo motivo que v2fhir escreve as suas: o mapeamento é onde os projetos de interoperabilidade falham, e os fracassos são silenciosos.

Source: github.com/biodream-llc/perfuse/internal/pas278

26.74 pdf

O pacote pdf escreve documentos de texto simples, utilizando apenas a biblioteca padrão.

O Document Writer do Mirth renderiza HTML para PDF, o que necessita de um mecanismo de layout. Isso não é o que este é. Este produz um documento de texto simples, paginado, com uma fonte monoespaçada, e existe porque a exigência real em quase todos os sites que usam esse conector é "colocar este relatório em um compartilhamento para que alguém possa imprimi-lo" - um resumo de alta, um relatório de resultados, uma reconciliação diária. Esses são textos.

Recusar a funcionalidade por completo deixaria um bloqueador de migração de nível 2 no lugar. Incorporar um mecanismo de renderização de HTML custaria mais do que o restante do binário e traria um fluxo de CVE com ele, o que anularia o argumento da lista de materiais. Então: texto, honestamente descrito como texto, e um site que realmente precisa de saída de tiposet é melhor atendido por um destino de arquivo e uma ferramenta construída para isso.

Por que escrever um PDF em vez de um arquivo de texto

Porque o destinatário é geralmente uma pessoa com uma impressora e um compartilhamento do Windows, e um arquivo .txt impresso a partir de um compartilhamento perde sua paginação, suas margens e frequentemente seus finais de linha. Um PDF imprime da mesma forma em todos os lugares, o que é o único motivo pelo qual alguém pediu um.

Source: github.com/biodream-llc/perfuse/internal/pdf

26.75 pgp

O pacote pgp criptografa, assina, decriptografa e verifica mensagens OpenPGP (RFC 9580, e RFC 4880 para pares mais antigos), para pagadores, centrais de compensação e agências estaduais que trocam arquivos sobre SFTP ou e-mail sob PGP.

A criptografia é github.com/ProtonMail/go-crypto, o fork mantido de golang.org/x/crypto/openpgp; nada aqui implementa um primitivo. Este pacote apenas carrega chaves e decide o que uma mensagem deve transportar.

Source: github.com/biodream-llc/perfuse/internal/pgp

26.76 pixv3

O pacote pixv3 é a face da versão 3 do HL7 do índice de pacientes: os perfis de cruzamento de identificadores de pacientes e de consulta de dados demográficos de pacientes da IHE, pois a maioria dos hospitais fora do mundo FHIR ainda os utiliza.

As respostas vêm do mesmo índice de pacientes que PIXm, PDQm, Patient/$match e a tela do índice, por isso um registro alimentado em v3 é encontrado sobre FHIR e vice-versa. As mensagens são escritas à mão, em ordem de esquema, pela razão hl7v3.Ack fornece.

Source: github.com/biodream-llc/perfuse/internal/pixv3

26.77 priorauth

O pacote priorauth implementa o fluxo de trabalho de autorização prévia do lado do provedor, exigido pelo CMS-0057. Ele envia solicitações de autorização prévia para APIs FHIR do pagador, rastreia respostas e converte entre tipos internos e recursos FHIR.

Source: github.com/biodream-llc/perfuse/internal/priorauth

26.78 privacidade

O pacote privacidade atende às solicitações de um sujeito de dados sob o GDPR e o GDPR do Reino Unido: encontre tudo o que este servidor mantém sobre uma pessoa, dê-o a eles (Artigos 15 e 20), apague-o (Artigo 17) e mantenha o que uma retenção legal cobre.

Ele alcança todos os lugares onde o Perfuse mantém dados de paciente: o repositório de mensagens (através do seu índice de identidade), a fila de entrega, o repositório FHIR (os recursos de Paciente da pessoa e tudo o que se refere a eles, com sua história), solicitações de autorização prévia armazenadas e o índice de paciente, cujos links ampliam um identificador em todos os números da pessoa. O que ele não pode alcançar ele nomeia: traços enviados a um coletor, o registro de auditoria (mantido, como o registro de quem fez o quê), e backups, que mantêm o que foi apagado até que expirem - então, toda exclusão é escrita em um livro-razão, como hashes de sal de identificadores em vez dos identificadores, e pode ser aplicada novamente a uma cópia restaurada.

Ele não decide nada em nome de ninguém. Se uma solicitação deve ser concedida e se uma isenção se aplica é a decisão do controlador; a exclusão necessita da aprovação de um segundo administrador, e uma retenção legal se recusa a concedê-la.

Source: github.com/biodream-llc/perfuse/internal/privacy

26.79 saúde pública

O pacote saúde pública implementa relatórios de saúde pública bidirecionais: relatórios de caso eletrônicos (eCR), relatórios de laboratório eletrônicos (ELR) e consultas de registro de imunização.

Cada hospital é legalmente obrigado a relatar certas condições — tuberculose, sarampo, hepatite, COVID-19, infecções sexualmente transmissíveis, doenças transmitidas por alimentos — para agências de saúde pública estaduais e locais. A relatórios acontece por meio de três interfaces distintas:

O pacote é bidirecional: ele relata para fora (ELR, eCR, VXU) e consulta de volta (VXQ/VXR). Todas as operações são em tempo real, em vez de lote noturno.

Segurança de thread: o SubmissionLog é seguro para uso concorrente. As funções de construtor são puras e seguras para serem chamadas de qualquer goroutine.

Source: github.com/biodream-llc/perfuse/internal/publichealth

26.80 publicado

O pacote publicado contém os guardiões dos pacotes importáveis do Perfuse, em um lugar.

hl7 foi o primeiro pacote publicado e carrega sua própria cópia dessas verificações. fhir e pas foram publicados para que um serviço de decisão, como o Vaglio, leia solicitações FHIR e PAS com exatamente o código que o Perfuse usa, em vez de uma cópia que se desvia: quatro leitores dos códigos de ação X12 neste repositório discordaram uma vez, e um leu uma negação como uma aprovação. Os guardiões são mantidos aqui em vez de copiados em cada pacote, pelo mesmo motivo.

Source: github.com/biodream-llc/perfuse/internal/published

26.81 fila

O pacote fila é uma fila de entrega perene, por destino.

Sem ele, um destino que está inativo por dois minutos perde tudo o que é enviado durante esses dois minutos: as tentativas de reenvio ocorrem na memória, e quando elas são esgotadas, a mensagem é registrada como falha e eliminada. Com ele, a mensagem é gravada em disco e mantém sua posição até que o destino volte a estar disponível.

Duas decisões de design influenciam tudo o mais.

A ordem é preservada por destino, e isso significa que um destino em fila deixa de utilizar o caminho rápido. O HL7 é um fluxo de eventos sobre os mesmos pacientes: um A01 admite, um A03 dá alta. Se um A01 com falha vai para a fila enquanto o próximo A03 é entregue diretamente, o sistema receptor vê uma alta para um paciente que nunca foi admitido. Portanto, assim que algo é colocado em fila para um destino, tudo para esse destino é colocado em fila atrás dele até que a fila seja esvaziada. Isso custa produtividade durante uma interrupção e não é opcional, porque a alternativa é nonsense clínico silencioso. É também a coisa específica que dá errado em outros motores quando alguém ativa threads de fila concorrentes para fazer um backlog drenar mais rápido.

Uma mensagem em fila é uma mensagem aceita. O remetente é informado AA, porque os bytes estão em disco e fsynced antes que o ack seja enviado. Dizer AE faria com que uma fila de armazenamento e reenvio funcionasse corretamente parecesse uma falha e convidasse o remetente a reenviar o que já possuímos.

Source: github.com/biodream-llc/perfuse/internal/queue

26.82 residência

A residência do pacote diz onde os dados deste servidor podem ir: as regiões de nuvem que um site permite (a EEA, o Reino Unido, a Suíça, ou regiões nomeadas uma a uma), e se a região de um conector é uma delas.

O Perfuse verifica o que pode saber. Um conector AWS nomeia sua região (S3, SQS, SNS), e um hostname AWS carrega uma (sqs.eu-west-2.amazonaws.com); esses são verificados quando um canal é salvo e carregado, para que um canal não possa enviar dados de paciente para um bucket na Virgínia a partir de um servidor cujos dados devem permanecer em Frankfurt. Um hostname simples (o sistema de um hospital, o listener MLLP de um parceiro) não diz nada sobre onde está, e não é julgado aqui: o registro de processamento lista todos os hosts para os quais um canal envia, para que o controlador possa verificar.

Source: github.com/biodream-llc/perfuse/internal/residency

26.83 rtpb

O pacote rtpb responde a solicitações de benefício de prescrição em tempo real da NCPDP: o que um medicamento custará a este membro neste farmacêutico, se precisa de autorização prévia ou de um passo primeiro, e quais alternativas custam menos.

A proposta CMS-0062-P propõe RTPB para pagadores afetados a partir de 1 de outubro de 2027. O XML é NCPDP RTPB v13 (PBv13). O esquema da NCPDP é licenciado, então os nomes dos elementos e a ordem seguem os exemplos públicos de RTPB da Surescripts e as Recomendações de Implementação Pública de RTPB da NCPDP (códigos de restrição de cobertura e o status de cobertura que cada um mapeia); uma resposta não é verificada contra o XSD aqui, e uma certificação de rede é onde isso acontece.

Source: github.com/biodream-llc/perfuse/internal/rtpb

26.84 s3put

O pacote s3put grava objetos no S3 usando apenas a biblioteca padrão.

A forma óbvia de se comunicar com o S3 é o SDK da AWS, e o SDK é enorme. Este projeto vende um binário estático com oito dependências diretas e uma lista de materiais que cabe em uma tela - isso é um argumento real com a pessoa que revisa software antes que um hospital o instale, e trocá-lo por um conector seria um mau negócio.

O que o S3 realmente precisa é de um HTTP PUT e de uma assinatura. A Versão 4 da Assinatura é totalmente especificada, é determinística e a AWS publica vetores de teste para ela. Então, ela é implementada aqui: cerca de duzentas linhas contra crypto/hmac e net/http, sem nenhuma nova dependência e nada a patchar quando o SDK tem um aviso.

O que este projeto deliberadamente não faz

Nenhuma upload multipart, nenhuma tentativa de reenvio própria, nenhuma cadeia de credenciais além de chaves estáticas e variáveis de ambiente padrão. Uma mensagem HL7 é de kilobytes, então o upload multipart resolve um problema que este não tem; o motor já tenta reenviar; e uma cadeia de credenciais de instância-papelaria significaria chamadas IMDS, lógica de cache e refresh, o que é onde uma implementação pequena deixa de ser pequena. Se alguém precisar disso, a resposta honesta é um destino de arquivo e uma ferramenta de sincronização, e não um SDK meio-construído.

Ele funciona com qualquer coisa que fale a API do S3 - MinIO, Ceph, Wasabi, Backblaze - porque é apenas HTTP assinado. Isso é um efeito colateral digno de ter, desde que um armazenamento de objetos de hospital é frequentemente não-AWS.

Source: github.com/biodream-llc/perfuse/internal/s3put

26.85 saml

Canonicalização XML Exclusiva (exc-c14n) de acordo com https://www.w3.org/TR/xml-exc-c14n/

Esta é a forma canônica exata de bytes que uma assinatura XML assina. Errar isso significa que assinaturas válidas parecem inválidas e - pior - uma implementação que obtém a maior parte certa passará nos testes contra suas próprias assinaturas enquanto rejeita respostas reais de IdP.

As regras que importam para SAML: - Declarações de namespace são renderizadas apenas se visivelmente utilizadas pelo elemento ou seus atributos. - Namespaces herdados que um elemento usa, mas não declara, são renderizados como se declarados nesse elemento. - Atributos são classificados: declarações de namespace primeiro (classificados por prefixo), então outros atributos (classificados por nome expandido: URI de namespace, então nome local). - Elementos vazios usam start-tag/end-tag, nunca self-closing. - Nós de texto são saídos verbatim; CDATA é substituído por seu conteúdo com escape de entidade. - Instruções de processamento e comentários fora do elemento do documento são excluídos.

Source: github.com/biodream-llc/perfuse/internal/saml

26.86 scim

O pacote scim implementa SCIM 2.0, o protocolo que os provedores de identidade usam para provisionar contas.

A Okta, Entra ID, Google Workspace e OneLogin todos falam a mesma linguagem. Um administrador adiciona alguém a um grupo no provedor de identidade e, dentro de um minuto, uma conta aparece aqui com o papel correto. Eles o removem e a conta some.

A desprovisionamento é o ponto

A provisionamento é uma conveniência. A desprovisionamento é o motivo pelo qual isso vale a pena ser construído, e é a metade que dá errado.

Quando alguém deixa uma organização, o provedor de identidade é o sistema que sabe primeiro - geralmente porque o RH termina o contrato e o provedor é impulsionado pelo registro do RH. Em seguida, informa a todos os aplicativos conectados para desabilitar a conta. Se a chamada falhar ou tiver sucesso sem realmente remover o acesso, um ex-funcionário mantém o acesso a um motor de integração clínica e ninguém descobre, porque nada está observando algo que não aconteceu.

Portanto, as partes deste pacote que mais importam são as que tornam a desprovisionamento real:

Por que é um pacote separado

As formas do SCIM não são do Perfuse. Ele tem seu próprio formato de erro, seu próprio envelope de lista, sua própria linguagem de patch e suas próprias opiniões sobre o caso de atributo. Manter a tradução em um lugar significa que os manipuladores podem ser sobre o que acontece com uma conta, em vez de sobre JSON.

Source: github.com/biodream-llc/perfuse/internal/scim

26.87 script

O script do pacote executa JavaScript do Mirth Connect.

O objetivo é que os scripts de um canal sejam movidos sem alterações. Isso é um exercício de compatibilidade, não um exercício de design, então a forma de tudo aqui é ditada pelo que o Mirth expõe: msg e tmp como árvores E4X, seis mapas com métodos do Map do Java, a família de funções de lookup $, logger e um punhado de objetos de utilidade cujos nomes de método e strings de formato de data são do Java.

Três decisões são nossas, em vez de do Mirth, e cada uma é uma partida deliberada:

Um script é executado com um prazo e é interrompido quando ele passa. O Mirth permitirá que um script loop infinitamente, o que leva o canal com ele; uma interface que para de aceitar admissões devido a um erro de digitação em um transformador não é aceitável, então sempre há um tempo limite.

A interoperabilidade do Java é recusada com um erro que nomeia a classe, em vez de retornar undefined. Um script que alcança Packages.java.sql não pode ser feito para funcionar aqui, e o resultado útil é uma mensagem que diz exatamente isso na linha onde acontece, não um NullPointerException três linhas depois.

O acesso a arquivos e bancos de dados está desativado, a menos que um canal o ative. O Mirth concede ambos a cada script por padrão. Um transformador que pode ler qualquer arquivo que o processo possa ler é uma coisa razoável para querer e um padrão irrazoável.

Source: github.com/biodream-llc/perfuse/internal/script

26.88 configurações

O pacote de configurações é a descrição única de tudo sobre um servidor Perfuse que um operador pode alterar.

Por que isso existe

Antes deste pacote, cerca de trinta coisas eram flags de linha de comando e nada mais. Alterar o tempo que as mensagens são mantidas significava editar uma definição de serviço e reiniciar, o que em um hospital significa um ticket de alteração - então, na prática, ninguém as alterava, e um padrão escolhido na primeira tarde se tornou a configuração para sempre.

Por que um registro em vez de um formulário

A forma óbvia de construir uma página de configurações é escrever o formulário. Isso produz duas descrições de cada configuração - uma no servidor que a valida e uma na interface que a renderiza - e elas se afastam. O afastamento é silencioso: um campo que o servidor parou de aceitar ainda tem um controle, então alguém o define, vê que foi salvo e não faz nada.

Então, uma configuração é declarada uma vez, aqui, com tudo o que é necessário para verificar e desenhar: que tipo de valor é, que controle é adequado, a qual grupo pertence, o que significa e se alterá-la tem efeito agora. A interface pede essa descrição e renderiza o que é dito. Adicionar uma configuração é uma entrada neste pacote e nenhum trabalho de interface.

TestEverySettingIsFullyDescribed impõe as partes que um humano tem que fornecer, porque uma configuração sem texto de ajuda é uma configuração que alguém adivinha.

Por que um arquivo em vez do banco de dados

As configurações vivem em um arquivo YAML que a interface edita no local, correspondendo à forma como os canais e as regras de alerta já funcionam. Três razões, em ordem de peso: o controle de alterações de um hospital quer configuração que possa ser difundida e colocada em controle de versão; um operador com a máquina, mas não o aplicativo, pode ler um arquivo e não pode ler um banco de dados; e restaurar as configurações de ontem não deve exigir que o aplicativo esteja funcionando.

Por que flags apenas semeiam

O ficheiro vence sempre que existe, e as flags fornecem o conteúdo inicial. A alternativa - flags sempre vencendo - tornaria a interface um mentiroso, desde que qualquer coisa passada na linha de comando poderia ser editada, guardada e silenciosamente ignorada.

Uma flag que discorda do ficheiro é relatada no arranque, nomeando ambos os valores, porque caso contrário a flag permanece na definição de serviço durante anos e a próxima pessoa a lê-la acredita nela.

Source: github.com/biodream-llc/perfuse/internal/settings

26.89 sftpconn

O pacote sftpconn abre ligações SFTP.

Dividido a partir dos conectores porque a parte interessante é a autenticação e a verificação da chave do host, e ambas são idênticas, independentemente de um canal estar a recolher ficheiros ou a escrevê-los. Duas cópias se desviariam, e a metade que se desviou seria a metade que parou de verificar.

Source: github.com/biodream-llc/perfuse/internal/sftpconn

26.90 sombra

O pacote shadow compara um canal candidato com o canal ao vivo.

A comparação em si é a parte fácil. O valor total está em duas garantias, e ambas são impostas por construção, em vez de por configuração:

Qualquer coisa menos do que isso e o modo sombra se torna uma forma de quebrar a produção enquanto tenta evitar quebrar a produção.

Source: github.com/biodream-llc/perfuse/internal/shadow

26.91 shl

O pacote shl implementa Links e Cartões de Saúde SMART: os códigos QR que o CMS pede aos prestadores de serviços para aceitar no check-in e para devolver com o registo da visita.

Um Link de Saúde SMART (Links de Saúde SMART STU 1) é shlink:/ seguido de JSON base64url: uma URL de manifesto, uma chave de 256 bits e, opcionalmente, um prazo de validade, um rótulo e flags (P passcode, L longo prazo, U um único ficheiro por GET). O receptor publica no URL do manifesto e recebe ficheiros, cada um um JWE encriptado com essa chave - alg dir, enc A256GCM, opcionalmente comprimido por DEFLATE - que contém JSON FHIR, Cartões de Saúde SMART ou um token de acesso SMART. O servidor que hospeda os ficheiros nunca vê a chave: ela viaja apenas no link, que é do paciente.

Um Cartão de Saúde SMART (Quadro de Cartões de Saúde SMART 1.4) é um pacote FHIR assinado: um JWS compacto, ES256, com uma carga útil comprimida por DEFLATE que nomeia o seu emissor, cuja chave pública está em <iss>/.well-known/jwks.json. Ele viaja como um código QR numérico shc:/ ou um ficheiro .smart-health-card.

Apenas a biblioteca padrão: crypto/aes, crypto/cipher, crypto/ecdsa e compress/flate cobrem tudo, e uma biblioteca JOSE traria uma superfície muito maior para dois algoritmos.

Source: github.com/biodream-llc/perfuse/internal/shl

26.92 smartauth

O pacote smartauth é um servidor de autorização de Lançamento de Aplicativos SMART: ele emite os tokens de acesso que o ponto final FHIR do Perfuse aceita.

Escrito contra a biblioteca padrão, como internal/oidc, que verifica o que este assina. Os tokens são JWTs assinados RS256, o único algoritmo que todos os clientes SMART e as regras de token de ID da especificação podem confiar.

Source: github.com/biodream-llc/perfuse/internal/smartauth

26.93 snmp

O pacote snmp é um agente SNMPv2c de leitura apenas: GET, GETNEXT e GETBULK sobre UDP contra uma tabela de valores que o chamador preenche, e armadilhas SNMPv2.

As mensagens são codificadas BER (X.690) aqui; nada nelas é criptografia (a cadeia de comunidade v2c é uma senha em texto simples, que é por que o agente só responde às redes que lhe são ditas).

Source: github.com/biodream-llc/perfuse/internal/snmp

26.94 soap

O pacote soap envia pedidos SOAP e lê falhas SOAP, usando apenas a biblioteca padrão.

O SOAP é uma grande cerimônia em torno de um POST HTTP, e ainda é como uma grande parte da intermediação hospitalar aceita dados - sistemas de administração de pacientes, repositórios de documentos, serviços de registo regional, qualquer coisa especificada na década em que isso era a resposta. O Mirth tem um conector de Serviço Web, por isso isso é um bloqueador de migração de nível 2 em vez de um recurso agradável.

Por que não um cliente gerado

A abordagem usual é pegar um WSDL e gerar tipos Go a partir dele. Essa é a resposta certa para um aplicativo que fala com um serviço conhecido, e a resposta errada aqui: o destino de um motor de integração é configurado por alguém que edita um canal, não recompilado, por isso o envelope tem que ser montado em tempo de execução a partir de um modelo que eles possam ver e alterar. Isso também significa que não há etapa de geração de código e nada para regenerar quando o extremo distante publica um novo WSDL.

O que este projeto deliberadamente não faz

Não há análise de WSDL, WS-Segurança, MTOM, nem WS-Addressing. Cada um deles é uma especificação por si só, e fingir que suporta um deles enquanto erra um detalhe é pior do que não oferecê-lo - uma assinatura que quase verifica é indistinguível de um ataque no extremo oposto. A WS-Segurança, em particular, é onde uma implementação parcial pode causar danos reais.

O que está aqui: envelopes SOAP 1.1 e 1.2, um corpo modelado, o cabeçalho SOAPAction e detecção de falhas que lê a string de falha em vez de relatar "500".

Source: github.com/biodream-llc/perfuse/internal/soap

26.95 sof

O pacote sof executa SQL em FHIR v2 ViewDefinitions: uma visão transforma cada recurso FHIR de um tipo em linhas de colunas nomeadas, por FHIRPath, para que os dados FHIR possam ser lidos como tabelas por motores SQL, planilhas e medidas de qualidade.

Ele segue o algoritmo de processamento da ViewDefinition (coluna, seleção, forEach, forEachOrNull, repetição, união de todos, onde, constantes, %rowIndex, getResourceKey e getReferenceKey) e é verificado contra os testes oficiais sql-on-fhir.

Source: github.com/biodream-llc/perfuse/internal/sof

26.96 sqldb

O pacote sqldb abre conexões de banco de dados para a fonte e destino de banco de dados.

Os drivers são registrados aqui e em nenhum outro lugar, então há exatamente um lugar que decide a que o Perfuse pode se conectar.

Source: github.com/biodream-llc/perfuse/internal/sqldb

26.97 sqlitedb

O pacote sqlitedb abre o SQLite da maneira como um servidor precisa: uma conexão para gravações e várias para leituras.

O motivo é um modo de falha que só aparece uma vez que uma implantação está em execução há um tempo. O SQLite no modo WAL permite que os leitores executem ao lado de um escritor, mas o pool de conexões do Go fica acima do SQLite, então um pool de um serializa tudo, independentemente do que o banco de dados permitiria. Uma pesquisa do navegador de mensagens que digitaliza a coluna de payload, então, segura a única conexão, e cada mensagem que chega aguarda atrás dela.

Medido nesta máquina, uma gravação leva 104µs com o repositório ocioso e 2,6ms enquanto uma pesquisa digitaliza quatro mil mensagens: vinte e cinco vezes mais lento. Isso escala com a tabela, então, em algumas centenas de milhares de mensagens armazenadas, um relatório se transforma em segundos de latência de entrega, e uma gravação está no caminho de confirmação. O remetente vê um tempo limite, reenvia e alguém passa uma manhã procurando por um problema na rede.

Dividir os pools não custa nada e remove a interação: os relatórios obtêm suas próprias conexões, e o escritor mantém uma para si, porque o SQLite permite exatamente um escritor de qualquer forma.

Source: github.com/biodream-llc/perfuse/internal/sqlitedb

26.98 etapas

Etapas de transformação declarativas, para qualquer formato de mensagem.

Por que isso é compartilhado

O vocabulário da etapa - definir, copiar, limpar, mapear, substituir, cortar, caso, cada um com uma descrição e uma condição opcional - não tem nada a ver com um formato específico. Três coisas diferem entre formatos: como um caminho é escrito, como um valor é lido e como é gravado novamente.

Esta é a mesma conclusão que a gramática de filtro alcançou em internal/expr, e pelo mesmo motivo. O X12 tinha um mecanismo de etapas e o NCPDP precisava de um; copiá-lo teria produzido um segundo mecanismo de quatrocentas linhas para manter em sincronia à mão, e então um terceiro para delimitado. O comportamento digno de ter é sutil o suficiente para que uma cópia não o mantenha - o motivo pelo qual o resultado é lido novamente após cada gravação, por exemplo, levou um defeito real para descobrir.

O que um formato fornece

Um Acessador: um compilador de caminho, um compilador de condição e um veto opcional em etapas que ele não pode honrar. Nada mais.

Source: github.com/biodream-llc/perfuse/internal/steps

26.99 stomp

O pacote stomp fala STOMP 1.2 para um corretor de mensagens.

Este é o que "suporte ao JMS" tem que significar em um programa que não é Java. O JMS é uma API em vez de um protocolo, então não há nada a implementar: o que um site realmente precisa é que o Perfuse fale com o corretor que está por trás de suas aplicações JMS.

STOMP em vez de OpenWire, e o raciocínio vale a pena registrar porque a resposta óbvia está errada. O OpenWire é o protocolo nativo do ActiveMQ e uma serialização binária de comandos JMS - semanas de trabalho, específico para uma família de corretor, e não documentado, exceto por sua implementação. O ActiveMQ detecta automaticamente STOMP, AMQP e MQTT na mesma porta que serve o OpenWire, então um protocolo de texto alcança os mesmos corretores. O STOMP cobre ActiveMQ Classic, Artemis e RabbitMQ; o AMQP 1.0 adicionaria Azure Service Bus e IBM MQ, e é o próximo sensato em vez do OpenWire.

Escrito contra a biblioteca padrão. Um cliente de corretor não é o lugar para uma dependência cujos modos de falha são de alguém mais para explicar, e o enquadramento aqui é pequeno o suficiente para que possuí-lo custe menos do que ler o rastreador de problemas deles.

Source: github.com/biodream-llc/perfuse/internal/stomp

26.100 loja

A loja de pacotes contém os dados que são genuinamente estado-ativos: utilizadores, sessões e um registo de auditoria.

Os canais são deliberadamente não incluídos aqui. Eles vivem em ficheiros, porque é isso que dá git, diffs, revisão de código e promoção de ambiente de forma gratuita. Colocar canais em uma base de dados é a decisão que obriga a comprar todos esses separadamente, e é o motivo pelo qual um produto de terceiros existe puramente para transportar canais Mirth entre a sua base de dados e um repositório git.

Portanto, a divisão é: configuração em ficheiros, identidade e história em SQLite.

Source: github.com/biodream-llc/perfuse/internal/store

26.101 tefca

O pacote tefca implementa as partes da participação TEFCA que não requerem uma ligação QHIN.

O que é real

Validação de propósito de uso, validação de configuração e o registo de auditoria - incluindo a sua persistência, a sua interface de consulta e a sua obrigação de registar tentativas falhadas, bem como as bem-sucedidas. Essa última parte não é uma questão técnica: uma série de entregas falhadas a um destinatário é como um parceiro mal configurado se manifesta, e uma série de consultas falhadas para diferentes pacientes é como a sondagem se manifesta.

O que não é

A rede. Não há transporte QHIN nesta compilação, por isso não há troca, e cada função de troca recusa com ErrExchangeNotImplemented em vez de retornar sucesso.

Essa distinção não era sempre traçada, e a forma como deu errado é digna de ser mantida. As quatro funções de troca costumavam validar as suas entradas, não fazer chamadas de rede e retornar sucesso; Deliver retornava uma resposta Aceite com um identificador de rastreio construído a partir do relógio. A camada de auditoria registava cada uma como uma troca concluída - no registo que existe para provar o que foi trocado quando alguém pergunta meses depois. Quatro testes afirmavam que comportamento e passavam.

O que é necessário para concluir

Integração com uma Rede de Informações de Saúde Qualificada, autenticação TLS mutua usando certificados emitidos através desse processo, e ou os perfis IHE que o Acordo Comum começou com ou FHIR Facilitado, conforme definido pelo procedimento operacional padrão do Projeto Sequoia, efetivo a 8 de março de 2026. Nada disso pode ser escrito de forma especulativa: é testado contra uma QHIN real ou não é testado, e uma implementação de troca não testada é o mesmo defeito que nenhuma implementação com um disfarce melhor.

Source: github.com/biodream-llc/perfuse/internal/tefca

26.102 inquilino

O pacote inquilino fornece as regras de identidade e isolamento para operação multi-inquilino.

Um HIE, uma câmara de compensação ou um provedor de serviços gerenciados executa um motor em nome de muitas organizações. Mirth não pode fazer isso - uma instância serve uma organização, e um MSP acaba executando cinquenta JVMs e cinquenta bases de dados.

O que um inquilino possui

Os seus canais, como um diretório de ficheiros. Os seus utilizadores. As suas mensagens, fila, registo de auditoria e recursos FHIR. As suas etiquetas de métricas. Nada é compartilhado, exceto o processo, as portas de escuta que foram alocadas e os administradores da plataforma.

Isolamento é estrutural, não lembrado

A falha perigosa aqui não é uma queda. É o inquilino A ver as mensagens do inquilino B, o que é uma violação relatável em vez de um bug. Um design onde cada consulta leva um parâmetro de inquilino_id falha na primeira vez que alguém escreve uma consulta e esquece um, e essa consulta parece perfeitamente correta em revisão.

Portanto, o inquilino não é um parâmetro. O acesso aos dados passa por um identificador que já o carrega, e não há como alcançar as tabelas sem um. Esquecer não é uma opção.

Source: github.com/biodream-llc/perfuse/internal/tenant

26.103 terminologia

O pacote terminologia mantém sistemas de código publicados (LOINC, SNOMED CT, RxNorm, ICD-10-CM, CPT e locais) para procurar códigos, e as tabelas de mapeamento de valores que não tinham, para alguém mapear.

Os sistemas de código são importados a partir dos ficheiros que os seus editores distribuem. Vários são licenciados (LOINC precisa de uma conta gratuita, SNOMED CT uma licença de afiliado, RxNorm uma licença UMLS, CPT uma licença AMA), por isso nenhum vem com Perfuse: um administrador que detém a licença carrega o ficheiro, e Perfuse regista quem o importou e quando.

Source: github.com/biodream-llc/perfuse/internal/terminology

26.104 tlsconf

O pacote tlsconf constrói a configuração TLS a partir de ficheiros e descreve certificados.

Esta é a equivalente gratuita de uma extensão do Mirth que agora é paga. A maior parte do valor não está na encriptação, que são apenas algumas linhas, mas na parte que impede que alguém implemente algo que pensa ser seguro e não é: recusar-se a saltar a verificação silenciosamente, insistir que um certificado de cliente seja realmente verificado quando um é solicitado, e dizer claramente quando um certificado está prestes a expirar.

Um certificado expirado em uma interface de alimentação é uma interrupção real de hospital, e isso acontece porque ninguém foi informado. A parte descritiva deste pacote existe por esse motivo.

Source: github.com/biodream-llc/perfuse/internal/tlsconf

26.105 tomirth

O pacote tomirth escreve um canal Perfuse novamente como XML de canal Mirth.

Por que isso existe. A objeção à adoção de um novo motor de integração raramente é "é bom". É "e se estivermos errados e ficarmos presos", e a resposta mais barata a isso é ser capaz de voltar atrás. O Perfuse lê os canais do Mirth desde o início; até agora, não podia escrever um, o que tornou a garantia unidirecional e, portanto, não muito garantida.

Como ele evita a armadilha que tornou a primeira tentativa inútil. O XML do Mirth é a saída do XStream, e o XStream lê os atributos de classe e versão como instruções: um elemento que não reconhece é descartado sem uma palavra, e um canal que não pode ser montado é armazenado com sua descrição substituída por "Este canal é inválido. Verifique se todas as extensões necessárias estão carregadas corretamente" e seus destinos descartados. Nada na resposta nomeia o elemento em questão. Um exportador que compõe blocos de propriedades a partir de uma leitura do formato, portanto, falha de uma maneira que é cara para diagnosticar, o que aconteceu: este repositório carregava um exportador com nove testes aprovados cuja saída o Mirth descartou, porque cada teste a comparou com nosso próprio analisador em vez de um servidor.

Então, nenhum dos blocos de propriedades é composto aqui. O scripts/mirth-dump-connector-templates.sh tem o ObjectXMLSerializer do Mirth serializar os padrões de cada classe de propriedades de conector, e esses documentos são comprometidos em templates/. Este pacote substitui valores neles, e o mirth.SetRawProperty recusa qualquer caminho que o modelo não contenha já - então um erro é um erro de nomeação do caminho, no momento da exportação, em vez de um canal que some na importação.

O que ele não fará. Um transporte sem equivalente no Mirth é recusado pelo nome em vez de aproximado. Uma exportação que silenciosamente transformasse um destino S3 em um escritor de arquivo seria pior do que nenhuma exportação, porque o canal importaria limpo e entregaria no local errado.

Source: github.com/biodream-llc/perfuse/internal/tomirth

26.106 trace

O pacote trace produz traços distribuídos para mensagens que se movem por um canal e os exporta sobre OTLP/HTTP com o encoding JSON.

Por que isso existe em vez do SDK OpenTelemetry: o SDK mais um exportador OTLP puxa cerca de sessenta módulos e adiciona tanto ao binário quanto todo o resto deste programa. O que é realmente necessário aqui é estreito - propagação de contexto de traço W3C, um modelo de span, amostragem de cabeça e um POST HTTP em lote - e o OTLP/JSON é um encoding estável documentado que pode ser produzido com a biblioteca padrão sozinha. Mesmo comércio que escolher lib/pq sobre pgx: pegue a coisa pequena quando apenas parte da coisa grande é desejada.

A consequência digna de menção: não há auto-instrumentação e nenhum exportador específico de fornecedor. Os spans são os que este programa cria deliberadamente, e eles vão para qualquer ponto de extremidade OTLP - um coletor, Jaeger, Grafana Tempo, Honeycomb, ingestão OTLP do Datadog.

A propriedade que importa mais do que os spans

Uma mensagem chega frequentemente carregando um cabeçalho traceparent do sistema que a enviou, e deixa em direção a um sistema que registrará um de seus próprios. Continuar esse traço em vez de começar um novo é o que torna possível uma visão única de "o EHR enviou isso, o motor transformou, o registro rejeitou". Os problemas de interface quase sempre são relatados como "enviamos e nada aconteceu", e essa pergunta é inrespondível sem um identificador que sobreviva ao pulo.

O rastreamento nunca deve afetar a entrega

Toda operação aqui é de melhor esforço. Os spans são descartados quando o buffer está cheio, as falhas de exportação são contadas e nunca repetidas no caminho da mensagem, e nenhuma chamada bloqueia na rede. Um span descartado é um incômodo. Uma mensagem atrasada ou perdida porque o backend de rastreamento estava lento é um incidente clínico, então o comércio nunca está em questão.

Source: github.com/biodream-llc/perfuse/internal/trace

26.107 transform

O pacote transform aplica alterações declarativas a uma mensagem.

Esta é a camada destinada a carregar o trabalho comum, com a scriptação mantida como uma escotilha de escape marcada. A distinção não é estilística. Um passo declarado em YAML pode ser validado antes de executar, mostrado em uma dif, revisado por alguém que não lê JavaScript, e relatado; um script só pode ser executado e esperado. A maior parte do que os transformadores do Mirth realmente fazem é entediante - copiar um campo, preencher um identificador, mapear um código por meio de uma tabela, limpar algo que não deve sair do prédio - e tudo isso pertence aqui.

Cada passo nomeia seu alvo explicitamente e cada passo é reversível no sentido de que diz o que fez, porque a falha mais cara em uma interface é uma transformação que ninguém sabia que estava acontecendo.

Source: github.com/biodream-llc/perfuse/internal/transform

26.108 translate

O pacote translate converte um canal Mirth em uma definição de canal Perfuse.

perfuse explain relata o que bloqueia uma migração. Isso faz a maior parte da migração, que é uma afirmação diferente e muito maior, por isso é deliberadamente conservador sobre o que ele irá afirmar.

Três regras moldam todo o processo.

Nada é silenciosamente descartado. Cada parte do canal de origem é traduzida, transportada literalmente como um script ou relatada como necessitando de intervenção humana. Um tradutor que omitisse silenciosamente uma etapa produziria um canal que começa, executa e perde dados — o pior resultado possível e o motivo pelo qual as pessoas desconfiam das ferramentas de migração.

Declarativo quando é certo, script quando não é. Uma etapa do Mapper que copia um campo se torna uma etapa declarativa, porque isso é legível e verificável. Uma etapa JavaScript se torna um script, porque o Perfuse executa o JavaScript do Mirth inalterado e reescrevê-lo em algo que pareça equivalente é exatamente onde um tradutor introduziria uma diferença que ninguém notaria.

A saída é destinada a ser lida. Ela contém comentários explicando de onde veio cada coisa e o que foi deixado para uma pessoa. Uma migração é revisada por alguém que tem que aprovar, e uma parede não anotada de YAML não pode ser revisada.

Source: github.com/biodream-llc/perfuse/internal/translate

26.109 udap

O pacote udap implementa a metade do cliente da Segurança HL7 para Registro, Autenticação e Autorização em Escala — a especificação em que o intercâmbio FHIR facilitado pelo TEFCA se baseia.

O UDAP é uma infraestrutura de chave pública acoplada ao OAuth 2.0. Uma comunidade de confiança emite certificados X.509 para seus membros; um membro prova quem é assinando JWTs com a chave privada e anexando a cadeia de certificados no cabeçalho do JWT. Isso substitui o segredo de cliente compartilhado do OAuth comum, que não escala para milhares de organizações que nunca se encontraram.

Por que este pacote existe. O intercâmbio TEFCA não pode ser totalmente verificado sem um QHIN real: ingressar em um requer onboard e certificados emitidos, e não pode ser falsificado. Mas o perfil de segurança subjacente é um guia de implementação publicado pela HL7 com servidores de referência públicos, e um deles responde na internet aberta. Então, a parte que pode ser verificada é verificada aqui, e a parte que não pode é recusada na fronteira em vez de ser adivinhada.

A distinção é importante devido ao que aconteceu com o SAML neste repositório: mil linhas de testes passaram, cinco delas especificamente sobre a canonicalização de assinatura, enquanto nenhum provedor de identidade real poderia autenticar alguém. Ambas as metades haviam sido escritas aqui e concordavam entre si. A lição tirada disso é que uma implementação de segurança não vale nada até que algo que alguém mais escreveu tenha aceito ou rejeitado.

Referências de especificação: - HL7 UDAP Security STU 1: http://hl7.org/fhir/us/udap-security/STU1/ - TEFCA SOP Facilitated FHIR Implementation v2.0, efetivo em 8 de março de 2026

Source: github.com/biodream-llc/perfuse/internal/udap

O pacote umlink transporta X12 278s para o sistema de gestão de utilização de um pagador e suas respostas de volta, as maneiras pelas quais esses sistemas são alcançados na prática: X12 no corpo de um POST HTTPS; envelope SOAP da CAQH CORE (Regra de Conectividade vC2.2.0, a que a maioria dos pagadores e CMS executam, e vC4.0.0); envelope MIME multipart da CAQH CORE (vC2.2.0); e arquivos em lote sobre SFTP.

Escrito a partir das Regras de Conectividade publicadas pela CAQH (vC2.2.0 e vC4.0.0), seu esquema XML e WSDL, e o Guia de Companion X12N 278 da esMD da CMS. Ele não é certificado pela CORE: a certificação é feita pelos fornecedores de teste autorizados pela CAQH.

Os links em tempo real retornam a resposta que o sistema UM forneceu, que pode ser uma resposta 278 ou, quando não conseguiu ler a solicitação, um 999 ou TA1: o chamador lê qual. O link em lote retorna ErrAnswerLater assim que o arquivo é entregue, e Poll coleta o que é retornado.

Source: github.com/biodream-llc/perfuse/internal/umlink

26.111 v2fhir

O pacote v2fhir mapeia mensagens HL7 v2 para recursos FHIR.

O mapeamento é onde os projetos de interoperabilidade realmente falham, por isso as regras que este pacote segue são declaradas em vez de implícitas:

Source: github.com/biodream-llc/perfuse/internal/v2fhir

26.112 vcs

O pacote vcs lê o histórico de arquivos de canal do git.

O histórico do canal é uma extensão paga em outro lugar, e é uma extensão paga porque esses motores mantêm canais em um banco de dados, então rastrear alterações significa construir um sistema de rastreamento de alterações. O Perfuse mantém canais em arquivos, então o histórico já existe e existe desde o primeiro commit. Este pacote apenas tem que lê-lo.

Ele chama o git em vez de incorporar uma biblioteca git. A biblioteca adicionaria uma grande dependência a um binário cujo ponto de venda é ter quatro, e não compraria nada: uma implantação que mantém seus canais sob controle de versão tem o git instalado, e uma que não obtém um claro "não é um repositório git" em vez de uma implementação ligeiramente diferente da mesma coisa.

Source: github.com/biodream-llc/perfuse/internal/vcs

26.113 vfs

O pacote vfs é o pequeno conjunto de operações de arquivo que um conector de sondagem precisa.

Por que uma interface em vez de quatro conectores

O Perfuse coleta arquivos de um disco local, um servidor SFTP, um servidor FTP, uma partilha do Windows e um servidor WebDAV. A transferência difere em cada caso. Tudo o que realmente decide se as mensagens sobrevivem não difere:

Escrito uma vez por transporte, essas regras seriam ligeiramente diferentes cinco vezes, e as diferenças só apareceriam como mensagens que desapareceram em um site. Portanto, elas são escritas uma vez, aqui, sobre a menor interface que as suporta.

O que é deliberadamente não está aqui

Nenhuma escrita, além do que a eliminação necessita. Enviar ficheiros é um problema diferente com modos de falha diferentes - um ficheiro parcialmente escrito no extremo distante, que os remetentes existentes lidam escrevendo para um nome temporário e renomeando. Dobrar ambas as direções em uma interface tornaria cada uma mais difícil de raciocinar.

Nenhuma recursividade. Um sondador que desce em subdiretórios recolhe o diretório de arquivo que acabou de mover um ficheiro.

Source: github.com/biodream-llc/perfuse/internal/vfs

26.114 vpn

O pacote vpn relata o estado dos túneis de VPN de site para site pelo qual o tráfego do parceiro é executado - AWS Site-to-Site VPN, conexões do Azure VPN Gateway e strongSwan - e mantém a folha de conexão de cada parceiro: configurações de túnel de ambos os lados, e se concordam.

Um túnel que está desligado parece, de um motor de integração, exatamente como um parceiro cujo motor está parado: as conexões expiram. Dizer "o túnel está desligado" em vez disso é a diferença entre chamar a equipe de rede e chamar o parceiro.

Somente leitura. Nada aqui muda um túnel, e nenhuma chave pré-compartilhada é lida, mantida ou exibida.

Source: github.com/biodream-llc/perfuse/internal/vpn

26.115 web

O pacote web serve a interface do utilizador construída a partir do interior do binário.

Os ativos estão incorporados em vez de enviados ao lado, por isso a implementação permanece em um ficheiro. Essa é a mesma razão pela qual o motor evita cgo: um operador deve ser capaz de copiar um binário para um servidor e executá-lo, sem JVM, sem instalador e sem diretório de ativos para sair do passo com o executável.

A saída construída é comprometida para que go build funcione em uma verificação sem Node instalado. Reconstrua com make web.

Source: github.com/biodream-llc/perfuse/internal/web

26.116 webauthn

O pacote webauthn verifica as passkeys.

Uma passkey é um par de chaves que o autenticador mantém - Touch ID, Windows Hello, um YubiKey, um telefone - onde a metade privada nunca deixa o dispositivo. Fazer login significa que o servidor envia um desafio aleatório, o autenticador assina após verificar se o utilizador está presente, e o servidor verifica a assinatura contra a chave pública que armazenou no registo.

A propriedade que importa não é que é conveniente. É que não há nada para phish. Uma palavra-passe pode ser digitada em uma cópia convincente de uma página de login; uma assinatura de passkey está ligada à origem para a qual foi criada, por isso a cópia obtém uma assinatura que o servidor não pode usar. Para um motor de integração que mantém as interfaces de um hospital, essa é a diferença que vale a pena ter.

O que esta implementação se recusa a fazer

A especificação é permissiva em lugares onde ser permissiva é como as implementações quebram. Esta não é:

Source: github.com/biodream-llc/perfuse/internal/webauthn

26.117 winservice

O pacote winservice executa o Perfuse como um serviço do Windows.

Este ficheiro é a metade de todos os lugares. Ele existe para que cmd/perfuse possa chamar este pacote sem embrulhar todos os sites de chamada em uma etiqueta de compilação: o subcomando é sempre compilado, e no Linux ou macOS explica que os serviços são uma ideia do Windows em vez de falhar por existir.

Recusar com uma frase clara é melhor do que esconder o subcomando. Alguém que segue as instruções do Windows na máquina errada é informado sobre o que está realmente acontecendo, e o equivalente para a sua plataforma.

Source: github.com/biodream-llc/perfuse/internal/winservice

26.118 x12

Ler e escrever valores em um caminho.

Porquê isto está separado do Path

path.go decide o que uma expressão de caminho significa. Este ficheiro resolve um contra uma troca real. Mantido à parte porque as regras de análise são dignas de ser lidas sem o tratamento de bytes, e porque o analisador é utilizado pelo validador de configuração, que não tem mensagem para resolver.

Porquê uma escrita reanalisar em vez de editar bytes no local

Segment.elements são subslices de Segment.raw, e Message.segs indexa em Message.raw. Editar um valor no local altera o comprimento de tudo o que se segue, por isso todas essas slices precisariam ser ajustadas, e qualquer uma que fosse perdida leria corretamente até a mensagem em que não o fizesse.

Portanto, uma escrita reconstrói o segmento, reconstrói a troca e analisa-a novamente. Isso custa uma análise por mensagem alterada e compra a garantia de que uma Message devolvida daqui é exatamente o que a análise dos seus próprios bytes produz. Não há estado em que os índices e os bytes discordem, porque esse estado é irrepresentável.

Source: github.com/biodream-llc/perfuse/internal/x12

26.119 x12xml

O pacote x12xml converte X12 (e outros EDI delimitados) para e do XML que o Mirth Connect e o Open Integration Engine escrevem para ele, e vice-versa.

Por que esse XML e não um dos nossos

O objetivo de uma forma XML de X12 é os sistemas que já usam um. Um site que se move do Mirth tem receptores construídos contra o que o tipo de dados EDI/X12 do Mirth emite, scripts que percorrem msg['CLM']['CLM.05']['CLM.05.1'], e motores upstream que enviam X12 como esse XML. Uma forma mais organizada da nossa própria não serviria a nenhum deles. Portanto, isso escreve exatamente o que o Open Integration Engine 4.6 escreve, e lê exatamente o que ele lê, e os testes comparam os dois byte a byte contra o serializador próprio do OIE.

Uma versão anterior deste pacote inventou a sua própria forma (uma raiz X12Interchange, elementos nomeados CLM05) e disse que correspondia à da Mirth. Não correspondia; nunca havia sido comparada com a Mirth, e nada no Perfuse a utilizava.

The format

A raiz é X12Transaction quando a mensagem começa com um segmento ISA e EDIMessage caso contrário, transportando os três delimitadores como atributos (segmentDelimiter, elementDelimiter, subelementDelimiter). Cada segmento é um elemento nomeado pelo seu identificador. Cada elemento de dados é SEG.NN, numerado a partir de 01 (ISA.01, CLM.05), e contém os seus componentes como SEG.NN.1, SEG.NN.2 e assim por diante: sempre pelo menos SEG.NN.1 para um elemento com um valor, nenhum para um vazio.

Os delimitadores são lidos a partir do ISA quando existe um: o separador de elementos a partir da posição 3, o separador de componentes a partir da posição 104 e o terminador de segmento a partir da posição 105, com um alimentador de linha após ele contado como parte dele. Caso contrário, são ~ * e:. O separador de repetição (ISA11) não é interpretado, o que também é o comportamento do OIE: um elemento repetido mantém o seu ^ dentro de um valor.

Isto é uma reimplementação do comportamento, escrita a partir da observação da saída do OIE e do seu formato documentado; nenhum código da Mirth está nele.

Source: github.com/biodream-llc/perfuse/internal/x12xml

26.120 xds

Pacote xds é IHE cross-enterprise document sharing: um Registro e Repositório de Documentos XDS.b (ITI-41 Provide and Register, ITI-18 Registry Stored Query, ITI-43 Retrieve Document Set), um Gateway de Resposta XCA sobre a mesma loja (ITI-38, ITI-39), e o lado do cliente de cada um, por isso um canal pode publicar um documento no repositório de outra organização e a console pode consultar um registro ou uma comunidade.

Os metadados são ebXML Registry 3.0 (ebRIM), como XDS.b define em IHE ITI TF-3 capítulo 4. É modelado aqui como structs Go cujas tags XML transportam os namespaces, por isso uma mensagem é lida da mesma forma independentemente dos prefixos que o remetente escolheu, e escrita corretamente com namespace.

Source: github.com/biodream-llc/perfuse/internal/xds

26.121 xmldsig

Pacote xmldsig implementa Assinaturas Digitais XML e o perfil XAdES delas.

Porquê isto está escrito em vez de emprestado

Um documento clínico assinado é um artefato legal. Afirma que uma pessoa nomeada, em um momento nomeado, assumiu a responsabilidade por um conjunto específico de bytes. Obter isso errado em qualquer direção é sério: uma assinatura que não pode ser verificada torna um documento válido parecer forjado, e um verificador que é muito generoso aceita um documento que alguém alterou.

A canonicalização é o problema inteiro

XML tem muitas sequências de bytes que significam a mesma coisa. A ordem dos atributos não é significativa, os prefixos de namespace podem ser renomeados, elementos vazios podem ser escritos de duas maneiras, e o espaço em branco dentro de uma tag é livre. Uma assinatura é sobre bytes, por isso antes de hashar qualquer coisa, ambos os lados devem concordar com exatamente uma sequência de bytes para um documento dado. Essa concordância é a canonicalização, e é onde as implementações dão errado, porque cada erro produz uma assinatura que verifica contra a própria saída e falha contra a saída de todos os outros.

Portanto, este ficheiro é a canonicalização, sozinho, com os seus próprios testes. Nada sobre assinatura aparece aqui.

Exclusivo em vez de inclusivo, por padrão

A canonicalização inclusiva puxa todas as declarações de namespace que estão no escopo, incluindo as que o elemento assinado nunca usa. Isso faz com que uma assinatura quebre quando o documento é posteriormente incorporado dentro de algo que declara um namespace não relacionado em um ancestral, o que é exatamente o que acontece quando um CDA é colocado dentro de um envelope SOAP ou um wrapper de metadados IHE. A canonicalização exclusiva inclui apenas as declarações que o elemento realmente usa, e é o que os perfis de troca de documentos especificam por esse motivo.

Source: github.com/biodream-llc/perfuse/internal/xmldsig

26.122 xtree

Pacote xtree é uma árvore XML mutável.

Três características muito diferentes precisam modificar XML: transformações HL7, que o Mirth modela como XML porque é isso que os seus scripts operam; documentos clínicos, que são XML nativamente; e as etapas de transformação declarativa. Eles compartilham esta árvore em vez de cada um crescer a sua própria, porque a alternativa é três modelos que discordam sobre o que significa um elemento vazio.

O objetivo de design é a fidelidade às semânticas E4X, desde que os scripts Mirth são E4X e o objetivo de executá-los inalterados é que eles se comportem da mesma forma. Isso impulsiona duas decisões que de outra forma pareceriam estranhas: um nó mantém um ponteiro para o seu pai, porque o E4X expõe parent(), e os filhos são ordenados com duplicatas permitidas, porque uma repetição de campo HL7 é literalmente um elemento repetido e os scripts indexam neles por posição.

Source: github.com/biodream-llc/perfuse/internal/xtree

26.123 pacote pas

O pacote pas lê os pedidos de Suporte de Autorização Prévia (PAS) da Da Vinci.

É o leitor que o próprio servidor PAS do Perfuse usa, publicado para que qualquer coisa que decida uma autorização prévia - as regras de um pagador, um sistema de gestão de utilização, um serviço de decisão como o Vaglio - leia um pedido com o mesmo código, e assim as mesmas respostas sobre o que um pedido contém. Dois leitores de um formato de mensagem são duas opiniões sobre ele.

Ele não tem dependências fora da biblioteca padrão. Um pedido é mantido como JSON decodificado (map[string]any) em vez de como recursos tipados, porque um Bundle PAS transporta quaisquer recursos de suporte que o fornecedor escolheu enviar, e um leitor que dropa o que não modela esconderia evidências da decisão.

req, problemas := pas.Ler(bundle, false) se len(problemas) > 0 { // recusar: o pedido não pode ser respondido corretamente } for _, svc := range req.Serviços() { // svc.Códigos, svc.Item, e req.Resolver para qualquer coisa que o item faça referência }

Source: github.com/biodream-llc/perfuse/pas

27 Índice de Chaves de Configuração

Toda chave em ordem alfabética, com os blocos em que pode aparecer. Uma chave que aparece em vários blocos significa a mesma coisa em cada um; onde não, os blocos são documentados separadamente e a diferença é declarada lá.

27.1 Todas as chaves

ChaveAparece em
access_key_idAcesso AWS, Autenticação FHIR, Destino S3
accountAcesso Azure Blob
ackOrigem HTTP, Origem SOAP, Origem
ack_sender_idOpções X12
ack_sender_qualifierOpções X12
acknowledgeOpções EDIFACT, Opções HL7v3, Opções X12
acksDestino Kafka
actionDestino SOAP
addrConexão AMQP, Destino Broker, Origem Broker, Conexão MQTT
addressConexão AMQP, Destino DICOM, Origem de Consulta DICOM, Destino, Endereço Direto, Destino TCP
ae_titleOrigem DICOM
after_queryOrigem de Banco de Dados
after_readOrigem Azure Blob, IMAP Direto, Origem de E-mail, Poll de Arquivos, Origem GCS, Origem S3, Origem SFTP
allowScripts
allow_clear_passwordDestino FTP
allow_unencryptedParceiro AS2, Recebimento PGP
allow_unsignedParceiro AS2
allowed_calling_aeOrigem DICOM
allowed_sendersOrigem de E-mail
amqpDestino, Origem
anchors_fileEndereço Direto
api_versionConexão IBMMQ
appendDestino, Destino SFTP
applicationConfirmação
armorEnvio PGP
arrives_asOpções X12
as2Destino, Origem
attachDestino SMTP
attach_nameDestino Direto, Destino SMTP
attachment_namesOrigem de E-mail
attachmentsCanal
attemptsRetentativa
authDestino FHIR, Destino PAS
authoritiesDestino MPI
azure_blobDestino, Origem
backoffConfiguração de Fila, Retentativa
base64Origem SOAP
batch_sizeOrigem de Banco de Dados, Poll de Arquivos
baudOrigem Serial
bccDestino SMTP
bearer_tokenDestino CDA, Destino FHIR, Destino HTTP, Destino PAS
big_endianEstruturação TCP
blobDestino Azure Blob
bodyDestino SMTP, Destino SOAP
brokerDestino, Origem
brokersDestino Kafka, Origem Kafka
bucketAcesso GCS, Destino S3, Origem S3
bundle_scriptDestino FHIR
called_aeDestino DICOM, Origem de Consulta DICOM
calling_aeDestino DICOM, Origem de Consulta DICOM
ccDestino SMTP
cdaDestino
cert_fileDestino AS2, Parceiro AS2, Origem AS2, Endereço Direto
channelDestino, Sombra
check_everyReferência de Contrato
cityInstalação ECR
claim_us_coreDestino FHIR
classDestino XDS
client_ca_fileXDR Direto
client_idAutenticação de E-mail, Autenticação FHIR, Conexão MQTT
client_secretAutenticação de E-mail, Autenticação FHIR
codeCódigo XDS
columnOrigem de Banco de Dados
columnsDelimitado
commentDelimitado
commit_after_deliveryOrigem Kafka
compareSombra
compressDestino AS2
compressionDestino Kafka
configDestino ELR
containerAcesso Azure Blob
content_typeDestino AMQP, Destino AS2, Destino Azure Blob, Destino Broker, Destino GCS, Destino HTTP, Destino S3, Destino XDS
contractCanal
credentials_fileAcesso GCP
dataTypeCanal
data_bitsOrigem Serial
databaseDestino, Origem
decrypt_withRecebimento PGP
default_identifier_systemDestino FHIR
delimitedCanal
delimiterDelimitado, Estruturação TCP
deployScripts
descriptionCanal
destinationDestino Broker, Origem Broker
destinationsCanal
dicomCanal, Destino, Origem
dicom_queryOrigem
dicomwebDestino, Origem
dirDestino CDA, Destino, Destino de Documento, Destino FTP, Poll de Arquivos, Origem SFTP, Origem SFTP
directDestino, Origem
direct_fromDestino XDS
direct_toDestino XDS
displayCódigo XDS
dnsDestino Direto
documentDestino
domainOrigem SMB
driverDestino de Banco de Dados, Origem de Banco de Dados
dsnDestino de Banco de Dados, Origem de Banco de Dados
duplicate_windowOrigem AS2
ecrDestino FHIR
edifactCanal
elementOrigem SOAP
elrDestino
emailOrigem
emit_on_first_pollOrigem de Consulta DICOM
enabledCanal, Destino, Configuração de Fila
encrypt_toEnvio PGP
endpointAcesso AWS, Acesso Azure Blob, Acesso GCP, Destino S3
envelopeOpções EDIFACT, Opções X12
error_dirPoll de Arquivos, Origem SFTP
error_folderIMAP Direto, Origem de E-mail
error_prefixOrigem Azure Blob, Origem GCS, Origem S3
expect_replyDestino TCP
extractAnexos
facilityConfirmação, Destino ECR
facility_idDestino SOAP
facility_typeDestino XDS
fail_on_bodyDestino HTTP
fault_is_successDestino SOAP
fault_on_nakOrigem SOAP
fhirDestino
fileReferência de Contrato, Origem
file_nameDestino AS2, Destino, Destino de Documento, Destino FTP, Envio PGP, Destino SFTP
file_rootsScripts
filterCanal, Delimitado, Destino, Opções HL7v3, Scripts
flow_controlOrigem Serial
follow_redirectsDestino HTTP
follow_symlinksOrigem de Arquivos
font_sizeDestino de Documento
formatDestino de Documento, Destino S3
framedOrigem Azure Blob, Destino FTP, Poll de Arquivos, Origem GCS, Destino S3, Origem S3, Destino SFTP, Origem SFTP
framingEstruturação TCP
fromDestino AS2, Destino SMTP
from_beginningOrigem Kafka
ftpDestino, Origem
gcsDestino, Origem
groupCanal, Origem Kafka
group_byDestino SNS, Destino SQS
has_headerDelimitado
headerDestino SOAP
headersDestino Broker, Destino CDA, Destino DICO Mweb, Destino FHIR, Destino HTTP, Destino Kafka, Destino SOAP, Destino XDS
heartbeatOrigem Broker
hl7v3Canal
hostDestino Broker, Origem Broker, IMAP Direto, Origem de E-mail, Destino FTP, Origem FTP, Destino SFTP, Origem SFTP, Origem SMB, Destino SMTP
hostnameConexão AMQP
httpDestino, Origem
ibm_mqDestino, Origem
idParceiro AS2, Origem AS2
id_typeDestino MPI
identifier_systemsDestino CDA, Destino FHIR
idle_timeoutOrigem DICOM, Origem, Origem TCP
ignoreSombra
imapOrigem Direta
includeScripts
include_trigger_eventConfirmação
insecure_skip_host_key_checkDestino SFTP, Origem SFTP
insecure_skip_verifyDestino FTP, Origem FTP, Destino SMTP, Origem Web DAV
intervalOrigem de Consulta DICOM
javascriptDestino, Origem
kafkaDestino, Origem
keep_aliveDestino TCP
keep_blank_linesDelimitado
keep_delimiterEstruturação TCP
keyAcesso Azure Blob, Destino Kafka, Destino S3
key_columnOrigem de Banco de Dados
key_fileDestino AS2, Origem AS2, Endereço Direto, Destino SFTP, Origem SFTP
key_passphraseDestino SFTP, Origem SFTP
known_hosts_fileDestino SFTP, Origem SFTP
landscapeDestino de Documento
languageScripts
ldapDestino Direto
length_bytesEstruturação TCP
length_includes_headerEstruturação TCP
levelOrigem de Consulta DICOM
limitOrigem de Consulta DICOM
lineInstalação ECR
listenOrigem AS2, Origem DICO Mweb, Origem DICOM, Origem Direta, XDR Direto, Origem HTTP, Origem SOAP, Origem, Origem TCP
loginDestino Broker, Origem Broker
mailboxIMAP Direto, Origem de E-mail
matchOrigem de Consulta DICOM
max_attemptsOrigem de Banco de Dados, Configuração de Fila
max_backoffConfiguração de Fila, Retentativa
max_bytesOrigem Direta
max_connectionsOrigem, Origem TCP
max_depthConfiguração de Fila
max_differencesSombra
max_file_sizePoll de Arquivos, Origem SFTP
max_message_sizeOrigem AS2, Origem de E-mail, Origem HTTP, Origem Kafka, Origem SOAP, Origem Serial, Origem, Destino TCP, Origem TCP
max_messagesOrigem Pub Sub, Origem SQS
max_object_bytesOrigem DICO Mweb, Origem DICOM
max_object_sizeOrigem Azure Blob, Origem GCS, Origem S3
max_open_connsDestino de Banco de Dados
mechanismAutenticação SASL Kafka
methodDestino HTTP
move_toOrigem Azure Blob, IMAP Direto, Origem de E-mail, Poll de Arquivos, Origem GCS, Origem S3, Origem SFTP
mpiDestino
mqttDestino, Origem
nameCanal, Destino de Canal, Destino, Instalação ECR
ncpdpCanal
no_compressEnvio PGP
no_mergeDestino MPI
non_persistentDestino IBMMQ
npiInstalação ECR
oauthOrigem de E-mail
objectDestino GCS
on_no_documentDestino CDA
order_byDestino Pub Sub
overReferência de Contrato
overlapOrigem de Consulta DICOM
paramsDestino de Banco de Dados
parityOrigem Serial
partner_cert_fileDestino AS2
partnersOrigem AS2
pasDestino
pass_plainRecebimento PGP
passcodeDestino Broker, Origem Broker
passphraseRecebimento PGP, Envio PGP
passwordConexão AMQP, Destino AS2, Destino DICO Mweb, Origem DICO Mweb, Destino Direto, IMAP Direto, Origem Direta, Origem de E-mail, Destino FTP, Origem FTP, Destino HTTP, Conexão IBMMQ, Autenticação SASL Kafka, Conexão MQTT, Destino SMTP, Destino SOAP, Origem SOAP, Origem Web DAV, Destino XDS
pathOrigem AS2, Origem DICO Mweb, Origem HTTP, Origem SOAP
path_styleDestino S3, Origem S3
patient_domainDestino XDS
patient_rootOrigem de Consulta DICOM
patternPoll de Arquivos, Origem SFTP
payerDestino PAS
persistentDestino Broker
pgpDestino, Origem
phoneInstalação ECR
poll_intervalOrigem Azure Blob, Origem de Banco de Dados, IMAP Direto, Origem de E-mail, Poll de Arquivos, Origem GCS, Origem IBMMQ, Origem Java Script, Origem S3, Origem SFTP
portIMAP Direto, Origem de E-mail, Origem Serial
postal_codeInstalação ECR
postprocessorScripts
practice_settingDestino XDS
prefetchOrigem AMQP
prefixOrigem Azure Blob, Origem GCS, Origem S3
preprocessorScripts
profileDestino SOAP, Origem SOAP
projectAcesso GCP
protocolOrigem de E-mail
providerAutenticação de E-mail
pubsubDestino, Origem
purposeDestino TEFCA
qosConexão MQTT
queryOrigem de Banco de Dados
query_timeoutOrigem de Banco de Dados
queueDestino, Conexão IBMMQ
queue_managerConexão IBMMQ
queue_urlDestino SQS, Origem SQS
quiet_afterOrigem Serial
quoteDelimitado
rawPoll de Arquivos
rctcDestino ECR, Destino ELR
read_timeoutOrigem HTTP, Origem SOAP
reassembleAnexos
receiptDestino AS2
receipt_urlDestino AS2
recipient_certs_dirDestino Direto
reconnectOrigem AMQP, Origem Broker, Origem MQTT, Origem Pub Sub
record_lengthEstruturação TCP
refresh_tokenAutenticação de E-mail
regionAcesso AWS, Autenticação FHIR, Destino S3
reject_on_warningDestino FHIR
relaxedDelimitado
reopen_afterOrigem Serial
replyOrigem Serial, Origem TCP
reply_textOrigem Serial, Origem TCP
request_mdnDestino Direto
require_agreementDestino CDA
require_signatureRecebimento PGP
response_elementOrigem SOAP
response_namespaceOrigem SOAP
response_transformerDestino
results_toDestino PAS, Destino TEFCA
retainDestino MQTT
retain_hoursDestino, Configuração de Fila
retryDestino
returnOrigem de Consulta DICOM
rootOrigem FTP, Origem de Arquivos, Origem SMB
s3Destino, Origem
sampleSombra
sasAcesso Azure Blob
saslDestino Kafka, Origem Kafka
schemeCódigo XDS
scopeAutenticação de E-mail, Autenticação FHIR
scriptCanal, Destino Java Script, Origem Java Script
scriptsCanal
secret_access_keyAcesso AWS, Autenticação FHIR, Destino S3
securityIMAP Direto, Origem de E-mail, Destino FTP, Origem FTP
selectorOrigem Broker
sender_deviceOpções HL7v3
sender_oidOpções HL7v3
serialOrigem
server_side_encryptionDestino S3
session_timeoutOrigem Kafka
session_tokenAcesso AWS, Autenticação FHIR, Destino S3
sftpDestino, Origem
shadowCanal
shareOrigem SMB
sign_withEnvio PGP
smbOrigem
smtpDestino
smtp_hostDestino Direto, Origem Direta
snsDestino
soapDestino, Origem
sop_classesOrigem DICOM
sort_byPoll de Arquivos
sourceCanal, Destino ECR
source_idDestino XDS
splitDelimitado, Opções EDIFACT, Opções X12
sqsDestino, Origem
ssn_systemDestino MPI
stable_forPoll de Arquivos, Origem SFTP
start_blockEstruturação TCP
starttlsDestino SMTP
stateInstalação ECR
statementDestino de Banco de Dados
stop_bitsOrigem Serial
storage_classDestino GCS, Destino S3
subjectDestino AS2, Destino Direto, Destino SMTP, Destino SNS
subscriptionOrigem Pub Sub
subscription_idOrigem Broker
success_on_undefinedDestino Java Script
success_statusDestino HTTP
suffixOrigem Azure Blob, Origem GCS, Origem S3
tablesCanal
takeOrigem de E-mail
tcpDestino, Origem
tefcaDestino
temp_suffixDestino, Destino de Documento, Destino FTP, Destino SFTP
templateOrigem de Banco de Dados, Destino de Documento
tenantAutenticação de E-mail
tenant_idAutenticação FHIR
textDestino Direto
tierDestino Azure Blob
timeoutConexão AMQP, Destino Broker, Origem Broker, Destino DICO Mweb, Destino DICOM, Origem de Consulta DICOM, Destino de Banco de Dados, Destino, Destino Direto, Destino de Documento, Destino FTP, Origem FTP, Destino IBMMQ, Destino Java Script, Origem Java Script, Destino Kafka, Origem Kafka, Conexão MQTT, Destino S3, Destino SFTP, Origem SFTP, Origem SMB, Destino SMTP, Destino SOAP, Scripts, Sombra, Destino TCP, Origem Web DAV, Destino XDS
timezoneDestino FHIR
titleDestino de Documento
tlsConexão AMQP, Destino AS2, Origem AS2, Destino Broker, Origem Broker, Destino DICO Mweb, Origem DICO Mweb, Destino DICOM, Origem DICOM, Destino, IMAP Direto, Origem de E-mail, Destino HTTP, Origem HTTP, Conexão IBMMQ, Destino Kafka, Origem Kafka, Conexão MQTT, Destino SOAP, Origem SOAP, Origem, Destino TCP, Origem TCP, Destino XDS
tls_certOrigem Direta, XDR Direto
tls_keyOrigem Direta, XDR Direto
toDestino AS2, Destino Direto, Destino SMTP
tokenDestino DICO Mweb, Origem DICO Mweb, Origem HTTP, Origem SOAP, Destino XDS
token_urlAutenticação de E-mail, Autenticação FHIR
topicDestino Kafka, Destino MQTT, Origem MQTT, Destino Pub Sub
topic_arnDestino SNS
topicsOrigem Kafka
transfer_syntaxesDestino DICOM, Origem DICOM
transformationsCanal, Opções DICOM, Delimitado, Opções HL7v3, Opções NCPDP, Opções de Script, Opções X12
transformerScripts
trim_paddingEstruturação TCP
trim_spaceDelimitado
typeDestino, Autenticação FHIR, Origem
undeployScripts
unencryptedDestino AS2
unsignedDestino AS2
unsigned_receiptDestino AS2
urlDestino AS2, Destino CDA, Destino DICO Mweb, Destino FHIR, Destino HTTP, Conexão IBMMQ, Destino SOAP, Origem Web DAV, Destino XDS
userDestino FTP, Origem FTP, Destino SFTP, Origem SFTP, Origem SMB, Origem Web DAV
usernameConexão AMQP, Destino AS2, Destino DICO Mweb, Origem DICO Mweb, Destino Direto, IMAP Direto, Origem Direta, Origem de E-mail, Destino HTTP, Conexão IBMMQ, Autenticação SASL Kafka, Conexão MQTT, Destino SMTP, Destino SOAP, Origem SOAP, Destino XDS
validate_before_sendDestino FHIR
verify_withRecebimento PGP
versionDestino CDA, Destino FHIR, Destino SOAP, Origem SOAP
visibility_timeoutOrigem SQS
wait_secondsOrigem SQS
warnings_are_errorsDestino SOAP
webdavOrigem
whenConfirmação
windowOrigem de Consulta DICOM
writeDestino CDA
wsdlOrigem SOAP
x12Canal
x12_asDestino
xdmDestino Direto
xdm_source_idDestino Direto
xdrOrigem Direta
xdsDestino