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:
- Tudo é configurável a partir da interface web. Um recurso acessível apenas a partir de um terminal ou um arquivo editado manualmente é tratado como um defeito, não como uma escolha de design.
- As mensagens podem ser rastreadas uma transformação de cada vez, mostrando o que cada etapa leu, o que mudou, o que pulou e por quê.
- O tráfego de teste pode ser gerado para corresponder à forma de uma fonte real sem conter nenhum de seus dados.
- Um canal pode ser proposto a partir de uma única mensagem de amostra, com uma declaração explícita do que a amostra não pode dizer.
- Antes de substituir um motor existente, sua saída e a do Perfuse podem ser comparadas mensagem por mensagem, com as diferenças agrupadas por campo.
1.2 O que está incluído
Tudo abaixo está no mesmo binário. Cada linha nomeia o capítulo que o cobre.
- Formatos. HL7 v2, FHIR R4, R4B e R5, DICOM, X12 (837, 835, 270/271, 276/277, 834, 278, 275), C-CDA e CDA, HL7 v3, NCPDP Telecommunication e SCRIPT, SMART Health Links e Cards, delimitados e brutos. Veja formatos de mensagem.
- Conectores. 28 tipos de origem e 32 tipos de destino, entre eles MLLP, arquivos, SFTP, bancos de dados, DICOM, Kafka, AMQP 1.0, MQTT, IBM MQ e armazenamento e mensagens da AWS, Azure e Google Cloud. Veja a referência de origem e a referência de destino.
- Alterando mensagens. Filtros, onze etapas de transformação declarativa, JavaScript (dialecto do Mirth incluído) e Lua, tabelas de mapeamento compartilhadas e conjuntos de código e sugestões de mapeamento. Veja filtragem e transformação.
- Entregando-as. Uma fila durável e ordenada por destino, repetições, cartas mortas que mantêm a mensagem e confirmações enviadas após a entrega. Veja entrega e confirmações.
- Observando a execução. Painéis, painéis de equipe, um mapa de fluxo, onze tipos de alerta, métricas, rastreamento e um repositório de mensagens que encontra as mensagens de um paciente em vários formatos. Veja alertas, o repositório de mensagens e depuração.
- Alterando uma interface ao vivo com segurança. Modo de sombra, contratos de alimentação, testes de canal e comparação de motor. Veja testes.
- Saindo do Mirth. Canais do Mirth, Open Integration Engine e BridgeLink explicados, traduzidos e exportados de volta. Veja migração.
- Pagadores e saúde pública. As quatro APIs CMS-0057, Da Vinci CRD, DTR, PAS, PDex e Plan-Net, CARIN Blue Button, um serviço de decisão opcional, eCR e ELR. Da Vinci CRD, DTR e PAS respondem às suas versões 2.2.x e 2.1.0. Veja CMS-0057.
- Quem pode fazer o quê. SAML, OpenID Connect, LDAP, passkeys, SCIM, TLS mútuo, seis funções, grupos de canal com uma função em cada, inquilinos, um servidor de autorização SMART, TEFCA e UDAP e um registro de auditoria. Veja segurança.
- Executando-o. Um binário estático para Linux, macOS e Windows, como um serviço, com uma visão de frota de vários servidores. Veja operações, a interface web, a linha de comando e opções de servidor.
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ão | Versão | Verificado |
|---|---|---|
| HL7 v2 | qualquer 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.1 | Validador HL7 v2 da NIST; tráfego real do Mirth e OIE |
| HL7 v2 para FHIR | Mapeamento 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 |
| FHIR | R4 (4.0.1), com R4B e R5 lidos e escritos | Validador FHIR da HL7; Inferno |
| C-CDA e CDA | C-CDA 2.1 | SITE da ONC (amostras C-CDA enviadas e recebidas via XDR); não por um esquema CDA |
| HL7 v3 | PIX e PDQ (IHE ITI-44, 45, 47) | Esquemas NE2008 da IHE e mensagens de exemplo |
| DICOM e DICOMweb | DIMSE C-STORE, C-FIND, C-MOVE, C-GET, C-ECHO; QIDO-RS, WADO-RS, WADO-URI, STOW-RS | Orthanc |
| 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 conectividade | vC2.2.0 SOAP e MIME, vC4.0.0 com MTOM | Um sistema UM substituto escrito a partir das regras da CAQH |
| NCPDP | Telecomunicação D.0; SCRIPT 2023011 (e 2017071) com ePA; Benefício de prescrição em tempo real v13 | Escrito a partir das guias de companhia públicas da Surescripts e seus exemplos; não contra os esquemas licenciados da NCPDP |
| UN/EDIFACT | sintaxe 3 e 4, CONTRL | pydifact 0.1.8 |
| Compartilhamento de documentos da IHE | XDS.b, XCA, XDR, MHD 4.2.2, PIXm, PDQm, XDM | Kit de ferramentas XDS da NIST; SITE da ONC |
| Mensagens seguras diretas | Declaração de aplicabilidade 1.2, XDR e XDM para Direto, DNS e descoberta de certificado LDAP | SITE da ONC; Ferramenta de descoberta de certificado da ONC (18 de 18) |
| AS2 | RFC 4130, compressão RFC 5402 | pyas2lib |
| Anexos assinados | HL7 DSDR, XAdES-X-L | xmlsec1, OpenSSL |
1.3.2 Guias de implementação do FHIR
| Guia | Lançamento | Verificado |
|---|---|---|
| US Core | conversões para 9.0.0 (USCDI v6); servidor FHIR contra 6.1.0 e 7.0.0 | o validador HL7; Inferno US Core |
| SMART App Launch | 2.2 | Inferno: 80 de 80 (aplicativo público) |
| Bulk Data Access | 2.0.0 | Inferno: 48 de 48 |
| Subscriptions R5 Backport | para R4 | um receptor HTTP real; os testes de notificação do kit PAS |
| Da Vinci CRD | 2.2.1 e 2.1.0 | Inferno 2.2.1: 92 passam, nenhum falha; 2.1.0 pelos próprios exemplos do guia |
| Da Vinci DTR | 2.2.0 e 2.1.0 | Inferno 2.2.0: 43 passam, 2 falham (um defeito do kit); 2.1.0 pelos próprios exemplos do guia |
| Da Vinci PAS | 2.2.1 e 2.1.0 | Inferno 2.2.1: 82 de 84; 2.1.0 pelos próprios exemplos do guia |
| Da Vinci PAS, enviando (lado do provedor) | 2.2.1 | a implementação de referência do pagador do HL7 Da Vinci PAS; não é um pagador de produção |
| Da Vinci PDex | 2.2.0 | Inferno PDex 2.0: pagador para pagador 19 de 19 |
Da Vinci HRex $member-match | 1.2.0 | Inferno PDex pagador para pagador |
| Da Vinci ATR | 2.1.0 | não verificado por uma ferramenta externa |
Da Vinci CDex $submit-attachment | 2.1 | não verificado por uma ferramenta externa |
| Da Vinci Plan-Net | 1.1.0 | Inferno: 199 passam, 10 falham (um defeito do kit) |
| Da Vinci US Drug Formulary | 2.1.0 | o validador HL7 |
| ISiK (hospitais alemães), servidor FHIR | Stufe 5, módulo básico | conjunto de testes ISiK 3.0.9 da gematik: 421 de 421 |
| PACIO Transitions of Care, Perfil de Medicamento, Diretivas Antecipadas, Funcionamento | 1.0.0, 1.0.0, 2.0.0-ballot, 2.0.0 | kits 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 Button | 2.2.0 | o validador HL7 |
| eCR | 2.1.2 | o validador HL7 |
| ELR | HL7 2.5.1 ELR Release 1 com suas erratas | ferramenta ELR da ONC: 28 de 28 |
| Resumo Internacional de Paciente | 2.0.0 | o validador HL7 |
| DEQM | 5.0.0 | o validador HL7 |
| SQL no FHIR | v2 | o conjunto de testes oficial: 144 de 144 |
| Cartões e Links de Saúde SMART | Cartões 1.4, Links STU 1 | o cartão de exemplo das especificações; uma biblioteca de visualização de Links de Saúde SMART publicada |
| Segurança UDAP | STU 1 | um servidor de autorização real e uma comunidade de confiança |
| FHIR Facilitado pela TEFCA | SOP v2.0 | nã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.
| Perfil | Lançamento | Recursos válidos |
|---|---|---|
| UK Core | STU2 2.0.2 | 185 de 187 |
| FR Core | 2.2.0 | 138 de 156 |
| ISiK Basismodul | 4.0.3 (Stufe 4) | 18 de 47; 42 de 47 com o script de bundle próprio do hospital |
| Nictiz nl-core | 0.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 Europa | 2.1.0 | 106 de 426 (o guia espera um documento, um resultado v2 não é) |
| Relatório de Alta Hospitalar HL7 Europa | 1.0.0 | 68 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.
-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:
- O bloco de fonte é plano para MLLP.
listenestá diretamente emsource, não dentro de um blocosource.mllp. Transportes que precisam de mais do que um endereço — HTTP, SOAP, DICOM — têm seu próprio sub-bloco, e esses estão listados na referência de fontes. - Um destino de arquivo precisa de
rootedir.rooté a fronteira contra a qual os caminhos são resolvidos e não podem escapar;diré onde as mensagens aterrissam dentro dele. - Não há transformação e não há filtro. Ambos são opcionais, e um canal com nenhum simplesmente passa as mensagens.
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:
- 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.
- A partir de algo que já funciona. Um conjunto de canais completos que precisam apenas dos endereços preenchidos.
- 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
- Canais explica o que é um canal e como suas partes se encaixam.
- Fluxo de mensagem segue uma mensagem da chegada à entrega, o que é a forma mais rápida de entender onde colocar uma alteração.
- Alertas vale a pena configurar antes de um feed ir ao vivo em vez de após o primeiro incidente.
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:
- Autorização prévia: Pedidos de PAS decididos dentro de 72 horas (expedidos) ou 7 dias (padrão) do CMS-0057, decididos tardiamente, aguardando e atrasados agora, com o tempo médio de decisão. Além disso, como os serviços solicitados foram respondidos (aprovados, modificados, negados, pendentes), como cada um se encontra agora, ao longo de 30 dias.
- Imagem: Objetos recebidos por C-STORE por modalidade e aqueles que não foram entregues. Além disso, o atraso de roteamento por canal (mediana e percentil 95), consultas C-FIND e falhas por canal de consulta e relatórios de imagem (um ORU cujo OBR-24 é uma seção de imagem ou um MDM) que não alcançaram todos os destinos.
- Ciclo de receita: Conjuntos de transações 999 aceitos, aceitos com erros e rejeitados, e reivindicações 277CA aceitas e rejeitadas (A3, A4, A6, A7, A8). Além disso, reivindicações 835 correspondentes ao número de conta de paciente para 837s enviados por meio deste servidor e os motivos de rejeição mais comuns.
- Laboratório: Tempo de entrega de resultados, desde a receita até o último destino de confirmação, e resultados críticos (OBX-8 HH, LL, AA, > ou <) que não alcançaram todos os destinos.
- Privacidade e segurança: Quem abriu mensagens, procurou pacientes ou leu autorizações prévias no console ao longo de 7 dias, a partir do registro de auditoria (abrir uma mensagem é auditado como
message.read). Além disso, cada token de API ativo e quando foi usado pela última vez; um token não utilizado por 90 dias é marcado.
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.
3.4.6 Ligações de saúde
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:
- As quatro APIs: se o Acesso do Paciente, Acesso do Prestador, Payer-to-Payer e Autorização Prévia estão prontas nesta instância,
e o que cada uma ainda necessita.
- Fila de revisor: os pedidos de PAS em espera de uma pessoa, primeiro o mais próximo do prazo, com os documentos enviados para cada; aprovar, negar ou
certificar menos unidades. Veja a fila de revisor.
- Reclamações para CARIN BB: um 837 e seu 835 convertidos para pacotes CARIN Blue Button.
- Autorização prévia para PDex: uma resposta de PAS convertida para uma autorização prévia PDex.
- Métricas de autorização prévia: a página pública anual de métricas de autorização prévia, visualizada a partir de um CSV de decisões.
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:
| Parte | Chave | Obrigatório | O que faz |
|---|---|---|---|
| Identidade | name | sim | Nomeia o canal. Deve ser único. |
| Tipo de dados | dataType | não | Como analisar as mensagens. O valor predefinido é HL7 v2. |
| Origem | source | sim | De onde as mensagens chegam. Exatamente um. |
| Filtro | filter | não | Decide quais mensagens aceitar. |
| Transformações | transformations | não | Mudanças ordenadas na mensagem. |
| Destinos | destinations | sim | Para 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.
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.
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. The source accepts the bytes. For a stream transport this includes de-framing — finding where one message ends and the next begins.
- 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. - Record. The message is written to the message store as received, before anything modifies it. This is what makes replay and reprocessing possible.
- 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. - Transform. The channel's
transformationsrun in order, each against the result of the last. - Fan out. Each destination gets a copy of the transformed message, applies its own transformations if it has any, and delivers.
- Record the outcome. Per destination: delivered, queued, failed, or filtered.
- 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.
5.4 Onde a mensagem é registrada
Antes do filtro e, portanto, antes de qualquer transformação. Três consequências:
- Uma mensagem que o filtro rejeitou ainda está na loja. Você pode ver o que chegou e confirmar que o filtro estava correto.
- Repetição e reprocessamento sempre começam do que realmente chegou, e não de uma versão parcialmente transformada.
- Uma alteração nas transformações pode ser testada contra tráfego histórico real, porque o original ainda está lá. Veja testing.
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
| Fase | Como a falha se manifesta | O que acontece |
|---|---|---|
| Chegada | Erro de estruturação, conexão interrompida no meio da mensagem | Registrado, conexão fechada, remetente tenta novamente |
| Análise | Não é válido para o tipo declarado | Registrado como falha de análise, confirmação negativa se a fonte espera uma |
| Filtro | O próprio filtro apresenta um erro | Tratado como recusa, registrado com o erro |
| Transformação | Uma etapa falha | Dependendo do on_error da etapa; consulte transformação |
| Entrega | Destino inacessível ou rejeita | Enfileirado 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.
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
| Etapa | O que ela faz |
|---|---|
set | Escreve um valor literal em um caminho, criando-o se ausente. |
copy | Copia um caminho para outro, com um valor padrão opcional quando a fonte estiver ausente. |
clear | Esvazia um campo, deixando-o presente. |
remove | Remove um campo completamente. |
map | Procura o valor atual em uma tabela e substitui-o. |
replace | Substituição de expressão regular dentro de um campo. |
pad | Preenche um valor com uma largura fixa. |
date | Converte uma data ou carimbo de data/hora entre formatos. |
trim | Remove espaços em branco circundantes. |
case | Converte 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:
setcria qualquer caminho que aborda, incluindo a estrutura interveniente. Isso é conveniente e significa quesetnunca pode demonstrar que um campo estava ausente — após a etapa, ele existe. Para testar o que acontece quando um campo está faltando, usecopyde um caminho que não está lá.- Um caminho sem índice aborda toda repetição e ocorrência, como faz em um filtro (onde
PID-3.5 == "SS"é verdadeiro quando qualquer repetição é). Em uma mensagem com cinco segmentos OBX,setemOBX-5altera todos os cinco, esetemPID-3.4relabela todos os identificadores em PID-3, incluindo o número nacional. Para alterar um, forneça o seu índice:PID-3(1).4,OBX(2)-5.
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:
fail— o padrão. A mensagem para e é registrada como uma falha de transformação.keep— deixa o valor original intacto.clear— esvazia o campo.
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:
- Um
mapapós umcasevê o valor convertido pelo caso, então as chaves da tabela devem corresponder à forma convertida. Uma tabela deM/Fapós uma etapa de minúsculas não corresponde a nada, silenciosamente, porque um valor não na tabela é deixado intacto. - Um
copyde um campo que uma etapa posterior remove ainda funciona, porque foi executado primeiro. O contrário não é verdade.
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:
- Valores de exemplo para um campo de origem, após um sinal de igual:
ZPI-1 = MRN00412, MRN00998 - O tipo de valor que um alvo mantém, da mesma forma:
PID-3.1 = mrn. Os tipos sãomrn,npi,ssn,phone,dateeemail.
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:
| Valor | O que é |
|---|---|
javascript | O padrão. Um script sem marcação é JavaScript. |
lua | A melhor escolha quando ninguém está migrando. |
wasm | Os 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.
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: [...]
statuséapproved(o padrão),draft(usado por nada) ouretired(mantido para registro, usado por nada).
(guardado para o registo, usado por nada).
- Duas edições de um nome com a mesma versão, ou duas edições aprovadas que começam no mesmo dia, são recusadas quando o ficheiro é carregado.
- Guardar uma nova versão sem data de início enquanto outra está aprovada data-a a partir de hoje, pelo que substitui a que está em vigor. Uma que tinha apenas começado hoje é reformada, uma vez que duas edições que começam no mesmo dia não deixam nenhuma regra.
- Os próprios
defaultestrictde um passo de mapeamento são usados quando o passo os define;
caso contrário, os da tabela.
- Na tela Tabelas, Mostrar versões lista cada edição com o seu estado, quem a guardou e quem a aprovou, e Comparar com a versão em vigor mostra o que uma edição adiciona, remove e altera.
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:
| Formato | Ficheiro | Sistema |
|---|---|---|
loinc | Loinc.csv a partir do lançamento da tabela LOINC | http://loinc.org |
icd10cm | o ficheiro de pedidos CMS (icd10cm_order_*.txt) ou ficheiro de códigos | http://hl7.org/fhir/sid/icd-10-cm |
rxnorm | RXNCONSO.RRF a partir do lançamento completo RxNorm | http://www.nlm.nih.gov/research/umls/rxnorm |
snomed | a descrição instantânea RF2 (sct2_Description_Snapshot-en_*.txt) | http://snomed.info/sct |
snomed-rf2 | um 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} |
claml | um 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 |
icd11 | a 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 |
csv | qualquer 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:
- uma tabela com nome
source_systemoutarget_systemtem as suas entradas verificadas quando
guardadas, e os códigos que não estão no sistema são listados na edição;
- Encontrar um código procura por código ou por palavras no nome;
- o servidor FHIR responde
CodeSystem/$lookupeCodeSystem/$validate-code
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:
- Uma fonte de corretor aceita um
selector, que filtra no corretor. Mensagens que este canal não quer nunca cruzam a rede. Em uma fila partilhada, é a diferença entre ler cem mensagens por dia e cem mil. - Uma fonte de base de dados decide o que devolve com a sua consulta.
- Uma fonte de ficheiro decide quais ficheiros pega com o seu padrão.
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.
| Valor | Formato |
|---|---|
hl7 | HL7 v2, o padrão delimitado por pipe. O padrão. |
hl7v3 | Documentos HL7 v3 e CDA, que são XML. |
x12 | ASC X12, utilizado para elegibilidade e reclamações. |
ncpdp | Padrão de telecomunicação NCPDP D.0 para reclamações de farmácia. |
script | NCPDP SCRIPT, prescrições eletrônicas. XML. |
dicom | Objetos de imagem DICOM. |
delimited | Texto delimitado CSV e outros. |
raw | Sem 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.
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:
x12: { arrives_as: xml }num canal X12 recebe esse XML e processa-o como o X12 que representa (a escolha Chega como do construtor);x12_as: xmlno destino envia o X12 como esse XML (a escolha Enviar como XML X12 do Mirth do construtor);perfuse x12 xml [file]eperfuse x12 from-xml [file]convertem na linha de comando.
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.
| Valor | Comportamento |
|---|---|
require | Recusar o interchange. O padrão. |
warn | Processá-lo e registrar a falha contra a mensagem. |
ignore | Nã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.
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ção | O que ela transporta |
|---|---|
835 | Aviso de remessa: o que foi pago, o que foi negado e os motivos de ajuste. |
275 | Anexos de reclamações: documentação clínica que apoia uma reclamação. |
277 | Status da reclamação, incluindo um pedido de documentação adicional do pagador. |
278 | Autorização prévia: o pedido de revisão e a decisão do pagador. |
999 | Confirmação funcional, que o Perfuse também gera. |
271 | Elegibilidade: se um paciente está coberto e os valores de copagamento, coinsurance, dedutível e fora de bolso, dentro e fora da rede. |
|---|---|
834 | Inscrição: membros adicionados, alterados e terminados, com cada linha de cobertura e suas datas. |
837 | Reclamaçõ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 chegou | O que significa | O que fazer |
|---|---|---|
HCR com ação A3 | O pagador considerou o pedido e não o certificará. | Apelar, ou mudar o plano de cuidados. |
Um segmento AAA | O 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:
- Nenhuma decisão é atualizada. A certificação parcial permanece parcial, e um pedido que o pagador se recusou a considerar não se torna uma recusa. Ambas as colapsos estão disponíveis no mapeamento óbvio e ambas estão erradas na direção dispendiosa.
- Nada é inventado para preencher um campo obrigatório. Um evento certificado sem número de autorização é relatado como tal, e não recebe um número plausível — um número fabricado produz uma reclamação que é negada posteriormente por um motivo que ninguém pode rastrear.
- Uma decisão transportada apenas no nível da linha é usada. Um pagador que responde por serviço pode deixar o evento sem uma decisão própria; ler apenas o nível do evento relatou que como pendente, e uma prática aguarda uma resposta que já tem enquanto a aprovação expira. Onde as linhas discordam, a menos favorável vence, porque um evento com uma linha recusada não é uma aprovação.
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 errado | Onde 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.
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.
- A carga útil está em
BDS, nãoBIN.BDS01nomeia um filtro,ASCouB64.BDS02é o comprimento eBDS03os dados. - A carga útil é uma entidade MIME, com cabeçalhos que dizem o que o documento é e um corpo base64. Com
B64a entidade em si é base64 também.
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.
- Onde as duas guias concordam, o Perfuse segue-as.
- Onde elas diferem, ele satisfaz ambas se puder.
CAT02éHLpara um documento HL7, que o esMD usa, eIApara uma imagem, que a UnitedHealthcare usa. - Caso contrário, envia o segmento opcional apenas quando lhe é dado o valor: o identificador de pedido de reembolso
REF*X1do esMD e a data de serviçoDTP*472da UnitedHealthcare.
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ê.
- O que é assinado. Todo o documento, exceto os participantes
legalAuthenticatoreauthenticator, para que cada signatário posterior deixe as assinaturas anteriores intactas. A assinatura diz isso com uma transformação XPath Filter 2.0 que qualquer biblioteca de assinatura XML pode avaliar. - Onde vai. Em Base64 em
sdtc:signatureTextno participante que assina, com uma descrição de texto simples de uma linha. O signatário é o autenticador legal do documento se tiver um autenticador não assinado, caso contrário um novoauthenticator. - O que afirma. O certificado do signatário, o tempo em UTC, um papel da taxonomia de fornecedores NUCC e um propósito da ASTM E1762. O propósito é *Assinatura do autor* para um autenticador legal e *Coautoria* caso contrário, como no exemplo do próprio guia.
- Quanto tempo dura. O guia pede XAdES-X-L, que transporta tudo o que um pagador precisa para verificar a assinatura anos depois sem alcançar a rede. Isso é o caminho de certificação, uma resposta OCSP ou CRL do CA, e duas marcas de tempo de uma autoridade de marca de tempo. O Perfuse busca os dados de revogação nos endereços do certificado e as marcas de tempo em
-tsa-url.
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:
- Um comprimento declarado que não corresponde aos dados é recusado, nomeando ambos os números. A pergunta útil é se a contagem do remetente estava errada ou se o ficheiro foi truncado durante o trânsito, e apenas os dois números respondem a isso.
BDS, o segmento binário006020, mantém a sua contagem emBDS02e os seus dados emBDS03. Foi recusado até que pudesse ser confirmado a partir de uma fonte publicada em vez de ser lembrado, e duas fontes agora confirmam: a tabelaBDSdo guia de acompanhamento esMD da CMS e o guia da UnitedHealthcare.
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.
| v2 | FHIR |
|---|---|
ADT | Paciente, 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. |
ORU | Relató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, OMG | ServiçoSolicitado. |
SIU | Compromisso, com o paciente, os profissionais de saúde de AIP e os locais de AIL. |
MDM | Referência de Documento que transporta o documento. |
VXU | Imunizaçã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.
- Estado. O estado do preenchedor em
SCH-25decide, e o evento de gatilho é usado apenas quando isso está vazio. - Slots bloqueados. Um slot bloqueado não é um compromisso com um paciente e não produz nenhum.
- Hora de início. É lida de
AIS,AIG,AILouAIPprimeiro, entãoSCH-11, porque a versão 2.5 moveu e as fontes de alimentação não se moveram todas com ela. - Durações. Uma duração em uma unidade que o Perfuse não reconhece é deixada de fora, não adivinhada.
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.
- Embedded documents. An embedded PDF, TIFF or JPEG (
ED) is carried byte for byte. Base64 that is not valid base64 is refused rather than passed on. - Types. The document type in
TXA-2is kept as sent and, where there is a clear equivalent, given the LOINC code US Core uses. - Signing. A note nobody has signed is
preliminary, andT11makes the documententered-in-error. - No content. A notification with no content (
T01,T03and the other odd-numbered events) produces no DocumentReference. FHIR requires content, and an empty attachment would look like the note while saying nothing.
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.
- Doses recusadas. Uma dose recusada ou não administrada (
RXA-20REouNA) énot-done, com o motivo deRXA-18. - Exclusões. Uma exclusão (
RXA-21D) éentered-in-error. - Registos históricos. Um registo transcrito de outro local (
RXA-9diferente de00) não é uma fonte primária. - Quantidades desconhecidas. Uma quantidade de
999significa desconhecida, não 999. - Rotas e locais. Cada dose assume a rota e o local do
RXRseguinte, por isso uma mensagem com duas doses não fornece a rota da primeira dose para a segunda.
Entrada desconfortável. Cada uma dessas é relatada nas notas em vez de decidida silenciosamente:
- Identificadores.
PID-2ePID-4, retirados após a v2.7, mas ainda enviados, são mantidos comoPID-3.CX.7eCX.8se tornam
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.
- Fusões.
MRGem um evento de fusão (A40e seus parentes) envia o registo aposentado também, inativo, comPatient.linkem ambos os sentidos. Em qualquer
outro evento, como um A08, nada é fundido e um aviso diz que o identificador anterior ainda está ativo.
- Tempos. Um tempo de nascimento em
PID-7vai para a extensãopatient-birthTime. Um carimbo de data/hora sem offset assume o fuso horário configurado,
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.
- Resultados. Repetições de um resultado de texto são unidas com quebras de linha. Um resultado
ED, ou um resultado codificado cujo valor é claramente Base64, se torna uma
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".
- Visitas. Um
A08com uma data de alta (PV1-45) é um encontro concluído. Uma classe de paciente ausente ou desconhecida é o sabor nulo
UNK, porque R4 exige uma classe.
- Segmentos Z são nomeados em um aviso, desde que não há um mapa padrão para eles.
- Nomes. Quando o remetente divide um nome de família (
XPN.1,XCN.2) nas suas partes - um prefixo de sobrenome e um sobrenome, o próprio e o do parceiro, como os nomes holandeses e flamengos são enviados -familyé o nome completo e as partes vão nas extensões de nome de família do HL7 (humanname-own-prefix,-own-name,-partner-prefix,-partner-name). - Procedimentos.
PR1torna-se um Procedimento com statusunknown, desde que um ADT não diz se foi feito ou planejado; o anestesista (PR1-8) e o cirurgião (PR1-11) são realizadores com funções SNOMED CT. Um código OPS também obtém sua categoria SNOMED CT do seu capítulo, pelo mapaOPS-SNOMED-Categoryda HL7 Deutschland, que o ISiK exige.
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 v6 | De | Como |
|---|---|---|
| Dados Demográficos do Paciente | PID | Nome, 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 Encontro | PV1 | Encontro com tipo, classe, período, localização e participantes |
| Informações de Instalação | PV1-3 | Localização, com a instalação como sua Organização gerenciadora |
| Problemas, Data de Início | DG1 | Condição (diagnóstico de encontro). DG1-5 é o início, como o mapa HL7 v2 para FHIR o tem |
| Alergias e Intolerâncias, Reação | AL1 | AlergiaIntolerância com categoria, criticidade e reação |
| Laboratório | ORU | Relatório de Diagnóstico, Observações, Espécime (de SPM), ServiceRequest |
| Pedidos | ORM, OML | ServiceRequest |
| Imunizações | VXU | Imunização |
| Notas Clínicas | MDM | DocumentReference |
| Membros da Equipe de Cuidados | PV1, TXA, DG1 | Profissional |
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:
- Registos marcados
entered-in-errorsão omitidos. - Uma condição resolvida é colocada sob doença passada, não problemas.
- Um pedido de medicamento que foi parado ou concluído é história, não um medicamento atual.
- As três secções que o IPS exige (problemas, alergias, medicamentos) estão sempre presentes. Quando uma delas não tem nada, a secção
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".
- Os profissionais de saúde, organizações, medicamentos e locais para os quais as entradas apontam são incluídos, para que o documento possa ser lido por si só.
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.
- Every one of the guide's fifteen sections is present, each with its own text, in the guide's order: advance directives,
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.
- A section the document did not have is said to be missing, never filled in. It goes out empty, with the coded reason
unavailable and the sentence "The sending document had no ... section". An empty allergy section must not read as "no known allergies".
- A section carried as text alone keeps its text and gets no entries. Prose is not turned into coded data. Functional
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.
- Coded entries become resources by the same rules as the ordinary conversion: allergies (US Core AllergyIntolerance),
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).
- Vital signs in FHIR's form. A systolic and a diastolic pressure taken together become one blood pressure panel
(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.
- Who and from where. The document's author becomes the Composition's author (a Practitioner, with the NPI when its check
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.
- Negation keeps its meaning. "No known allergies" (a negated allergy to any substance) is sent as SNOMED CT
716186003; a
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:
- A channel: a
cdadestination withwrite: transferposts each document's transfer summary to the FHIR server's
Bundle endpoint (url), or writes <document>.transfer.json to dir. In the channel builder: Emit › A PACIO transfer summary.
- The command line:
perfuse fhir transfer [-authority OID=URI] [-out dir] <document.xml>.... - The console: Documents, turn on Also make a PACIO transfer summary, and read the document.
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ópico | Dispara em | Filtros |
|---|---|---|
https://perfuse.health/fhir/SubscriptionTopic/encounter | Encontro criado ou atualizado | patient, status, class |
https://perfuse.health/fhir/SubscriptionTopic/appointment | Compromisso criado ou atualizado | patient, 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:
- An acknowledged change is never a lost notification. The notification is recorded in the same database transaction as the change it describes, and delivered from there, so it survives a restart. A test writes an Encounter, starts a new server on the same database, and checks the notification arrives.
- Notifications arrive in order, and gaps are visible. Event 2 is not sent before event 1 is accepted, and each notification carries the running count, so a receiver can tell when it has missed one.
- The server decides when a subscription is active. A new subscription is
requested, and becomesactiveonly when the endpoint accepts a handshake. A client that asks foractivegetsrequested. A refused handshake is tried again four times over about fifteen seconds before the subscription is anerror: it goes out the moment the subscription is stored, often before the client that created it is listening. - A full-resource notification carries the version that changed. A discharge notification carries the discharge, not whatever the Encounter had become by the time delivery succeeded.
- Failure is bounded. A refused delivery is retried with a growing delay. After ten consecutive failures the subscription goes to
error: later changes are counted but not queued, and updating the subscription resumes delivery from the oldest held notification. The count then shows how many were missed.
O que um cliente pode fazer o servidor fazer é limitado deliberadamente:
- Os endpoints devem ser
httpsa menos que o operador passe-fhir-subscriptions-allow-http, que é para um receptor de teste. - A política de saída é aplicada quando uma assinatura é criada, novamente a cada entrega e no endereço que cada conexão atinge efetivamente (para que um nome que muda o que resolve entre a verificação e a conexão ainda seja recusado); redirecionamentos não são seguidos.
- A carga útil padrão é
id-only, que diz o que foi alterado e permite que o receptor o obtenha com suas próprias credenciais. - Nada do que o receptor envia de volta é mostrado a alguém, apenas seu código de status.
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:
- canais diferentes de
rest-hook - batimentos cardíacos
- notificações de exclusão
- as operações
$statuse$events
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.
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}
- O destino está em entrega, sob Arquivos DICOMweb.
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ço | Ator | Transações |
|---|---|---|
/xds/repository | Repositório de Documentos | ITI-41 Fornecer e Registrar Conjunto de Documentos-b, ITI-43 Recuperar Conjunto de Documentos |
/xds/registry | Registro de Documentos | ITI-18 Consulta de Registro Armazenada (todas as treze consultas armazenadas), ITI-42 Registrar Conjunto de Documentos-b |
/xca/gateway | Gateway de Resposta XCA | ITI-38 Consulta de Gateway Cruzado, ITI-39 Recuperar Gateway Cruzado, com -xds-home-community urn:oid:... |
/mhd | Recipiente e Responder de Documentos MHD | ITI-65 Fornecer Pacote de Documentos, ITI-66 Encontrar Listas, ITI-67 Encontrar Referências de Documentos, ITI-68 Recuperar Documento |
/mhd/Patient | Fornecedor PDQm e Gerente PIXm | ITI-78 Consulta de Demografia de Paciente, ITI-83 Patient/$ihe-pix, a partir do armazenamento de Pacientes do FHIR |
/pixv3 | Gerente PIX (HL7 v3) | ITI-44 Alimentação de Identidade de Paciente HL7 V3, ITI-45 Consulta PIXV3, a partir do índice de pacientes (-mpi) |
/pdqv3 | Fornecedor 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:
periodStarteperiodEnd: obrigatórios. Uma data significa o dia todo.reportType:summary,subjectousubject-list.subject:Patient/<id>.reporter:Organization/<id>. Quando está ausente, o relatório contém uma Organização nomeada porserve -measure-reporter.measure: uma Medida enviada inline, como um parâmetro POST.
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:
- 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.
- 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.
- 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óprios | Colocados à frente de um revisor com a pessoa certa | Perdidos | Ligações erradas | |
|---|---|---|---|---|
| Ligação automática desligada (o predefinido) | 0 | 2.649 de 3.000 | 351 | 0 |
| Ligada, pesos predefinidos | 1.637 | 1.012 | 351 | 0 |
| Ligada, pesos estimados a partir dos registos | 1.622 | 1.070 | 308 | 0 |
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.
8.16 Ligações e Cartões de Saúde SMART
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.
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:
| Valor | O que é enviado |
|---|---|
none | Nada. O padrão. |
999 | Acuso de recibo de implementação. Substitui o 997 para transações HIPAA. |
997 | Acuso de recibo funcional. Mais antigo, e ainda o que muitas conexões de pagador esperam. |
ta1 | Acuso 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.
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
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:
| Chave | O que faz |
|---|---|
enabled | Se as mensagens com falha são colocadas em fila. |
max_attempts | Quantas vezes tentar antes de desistir. |
backoff | Aguarde antes da primeira retentativa. |
max_backoff | Teto no tempo de espera crescente. |
max_depth | Maior número de mensagens a manter. Não definido significa sem limite. |
retain_hours | Quanto 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.
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 responde | Registos 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 gravidade | Falhou, com a localização, código e texto de cada ERR no erro. |
| AR ou CR | Falhou, da mesma forma. |
| Uma falha SOAP (senha incorreta, mensagem muito grande) | Falhou, com o motivo do registo. |
| Algo que não é uma mensagem HL7 | Falhou. |
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
| Resultado | Significado |
|---|---|
Delivered | O destino aceitou a mensagem. Para MLLP, um acuso de receção positivo foi recebido. |
Queued | A entrega falhou e a mensagem será repetida. |
Failed | A entrega falhou e não será repetida, seja porque a colocação em fila está desativada ou as tentativas estão esgotadas. |
Filtered | O 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.
framing | O que escreve |
|---|---|
mllp | 0x0b antes, 0x1c 0x0d depois. O mesmo enquadramento que um destino MLLP utiliza. |
delimited | Um delimiter após cada mensagem, e um start_block opcional antes dela. |
fixed | Registos preenchidos ou truncados para record_length. |
length | Um prefixo length_bytes. big_endian e length_includes_header ambos têm duas convenções no mundo e a diferença é silenciosa. |
whole | Uma 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.
- Numa origem, o ficheiro inteiro, objeto, anexo de e-mail ou corpo da solicitação é
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.
- Num destino, o que teria sido entregue é encriptado (para qualquer um de
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.
| Confirmado | Presente downstream depois | Confirmado mas faltando |
|---|---|---|
| 255 | 255 | 0 |
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ós | Confirmado | Presente downstream | Perdido |
|---|---|---|---|
| 5 | 5 | 1 | 4 |
| 25 | 25 | 1 | 24 |
| 75 | 75 | 2 | 73 |
| 110 | 110 | 2 | 108 |
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
| Tipo | Dispara quando |
|---|---|
error-rate | As falhas excedem uma proporção do tráfego. |
queue-depth | Uma fila tem mais de N mensagens esperando. |
queue-age | A mensagem mais antiga na fila é mais antiga do que uma duração. |
queue-stuck | Uma fila não está drenando nada. |
no-traffic | Nada chegou por um período fixo. |
below-rhythm | O tráfego está bem abaixo do que essa fonte normalmente faz *neste momento da semana*. |
channel-down | Um canal que deveria estar em execução não está. |
script-errors | Um script está falhando. |
rows-quarantined | Uma fonte de banco de dados está colocando linhas de lado. |
slow-delivery | As entregas estão tendo sucesso, mas estão demorando muito. |
contract | Uma mensagem viola o contrato declarado do canal. |
phi-volume | Um canal carrega várias vezes sua taxa usual para a hora. |
phi-after-hours | Um canal que só carrega tráfego diurno carrega algum à noite. |
phi-new-destination | Um canal entrega para um endereço que nunca enviou antes. |
phi-bulk-reads | Uma 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.
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:
below-rhythm— a fonte parou quando não deveria estar quieta.error-rate— as mensagens estão chegando e falhando.queue-age— algo está preso, em vez de apenas ocupado.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.
- Explosões (
phi-volume). A taxa de cada canal é comparada com sua própria história na mesma hora do dia, então uma manhã movimentada não é notícia. O limiar é um múltiplo da taxa usual, três por padrão. Uma explosão geralmente é uma fila de espera sendo liberada após uma interrupção, e também é o que os registros sendo extraídos por meio de um feed parecem. - Tráfego noturno em um canal diurno (
phi-after-hours). Um canal é considerado diurno quando menos de 2 por cento do que ele carregou caiu fora das 07:00 às 19:00, no fuso horário do servidor. - Um novo destino (
phi-new-destination). O endereço é o que o destino nomeia: um host e porta, uma URL, uma pasta. Renomear um destino não é notícia; apontar um para um novo host é. Os endereços que cada canal enviou são mantidos emaccess-watch.jsonao lado do banco de dados, então um destino alterado enquanto o servidor estava desligado ainda é relatado. - Leituras em massa (
phi-bulk-reads). Contado a partir do rastro de auditoria: mensagens abertas, pacientes procurados ou visualizados (PDQm, PIXm, busca de identidade), documentos e imagens lidos (XDS, MHD, DICOMweb), autorizações anteriores lidas, resumos e visualizações executados. Ler o mesmo registro novamente não conta duas vezes. O limiar é quantos registros diferentes em um minuto, dez por padrão, por uma conta de um endereço.
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.
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:
- O que o filtro leu. Quais campos ele olhou e quais valores ele encontrou. Um filtro que rejeita tudo normalmente lê um caminho que não existe nesta fonte de dados, e este o nomeia.
- Cada transformação. O que ele alterou, de quê para quê.
- O que cada destino decidiu. Se aceitaria a mensagem e por quê não, se não a aceitasse.
- A saída. A mensagem como cada destino a enviaria.
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
| Resultado | Significado |
|---|---|
changed | O passo foi executado e modificou a mensagem. |
no-effect | O passo foi executado, e a mensagem não foi alterada. |
skipped | A condição when do passo foi falsa, por isso ele não foi executado. |
failed | O 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.
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:
- Dispara eventos nos proporções realmente observadas, com pelo menos um de cada um, para que um evento raro ainda apareça.
- Campos preenchidos nas taxas em que realmente são — portanto, o caso em que um campo está *ausente* é testado, o que é o caso que quebra as coisas.
- Repetições onde ocorrem repetições, estrutura composta onde ocorre.
- Códigos extraídos das tabelas de códigos realmente vistas.
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.
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êiner | Verificações | O que encontrou |
|---|---|---|
| Keycloak 26 | web/e2e-saml/, e fixtures internal/saml | Um 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 Entra | Testes e fixtures internal/saml ao vivo | Dois 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 FHIR | go test ./internal/engine/ -run HAPI | Um 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 |
| ActiveMQ | go test ./internal/engine/ -run RealBroker | Correto, 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 cliente | go test ./internal/engine/ -run ClientCertificate | Correto |
| Orthanc (um PACS real) | go test ./internal/engine/ -run RealPACS | Correto. Um C-STORE chega e o nome do paciente, identificador, data de estudo, modalidade e classe SOP todos sobrevivem |
| PostgreSQL | go test ./internal/engine/ -run RealPostgres | Correto, 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-server | go test ./internal/engine/ -run OpenSSHServer | Correto. 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.2 | go test ./internal/mirth/ -run RealMirth | Correto 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:
- SMB contra uma partilha do Windows real — o código do protocolo está completo e testado para segurança de caminho e tratamento de argumentos, mas nenhum teste abre um soquete para um servidor associado a um domínio.
- Uma porta serial real.
- O importador Mirth contra XML real produzido pelo Mirth. Testado contra o Mirth 4.5.2 em um contêiner, e a descoberta foi sobre este repositório: o único fixture de migração aqui foi escrito à mão e o Mirth não o carrega — ele armazena o canal como inválido e descarta todos os conectores. O que foi resolvido é que os atributos
versionque o Mirth real escreve em cada elemento analisam o mesmo canal, então eles não são um perigo; o que não foi resolvido é tudo o mais que uma exportação real contém. - SAML contra um provedor de identidade comercial hospedado. O Keycloak é verificado; um provedor prova que uma implementação corresponde a um fornecedor.
- Uma reclamação NCPDP por meio de um comutador de farmácia real.
- Uma mensagem SCRIPT por meio do Surescripts, onde a certificação é um processo comercial em vez de técnico.
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.
| Resultado | Contagem |
|---|---|
| Recursos validados com nenhum achado | 13.723 |
| Recursos relatados como inválidos | 0 |
| Arquivos recusados como um tipo de recurso não implementado | 753 |
| Entradas de pacote puladas como um tipo não implementado | 1.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ção | Do Administrador | O que é transferido |
|---|---|---|
| Um canal | Exportar Canal | O canal |
| Um grupo de canais | Exportar Grupo | Cada canal nele, cada um mantendo o grupo |
| Modelos de código | Exportar Modelos de Código | Cada biblioteca como um arquivo de script |
| Uma cópia de segurança do servidor | Backup de Configuração, ou GET /api/server/configuration | Todos 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.
15.4.1 Quatro números, não uma taxa de aprovação
| Resultado | Significado |
|---|---|
| Idêntico | Byte por byte o mesmo. |
| Apenas cosmético | Difere em maneiras que não carregam informações — campos vazios finais, um terminador final. |
| Diferente | O valor de um campo é diferente. |
| Não executaria | O 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
- Importe os canais e resolva qualquer coisa relatada como ilegível.
- Para cada canal, revise os avisos. A maioria será de scripts.
- Exporte alguns milhares de pares de mensagens do Mirth para o canal mais movimentado e execute a comparação.
- Trabalhe nos resultados. Os sistemáticos são uma decisão cada.
- Execute novamente até que as únicas diferenças sejam as que você decidiu que estão corretas.
- 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.
- 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.
| Pacote | Classes |
|---|---|
java.util | ArrayList, 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.lang | String, StringBuilder, StringBuffer, Integer, Long, Short, Byte, Double, Float, Boolean, Math, System (tempo e separador de linha apenas) |
java.text, java.math, java.net, java.nio | SimpleDateFormat e DateFormat (letras de padrão do Mirth), BigDecimal (como um double), URLEncoder, URLDecoder, StandardCharsets |
| Apache Commons | lang3.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
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
| API | O que serve | Guias | Activado por |
|---|---|---|---|
| Acesso ao Paciente | As reclamações, dados clínicos e autorizações anteriores de um membro, para um aplicativo que ele escolhe | CARIN Blue Button 2.2.0, PDex 2.2.0, US Core, SMART App Launch | -fhir e um emissor SMART (-smart-issuer) |
| Acesso ao Prestador | O mesmo para os membros atribuídos a um prestador, em massa | PDex 2.2.0, Da Vinci ATR 2.1.0, Bulk Data | -fhir-payer-apis e -fhir-bulk-export |
| Payer-to-Payer | O registo de um membro para outro pagador, após correspondência | HRex 1.2.0 $member-match, PDex 2.2.0 | -fhir-payer-apis |
| Autorização Prévia | O que uma ordem precisa, a documentação, então o pedido e a decisão | Da 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:
- 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);
- a partir do registro do chamador:
davinci_version: "2.1"em um cliente SMART (-smart-clients) ou um cliente CDS (-cds-clients); - 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:
billing_codes: os códigos a faturar.details: limites e custos, comoallowed-periodouin-network-copay.contact: quem contactar.expiry_days: quanto tempo a resposta é válida.depends_on: códigos de outras ordens que a resposta depende, para que o EHR pergunte novamente se elas mudarem.doc_purpose: para que serve a documentação (withclaim,withorder,retain-doc).withpaé recusado, porque a própria invariant crd-ci-q4 do CRD 2.2.1 o rejeita.
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ê:
- um paciente que não é membro recebe
no-member-found; - um membro cuja cobertura não corresponde recebe
coverage-not-found; - uma autorização prévia já aprovada para o serviço (um ClaimResponse com um
preAuthRef) faz com que a resposta sejasatisfied,
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:
- O sistema de identificador. CARIN exige que o identificador do membro nomeie o namespace do pagador.
-systemé obrigatório; não há padrão, porque um padrão daria a todos os pagadores que usam Perfuse o mesmo namespace. - O status de rede. Nenhuma transação diz se o provedor de faturamento está na rede, e isso decide o que o membro paga. Sem
-networko status de pagamento do benefício éothere a conversão anota o motivo. - Uma reclamação que o 835 não menciona. Uma ExplanationOfBenefit CARIN é uma reclamação julgada. Sem o 835 não há número de reclamação do pagador, não há pagamento e não há responsabilidade do membro, então a reclamação é relatada como pulada e não convertida.
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:
POST /fhir/Patient/$member-match— correspondência de membros HRex. Os identificadores de cobertura se restringem a alguns candidatos, e o nome da família e a data de nascimento devem concordar; um nome dado é comparado por inicial, e gênero apenas quando ambos os lados o declaram. Mais de um candidato sobrevivente não é uma correspondência, e a resposta é 422 em vez de uma suposição, porque uma suposição divulga as reclamações de um estranho. Um Consentimento ativo que permita a divulgação é necessário, desde que a API Payer-to-Payer seja opt-in para o membro;-fhir-member-match-without-consentdesativa isso para testes.GETouPOST /fhir/Group/{id}/$davinci-data-export— a exportação em massa Da Vinci dos membros atuais de um Grupo.exportTypeescolhe a audiência:hl7.fhir.us.davinci-pdex#provider-downloadou#provider-deltapara Acesso ao Fornecedor,#payertopayerpara Payer-to-Payer.GET /fhir/Group/{id}/$export— a exportação de dados em massa padrão do Grupo, tratada como Acesso ao Fornecedor.
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ção | Resposta |
|---|---|
PAInitiationRequest | Closed 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. |
PARequest | Decidido 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. |
PAAppealRequest | Um caso negado decidido novamente, com base no motivo em PANote (um recurso sem um é solicitado). |
PACancelRequest | Approved 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:
| Transporte | O que é enviado | Autenticação |
|---|---|---|
x12 (padrão) | A 278 enviada como application/edi-x12; a resposta é o corpo da resposta | Um token de portador, OAuth, Autenticação Básica HTTP, um certificado de cliente |
core-soap | O 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 MTOM | vC2.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-mime | O envelope CAQH CORE vC2.2.0 HTTP MIME multipart, o payload como uma parte de arquivo | O nome de usuário e a senha do envelope, ou um certificado de cliente |
sftp | Cada 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:
| Status | Significado |
|---|---|
| Pronto aqui | O Perfuse fornece e está ativado. |
| Pronto, com uma lacuna | Está ativado e parte do critério está fora dele (nomeado na tela). |
| Construído, não ativado | O Perfuse fornece; a tela nomeia a configuração ou sinalizador que o ativa. |
| Sua tarefa | A parte da organização: um acordo, uma certificação, publicação no Diretório Nacional de Prestadores. |
| Não construído | O software faria e o Perfuse não. |
O que os quatro em vigor precisam deste servidor:
| Critério | No Perfuse | Ativar |
|---|---|---|
| 13 APIs FHIR, US Core, Dados em Massa | O endpoint FHIR com seu CapabilityStatement e $export | -fhir, -fhir-bulk-export |
| 14 Documentos como anexos FHIR | DocumentReference com Binário e IHE MHD sobre o registro XDS | -fhir (MHD também -xds) |
| 15 Notificações de encontro e compromisso | Assinaturas baseadas em tópicos (R5 Backport para R4) a partir de feeds ADT e SIU | -fhir-subscriptions |
| 16 Localizador de registros | O 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.
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ção | Pode |
|---|---|
| Monitor | Verificar 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. |
| Visualizador | Também ler mensagens, arquivos de canal, rastros e log de atividade. |
| Operador | Também reenviar: reprocessar uma mensagem, reproduzir um canal e tentar novamente entregas em fila. |
| Editor | Também criar e alterar canais e executar comparações. |
| Administrador | També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:
- Tokens da API do Perfuse, criados em Utilizadores → Credenciais de máquina ou com
perfuse token create. Cada um possui um papel e pode ser
limitado a Grupos FHIR. Este é o padrão quando nenhum servidor de autorização SMART está configurado.
- Tokens de acesso SMART, do próprio servidor de autorização do Perfuse (
-smart-clients) ou de um servidor externo (-smart-issuer). Cada
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:
- Escreve por minuto a partir de um cliente (
-fhir-writes-per-minute): cria, atualiza e elimina a partir de um endereço de cliente. Acima disso, uma escrita é respondida com 429 eRetry-After: 60. Leituras e pesquisas, incluindo pesquisas por POST, nunca são contadas. - Mais recursos mantidos (
-fhir-max-resources): além disso, novos recursos são recusados com 507, enquanto atualizações e eliminações ainda funcionam.
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>" } } } }
| Ferramenta | Papel | O que faz |
|---|---|---|
server_status, list_channels, queue, alerts | monitor | Se as coisas funcionam, sem conteúdo de mensagem |
get_channel, search_messages, get_message, find_patient, fhir_search | visualizador | Canais, mensagens (com conteúdo), mensagens de um paciente em vários formatos, uma pesquisa FHIR |
retry_delivery, reprocess_message | operador, e mcp:write | Repetir uma entrega em fila, enviar uma mensagem através do seu canal novamente |
start_channel, stop_channel | administrador, e mcp:write | Iniciar 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ém | Encontrado por |
|---|---|
| Mensagens | o í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 entrega | lendo os identificadores de cada mensagem enfileirada |
| O armazém FHIR | os recursos de Paciente que transportam um identificador, e cada recurso cujas referências indexadas apontam para um |
| Pedidos de autorização prévia | os identificadores do paciente do pedido |
| O índice de paciente | o 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.
- Acesso e portabilidade: Transferir cópia fornece um ficheiro zip: cada mensagem tal como recebida com o seu registo, cada recurso FHIR com todas as versões armazenadas, pedidos de autorização anteriores e respostas, e os registos do índice do paciente, tudo em JSON, com um ficheiro README que explica o que cada parte é. Marcar como respondido fecha-o.
- Eliminação: um segundo administrador aprova-a (quem a registou não pode).
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).
- Restrição: registada como uma ordem judicial, de modo que nada é eliminado ou expira enquanto dura.
- Recusar fecha um pedido com o seu motivo, que deve ser comunicado à pessoa.
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.
- Canais: quantos canais o inquilino pode ter. Criar um mais é recusado, com a contagem e o limite.
- Mensagens por minuto: quantas mensagens os canais juntos podem receber em um minuto.
- Armazenamento: quanto conteúdo de mensagem armazenada ele pode manter, em megabytes.
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:
- Apenas o certificado configurado é confiável. Um certificado transportado dentro de uma resposta nunca é usado. Um atacante que pode enviar um documento também pode colocar seu próprio certificado nele, e um verificador que o lê é qualquer um que possa autenticar como qualquer um.
- Uma resposta tem que responder a um acesso iniciado por este servidor. O Perfuse lembra do pedido que enviou e recusa uma resposta que nomeia qualquer outra coisa, ou nomeia um pedido que já foi respondido. Sem essa verificação, uma resposta válida é um token de portador para quem a possui: alguém acessa como ele mesmo, mantém a resposta e a publica no seu navegador, e você então está dentro da conta dele com o registro de auditoria gravando o nome dele.
- Os acessos iniciados no provedor de identidade estão, portanto, desativados por padrão. Ative *Aceitar acessos iniciados no provedor de identidade* apenas se precisar de um portal de tiles, e sabendo que é o que torna o acima possível.
- O atributo de grupo não tem um valor padrão e é necessário. Entra envia
groups, Okta envia o que a aplicação foi configurada para enviar, ADFS envia um URI de reclamação. Uma suposição produziria um acesso que funciona e não concede nada a ninguém. Se um acesso for recusado por não ter um papel, o log do servidor nomeia os atributos que chegaram — o que geralmente é a resposta completa. - A URL de resposta deve corresponder exatamente ao que está registrado no provedor. Uma resposta diz para onde foi destinada e uma resposta endereçada em outro lugar é recusada, porque aceitá-la significaria aceitar uma resposta destinada a um serviço diferente.
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.
| Provedor | Geralmente envia | Notas |
|---|---|---|
| Keycloak | groups | Precisa de um mapeador de associação de grupo adicionado ao cliente. |
| Entra ID | um URI de reclamação que termina /claims/groups | Envia IDs de objeto de grupo, a menos que a aplicação seja configurada para enviar nomes. Mapeie os IDs ou altere o provedor. |
| Okta | o que a aplicação foi configurada para enviar | Comumente groups, com um filtro decidindo quais são enviados. |
| ADFS | um URI de reclamação | Assina 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.
- Desabilitar uma conta encerra suas sessões imediatamente, e o servidor verifica que nenhuma sobreviveu antes de responder. Um provedor nunca é informado de que uma conta foi desabilitada quando não foi, porque um provedor não tenta novamente o que foi informado que teve sucesso.
- Excluir desabilita primeiro, então exclui, para que uma falha no meio do processo deixe uma conta com a qual ninguém possa fazer login. O histórico de auditoria de uma conta removida é mantido.
- A função vem dos grupos ou funções de uma pessoa, combinados por nome: um grupo cujo nome contém *admin*, *editor*, *operador*, *visualizador* (ou *somente leitura*) ou *monitor* concede essa função, então
APP-Perfuse-EditorePerfuse Operatorsfuncionam como estão nomeados. Qualquer outra coisa recebe-scim-default-role, visualizador a menos que definido de outra forma. Plataforma nunca pode ser concedida dessa forma. - Não há senhas. Uma conta criada pelo SCIM faz login por meio do provedor de identidade; uma segunda senha que ninguém upstream sabe sobre sobreviveria a uma desabilitação lá.
/scim/v2/ServiceProviderConfigdiz o que é suportado: criar, ler, substituir, corrigir e excluir Usuários, e filtros até 200 resultados. Operações em massa, classificação e ETags não são.
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.
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
- O agente responde a GET, GETNEXT e GETBULK, e apenas a partir das redes em
-snmp-allow: a comunidade v2c é uma palavra-passe enviada em claro, por isso nunca está aberta a todos. Uma comunidade com menos de 6 caracteres, oupublic/private, impede que o servidor inicie. - Ele serve o grupo do sistema (sysDescr, sysUpTime, sysName a partir do rótulo da frota, sysContact, sysLocation), totais sob
BASE.1(canais, em execução, quebrados, recebidos, entregues, falhados, enfileirados) e uma tabela de canais sobBASE.2.1(nome, em execução ou parado, recebidos, entregues, falhados, enfileirados, idade da mensagem enfileirada mais antiga). Os números são os mesmos que o painel e/metricsmostram. - As armadilhas vão para todos os gestores em
-snmp-traps:BASE.0.1um alerta disparou,BASE.0.2resolveu, transportando o tipo de alerta, gravidade, canal, destino e resumo. Nunca conteúdo de mensagem. Um alerta reconhecido não envia armadilha. BASEé1.3.6.1.4.1.8072.9999.9999.16(espaço experimental do Net-SNMP) a menos que-snmp-base-oido coloque sob o seu próprio número de empresa. Transferir o MIB na página de Definições (ouGET /api/snmp/mib) fornece um MIB para a base em uso; o mesmo painel diz se o agente está respondendo e quantas armadilhas foram enviadas.
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.
active-passive: o líder executa todos os canais e todos os trabalhos que devem ser executados uma vez (notificações de assinatura do FHIR). Os outros esperam. O mais simples de raciocinar e o que um site com um servidor ocupado e um de reserva deseja.active-active: os canais são distribuídos pelos servidores ativos, mais ou menos uniformemente. Um servidor que para transfere os seus canais para os restantes; um que se junta assume a sua parte à medida que os canais ficam livres, um de cada vez. Canais que encaminham uns para os outros (um destino de canal) são executados em um servidor e se movem juntos, porque o encaminhamento acontece dentro de um servidor. Um administrador pode mover um canal manualmente a partir de Monitor → Frota; ele permanece onde foi colocado enquanto esse servidor estiver vivo.
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:
| Teste | Mensagens | Respondidas mas perdidas | Duplicados | Tempo 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 meio | 2.000 | 0 | 0 | 15 s |
| Um líder Linux cortado do banco de dados (firewall), seu processo deixado em execução | 3.000 | 0 | 1 | 16 s |
| Um líder Windows cortado do banco de dados | 3.000 | 0 | 0 | 20 s |
| O líder morto enquanto um servidor tinha seu relógio 2 minutos à frente e outro 90 segundos atrasado | 2.000 | 0 | 0 | 18 s |
| Ativo-ativo, quatro fontes de dados sobre três servidores, um morto e trazido de volta | 6.000 | 0 | 2 | 24 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.
-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:
- O mesmo sal sempre produz o mesmo corpus, então um corpus compartilhado pode ser regenerado em vez de arquivado.
- Mantenha o sal em segredo. Pseudônimos são derivados de valores reais, então qualquer pessoa que detenha o sal pode confirmar uma suposição sobre quem um registro se refere.
-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.
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:
-measure FILE, or-measure example:IDfor a shipped example: required.-exampleslists the examples.-period-startand-period-end: required.-type summary|subject|subject-list.-subject Patient/ID.-reporter NAME.-o FILE.
Veja medidas de qualidade digitais.
19.6.5 Flags FHIR em perfuse serve
| Flag | Efeito |
|---|---|
-fhir | Servir o endpoint FHIR em /fhir. Ativado por predefinição. |
-fhir-version | A versão servida. R4 por predefinição. |
-fhir-read-only | Recusar escritas. |
-fhir-api-tokens | Com SMART configurado, aceitar tokens de API do Perfuse, bem como tokens SMART (desativado por predefinição; também em Configurações → FHIR). |
-fhir-bulk-export | Ativar $export. Desativado por predefinição. |
-fhir-subscriptions | Ativar 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-http | Permitir que as assinaturas entreguem para http simples. Para um receptor de teste, nunca para dados de paciente em uma rede. |
-fhir-patient-directory-search | Permitir 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-declares | Guias 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
| Option | Takes | Default | What it does | In the console |
|---|---|---|---|---|
-addr | string | 127.0.0.1:8080, or 127.0.0.1:8443 with -tls-cert | address to serve the interface on | — |
-alert-severity | string | warning | minimum severity to send to the webhook: warning or critical | Settings › Alerts › Delivery: Only send alerts at least this serious |
-alert-webhook | string | — | 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 content | Settings › Alerts › Delivery: Send alerts to this address |
-alerts | string | — | 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-egress | on/off | — | permit destinations pointed at cloud instance metadata addresses, which hold this machine's credentials | Settings › Security › What may leave: Allow destinations at cloud instance metadata addresses |
-cds-clients | string | — | 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 |
-channels | string | ./channels | directory holding channel files | — |
-cluster | string | — | 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-lease | duration | 15s | how long a crashed server holds its work before another takes it over; renewed five times as often | — |
-crd-advisor-ca | string | — | 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-env | string | — | 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-url | string | — | 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 it | Settings › Payers › Decision service: Advice before submitting (CRD) |
-crd-rules | string | — | a Da Vinci CRD rules file: serve coverage requirements over CDS Hooks at /cds-services | Settings › Payers › Prior authorization: Coverage rules file (Da Vinci CRD) |
-dashboards | string | — | a file mapping directory groups and roles to the dashboard each opens on | Settings › Monitoring › Dashboards: Which dashboard each group opens on (file) |
-data | string | — | 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-version | string | 2.2 | the 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) | — |
-db | string | ./perfuse.db | database for users, messages and stored resources: a file, or a postgres:// URL for servers that share one store (a cluster) | — |
-demo-account | string | — | for a public demonstration server: username:password of a shared viewer account shown on the sign-in page | — |
-dicomweb-archive | string | — | keep imaging objects in this directory and serve them over DICOMweb (QIDO-RS, WADO-RS, WADO-URI, STOW-RS) at /dicomweb | Settings › Data › Imaging archive: Keep images in this folder and serve them over DICOMweb |
-dicomweb-cors | string | — | comma-separated browser origins, such as an OHIF viewer's, allowed to call /dicomweb | Settings › Data › Imaging archive: Browser origins allowed to call it |
-drain-for | duration | — | 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-agency | string | — | 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-responses | on/off | — | accept eCR Reportability Responses at the FHIR endpoint's $process-message, storing each as DocumentReference/<id> derived from the eICR it answers | Settings › Public health › Case reporting: Receive Reportability Responses |
-engine | on/off | true | run the channel engine in this process, so the interface can start, stop and monitor channels | — |
-epa-payer-id | string | — | 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-channel | string | — | 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 network | Settings › Payers › Drug formulary: Channel that sends later ePA decisions |
-fhir | on/off | true | serve a FHIR endpoint at /fhir | Settings › FHIR › The FHIR server: Serve a FHIR endpoint at /fhir |
-fhir-api-tokens | on/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-export | on/off | — | enable $export, which produces a file holding every record the FHIR endpoint serves | Settings › FHIR › Bulk data: Bulk Data export ($export) |
-fhir-declares | string | — | guides this FHIR server declares in its capability statement, comma-separated: a CapabilityStatement address, or Type=profile address | Settings › FHIR › Capability statement: Guides this server declares |
-fhir-max-resources | int | — | 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-consent | on/off | — | let $member-match answer without an active Consent; the Payer-to-Payer API is opt-in, so only for testing | Settings › Payers › CMS-0057-F: Answer $member-match without the member's consent |
-fhir-open | on/off | — | serve the FHIR endpoint with no authentication at all, exposing every stored record | Settings › FHIR › Access: Let anyone read the FHIR endpoint without signing in |
-fhir-patient-directory-search | on/off | — | let a token limited to one patient search the directory (practitioners, organisations, locations) within its scopes | Settings › FHIR › Access: Let a patient's app search the directory |
-fhir-payer-apis | on/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-export | Settings › Payers › CMS-0057-F: The CMS-0057-F payer APIs |
-fhir-read-only | on/off | — | refuse writes to the FHIR endpoint | Settings › FHIR › Access: Refuse writes to the FHIR endpoint |
-fhir-subscriptions | on/off | — | enable topic-based subscriptions, which send encounter and appointment notifications to URLs FHIR clients choose | Settings › FHIR › Notifications: FHIR subscriptions (encounter and appointment notifications) |
-fhir-subscriptions-allow-http | on/off | — | let subscriptions deliver to plain-http endpoints; for a test receiver, never for patient data on a network | Settings › FHIR › Notifications: Allow subscriptions to notify plain-HTTP addresses |
-fhir-version | string | 4.0.1 | FHIR release to serve: R4, R4B or R5 | Settings › FHIR › The FHIR server: FHIR version clients see |
-fhir-writes-per-minute | int | — | 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-label | string | — | how this instance names itself in a fleet view (default: hostname) | Settings › Fleet › This server: Name for this server |
-formulary | string | — | 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 it | Settings › Payers › Drug formulary: Drug formulary file |
-icd11-client-id | string | — | a WHO ICD API client: ICD-11 codes not imported are looked up there | Settings › Data › Code systems: WHO ICD API client ID |
-icd11-client-secret | string | — | the WHO ICD API client's secret | Settings › Data › Code systems: WHO ICD API client secret |
-icd11-release | string | 2025-01 | the ICD-11 MMS release the WHO ICD API is asked about | Settings › Data › Code systems: ICD-11 release to ask for |
-icd11-url | string | — | the ICD API's address when it is not the WHO's: the WHO's ICD-API container on your network needs no client | Settings › Data › Code systems: ICD API address |
-index-identity | on/off | true | index 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 off | Settings › Data › What is kept: Index patient identifiers |
-insecure | on/off | — | serve over plain HTTP on a non-loopback address (not recommended) | — |
-inventory | string | — | write a Markdown inventory of every interface to this file, and keep it current | Settings › Monitoring › Inventory: Write an interface inventory to |
-inventory-every | duration | 24h0m0s | how often to rewrite the interface inventory | Settings › Monitoring › Inventory: Rewrite the inventory every |
-json-logs | on/off | — | emit structured JSON logs | Settings › Monitoring › Logging: Write logs as JSON |
-ldap | string | — | YAML file configuring directory (LDAP) sign-in (default: ldap.yaml beside the database, once saved in the console) | — |
-log-file | string | — | 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 | — |
-mcp | on/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 access | Settings › Security › AI agents (MCP): Let AI agents connect over MCP |
-measure-reporter | string | Perfuse | the reporting organisation's name on MeasureReports from $evaluate-measure when the request names no reporter | — |
-metrics-open | on/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's | Settings › Security › Metrics: Serve /metrics without a token |
-metrics-token | string | — | 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 /metrics | Settings › Security › Metrics: Token a metrics scraper presents |
-mpi | on/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-tenant | on/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-address | string | — | this server's console URL as the other servers and a load balancer reach it | — |
-node-name | string | — | this server's name in the cluster (default: an id kept in -data) | — |
-oidc | string | — | YAML file configuring OpenID Connect sign-in (default: oidc.yaml beside the database, once saved in the console) | — |
-pas | on/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 result | Settings › Payers › Prior authorization: Da Vinci PAS prior authorization server |
-pas-278-ca | string | — | a PEM file of certificate authorities to trust for the UM system beside the system's | Settings › Payers › Utilization management link: Certificate authorities to trust for the UM system |
-pas-278-cert | string | — | 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-receiver | string | — | 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-version | string | — | 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-sender | string | — | 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-version | string | 2.2.0 | the 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-key | string | — | the private key (PEM) for -pas-278-cert | Settings › Payers › Utilization management link: Client certificate key file |
-pas-278-oauth-client-id | string | — | the OAuth client ID for -pas-278-oauth-token-url | Settings › Payers › Utilization management link: OAuth client ID |
-pas-278-oauth-scope | string | — | the scope asked for with the OAuth token, when the UM system wants one | Settings › Payers › Utilization management link: OAuth scope |
-pas-278-oauth-secret-env | string | — | 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-url | string | — | 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-env | string | — | 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-id | string | — | the UMO's payer ID (NM1*X3) when the request's insurer carries no identifier | Settings › Payers › Utilization management link: Payer ID for the 278s |
-pas-278-production | on/off | — | mark the 278s sent as production (ISA15 P) rather than test | Settings › Payers › Utilization management link: Mark the 278s as production |
-pas-278-receiver | string | — | ISA08/GS03 receiver ID on the 278s sent to the UM system | Settings › Payers › Utilization management link: Receiver ID on the 278s |
-pas-278-sender | string | PERFUSE | ISA06/GS02 sender ID on the 278s sent to the UM system | Settings › Payers › Utilization management link: Sender ID on the 278s |
-pas-278-sftp | string | — | host:port of the UM system's SFTP server, for -pas-278-transport sftp | Settings › Payers › Utilization management link: SFTP server |
-pas-278-sftp-every | duration | 1m0s | how often the SFTP inbound folder is read | Settings › Payers › Utilization management link: Read the SFTP inbound folder every |
-pas-278-sftp-inbound | string | — | the SFTP folder the UM system's 278 responses, 999s and TA1s are collected from | Settings › Payers › Utilization management link: SFTP inbound folder |
-pas-278-sftp-key | string | — | an OpenSSH private key file for the SFTP user, instead of a password | Settings › Payers › Utilization management link: SFTP key file |
-pas-278-sftp-known-hosts | string | — | an OpenSSH known_hosts file holding the SFTP server's key; required, so requests never go to whoever answers | Settings › Payers › Utilization management link: SFTP known_hosts file |
-pas-278-sftp-outbound | string | — | the SFTP folder the 278 requests (and the 999s for the answers) are put in | Settings › Payers › Utilization management link: SFTP outbound folder |
-pas-278-sftp-password-env | string | — | 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-user | string | — | the SFTP user name | Settings › Payers › Utilization management link: SFTP user |
-pas-278-token-env | string | — | 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-transport | string | x12 | how 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-url | string | — | 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-278 | Settings › Payers › Utilization management link: Send PAS requests on to the UM system at |
-pas-278-user | string | — | user name for the UM system: CORE's UserName (WS-Security UsernameToken in SOAP), or HTTP Basic for x12 | Settings › Payers › Utilization management link: User name |
-pas-decider-ca | string | — | 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-env | string | — | 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-url | string | — | 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-url | Settings › Payers › Decision service: Decision service URL |
-passkey-allowed-models | string | — | comma-separated authenticator AAGUIDs that may enrol; requires -passkey-attestation-roots | — |
-passkey-attestation-roots | string | — | a PEM file of authenticator vendor certificates; passkey attestation is verified against these | — |
-passkey-domain | string | — | 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 off | Settings › Sign-in › Passkeys: Domain passkeys are bound to |
-passkey-name | string | Perfuse | the name an authenticator shows a person when they register a passkey | Settings › Sign-in › Passkeys: Name shown on the device |
-passkey-origins | string | — | comma-separated origins the console is reached at, with scheme and port: https://perfuse.example.org. Defaults to https:// plus the domain | Settings › Sign-in › Passkeys: Other origins passkeys are accepted from |
-peers | string | — | YAML file listing other Perfuse instances to show in a fleet view | Settings › Fleet › Fleet: Other Perfuse servers to show (file) |
-public-url | string | — | 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 |
-rctc | string | — | eCR trigger codes for the case report preview: a FHIR ValueSet or Bundle of them, such as the eRSD | Settings › Public health › Case reporting: Trigger codes file (RCTC or eRSD) |
-residency | string | — | 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 refused | Settings › Data › Data protection: Where data may go (cloud regions) |
-retention-days | int | 30 | how long to keep recorded messages; 0 keeps them for ever, which will eventually fill the disk | Settings › Data › How long it is kept: Delete records after |
-saml | string | — | YAML file configuring SAML 2.0 sign-in (default: saml.yaml beside the database, once saved in the console) | — |
-scim | on/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 leaves | Settings › Sign-in › Automatic accounts: Let the identity provider manage accounts |
-scim-default-role | string | viewer | role 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 | — |
-settings | string | — | settings file the web interface may edit (default: perfuse-settings.yaml beside the database) | — |
-shl-allow-http | on/off | — | let a received SMART Health Link point at plain HTTP; for testing only | Settings › Public health › Health links: Allow SMART Health Links over plain HTTP |
-signing-cert | string | — | certificate for signing documents (defaults to -tls-cert) | Settings › Security › Document signing: Certificate for signing documents |
-signing-key | string | — | key for signing documents (defaults to -tls-key) | Settings › Security › Document signing: Key for signing documents |
-smart-audience | string | — | the audience a SMART token must be issued for, normally the FHIR base URL | Settings › SMART › Authorization: Audience tokens must name |
-smart-authorize | string | — | the authorization endpoint to advertise to SMART apps | Settings › SMART › Authorization: Authorization endpoint |
-smart-backend-services | on/off | — | advertise that the SMART authorization server issues backend-services (client_credentials, signed JWT) tokens | Settings › SMART › Built-in server: Backend Services (system-to-system tokens) |
-smart-clients | string | — | run Perfuse's own SMART authorization server at /auth for the apps registered in this YAML file | Settings › SMART › Built-in server: Registered apps file (turns on the built-in server) |
-smart-issuer | string | — | accept SMART on FHIR access tokens from this authorization server | Settings › SMART › Authorization: Accept SMART access tokens from this authorization server |
-smart-jwks | string | — | 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-uri | string | — | 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-key | string | smart-signing.key | the built-in authorization server's RSA signing key (PEM, mode 0600), created if missing | Settings › SMART › Built-in server: Signing key file |
-smart-oidc | string | — | 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_subject | Settings › SMART › Built-in server: Sign people in through the OpenID Connect provider |
-smart-token | string | — | the token endpoint to advertise to SMART apps | Settings › SMART › Authorization: Token endpoint |
-smart-users | string | — | 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-allow | string | — | comma-separated networks or addresses the SNMP agent answers, such as 10.0.5.0/24; required with -snmp-listen | Settings › Monitoring › SNMP: Networks that may ask |
-snmp-base-oid | string | 1.3.6.1.4.1.8072.9999.9999.16, Net-SNMP's experimental space | where Perfuse's values sit, under your enterprise number | Settings › Monitoring › SNMP: Base OID |
-snmp-community | string | — | the SNMPv2c community (a password sent in clear: at least 6 characters, not public or private) | Settings › Monitoring › SNMP: SNMP community |
-snmp-contact | string | — | sysContact the SNMP agent reports | Settings › Monitoring › SNMP: Contact (sysContact) |
-snmp-listen | string | — | answer SNMPv2c GET/GETNEXT/GETBULK on this UDP address, such as :161 (off when empty). Read-only: channel states, counts and queue depths | Settings › Monitoring › SNMP: Answer SNMP on this address |
-snmp-location | string | — | sysLocation the SNMP agent reports | Settings › Monitoring › SNMP: Location (sysLocation) |
-snmp-traps | string | — | comma-separated managers (host or host:port, default port 162) that receive an SNMPv2 trap when an alert fires or resolves | Settings › Monitoring › SNMP: Send traps to |
-store-messages | on/off | true | record every message handled, which is what makes the message browser work | Settings › Data › What is kept: Keep a record of each message |
-store-payloads | on/off | true | store message contents as well as their outcomes; turn this off where PHI must not be held at rest | Settings › Data › What is kept: Keep message contents |
-tls-cert | string | — | TLS certificate file | Settings › Security › Encryption: TLS certificate file |
-tls-key | string | — | TLS private key file | Settings › Security › Encryption: TLS private key file |
-trace-endpoint | string | — | OTLP/HTTP base URL to export message traces to, for example http://localhost:4318 | Settings › Monitoring › Tracing: Send traces to |
-trace-instance | string | — | name for this instance in traces; defaults to the hostname, which is what distinguishes replicas | Settings › Monitoring › Tracing: This instance's name in traces |
-trace-sample | float | 1 | fraction of traces to record, 0 to 1 | — |
-tsa-url | string | — | RFC 3161 time-stamping authority for DSDR signatures on claims attachments | Settings › Security › Document signing: Time-stamping authority |
-vpn | string | — | 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.yaml | Settings › Monitoring › Connections: VPN tunnels to watch (file) |
-watch-access | on/off | true | watch traffic and reads of patient data for what a breach looks like (bursts, night traffic, new destinations, bulk reads) and raise alerts | — |
-xds | string | — | 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/registry | Settings › Data › Document sharing (IHE XDS): Keep documents here as an XDS registry and repository |
-xds-home-community | string | — | this community's home community id (urn:oid:...), so /xca/gateway answers XCA ITI-38 and ITI-39 for it | Settings › 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.
| Chave | Tipo | Obrigatório | Predefinição |
|---|---|---|---|
name | texto | sim | — |
description | texto | não | — |
group | texto | não | — |
attachments | Anexos (um bloco, omitir para não incluir) | não | — |
delimited | Delimitado (um bloco, omitir para não incluir) | não | — |
tables | lista de texto | não | — |
contract | ContractRef (um bloco, omitir para não incluir) | não | — |
enabled | verdadeiro ou falso (um bloco, omitir para não incluir) | não | — |
dataType | DataType | não | hl7 |
hl7v3 | HL7v3Options (um bloco, omitir para não incluir) | não | — |
x12 | X12Options (um bloco, omitir para não incluir) | não | — |
ncpdp | NCPDPOptions (um bloco, omitir para não incluir) | não | — |
edifact | EDIFACTOptions (um bloco, omitir para não incluir) | não | — |
script | ScriptOptions (um bloco, omitir para não incluir) | não | — |
dicom | DICOMOptions (um bloco, omitir para não incluir) | não | — |
source | Fonte | sim | — |
filter | texto | não | — |
transformations | lista de transform.Step | não | — |
scripts | Scripts (um bloco, omitir para não incluir) | não | — |
shadow | Shadow (um bloco, omitir para não incluir) | não | — |
destinations | lista de Destino | sim | — |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
prefetch | número inteiro | não | 10 |
reconnect | duração, como 30s ou 5m | não | 5s |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
listen | texto | sim | — |
path | texto | não | — |
tls | tlsconf.Settings (um bloco, omitir para deixar de fora) | não | — |
id | texto | sim | — |
cert_file | texto | sim | — |
key_file | texto | sim | — |
partners | lista de AS2Partner | sim | — |
max_message_size | número inteiro | não | — |
duplicate_window | duração, como 30s ou 5m | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
prefix | texto | sim | — |
suffix | texto | não | — |
after_read | texto | não | — |
move_to | texto | não | processado/ |
error_prefix | texto | não | erro/ |
poll_interval | duração, como 30s ou 5m | não | 30s |
max_object_size | número inteiro | não | 16 MiB |
framed | verdadeiro ou falso | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
addr | texto | sim | — |
destination | texto | sim | — |
login | texto | não | — |
passcode | texto | não | — |
host | texto | não | o host do endereço |
selector | texto | não | — |
subscription_id | texto | não | o nome do canal |
heartbeat | duração, como 30s ou 5m | não | trinta segundos |
reconnect | duração, como 30s ou 5m | não | cinco segundos |
timeout | duração, como 30s ou 5m | não | trinta segundos |
tls | tlsconf.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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
address | texto | sim | — |
called_ae | texto | sim | — |
calling_ae | texto | não | — |
level | texto | não | ESTUDO |
patient_root | verdadeiro ou falso | não | — |
match | mapeamento de texto para texto | não | — |
return | lista de texto | não | — |
interval | duração, como 30s ou 5m | sim | — |
window | duração, como 30s ou 5m | não | — |
overlap | duração, como 30s ou 5m | não | uma hora |
limit | número inteiro | não | 500 |
timeout | duração, como 30s ou 5m | não | dois minutos |
tls | tlsconf.Settings (um bloco, omitir para deixar de lado) | não | — |
emit_on_first_poll | verdadeiro ou falso | não | falso |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
listen | texto | sim | — |
ae_title | texto | não | — |
allowed_calling_ae | lista de texto | não | — |
sop_classes | lista de texto | não | — |
transfer_syntaxes | lista de texto | não | — |
max_object_bytes | número inteiro | não | — |
idle_timeout | duração, como 30s ou 5m | não | — |
tls | tlsconf.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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
listen | texto | sim | — |
path | texto | não | /dicom-web |
token | texto | não | — |
username | texto | não | — |
password | texto | não | — |
max_object_bytes | número inteiro | não | — |
tls | tlsconf.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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
driver | texto | sim | — |
dsn | texto | sim | — |
query | texto | sim | — |
after_query | texto | não | — |
key_column | texto | não | — |
template | texto | não | — |
column | texto | não | — |
poll_interval | duração, como 30s ou 5m | não | — |
batch_size | número inteiro | não | 100 |
max_attempts | número inteiro | não | 3 |
query_timeout | duração, como 30s ou 5m | não | 30s |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
listen | texto | não | — |
tls_cert | texto | não | — |
tls_key | texto | não | — |
max_bytes | número inteiro | não | — |
smtp_host | texto | não | — |
username | texto | não | — |
password | texto | não | — |
imap | DirectIMAP (um bloco, omitir para deixar de fora) | não | — |
xdr | DirectXDR (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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
protocol | texto | não | — |
host | texto | sim | — |
port | número inteiro | não | — |
security | texto | não | — |
tls | tlsconf.Settings (um bloco, omitir para não incluir) | não | — |
username | texto | sim | — |
password | texto | não | — |
oauth | EmailOAuth (um bloco, omitir para não incluir) | não | — |
mailbox | texto | não | — |
take | texto | não | — |
attachment_names | lista de texto | não | — |
allowed_senders | lista de texto | não | — |
after_read | texto | não | — |
move_to | texto | não | — |
error_folder | texto | não | — |
poll_interval | duração, como 30s ou 5m | não | — |
max_message_size | número inteiro | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
host | texto | sim | — |
user | texto | não | — |
password | texto | não | — |
security | ftpconn.Security | não | explícito |
insecure_skip_verify | verdadeiro ou falso | não | — |
root | texto | não | — |
timeout | duração, como 30s ou 5m | não | trinta 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.
| Chave | Tipo | Obrigatório | Predefinido |
|---|---|---|---|
root | texto | sim | — |
follow_symlinks | verdadeiro ou falso | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
prefix | texto | sim | — |
suffix | texto | não | — |
after_read | texto | não | — |
move_to | texto | não | processado/ |
error_prefix | texto | não | erro/ |
poll_interval | duração, como 30s ou 5m | não | 30s |
max_object_size | número inteiro | não | 16 MiB |
framed | verdadeiro ou falso | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
listen | texto | sim | — |
path | texto | não | "/" |
tls | tlsconf.Settings (um bloco, omitir para deixar de fora) | não | — |
token | texto | não | — |
max_message_size | número inteiro | não | — |
read_timeout | duração, como 30s ou 5m | não | — |
ack | Ack | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
poll_interval | duração, como 30s ou 5m | não | 2s |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
script | texto | sim | — |
poll_interval | duração, como 30s ou 5m | não | — |
timeout | duração, como 30s ou 5m | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
brokers | lista de texto | sim | — |
topics | lista de texto | sim | — |
group | texto | sim | — |
from_beginning | verdadeiro ou falso | não | — |
commit_after_delivery | verdadeiro ou falso (um bloco, omitir para deixar de fora) | não | — |
max_message_size | número inteiro | não | o limite do canal |
session_timeout | duração, como 30s ou 5m | não | quarenta e cinco segundos |
timeout | duração, como 30s ou 5m | não | trinta segundos |
sasl | KafkaSASL (um bloco, omitir para deixar de fora) | não | — |
tls | tlsconf.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.
| Chave | Tipo | Obrigatório | Predefinido |
|---|---|---|---|
topic | texto | sim | — |
reconnect | duração, como 30s ou 5m | não | 5s |
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.
| Chave | Tipo | Obrigatório | Predefinido |
|---|---|---|---|
subscription | texto | sim | — |
max_messages | número inteiro | não | 10 |
reconnect | duração, como 30s ou 5m | não | 5s |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
bucket | texto | sim | — |
path_style | verdadeiro ou falso | não | — |
prefix | texto | não | — |
suffix | texto | não | — |
after_read | texto | não | — |
move_to | texto | não | processado/ |
error_prefix | texto | não | erro/ |
poll_interval | duração, como 30s ou 5m | não | 30s |
max_object_size | número inteiro | não | 16 MiB |
framed | verdadeiro ou falso | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
host | texto | sim | 22 |
user | texto | sim | — |
password | texto | não | — |
key_file | texto | não | — |
key_passphrase | texto | não | — |
known_hosts_file | texto | não | — |
insecure_skip_host_key_check | verdadeiro ou falso | não | — |
dir | texto | sim | — |
pattern | texto | não | tudo |
poll_interval | duração, como 30s ou 5m | não | — |
after_read | texto | não | — |
move_to | texto | não | — |
error_dir | texto | não | — |
stable_for | duração, como 30s ou 5m | não | 5s |
framed | verdadeiro ou falso | não | — |
max_file_size | número inteiro | não | 64MB |
timeout | duração, como 30s ou 5m | não | 60s |
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.
| Chave | Tipo | Obrigatório | Predefinido |
|---|---|---|---|
host | texto | sim | — |
share | texto | sim | — |
user | texto | não | — |
password | texto | não | — |
domain | texto | não | — |
root | texto | não | — |
timeout | duração, como 30s ou 5m | não | trinta 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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
listen | texto | sim | — |
profile | texto | não | — |
path | texto | não | "/" |
version | texto | não | 1 |
element | texto | não | — |
base64 | verdadeiro ou falso | não | — |
response_element | texto | não | "AckResponse" |
response_namespace | texto | não | — |
wsdl | texto | não | — |
tls | tlsconf.Settings (um bloco, omitir para deixar de fora) | não | — |
token | texto | não | — |
username | texto | não | — |
password | texto | não | — |
max_message_size | número inteiro | não | — |
read_timeout | duração, como 30s ou 5m | não | — |
ack | Ack | não | — |
fault_on_nak | verdadeiro ou falso | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
queue_url | texto | sim | — |
wait_seconds | número inteiro | não | 20: uma fila vazia custa um pedido a cada vinte segundos |
max_messages | número inteiro | não | 10 |
visibility_timeout | duração, como 30s ou 5m | não | a 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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
port | texto | sim | — |
baud | número inteiro | sim | — |
data_bits | número inteiro | não | 8 |
parity | texto | não | none |
stop_bits | texto | não | 1 |
flow_control | texto | não | none |
max_message_size | número inteiro | não | — |
quiet_after | duração, como 30s ou 5m | não | — |
reply | texto | não | — |
reply_text | texto | não | — |
reopen_after | duração, como 30s ou 5m | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
type | SourceType | sim | — |
listen | texto | sim | — |
max_message_size | número inteiro | não | — |
idle_timeout | duração, como 30s ou 5m | não | — |
max_connections | número inteiro | não | — |
tls | tlsconf.Settings (um bloco, omitir para não usar) | não | — |
http | HTTPSource (um bloco, omitir para não usar) | não | — |
soap | SOAPSource (um bloco, omitir para não usar) | não | — |
dicomweb | DICOMwebSource (um bloco, omitir para não usar) | não | — |
direct | DirectSource (um bloco, omitir para não usar) | não | — |
dicom | DICOMSource (um bloco, omitir para não usar) | não | — |
file | FileSource (um bloco, omitir para não usar) | não | — |
tcp | TCPSource (um bloco, omitir para não usar) | não | — |
ftp | FTPSource (um bloco, omitir para não usar) | não | — |
smb | SMBSource (um bloco, omitir para não usar) | não | — |
webdav | WebDAVSource (um bloco, omitir para não usar) | não | — |
serial | SerialSource (um bloco, omitir para não usar) | não | — |
dicom_query | DICOMQuerySource (um bloco, omitir para não usar) | não | — |
broker | BrokerSource (um bloco, omitir para não usar) | não | — |
kafka | KafkaSource (um bloco, omitir para não usar) | não | — |
sqs | SQSSource (um bloco, omitir para não usar) | não | — |
s3 | S3Source (um bloco, omitir para não usar) | não | — |
amqp | AMQPSource (um bloco, omitir para não usar) | não | — |
azure_blob | AzureBlobSource (um bloco, omitir para não usar) | não | — |
email | EmailSource (um bloco, omitir para não usar) | não | — |
as2 | AS2Source (um bloco, omitir para não usar) | não | — |
pgp | PGPReceive (um bloco, omitir para não usar) | não | — |
mqtt | MQTTSource (um bloco, omitir para não usar) | não | — |
ibm_mq | IBMMQSource (um bloco, omitir para não usar) | não | — |
pubsub | PubSubSource (um bloco, omitir para não usar) | não | — |
gcs | GCSSource (um bloco, omitir para não usar) | não | — |
database | DatabaseSource (um bloco, omitir para não usar) | não | — |
sftp | SFTPSource (um bloco, omitir para não usar) | não | — |
javascript | JavaScriptSource (um bloco, omitir para não usar) | não | — |
ack | Ack | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
listen | texto | sim | — |
max_message_size | número inteiro | não | — |
idle_timeout | duração, como 30s ou 5m | não | — |
max_connections | número inteiro | não | — |
reply | texto | não | — |
reply_text | texto | não | — |
tls | tlsconf.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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
url | texto | sim | — |
user | texto | não | — |
password | texto | não | — |
insecure_skip_verify | verdadeiro ou falso | não | — |
timeout | duração, como 30s ou 5m | não | sessenta 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.
| Chave | Tipo | Obrigatório | Predefinição |
|---|---|---|---|
content_type | texto | não | o 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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
url | texto | sim | — |
from | texto | sim | — |
to | texto | sim | — |
cert_file | texto | não | — |
key_file | texto | não | — |
partner_cert_file | texto | não | — |
unsigned | verdadeiro ou falso | não | — |
unencrypted | verdadeiro ou falso | não | — |
compress | verdadeiro ou falso | não | — |
receipt | texto | não | — |
unsigned_receipt | verdadeiro ou falso | não | — |
receipt_url | texto | não | — |
content_type | texto | não | — |
file_name | texto | não | — |
subject | texto | não | — |
username | texto | não | — |
password | texto | não | — |
tls | tlsconf.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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
blob | texto | não | ${date}/${channel}/${control_id} |
tier | texto | não | — |
content_type | texto | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
addr | texto | sim | — |
destination | texto | sim | — |
login | texto | não | — |
passcode | texto | não | — |
host | texto | não | o host do endereço |
content_type | texto | não | text/plain para HL7 |
headers | mapeamento de texto para texto | não | — |
persistent | verdadeiro ou falso (um bloco, omitir para deixar de fora) | não | verdadeiro |
timeout | duração, como 30s ou 5m | não | — |
tls | tlsconf.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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
url | texto | não | — |
dir | texto | não | — |
write | texto | não | — |
version | texto | não | R5 |
identifier_systems | mapeamento de texto para texto | não | — |
require_agreement | verdadeiro ou falso | não | — |
on_no_document | texto | não | — |
headers | mapeamento de texto para texto | não | — |
bearer_token | texto | nã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.
| Chave | Tipo | Obrigatório | Predefinido |
|---|---|---|---|
name | texto | sim | — |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
address | texto | sim | — |
called_ae | texto | não | — |
calling_ae | texto | não | — |
transfer_syntaxes | lista de texto | não | — |
timeout | duração, como 30s ou 5m | não | — |
tls | tlsconf.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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
url | texto | sim | — |
token | texto | não | — |
username | texto | não | — |
password | texto | não | — |
headers | mapeamento de texto para texto | não | — |
tls | tlsconf.Settings (um bloco, omitir para deixar de fora) | não | — |
timeout | duração, como 30s ou 5m | não | — |
23.9 Destino de Banco de Dados
DatabaseDestination escreve cada mensagem em um banco de dados.
Definido como DatabaseDestination em internal/config.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
driver | texto | sim | — |
dsn | texto | sim | — |
statement | texto | sim | — |
params | lista de texto | não | — |
timeout | duração, como 30s ou 5m | não | 30s |
max_open_conns | número inteiro | não | 4 |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
name | texto | sim | — |
type | DestinationType | sim | — |
enabled | verdadeiro ou falso (um bloco, omitir para deixar de fora) | não | — |
filter | texto | não | — |
address | texto | não | — |
dir | texto | não | — |
file_name | texto | não | — |
temp_suffix | texto | não | " |
append | verdadeiro ou falso | não | — |
retain_hours | número inteiro | não | — |
tls | tlsconf.Settings (um bloco, omitir para deixar de fora) | não | — |
fhir | FHIRDestination (um bloco, omitir para deixar de fora) | não | — |
cda | CDADestination (um bloco, omitir para deixar de fora) | não | — |
http | HTTPDestination (um bloco, omitir para deixar de fora) | não | — |
database | DatabaseDestination (um bloco, omitir para deixar de fora) | não | — |
sftp | SFTPDestination (um bloco, omitir para deixar de fora) | não | — |
tcp | TCPDest (um bloco, omitir para deixar de fora) | não | — |
smtp | SMTPDestination (um bloco, omitir para deixar de fora) | não | — |
channel | ChannelDestination (um bloco, omitir para deixar de fora) | não | — |
s3 | S3Destination (um bloco, omitir para deixar de fora) | não | — |
ftp | FTPDestination (um bloco, omitir para deixar de fora) | não | — |
document | DocumentDestination (um bloco, omitir para deixar de fora) | não | — |
soap | SOAPDestination (um bloco, omitir para deixar de fora) | não | — |
dicomweb | DICOMwebDestination (um bloco, omitir para deixar de fora) | não | — |
xds | XDSDestination (um bloco, omitir para deixar de fora) | não | — |
direct | DirectDestination (um bloco, omitir para deixar de fora) | não | — |
as2 | AS2Destination (um bloco, omitir para deixar de fora) | não | — |
mpi | MPIDestination (um bloco, omitir para deixar de fora) | não | — |
tefca | TEFCADestination (um bloco, omitir para deixar de fora) | não | — |
pas | PASDestination (um bloco, omitir para deixar de fora) | não | — |
x12_as | texto | não | — |
dicom | DICOMDestination (um bloco, omitir para deixar de fora) | não | — |
javascript | JavaScriptDestination (um bloco, omitir para deixar de fora) | não | — |
broker | BrokerDestination (um bloco, omitir para deixar de fora) | não | — |
kafka | KafkaDestination (um bloco, omitir para deixar de fora) | não | — |
sqs | SQSDestination (um bloco, omitir para deixar de fora) | não | — |
sns | SNSDestination (um bloco, omitir para deixar de fora) | não | — |
amqp | AMQPDestination (um bloco, omitir para deixar de fora) | não | — |
azure_blob | AzureBlobDestination (um bloco, omitir para deixar de fora) | não | — |
mqtt | MQTTDestination (um bloco, omitir para deixar de fora) | não | — |
ibm_mq | IBMMQDestination (um bloco, omitir para deixar de fora) | não | — |
pubsub | PubSubDestination (um bloco, omitir para deixar de fora) | não | — |
gcs | GCSDestination (um bloco, omitir para deixar de fora) | não | — |
elr | ELRDestination (um bloco, omitir para deixar de fora) | não | — |
pgp | PGPSend (um bloco, omitir para deixar de fora) | não | — |
response_transformer | texto | não | — |
timeout | duração, como 30s ou 5m | não | — |
retry | Retry | não | — |
queue | QueueConfig (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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
to | lista de texto | sim | — |
subject | texto | não | — |
text | texto | não | — |
attach_name | texto | não | — |
xdm | verdadeiro ou falso | não | — |
xdm_source_id | texto | não | — |
recipient_certs_dir | texto | não | — |
dns | texto | não | — |
ldap | texto | não | — |
smtp_host | texto | sim | — |
username | texto | não | — |
password | texto | não | — |
request_mdn | verdadeiro ou falso | não | — |
timeout | duração, como 30s ou 5m | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
dir | texto | sim | — |
format | DocumentFormat | não | |
template | texto | sim | — |
title | texto | não | — |
file_name | texto | não | — |
font_size | número | não | 10 |
landscape | verdadeiro ou falso | não | — |
temp_suffix | texto | não | " |
timeout | duração, como 30s ou 5m | não | 30s |
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.
| Chave | Tipo | Obrigatório | Predefinição |
|---|---|---|---|
rctc | texto | não | — |
source | texto | sim | — |
facility | ECRFacility | sim | — |
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.
| Chave | Tipo | Obrigatório | Predefinição |
|---|---|---|---|
config | texto | sim | — |
rctc | texto | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
url | texto | sim | — |
version | texto | não | R5 |
timezone | texto | não | — |
default_identifier_system | texto | não | — |
identifier_systems | mapeamento de texto para texto | não | — |
claim_us_core | verdadeiro ou falso | não | — |
validate_before_send | verdadeiro ou falso (um bloco, omitir para deixar de fora) | não | verdadeiro: 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_warning | verdadeiro ou falso | não | — |
headers | mapeamento de texto para texto | não | — |
bearer_token | texto | não | — |
auth | FHIRAuth (um bloco, omitir para deixar de fora) | não | — |
ecr | ECRDestination (um bloco, omitir para deixar de fora) | não | — |
bundle_script | texto | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
host | texto | sim | 21 |
user | texto | não | — |
password | texto | não | — |
security | FTPSecurity | não | explícito em vez de nenhum |
insecure_skip_verify | verdadeiro ou falso | não | — |
allow_clear_password | verdadeiro ou falso | não | — |
dir | texto | sim | — |
file_name | texto | não | — |
temp_suffix | texto | não | " |
framed | verdadeiro ou falso | não | — |
timeout | duração, como 30s ou 5m | não | 60s |
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.
| Chave | Tipo | Obrigatório | Predefinição |
|---|---|---|---|
object | texto | não | ${date}/${channel}/${control_id} |
storage_class | texto | não | — |
content_type | texto | nã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.
| Chave | Tipo | Obrigatório | Predefinição |
|---|---|---|---|
url | texto | sim | — |
method | texto | não | — |
content_type | texto | não | — |
headers | mapeamento de texto para texto | não | — |
bearer_token | texto | não | — |
username | texto | não | — |
password | texto | não | — |
tls | tlsconf.Settings (um bloco, omitir para deixar de fora) | não | — |
success_status | lista de número inteiro | não | qualquer 2xx |
fail_on_body | lista de texto | não | — |
follow_redirects | verdadeiro ou falso | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
non_persistent | true ou false | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
script | texto | sim | — |
timeout | duração, como 30s ou 5m | não | — |
success_on_undefined | verdadeiro ou falso (um bloco, omitir para deixar de fora) | não | verdadeiro |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
brokers | lista de texto | sim | — |
topic | texto | sim | — |
key | texto | não | — |
acks | texto | não | all |
compression | texto | não | snappy |
headers | mapeamento de texto para texto | não | — |
timeout | duração, como 30s ou 5m | não | trinta segundos |
sasl | KafkaSASL (um bloco, omitir para deixar de fora) | não | — |
tls | tlsconf.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.
| Chave | Tipo | Obrigatório | Predefinido |
|---|---|---|---|
authorities | mapeamento de texto para texto | não | — |
id_type | texto | não | — |
ssn_system | texto | não | — |
no_merge | verdadeiro ou falso | nã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.
| Chave | Tipo | Obrigatório | Predefinido |
|---|---|---|---|
topic | texto | sim | — |
retain | verdadeiro ou falso | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
payer | texto | sim | — |
bearer_token | texto | não | — |
auth | FHIRAuth (um bloco, omitir para não incluir) | não | — |
results_to | texto | nã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.
| Chave | Tipo | Obrigatório | Predefinido |
|---|---|---|---|
topic | texto | sim | — |
order_by | texto | não | — |
23.26 Destino S3
S3Destination escreve cada mensagem como um objeto.
Definido como S3Destination em internal/config.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
bucket | texto | sim | — |
region | texto | sim | — |
key | texto | não | um caminho com partições de data mais o ID de controle |
access_key_id | texto | não | — |
secret_access_key | texto | não | — |
session_token | texto | não | — |
endpoint | texto | não | — |
path_style | verdadeiro ou falso | não | — |
server_side_encryption | texto | não | — |
content_type | texto | não | application/hl7-v2 para HL7 e texto/plano caso contrário |
framed | verdadeiro ou falso | não | — |
timeout | duração, como 30s ou 5m | não | 60s |
storage_class | texto | não | — |
format | texto | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
host | texto | sim | 22 |
user | texto | sim | — |
password | texto | não | — |
key_file | texto | não | — |
key_passphrase | texto | não | — |
known_hosts_file | texto | não | — |
insecure_skip_host_key_check | verdadeiro ou falso | não | — |
dir | texto | sim | — |
file_name | texto | não | um carimbo de data/hora mais o ID de controle |
temp_suffix | texto | não | " |
framed | verdadeiro ou falso | não | — |
append | verdadeiro ou falso | não | — |
timeout | duração, como 30s ou 5m | não | 60s |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
host | texto | sim | — |
from | texto | sim | — |
to | lista de texto | sim | — |
cc | lista de texto | não | — |
bcc | lista de texto | não | — |
subject | texto | não | — |
body | texto | não | — |
attach | verdadeiro ou falso | não | — |
attach_name | texto | não | o ID de controle com um |
username | texto | não | — |
password | texto | não | — |
starttls | verdadeiro ou falso (um bloco, omitir para deixar de fora) | não | — |
insecure_skip_verify | verdadeiro ou falso | não | — |
timeout | duração, como 30s ou 5m | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
topic_arn | texto | sim | — |
subject | texto | não | — |
group_by | texto | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
url | texto | sim | — |
profile | texto | não | — |
facility_id | texto | não | — |
warnings_are_errors | verdadeiro ou falso | não | — |
action | texto | não | — |
version | texto | não | 1 |
body | texto | sim | — |
header | texto | não | — |
headers | mapeamento de texto para texto | não | — |
username | texto | não | — |
password | texto | não | — |
tls | tlsconf.Settings (um bloco, omitir para deixar de fora) | não | — |
fault_is_success | lista de texto | não | — |
timeout | duração, como 30s ou 5m | não | 30s |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
queue_url | texto | sim | — |
group_by | texto | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
address | texto | sim | — |
max_message_size | número inteiro | não | — |
timeout | duração, como 30s ou 5m | não | — |
expect_reply | verdadeiro ou falso | não | — |
keep_alive | verdadeiro ou falso | não | — |
tls | tlsconf.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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
purpose | texto | sim | — |
results_to | texto | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
url | texto | sim | — |
source_id | texto | sim | — |
patient_domain | texto | não | — |
facility_type | XDSCode | sim | — |
practice_setting | XDSCode | sim | — |
class | XDSCode (um bloco, omitir para deixar de fora) | não | — |
content_type | XDSCode (um bloco, omitir para deixar de fora) | não | — |
token | texto | não | — |
username | texto | não | — |
password | texto | não | — |
headers | mapeamento de texto para texto | não | — |
tls | tlsconf.Settings (um bloco, omitir para deixar de fora) | não | — |
timeout | duração, como 30s ou 5m | não | — |
direct_from | texto | não | — |
direct_to | lista de texto | nã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.
| Chave | Tipo | Obrigatório | Predefinição |
|---|---|---|---|
extract | lista de attach.Regra | sim | — |
reassemble | verdadeiro ou falso (um bloco, omitir para deixar de fora) | não | verdadeiro |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
delimiter | texto | não | — |
quote | texto | não | aspas duplas |
comment | texto | não | — |
has_header | verdadeiro ou falso | não | — |
columns | lista de texto | não | — |
trim_space | verdadeiro ou falso | não | — |
relaxed | verdadeiro ou falso | não | — |
split | verdadeiro ou falso (um bloco, omitir para deixar de fora) | não | verdadeiro |
keep_blank_lines | verdadeiro ou falso | não | — |
filter | texto | não | — |
transformations | lista de etapas.Step | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
filter | texto | não | — |
acknowledge | verdadeiro ou falso (um bloco, omitir para deixar de fora) | não | — |
sender_device | texto | não | — |
sender_oid | texto | não | — |
transformations | lista de etapas hl7v3.Step | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
framing | texto | sim | — |
delimiter | texto | não | — |
start_block | texto | não | — |
keep_delimiter | verdadeiro ou falso | não | — |
record_length | número inteiro | não | — |
trim_padding | verdadeiro ou falso (um bloco, omitir para deixar de fora) | não | — |
length_bytes | número inteiro | não | — |
big_endian | verdadeiro ou falso | não | — |
length_includes_header | verdadeiro ou falso | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
envelope | EnvelopePolicy | não | exigir |
split | verdadeiro ou falso | não | — |
acknowledge | texto | não | — |
ack_sender_id | texto | não | — |
ack_sender_qualifier | texto | não | — |
arrives_as | texto | não | — |
transformations | lista de x12.Step | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
addr | texto | sim | — |
address | texto | sim | — |
username | texto | não | — |
password | texto | não | — |
hostname | texto | não | o host de addr |
tls | tlsconf.Settings (um bloco, omitir para deixar de fora) | não | — |
timeout | duração, como 30s ou 5m | não | 30s |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
id | texto | sim | — |
cert_file | texto | sim | — |
allow_unsigned | verdadeiro ou falso | não | — |
allow_unencrypted | verdadeiro ou falso | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
region | texto | sim | — |
access_key_id | texto | não | — |
secret_access_key | texto | não | — |
session_token | texto | não | — |
endpoint | texto | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
when | AckWhen | não | — |
application | texto | não | — |
facility | texto | não | — |
include_trigger_event | verdadeiro ou falso | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
account | texto | sim | — |
container | texto | sim | — |
key | texto | não | — |
sas | texto | não | — |
endpoint | texto | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
file | texto | sim | — |
check_every | texto | não | 15 minutos |
over | número inteiro | não | 500 |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
transformations | lista de dicom.Step | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
address | texto | sim | — |
cert_file | texto | sim | — |
key_file | texto | sim | — |
anchors_file | texto | sim | — |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
host | texto | sim | — |
port | número inteiro | não | — |
security | texto | não | — |
username | texto | sim | — |
password | texto | não | — |
mailbox | texto | não | — |
after_read | texto | não | — |
move_to | texto | não | — |
error_folder | texto | não | — |
poll_interval | duração, como 30s ou 5m | não | — |
tls | tlsconf.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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
listen | texto | sim | — |
tls_cert | texto | não | — |
tls_key | texto | não | — |
client_ca_file | texto | não | — |
25.11 Instalação ECR
ECRFacility é a organização que envia relatórios de casos.
Definido como ECRFacility em internal/config.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
name | texto | sim | — |
npi | texto | não | — |
phone | texto | sim | — |
line | texto | não | — |
city | texto | sim | — |
state | texto | sim | — |
postal_code | texto | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
envelope | texto | não | — |
split | verdadeiro ou falso | não | — |
acknowledge | texto | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
provider | texto | sim | — |
tenant | texto | não | — |
token_url | texto | não | — |
client_id | texto | sim | — |
client_secret | texto | não | — |
refresh_token | texto | não | — |
scope | texto | nã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:
- aws: AWS HealthLake, que aceita solicitações assinadas com Signature Version 4 para o serviço "healthlake" - nenhum token. - azure: Azure Health Data Services, que aceita um token de ID da Microsoft Entra para a audiência do serviço FHIR, obtido com a concessão de credenciais de cliente de um registro de aplicativo que detém o papel de Colaborador de Dados FHIR. - client_credentials: qualquer ponto de extremidade de token OAuth 2.0 - Keycloak, Okta, um serviço de backend SMART com um segredo de cliente.
Os tokens são buscados quando necessário e reutilizados até um minuto antes de expirarem.
Definido como FHIRAuth em internal/config.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
type | texto | sim | — |
region | texto | não | — |
access_key_id | texto | não | — |
secret_access_key | texto | não | — |
session_token | texto | não | — |
tenant_id | texto | não | — |
token_url | texto | não | — |
client_id | texto | não | — |
client_secret | texto | não | — |
scope | texto | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
dir | texto | sim | — |
pattern | texto | não | — |
poll_interval | duração, como 30s ou 5m | não | — |
after_read | texto | não | — |
move_to | texto | não | — |
error_dir | texto | não | — |
stable_for | duração, como 30s ou 5m | não | — |
max_file_size | número inteiro | não | — |
framed | verdadeiro ou falso | não | — |
raw | verdadeiro ou falso | não | — |
batch_size | número inteiro | não | — |
sort_by | texto | não | nome |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
project | texto | não | — |
credentials_file | texto | não | — |
endpoint | texto | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
bucket | texto | sim | — |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
url | texto | sim | — |
queue_manager | texto | sim | — |
queue | texto | sim | — |
username | texto | não | — |
password | texto | não | — |
tls | tlsconf.Settings (um bloco, omitir para não incluir) | não | — |
api_version | texto | não | — |
timeout | duração, como 30s ou 5m | não | 30s |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
mechanism | texto | sim | — |
username | texto | sim | — |
password | texto | sim | — |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
addr | texto | sim | — |
client_id | texto | não | — |
username | texto | não | — |
password | texto | não | — |
tls | tlsconf.Settings (um bloco, omitir para não incluir) | não | — |
qos | número inteiro (um bloco, omitir para não incluir) | não | — |
timeout | duração, como 30s ou 5m | não | 30s |
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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
transformations | lista de ncpdp.Step | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
decrypt_with | texto | não | — |
passphrase | texto | não | — |
verify_with | lista de texto | não | — |
require_signature | verdadeiro ou falso | não | — |
allow_unencrypted | verdadeiro ou falso | não | — |
pass_plain | verdadeiro ou falso | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
encrypt_to | lista de texto | não | — |
sign_with | texto | não | — |
passphrase | texto | não | — |
armor | verdadeiro ou falso | não | — |
no_compress | verdadeiro ou falso | não | — |
file_name | texto | nã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.
| Chave | Tipo | Obrigatório | Predefinição |
|---|---|---|---|
enabled | verdadeiro ou falso | não | — |
max_attempts | número inteiro | não | — |
backoff | duração, como 30s ou 5m | não | — |
max_backoff | duração, como 30s ou 5m | não | — |
max_depth | número inteiro | não | — |
retain_hours | número inteiro | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
attempts | número inteiro | não | — |
backoff | duração, como 30s ou 5m | não | — |
max_backoff | duração, como 30s ou 5m | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
transformations | lista de hl7v3.Step | nã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.
| Chave | Tipo | Obrigatório | Padrão |
|---|---|---|---|
filter | texto | não | — |
transformer | texto | não | — |
preprocessor | texto | não | — |
deploy | texto | não | — |
undeploy | texto | não | — |
postprocessor | texto | não | — |
language | texto | não | — |
timeout | duração, como 30s ou 5m | não | — |
include | lista de texto | não | — |
file_roots | lista de texto | não | — |
allow | lista de texto | nã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:
- A sombra nunca entrega. Seus destinos não são construídos, por isso não há caminho de código de um canal de sombra para um receptor, e nenhuma configuração pode criá-lo por engano. - A sombra nunca afeta o canal ativo. Ela é executada após a mensagem ativa ter sido entregue e confirmada, e uma sombra que entra em pânico, lança ou trava é registrada como uma falha de sombra e nada mais.
Definido como Shadow em internal/config.
| Chave | Tipo | Requerido | Padrão |
|---|---|---|---|
channel | texto | sim | — |
sample | número | não | 1 |
compare | lista de texto | não | — |
ignore | lista de texto | não | — |
max_differences | número inteiro | não | 100 |
timeout | duração, como 30s ou 5m | não | 5s |
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.
| Chave | Tipo | Obrigatório | Predefinido |
|---|---|---|---|
code | texto | sim | — |
scheme | texto | sim | — |
display | texto | nã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:
- O tipo de conteúdo declarado é ignorado. Os bytes são detectados, e o resultado deve estar em uma lista de permissões. Um arquivo chamado logo.png contendo HTML é HTML. - SVG é aceito, porque é o que as empresas realmente têm, mas é um formato de documento executável: pode carregar elementos de script, atributos de tratamento de eventos, referências externas e objetos estrangeiros incorporados. Ele é reescrito para remover todos esses antes de ser armazenado, e a reescrita é verificada plantando cada ataque em um teste. - Ele é servido com uma política de segurança de conteúdo que permite nada, com detecção desabilitada e como uma imagem inline sem anexos apenas. Mesmo um bug de sanitização não deve se tornar execução de script na origem da própria console. - O nome do arquivo carregado nunca é usado para construir um caminho. O nome armazenado é derivado do tipo detectado, então um nome como ../../etc/perfuse não pode escapar em lugar nenhum.
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:
- ativo-passivo: um lease, "líder". Seu detentor executa todos os canais e todos os trabalhos que devem ser executados uma vez (notificações de assinatura, alertas). Os outros esperam, e o primeiro a ver o lease expirar assume o controle. - ativo-ativo: o líder ainda executa os trabalhos, e cada canal tem um lease próprio, distribuído uniformemente sobre os servidores ativos. Um servidor que deixa o aglomerado entrega seus canais ao restante; um que se junta assume sua parte à medida que eles ficam livres.
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:
- O resumo é sobre o documento inteiro, deixando de fora todos os elementos legalAuthenticator e authenticator (seção 3.1.2), para que signatários posteriores não quebrem assinaturas anteriores. Expresso na assinatura como uma transformação de filtro XPath 2.0, que qualquer implementação de XML-DSig pode avaliar. - A assinatura é XAdES-X-L (3.1.1, ESMD-1 a ESMD-6): o certificado de assinatura, hora de assinatura UTC, um papel da taxonomia de provedor NUCC, um propósito de assinatura de ASTM E1762, o caminho de certificação em CertificateValues e uma resposta OCSP ou CRL em RevocationValues, com os carimbos de data/hora X-L construídos. - É transportado em base64 em sdtc:signatureText no participante que assinou, com uma miniatura de texto simples (3.3, ESMD-7 a ESMD-16), dentro de digitalSignature/authorizedSigner.
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.
- Uma decisão nunca é atualizada. A certificação parcial não se torna aprovação, e um pedido que o pagador se recusou a considerar não se torna uma recusa. Ambas as quedas estão disponíveis no mapeamento óbvio e ambas estão erradas na direção que custa a alguém semanas: um recurso apresentado contra uma decisão que ninguém fez, ou seis sessões agendadas contra três aprovadas. - Nada é inventado para preencher um campo necessário. Onde o formato de destino exige algo que a fonte não carrega, o mapeamento relata como uma nota em vez de fornecer um padrão plausível. Um número de autorização fabricado é pior do que um ausente. - Todo julgamento é relatado. As notas voltam com o resultado, para que uma pessoa possa ler o punhado que precisou de uma decisão em vez de toda a saída. - As viagens de ida e volta são testadas, não presumidas. Um mapeamento que perde um campo em uma direção é encontrado convertendo de volta e comparando, que é a única maneira de ver um campo que ninguém pensou em afirmar.
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.
- ITI-44, Alimentação de Identidade de Paciente HL7 V3: uma fonte adiciona um paciente (PRPA_IN201301UV02), revisa um (PRPA_IN201302UV02) ou afirma que dois registros são a mesma pessoa (PRPA_IN201304UV02). Respondido com MCCI_IN000002UV01. - ITI-45, Consulta PIXV3: os outros identificadores da pessoa que detém um (PRPA_IN201309UV02 -> PRPA_IN201310UV02). - ITI-47, Consulta PDQV3: as pessoas que correspondem a algumas informações demográficas (PRPA_IN201305UV02 -> PRPA_IN201306UV02), com continuação (QUQI_IN000003UV01) e cancelamento (QUQI_IN000003UV01_Cancel).
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:
- ELR: mensagens ORU^R01 HL7 2.5.1 que transportam resultados de laboratório para agências de saúde pública (elr.go). - eCR: relatórios de caso eletrônicos iniciais baseados em FHIR (eICR) quando uma condição relatória é diagnosticada. - Registro de imunização: VXU^V04 para relatar vacinações administradas e VXQ^V01 para consultar a história de imunização de um paciente.
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:
- Definir ativo como falso termina todas as sessões imediatamente, não na próxima expiração. Uma guia do navegador deixada aberta em um laptop que foi para casa com um funcionário demitido deve parar de funcionar, e uma sessão que sobrevive até expirar é uma sessão que sobrevive à demissão. - Uma falha é uma falha. O SCIM não tem semântica de retry que um aplicativo possa confiar, então retornar 200 por algo que não aconteceu significa que o provedor de identidade registra a desprovisionamento como concluída e nunca tenta novamente. - Excluir um usuário é tratado da mesma forma que desabilitar: o acesso termina. O histórico de auditoria é mantido independentemente, porque um registro que nomeia alguém que não existe mais é pior do que um marcado como retirado.
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:
- Uma sombra não pode entregar. Ela contém um pipeline de transformação e nenhum remetente, por isso não há caminho de código de aqui para um receptor. Uma configuração não pode criar um e um erro não pode ativá-lo. - Uma sombra não pode afetar o canal ao vivo. Ela é chamada após a mensagem ao vivo ter sido entregue e confirmada, seus panics são recuperados e seus tempos limite são seus.
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
26.110 umlink
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:
- Um valor que não pode ser mapeado é preservado como texto, nunca adivinhado. Um código local transformado em um código padrão plausível é pior do que um valor não codificado, porque o receptor acredita. - Cada decisão de mapeamento que envolveu julgamento é relatada como uma nota, para que um humano possa verificar as que importam em vez de ler toda a saída. - Os carimbos de data e hora são convertidos, não copiados. Os carimbos de data e hora HL7 v2 não são ISO 8601, e um dateTime que carrega um horário local sem offset é a razão mais comum pela qual um recurso convertido é rejeitado. - As unidades mantêm seu texto original e ganham um código UCUM apenas quando o mapeamento é certo. Um código de unidade errado é um defeito de segurança do paciente, não um problema de formatação.
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:
- Um ficheiro que está a ser escrito e um ficheiro que terminou de ser escrito são indistinguíveis. Não há bloqueio, não há sinalizador e não há notificação em nenhum desses transportes - há um tamanho e um tempo de modificação, e ambos são verdadeiros para um ficheiro meio escrito. Ler demasiado cedo recolhe metade de uma mensagem, e o HL7 não tem terminador, por isso metade de uma mensagem é muitas vezes ainda analisável. O MSH está intacto, os segmentos que chegaram estão bem formados, os que não chegaram estão simplesmente ausentes. É aceite, confirmado, armazenado, entregue, e nada mencionará isso. - Um ficheiro não deve ser eliminado até que todas as mensagens nele sejam aceites, porque o ficheiro é a única cópia. - Um ficheiro que falhou não deve ser recolhido novamente na próxima sondagem para sempre, e não deve ser silenciosamente eliminado.
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 é:
- O algoritmo de assinatura é fixado no registo e armazenado com a chave. Nada no login lê um algoritmo do cliente, porque isso é confusão de algoritmo e não há função aqui que possa fazer isso. - A origem é comparada exatamente, nunca por prefixo ou sufixo. Uma verificação que aceita qualquer coisa que termine no domínio correto aceita uma subdomínio de um atacante. - Um desafio é de uso único e expira. É eliminado quando consumido, por isso uma afirmação capturada não pode ser reproduzida. - A atestação não é confiável para nada. A declaração de atestação é analisada para extrair a credencial e, em seguida, a sua assinatura é ignorada, porque verificar adequadamente precisa de um repositório de raiz mantido e fingir verificar é pior do que não reivindicar. - O contador de assinatura é verificado quando o autenticador fornece um, e a sua ausência não é tratada como suspeita. Muitos autenticadores legitimamente o deixam em zero.
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
| Chave | Aparece em |
|---|---|
access_key_id | Acesso AWS, Autenticação FHIR, Destino S3 |
account | Acesso Azure Blob |
ack | Origem HTTP, Origem SOAP, Origem |
ack_sender_id | Opções X12 |
ack_sender_qualifier | Opções X12 |
acknowledge | Opções EDIFACT, Opções HL7v3, Opções X12 |
acks | Destino Kafka |
action | Destino SOAP |
addr | Conexão AMQP, Destino Broker, Origem Broker, Conexão MQTT |
address | Conexão AMQP, Destino DICOM, Origem de Consulta DICOM, Destino, Endereço Direto, Destino TCP |
ae_title | Origem DICOM |
after_query | Origem de Banco de Dados |
after_read | Origem Azure Blob, IMAP Direto, Origem de E-mail, Poll de Arquivos, Origem GCS, Origem S3, Origem SFTP |
allow | Scripts |
allow_clear_password | Destino FTP |
allow_unencrypted | Parceiro AS2, Recebimento PGP |
allow_unsigned | Parceiro AS2 |
allowed_calling_ae | Origem DICOM |
allowed_senders | Origem de E-mail |
amqp | Destino, Origem |
anchors_file | Endereço Direto |
api_version | Conexão IBMMQ |
append | Destino, Destino SFTP |
application | Confirmação |
armor | Envio PGP |
arrives_as | Opções X12 |
as2 | Destino, Origem |
attach | Destino SMTP |
attach_name | Destino Direto, Destino SMTP |
attachment_names | Origem de E-mail |
attachments | Canal |
attempts | Retentativa |
auth | Destino FHIR, Destino PAS |
authorities | Destino MPI |
azure_blob | Destino, Origem |
backoff | Configuração de Fila, Retentativa |
base64 | Origem SOAP |
batch_size | Origem de Banco de Dados, Poll de Arquivos |
baud | Origem Serial |
bcc | Destino SMTP |
bearer_token | Destino CDA, Destino FHIR, Destino HTTP, Destino PAS |
big_endian | Estruturação TCP |
blob | Destino Azure Blob |
body | Destino SMTP, Destino SOAP |
broker | Destino, Origem |
brokers | Destino Kafka, Origem Kafka |
bucket | Acesso GCS, Destino S3, Origem S3 |
bundle_script | Destino FHIR |
called_ae | Destino DICOM, Origem de Consulta DICOM |
calling_ae | Destino DICOM, Origem de Consulta DICOM |
cc | Destino SMTP |
cda | Destino |
cert_file | Destino AS2, Parceiro AS2, Origem AS2, Endereço Direto |
channel | Destino, Sombra |
check_every | Referência de Contrato |
city | Instalação ECR |
claim_us_core | Destino FHIR |
class | Destino XDS |
client_ca_file | XDR Direto |
client_id | Autenticação de E-mail, Autenticação FHIR, Conexão MQTT |
client_secret | Autenticação de E-mail, Autenticação FHIR |
code | Código XDS |
column | Origem de Banco de Dados |
columns | Delimitado |
comment | Delimitado |
commit_after_delivery | Origem Kafka |
compare | Sombra |
compress | Destino AS2 |
compression | Destino Kafka |
config | Destino ELR |
container | Acesso Azure Blob |
content_type | Destino AMQP, Destino AS2, Destino Azure Blob, Destino Broker, Destino GCS, Destino HTTP, Destino S3, Destino XDS |
contract | Canal |
credentials_file | Acesso GCP |
dataType | Canal |
data_bits | Origem Serial |
database | Destino, Origem |
decrypt_with | Recebimento PGP |
default_identifier_system | Destino FHIR |
delimited | Canal |
delimiter | Delimitado, Estruturação TCP |
deploy | Scripts |
description | Canal |
destination | Destino Broker, Origem Broker |
destinations | Canal |
dicom | Canal, Destino, Origem |
dicom_query | Origem |
dicomweb | Destino, Origem |
dir | Destino CDA, Destino, Destino de Documento, Destino FTP, Poll de Arquivos, Origem SFTP, Origem SFTP |
direct | Destino, Origem |
direct_from | Destino XDS |
direct_to | Destino XDS |
display | Código XDS |
dns | Destino Direto |
document | Destino |
domain | Origem SMB |
driver | Destino de Banco de Dados, Origem de Banco de Dados |
dsn | Destino de Banco de Dados, Origem de Banco de Dados |
duplicate_window | Origem AS2 |
ecr | Destino FHIR |
edifact | Canal |
element | Origem SOAP |
elr | Destino |
email | Origem |
emit_on_first_poll | Origem de Consulta DICOM |
enabled | Canal, Destino, Configuração de Fila |
encrypt_to | Envio PGP |
endpoint | Acesso AWS, Acesso Azure Blob, Acesso GCP, Destino S3 |
envelope | Opções EDIFACT, Opções X12 |
error_dir | Poll de Arquivos, Origem SFTP |
error_folder | IMAP Direto, Origem de E-mail |
error_prefix | Origem Azure Blob, Origem GCS, Origem S3 |
expect_reply | Destino TCP |
extract | Anexos |
facility | Confirmação, Destino ECR |
facility_id | Destino SOAP |
facility_type | Destino XDS |
fail_on_body | Destino HTTP |
fault_is_success | Destino SOAP |
fault_on_nak | Origem SOAP |
fhir | Destino |
file | Referência de Contrato, Origem |
file_name | Destino AS2, Destino, Destino de Documento, Destino FTP, Envio PGP, Destino SFTP |
file_roots | Scripts |
filter | Canal, Delimitado, Destino, Opções HL7v3, Scripts |
flow_control | Origem Serial |
follow_redirects | Destino HTTP |
follow_symlinks | Origem de Arquivos |
font_size | Destino de Documento |
format | Destino de Documento, Destino S3 |
framed | Origem Azure Blob, Destino FTP, Poll de Arquivos, Origem GCS, Destino S3, Origem S3, Destino SFTP, Origem SFTP |
framing | Estruturação TCP |
from | Destino AS2, Destino SMTP |
from_beginning | Origem Kafka |
ftp | Destino, Origem |
gcs | Destino, Origem |
group | Canal, Origem Kafka |
group_by | Destino SNS, Destino SQS |
has_header | Delimitado |
header | Destino SOAP |
headers | Destino Broker, Destino CDA, Destino DICO Mweb, Destino FHIR, Destino HTTP, Destino Kafka, Destino SOAP, Destino XDS |
heartbeat | Origem Broker |
hl7v3 | Canal |
host | Destino Broker, Origem Broker, IMAP Direto, Origem de E-mail, Destino FTP, Origem FTP, Destino SFTP, Origem SFTP, Origem SMB, Destino SMTP |
hostname | Conexão AMQP |
http | Destino, Origem |
ibm_mq | Destino, Origem |
id | Parceiro AS2, Origem AS2 |
id_type | Destino MPI |
identifier_systems | Destino CDA, Destino FHIR |
idle_timeout | Origem DICOM, Origem, Origem TCP |
ignore | Sombra |
imap | Origem Direta |
include | Scripts |
include_trigger_event | Confirmação |
insecure_skip_host_key_check | Destino SFTP, Origem SFTP |
insecure_skip_verify | Destino FTP, Origem FTP, Destino SMTP, Origem Web DAV |
interval | Origem de Consulta DICOM |
javascript | Destino, Origem |
kafka | Destino, Origem |
keep_alive | Destino TCP |
keep_blank_lines | Delimitado |
keep_delimiter | Estruturação TCP |
key | Acesso Azure Blob, Destino Kafka, Destino S3 |
key_column | Origem de Banco de Dados |
key_file | Destino AS2, Origem AS2, Endereço Direto, Destino SFTP, Origem SFTP |
key_passphrase | Destino SFTP, Origem SFTP |
known_hosts_file | Destino SFTP, Origem SFTP |
landscape | Destino de Documento |
language | Scripts |
ldap | Destino Direto |
length_bytes | Estruturação TCP |
length_includes_header | Estruturação TCP |
level | Origem de Consulta DICOM |
limit | Origem de Consulta DICOM |
line | Instalação ECR |
listen | Origem AS2, Origem DICO Mweb, Origem DICOM, Origem Direta, XDR Direto, Origem HTTP, Origem SOAP, Origem, Origem TCP |
login | Destino Broker, Origem Broker |
mailbox | IMAP Direto, Origem de E-mail |
match | Origem de Consulta DICOM |
max_attempts | Origem de Banco de Dados, Configuração de Fila |
max_backoff | Configuração de Fila, Retentativa |
max_bytes | Origem Direta |
max_connections | Origem, Origem TCP |
max_depth | Configuração de Fila |
max_differences | Sombra |
max_file_size | Poll de Arquivos, Origem SFTP |
max_message_size | Origem AS2, Origem de E-mail, Origem HTTP, Origem Kafka, Origem SOAP, Origem Serial, Origem, Destino TCP, Origem TCP |
max_messages | Origem Pub Sub, Origem SQS |
max_object_bytes | Origem DICO Mweb, Origem DICOM |
max_object_size | Origem Azure Blob, Origem GCS, Origem S3 |
max_open_conns | Destino de Banco de Dados |
mechanism | Autenticação SASL Kafka |
method | Destino HTTP |
move_to | Origem Azure Blob, IMAP Direto, Origem de E-mail, Poll de Arquivos, Origem GCS, Origem S3, Origem SFTP |
mpi | Destino |
mqtt | Destino, Origem |
name | Canal, Destino de Canal, Destino, Instalação ECR |
ncpdp | Canal |
no_compress | Envio PGP |
no_merge | Destino MPI |
non_persistent | Destino IBMMQ |
npi | Instalação ECR |
oauth | Origem de E-mail |
object | Destino GCS |
on_no_document | Destino CDA |
order_by | Destino Pub Sub |
over | Referência de Contrato |
overlap | Origem de Consulta DICOM |
params | Destino de Banco de Dados |
parity | Origem Serial |
partner_cert_file | Destino AS2 |
partners | Origem AS2 |
pas | Destino |
pass_plain | Recebimento PGP |
passcode | Destino Broker, Origem Broker |
passphrase | Recebimento PGP, Envio PGP |
password | Conexã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 |
path | Origem AS2, Origem DICO Mweb, Origem HTTP, Origem SOAP |
path_style | Destino S3, Origem S3 |
patient_domain | Destino XDS |
patient_root | Origem de Consulta DICOM |
pattern | Poll de Arquivos, Origem SFTP |
payer | Destino PAS |
persistent | Destino Broker |
pgp | Destino, Origem |
phone | Instalação ECR |
poll_interval | Origem 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 |
port | IMAP Direto, Origem de E-mail, Origem Serial |
postal_code | Instalação ECR |
postprocessor | Scripts |
practice_setting | Destino XDS |
prefetch | Origem AMQP |
prefix | Origem Azure Blob, Origem GCS, Origem S3 |
preprocessor | Scripts |
profile | Destino SOAP, Origem SOAP |
project | Acesso GCP |
protocol | Origem de E-mail |
provider | Autenticação de E-mail |
pubsub | Destino, Origem |
purpose | Destino TEFCA |
qos | Conexão MQTT |
query | Origem de Banco de Dados |
query_timeout | Origem de Banco de Dados |
queue | Destino, Conexão IBMMQ |
queue_manager | Conexão IBMMQ |
queue_url | Destino SQS, Origem SQS |
quiet_after | Origem Serial |
quote | Delimitado |
raw | Poll de Arquivos |
rctc | Destino ECR, Destino ELR |
read_timeout | Origem HTTP, Origem SOAP |
reassemble | Anexos |
receipt | Destino AS2 |
receipt_url | Destino AS2 |
recipient_certs_dir | Destino Direto |
reconnect | Origem AMQP, Origem Broker, Origem MQTT, Origem Pub Sub |
record_length | Estruturação TCP |
refresh_token | Autenticação de E-mail |
region | Acesso AWS, Autenticação FHIR, Destino S3 |
reject_on_warning | Destino FHIR |
relaxed | Delimitado |
reopen_after | Origem Serial |
reply | Origem Serial, Origem TCP |
reply_text | Origem Serial, Origem TCP |
request_mdn | Destino Direto |
require_agreement | Destino CDA |
require_signature | Recebimento PGP |
response_element | Origem SOAP |
response_namespace | Origem SOAP |
response_transformer | Destino |
results_to | Destino PAS, Destino TEFCA |
retain | Destino MQTT |
retain_hours | Destino, Configuração de Fila |
retry | Destino |
return | Origem de Consulta DICOM |
root | Origem FTP, Origem de Arquivos, Origem SMB |
s3 | Destino, Origem |
sample | Sombra |
sas | Acesso Azure Blob |
sasl | Destino Kafka, Origem Kafka |
scheme | Código XDS |
scope | Autenticação de E-mail, Autenticação FHIR |
script | Canal, Destino Java Script, Origem Java Script |
scripts | Canal |
secret_access_key | Acesso AWS, Autenticação FHIR, Destino S3 |
security | IMAP Direto, Origem de E-mail, Destino FTP, Origem FTP |
selector | Origem Broker |
sender_device | Opções HL7v3 |
sender_oid | Opções HL7v3 |
serial | Origem |
server_side_encryption | Destino S3 |
session_timeout | Origem Kafka |
session_token | Acesso AWS, Autenticação FHIR, Destino S3 |
sftp | Destino, Origem |
shadow | Canal |
share | Origem SMB |
sign_with | Envio PGP |
smb | Origem |
smtp | Destino |
smtp_host | Destino Direto, Origem Direta |
sns | Destino |
soap | Destino, Origem |
sop_classes | Origem DICOM |
sort_by | Poll de Arquivos |
source | Canal, Destino ECR |
source_id | Destino XDS |
split | Delimitado, Opções EDIFACT, Opções X12 |
sqs | Destino, Origem |
ssn_system | Destino MPI |
stable_for | Poll de Arquivos, Origem SFTP |
start_block | Estruturação TCP |
starttls | Destino SMTP |
state | Instalação ECR |
statement | Destino de Banco de Dados |
stop_bits | Origem Serial |
storage_class | Destino GCS, Destino S3 |
subject | Destino AS2, Destino Direto, Destino SMTP, Destino SNS |
subscription | Origem Pub Sub |
subscription_id | Origem Broker |
success_on_undefined | Destino Java Script |
success_status | Destino HTTP |
suffix | Origem Azure Blob, Origem GCS, Origem S3 |
tables | Canal |
take | Origem de E-mail |
tcp | Destino, Origem |
tefca | Destino |
temp_suffix | Destino, Destino de Documento, Destino FTP, Destino SFTP |
template | Origem de Banco de Dados, Destino de Documento |
tenant | Autenticação de E-mail |
tenant_id | Autenticação FHIR |
text | Destino Direto |
tier | Destino Azure Blob |
timeout | Conexã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 |
timezone | Destino FHIR |
title | Destino de Documento |
tls | Conexã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_cert | Origem Direta, XDR Direto |
tls_key | Origem Direta, XDR Direto |
to | Destino AS2, Destino Direto, Destino SMTP |
token | Destino DICO Mweb, Origem DICO Mweb, Origem HTTP, Origem SOAP, Destino XDS |
token_url | Autenticação de E-mail, Autenticação FHIR |
topic | Destino Kafka, Destino MQTT, Origem MQTT, Destino Pub Sub |
topic_arn | Destino SNS |
topics | Origem Kafka |
transfer_syntaxes | Destino DICOM, Origem DICOM |
transformations | Canal, Opções DICOM, Delimitado, Opções HL7v3, Opções NCPDP, Opções de Script, Opções X12 |
transformer | Scripts |
trim_padding | Estruturação TCP |
trim_space | Delimitado |
type | Destino, Autenticação FHIR, Origem |
undeploy | Scripts |
unencrypted | Destino AS2 |
unsigned | Destino AS2 |
unsigned_receipt | Destino AS2 |
url | Destino AS2, Destino CDA, Destino DICO Mweb, Destino FHIR, Destino HTTP, Conexão IBMMQ, Destino SOAP, Origem Web DAV, Destino XDS |
user | Destino FTP, Origem FTP, Destino SFTP, Origem SFTP, Origem SMB, Origem Web DAV |
username | Conexã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_send | Destino FHIR |
verify_with | Recebimento PGP |
version | Destino CDA, Destino FHIR, Destino SOAP, Origem SOAP |
visibility_timeout | Origem SQS |
wait_seconds | Origem SQS |
warnings_are_errors | Destino SOAP |
webdav | Origem |
when | Confirmação |
window | Origem de Consulta DICOM |
write | Destino CDA |
wsdl | Origem SOAP |
x12 | Canal |
x12_as | Destino |
xdm | Destino Direto |
xdm_source_id | Destino Direto |
xdr | Origem Direta |
xds | Destino |