1 Introduzione

Perfuse sposta messaggi clinici tra sistemi che non sono stati progettati per comunicare tra loro. Un laboratorio invia risultati in HL7 v2; il sistema di gestione della pratica si aspetta di riceverli con posizioni di campo diverse, un identificatore di paziente diverso e un acknowledgement entro cinque secondi. Qualcosa deve essere posizionato al centro, e quel qualcosa è un motore di integrazione.

Questo manuale descrive cosa fa Perfuse, ogni opzione che accetta e — dove una decisione non è ovvia — perché funziona in quel modo.

1.1 A cosa serve Perfuse

Un'interfaccia singola tra due sistemi clinici è solitamente costosa, con un prezzo che varia dalle decine di migliaia di euro, con il 15-20% di quel costo aggiuntivo ogni anno per la manutenzione. Gran parte di quel costo non è il lavoro; è che il lavoro richiede qualcuno che abbia già lavorato con HL7, e la maggior parte delle pratiche non assume qualcuno con queste competenze.

Perfuse è stato costruito sull'assunzione che la persona che lo configura abbia un problema da risolvere e non abbia esperienza precedente con HL7. Quell'assunzione si manifesta in luoghi specifici:

Il capitolo su testing e quello su migration esistono perché la risposta a "perché dovrei fidarmi di questo" deve essere basata su prove che tu stesso puoi raccogliere, non su una dichiarazione fatta qui.

1.2 Cosa contiene

Tutto ciò che segue è nel singolo file binario. Ogni riga nomina il capitolo che lo copre.

1.3 Standard e versioni

Quale versione di ogni standard Perfuse implementa e come è stata verificata. "Verificata" nomina lo strumento o la fonte esterna che ha giudicato il risultato; se nulla all'esterno lo ha giudicato, dice così. I risultati provengono da dati di test, non da un sito di produzione.

1.3.1 Messaggistica e documenti

StandardVersioneVerificata
HL7 v2qualsiasi versione: i messaggi vengono letti dai propri separatori, non da uno schema di versione; le conferme predefinite sono 2.5.1Validatore HL7 v2 NIST; traffico reale Mirth e OIE
HL7 v2 a FHIRmappatura V2-to-FHIR di HL7 (ADT, ORU, SIU, MDM, VXU e i segmenti in essi)Validatore FHIR HL7 contro US Core, UK Core, FR Core, ISiK, nl-core e HL7 Europa
FHIRR4 (4.0.1), con R4B e R5 letti e scrittiValidatore FHIR HL7; Inferno
C-CDA e CDAC-CDA 2.1SITO ONC (campioni C-CDA inviati e ricevuti tramite XDR); non da uno schematron CDA
HL7 v3PIX e PDQ (IHE ITI-44, 45, 47)Schemi NE2008 IHE e messaggi di esempio
DICOM e DICOMwebDIMSE C-STORE, C-FIND, C-MOVE, C-GET, C-ECHO; QIDO-RS, WADO-RS, WADO-URI, STOW-RSOrthanc
X12 (HIPAA)005010: 837, 835, 270/271 (X279A1), 276/277 (X212), 834, 278 richiesta (X217) e inchiesta (X215); 275 in 006020 (X314)Guide di accompagnamento dei pagatori pubblicate; campioni CMS esMD
CAQH CORE connettivitàvC2.2.0 SOAP e MIME, vC4.0.0 con MTOMUn sistema UM sostitutivo scritto dalle regole CAQH
NCPDPTelecommunicazione D.0; SCRIPT 2023011 (e 2017071) con ePA; Real-Time Prescription Benefit v13Scritto dalle guide di accompagnamento pubbliche Surescripts e dai loro esempi; non contro gli schemi NCPDP con licenza
UN/EDIFACTsintassi 3 e 4, CONTRLpydifact 0.1.8
Condivisione di documenti IHEXDS.b, XCA, XDR, MHD 4.2.2, PIXm, PDQm, XDMToolkit XDS NIST; SITO ONC
Messaggistica sicura DirectDichiarazione di applicabilità 1.2, XDR e XDM per Direct, DNS e LDAP discovery certificateSITO ONC; Strumento di discovery del certificato ONC (18 su 18)
AS2RFC 4130, compressione RFC 5402pyas2lib
Allegati firmatiHL7 DSDR, XAdES-X-Lxmlsec1, OpenSSL

1.3.2 Guide all'implementazione di FHIR

GuidaRilascioVerificato
US Coreconversioni in 9.0.0 (USCDI v6); server FHIR contro 6.1.0 e 7.0.0il validatore HL7; Inferno US Core
SMART App Launch2.2Inferno: 80 di 80 (app pubblica)
Bulk Data Access2.0.0Inferno: 48 di 48
Abbonamenti R5 Backportper R4un ricevitore HTTP reale; i test di notifica del kit PAS
Da Vinci CRD2.2.1 e 2.1.0Inferno 2.2.1: 92 superati, nessuno fallito; 2.1.0 dagli esempi della guida stessa
Da Vinci DTR2.2.0 e 2.1.0Inferno 2.2.0: 43 superati, 2 falliti (un difetto del kit); 2.1.0 dagli esempi della guida stessa
Da Vinci PAS2.2.1 e 2.1.0Inferno 2.2.1: 82 di 84; 2.1.0 dagli esempi della guida stessa
Da Vinci PAS, invio (lato fornitore)2.2.1l'implementazione di riferimento del pagatore Da Vinci PAS; non un pagatore di produzione
Da Vinci PDex2.2.0Inferno PDex 2.0: pagatore a pagatore 19 di 19
Da Vinci HRex $member-match1.2.0Inferno PDex pagatore a pagatore
Da Vinci ATR2.1.0non verificato da uno strumento esterno
Da Vinci CDex $submit-attachment2.1non verificato da uno strumento esterno
Da Vinci Plan-Net1.1.0Inferno: 199 superati, 10 falliti (un difetto del kit)
Da Vinci US Drug Formulary2.1.0il validatore HL7
ISiK (ospedali tedeschi), server FHIRStufe 5, modulo di basesuite di test ISiK di gematik 3.0.9: 421 di 421
PACIO Transizioni di assistenza, Profilo farmacologico, Direttive anticipate, Funzionamento1.0.0, 1.0.0, 2.0.0-ballot, 2.0.0kit Inferno PACIO con dati PACIO: ogni errore nei dati o nel kit. C-CDA al documento TOC: il validatore HL7 sugli esempi HL7, un errore rimasto, la guida stessa
CARIN Blue Button2.2.0il validatore HL7
eCR2.1.2il validatore HL7
ELRHL7 2.5.1 ELR Release 1 con le sue erratestrumento ELR di ONC: 28 di 28
Riepilogo internazionale del paziente2.0.0il validatore HL7
DEQM5.0.0il validatore HL7
SQL su FHIRv2la suite di test ufficiale: 144 di 144
SMART Health Cards e LinksCards 1.4, Links STU 1la carta di esempio delle specifiche; una libreria di visualizzazione SMART Health Links pubblicata
Sicurezza UDAPSTU 1un server di autorizzazione reale e una comunità di trust
FHIR facilitato da TEFCASOP v2.0non verificato contro un QHIN reale

1.3.3 Profili nazionali e europei

Verificato convertendo messaggi HL7 v2 pubblicati o inventati e convalidando ogni risorsa; i risultati completi e le ragioni di ogni fallimento sono nella cartella conformance/national del repository.

ProfiloRilascioRisorse valide
UK CoreSTU2 2.0.2185 di 187
FR Core2.2.0138 di 156
ISiK Basismodul4.0.3 (Stufe 4)18 di 47; 42 di 47 con lo script del bundle dell'ospedale
Nictiz nl-core0.12.1-beta.1 (zib 2020)12 di 24; 18 di 24 con lo script del bundle dell'ospedale
HL7 Europe Laboratory Report2.1.0106 di 426 (la guida si aspetta un documento a v2 risultato non è)
HL7 Europe Hospital Discharge Report1.0.068 di 69

Nessuno di questi è un certificato. Perfuse non è stato certificato da ONC, CMS, gematik, Nictiz, NHS England o da chiunque altro.

1.4 Cosa sostituisce

Perfuse copre il terreno occupato da Mirth Connect e può importare direttamente le esportazioni dei canali Mirth. Il capitolo su migration descrive cosa si traduce in modo pulito, cosa richiede una decisione e come dimostrare che il risultato corrisponde prima di passare alla versione definitiva.

Le differenze che contano nell'uso quotidiano sono il debugging e il silenzio. In Mirth, vedere cosa un trasformatore abbia fatto a un messaggio solitamente significa ridistribuire il canale con la registrazione aggiunta. In Perfuse, qualsiasi messaggio registrato può essere riprodotto attraverso la configurazione corrente e ispezionato passo dopo passo, senza toccare il canale in esecuzione. E dove un allarme Mirth su "nessun traffico" è una soglia fissa che è inutile su qualsiasi flusso che è silenzioso di notte, Perfuse apprende cosa cada flusso normale settimanale sembri e si allarma contro di esso.

1.5 Come leggere questo manuale

I primi capitoli sono concettuali e vale la pena leggerli in ordine: canali, flusso di messaggi, quindi trasformazione. Tutto ciò che segue può essere letto come necessario.

I capitoli di riferimento vicino alla fine elencano ogni chiave di configurazione, il suo tipo, se è richiesta e il valore predefinito. Quei capitoli sono generati dal codice sorgente, quindi non possono descrivere un'opzione che non esiste o omettere una che esiste. Se una chiave appare in un file di configurazione e non nell'indice, non è una chiave di Perfuse.

1.6 Convenzioni

La configurazione è in YAML. La maggior parte delle chiavi sono in snake_case sulla rete — max_message_size, idle_timeout — e questo manuale fornisce sempre la forma sulla rete, perché è quello che si digita. C'è un'eccezione storica, dataType su un canale, che è in camelCase; è documentata in quel modo nel riferimento del canale e accettata solo con quella ortografia.

I riferimenti ai campi in HL7 utilizzano la notazione usuale: PID-5 è il quinto campo del segmento PID, PID-5.1 è il suo primo componente e PID-3(2) è la seconda ripetizione del terzo campo. Un percorso scritto senza una ripetizione si riferisce a ogni ripetizione (vedere percorsi).

Le durate sono scritte come un numero e un'unità — 30s, 5m, 2h. Un numero senza unità non è una durata e verrà rifiutato piuttosto che essere oggetto di congetture.

2 Guida introduttiva

Perfuse è un singolo file eseguibile con un'interfaccia web incorporata. Non c'è un server di applicazioni da installare, non c'è un database da configurare e non c'è una console di amministrazione separata.

2.1 Esecuzione

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

-channels è una directory di file YAML, uno per canale. -db è un file SQLite che contiene i messaggi registrati, gli utenti e la cronologia di audit; viene creato se non esiste.

Al primo avvio senza utenti configurati, viene creata un'account amministratore e la sua password viene scritta nel log una volta. Quella password non è più recuperabile dopo.

Eseguire senza -tls-cert e -tls-key serve HTTP non crittografato. Ciò è accettabile su un indirizzo di loopback per un primo sguardo e non è accettabile altrove: l'interfaccia web trasporta credenziali e contenuto dei messaggi, entrambi leggibili sulla rete senza TLS. Vedi sicurezza.

2.2 Il primo canale

Un canale necessita di un nome, una sorgente e almeno una destinazione. Il più piccolo canale utile riceve HL7 su MLLP e scrive ogni messaggio su un file:

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

Salva ciò come channels/first-feed.yaml e verrà caricato senza riavvio.

Tre cose di quel file sono degne di nota, perché sono la forma di ogni canale:

2.3 Creare un canale dall'interfaccia

Tutto ciò che è stato fatto sopra può essere fatto dall'interfaccia web invece, e per un primo canale è la via migliore perché il modulo non ti lascerà produrre un file che non carica.

Il costruttore offre tre modi per iniziare:

  1. Da un messaggio che qualcuno ti ha inviato. Incolla il campione che il laboratorio o il fornitore ti ha inviato via email. Perfuse legge e propone un canale, insieme a tre elenchi separati: ciò che il campione mostra, ciò che è stato indovinato e ciò che nessun campione può dirti. Ciò è descritto in testing.
  2. Da qualcosa che già funziona. Un set di canali completi che necessitano solo degli indirizzi compilati.
  3. Da nulla. Un modulo vuoto. Disponibile, ma è il più lento dei tre e il più facile da sbagliare.

2.4 Verificare che funzioni prima di collegare qualcosa

Due cose possono essere fatte prima che il sistema di invio esista.

Inviare un messaggio a mano dall'interfaccia — il mittente del messaggio accetta testo incollato e riporta cosa gli è successo, compresi quali destinazioni l'hanno accettato e cosa ogni trasformazione ha fatto.

O generare traffico di test. Se il canale ha gestito alcuni messaggi, Perfuse può imparare la loro forma e produrre più messaggi simili, nelle stesse proporzioni, senza alcun contenuto originale. Vedi testing.

2.5 Cosa fare dopo

3 L'Interfaccia Web

Perfuse è costruito sull'assunzione che tutto sia possibile da eseguire dal browser e una funzionalità che può essere raggiunta solo modificando un file è trattata come un difetto. Questo capitolo è una panoramica di ciò che si trova dietro ogni parte della navigazione, organizzato nel modo in cui è l'interfaccia: per la domanda che si sta ponendo.

La barra contiene Dashboard e Canali direttamente, perché sono dove la maggior parte delle sessioni inizia e termina. Tutto il resto è raggruppato e i gruppi sono nominati dopo le domande piuttosto che dopo i sottosistemi — non si va al "sottosistema di audit", si va a scoprire chi ha modificato qualcosa.

3.1 Lettura dell'intestazione

Ci sono cinque cose nell'intestazione che è facile perdere.

Ogni vista ha un indirizzo. La barra degli indirizzi segue la vista — #/channels, #/messages, #/settings — quindi un reload ritorna ad esso, un segnalibro lo apre, un collegamento inviato a un collega li porta su di esso e il pulsante indietro si sposta tra le viste invece di uscire dalla console. Un indirizzo che nomina una vista al di sopra del proprio ruolo apre il cruscotto invece.

Ricerca, o ⌘K. Cerca attraverso canali, impostazioni, messaggi e il manuale, il che significa che è solitamente più veloce della navigazione — in particolare per un'impostazione il cui nome si ricorda a metà.

Tema. Tre di essi: Midnight, Dark e Light. Midnight è quasi nero ed è ciò che una visualizzazione a muro in una stanza dei server di solito vuole; Dark è un grigio neutro più morbido; Light è per un laptop accanto a una finestra. La scelta è archiviata nel browser piuttosto che contro l'account, perché un tema è una proprietà di dove qualcuno si trova, non di chi è — lo stesso operatore vuole Midnight sul muro e Light sul treno. La preferenza della macchina stessa viene consultata una volta, per scegliere un default sensibile la prima volta.

Lingua. La console in inglese (ordine di data UK o US), tedesco, francese, olandese, spagnolo, italiano, portoghese, polacco, svedese, danese, norvegese o finlandese, con date e numeri scritti nel modo in cui la locale li scrive. La scelta viene mantenuta nel browser e la lingua del browser viene utilizzata fino a quando non se ne sceglie una. Le traduzioni sono state eseguite da una macchina e non sono ancora state revisionate da madrelingua; l'inglese è il riferimento e il selettore lo indica. Il codice, i messaggi, i payload, i nomi dei canali e tutto ciò che viene digitato non vengono mai tradotti. Il manuale viene pubblicato nelle stesse lingue all'indirizzo https://perfuse.health/manual/<language>/ (il Manuale di questo server è quello inglese).

Manuale. Il documento che si sta leggendo, servito dal server in esecuzione. È lo stesso file che il binary può scrivere su disco, quindi descrive sempre la versione di fronte a voi piuttosto che l'ultima versione rilasciata.

3.2 Monitor — se funziona e cosa è successo

3.2.1 Dashboard

Lo stato di ogni canale, il throughput e tutto ciò che è attualmente sbagliato. Questo è lo schermo da lasciare aperto.

3.2.2 Messaggi

Ogni messaggio che è arrivato, cosa è stato trasformato, per destinazione e cosa gli è successo. Ricerchabile, compreso tramite un'espressione di filtro, quindi "mostrami quelli da questo mittente che sono stati rifiutati" è una query piuttosto che un pomeriggio.

Un messaggio può essere riprodotto da qui e rielaborato attraverso la *configurazione corrente* piuttosto che quella che era live al momento — che è il modo in cui si conferma che una correzione funziona contro il traffico che lo ha rotto. Vedi l'archivio di messaggi per cosa viene mantenuto e per quanto tempo.

3.2.3 Coda

Cosa sta aspettando di essere consegnato e perché. Una coda che non si svuota è l'avvertimento precoce più utile che un motore di integrazione produce e vale la pena accoppiarlo con una regola di allarme in modo che nessuno debba essere in ascolto. Vedi consegna.

3.2.4 Allertamenti

Cosa è stato attivato e quali sono le regole. Le regole vengono modificate qui piuttosto che in un file. Vedi allarmi.

3.2.5 Metriche

Throughput, latenza e tassi di errore nel tempo. Utile per le domande di capacità e, più spesso, per i pacchetti di amministrazione — il che è il motivo per cui il logo del sito appare su di esso se ne è stato caricato uno.

3.2.6 SQL su FHIR

SQL su viste FHIR: seleziona un esempio o una vista salvata, o scrivine una, eseguila sullo store FHIR di questo server (tutti i pazienti o uno) o su risorse incollate, vedi le righe con i loro tipi e scarica CSV, NDJSON o Parquet. Salva la conserva per l'endpoint FHIR $sql-run. Vedi formati di messaggio.

3.2.7 Misure di qualità

Misure di qualità digitali: seleziona un esempio o una Misura nello store FHIR, o scrivine una con criteri FHIRPath. Scegli un periodo di misurazione e un report (riassunto, riassunto con elenchi di pazienti o un paziente) e valuta su lo store FHIR o risorse incollate. Lo schermo mostra il conteggio di ogni popolazione e i pazienti, il punteggio e gli strati. Scarica MeasureReport salva il risultato FHIR e Salva nello store FHIR conserva la Misura per Measure/$evaluate-measure. Le Misure in CQL sono rifiutate: Perfuse non ha un motore CQL. Vedi misure di qualità digitali.

3.2.8 Mappa del flusso

Un'immagine di come i messaggi si muovono effettivamente: quali sorgenti alimentano quali canali e quali destinazioni raggiungono.

Il suo valore non è una decorazione. Ogni proprietà accumula un canale che nessuno ricorda di aver commissionato e una destinazione che nessuno si è reso conto di essere ancora in ricezione, e entrambi sono visibili qui in un modo che non lo sono in un elenco di file di canali.

3.2.9 Cruscotti di squadra

Un dashboard per ogni tipo di persona che guarda le interfacce: Operazioni, Connessioni, Analista di interfaccia, Autorizzazione preventiva, Imaging, Ciclo di fatturazione, Laboratorio, Privacy e sicurezza e un riassunto del dipartimento in parole semplici. I riquadri mostrano conteggi, stati e tempi, mai un messaggio o un paziente, quindi un dashboard può essere inviato a un manager o a uno schermo di parete senza allargare chi vede i dati dei pazienti.

Ogni persona apre il cruscotto del proprio gruppo di directory o ruolo. -dashboards dashboards.yaml li mappa:

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

Un gruppo vince su un ruolo e chiunque non corrisponda si apre su Operazioni. Organizza riquadri nasconde e riordina i riquadri, il selettore di canale li filtra e Salva come mia vista li conserva come proprio dashboard fino a Reset.

Esporta in Grafana scarica il cruscotto come JSON di Grafana su /metrics, con una variabile di origine dei dati e un filtro di canale, per chiunque abbia bisogno di più della configurazione leggera. I riquadri senza metriche alle spalle vengono esclusi e la descrizione dell'esportazione nomina questi ultimi.

La piastrella Connessioni controlla ogni destinazione in rete in strati. Cerca il nome, apre una connessione TCP, completa il TLS dove viene utilizzato e legge l'ultimo recapito e fallimento del destinatario dal traffico reale. Ogni fallimento indica cosa significa, ad esempio "rifiutato: il motore del partner è probabilmente fermato", "scaduto: un firewall o un tunnel VPN che è down" o "un certificato da un'autorità che questo server non si fida". Nulla viene inviato al partner, con un'eccezione: un registro di immunizzazione che non ha avuto traffico per sette giorni viene chiesto il suo CDC connectivityTest, che non invia nulla. Con -vpn tunnels.yaml la piastrella Tunnel VPN accanto ad esso legge lo stato di ogni tunnel del partner da AWS Site-to-Site VPN, una connessione Azure VPN Gateway o strongSwan su questo host, in modo che un timeout possa essere distinto da un tunnel che è down. Confronta anche le impostazioni IKE e IPsec di entrambi i lati, poiché la nuvola segnala le nostre e il file elenca le loro, e indica dove non possono concordare. La scheda di connessione scarica le impostazioni di un partner affiancate come Markdown per inviarle; non memorizza mai una chiave condivisa pre-condivisa. Le figure che un dashboard necessita che non sono ancora registrate vengono elencate sotto Non misurate ancora invece di essere disegnate come piastrelle vuote.

I cruscotti di dipartimento calcolano le proprie figure sul server, e ognuno dice quale finestra e quale sorgente copre:

3.2.10 Condividere cosa contiene effettivamente un flusso

Profilo di questo flusso segnala cosa sta realmente arrivando: quali eventi di trigger, quali campi sono popolati e con quale frequenza, quali forme assumono i valori, e quali codici un mittente utilizza effettivamente. Quell'ultimo è di solito il fatto più utile in esso.

Un profilo può essere scaricato e inviato a qualcun altro. Ha bisogno di un nome e — obbligatorio — quale sistema ha prodotto il flusso, perché la domanda che uno sconosciuto fa a un profilo condiviso è se descrive il proprio sistema, e un campo opzionale renderebbe "Sconosciuto" la risposta più comune in qualsiasi raccolta condivisa.

Non contiene dati del paziente, e ciò viene verificato piuttosto che assunto. Un profilo è statistico: conteggi, tassi, lunghezze, forme. I valori vengono mantenuti solo per i campi che lo standard definisce come tabelle di codici, perché un valore della tabella dei codici non è identificativo. I valori degli identificatori non vengono mai elencati.

Due a questo essere una promessa piuttosto che una speranza, seguono due cose. Il server ricostruisce il profilo dai messaggi archiviati quando lo esporti, piuttosto che inviare quello visualizzato sullo schermo — quindi ciò che esce dall'edificio è stato assemblato dal profiler, che ha un test che prova questa proprietà, e non da un browser. E l'esportazione rifiuta categoricamente se un profilo elenca mai valori per un campo che non è una tabella di codici, nominando il campo ma non i valori.

Un profilo che arriva da altrove viene controllato allo stesso modo all'ingresso, per un motivo diverso: è stato prodotto da qualcuno la cui cura è sconosciuta, e mostrare gli identificatori dei suoi pazienti sarebbe una violazione di questa server. Importare uno non cambia nulla — un profilo descrive un feed, e decidere cosa farne è una decisione separata.

3.3 Crea — modifica cosa fa un canale e prova prima che sia attivo

3.3.1 Canali

Il costruttore di canali. Sorgenti, destinazioni, filtri, trasformazioni, script e test, con il file YAML generato visualizzato accanto al modulo mentre si lavora — quindi il file non è mai un mistero, e chiunque preferisca il file può leggere insieme.

Vedi canali per cosa sono le parti e trasformazione per cosa fanno i passaggi.

3.3.2 Script

Un'area di lavoro per script, separata dal costruttore perché scrivere uno script e collegare uno script sono attività diverse.

Tutti e sette gli slot sono offerti — filtro, trasformatore, pre-elaboratore, post-elaboratore, scrittore, ciclo di vita e lettore — e scegliere quello giusto è importante, perché lo slot decide cosa lo script riceve e cosa si aspetta che restituisca. Controllare uno script come il tipo sbagliato non è una soluzione; compila una cosa diversa.

Sono disponibili JavaScript, Lua e WebAssembly. Vedere transformation.

3.3.3 Contratti

Aspettative su come debba apparire un feed, create e verificate qui, nonché da perfuse contract. Vedi la riga di comando.

3.3.4 Tabelle

Tabelle di ricerca e set di codici: le mapping che trasformano i codici di un sistema in quelli di un altro. Modificabili qui in modo che aggiungere un codice non sia una distribuzione.

3.3.5 AI Mapper

Propone mapping di campi con un punteggio di confidenza per ciascuno e si astiene dal fare supposizioni. Nonostante il nome, non utilizza alcun modello linguistico e non effettua alcuna chiamata di rete: le suggerimenti provengono da regole, nomi di campi e contenuti del campione, su questo server. Propone inoltre un canale da un singolo messaggio di esempio e afferma esplicitamente cosa il campione non può dirgli. Questa seconda parte è quella che lo rende affidabile - una proposta che sembra completa potrebbe invitarti a credere a cose che il messaggio non ha mai detto.

3.3.6 Area di prova

Un blocco note per messaggi e trasformazioni. Incolla un messaggio, applica passaggi, vedi il risultato.

Nessun messaggio viene inviato da nessuna parte una volta caricata la pagina, che è il motivo per cui esiste in questa forma: è sicuro incollare qualcosa di reale, con la comprensione che rimane nel browser.

3.3.7 Ombra

Esegue il traffico attraverso una configurazione candidata accanto a quella live e segnala le differenze, in modo che una modifica possa essere dimostrata prima di essere considerata attendibile. Lo stesso concetto di perfuse compare, applicato a una modifica piuttosto che a una migrazione. Vedi testing.

3.4 Scambio — gli standard che questo server parla ad altre organizzazioni

3.4.1 Laboratorio FHIR

Converte HL7 v2 in FHIR, convalida una risorsa e ispeziona il risultato. I campioni coprono ammissioni, risultati di laboratorio, appuntamenti, note cliniche, immunizzazioni e una visita segnalabile. La convalida include US Core, che è il profilo contro cui è scritta la regolamentazione americana, quindi questo risponde a "è ciò che ci hanno inviato effettivamente conforme" senza adottare nulla.

Caso di report pubblico costruisce l'eCR eICR che una destinazione di segnalazione dei casi invierebbe per il messaggio. Mostra quale codice di attivazione ha reso la visita segnalabile, cosa il report doveva contrassegnare come mancante e il documento stesso. Un messaggio con nulla di segnalabile ottiene il motivo al posto suo. Nulla viene inviato da qui.

3.4.2 Abbonamenti

Abbonamenti FHIR e se le loro notifiche stanno arrivando: eventi, accettati, in attesa e l'ultimo motivo per cui uno è stato rifiutato. Gli abbonamenti sono creati da client FHIR attraverso l'API FHIR, non da questa pagina, e le credenziali che hanno fornito al server non vengono mai visualizzate. Vedere formati di messaggio.

3.4.3 Documenti

Documenti clinici — CDA e la forma stampabile di un documento. Utile quando l'oggetto scambiato è una sintesi di dimissione piuttosto che un messaggio.

3.4.4 Condivisione di documenti

Il registro e il repository IHE XDS.b iniziato con -xds: quanti documenti, pazienti e insiemi di invio contiene e quanti sono stati sostituiti; gli indirizzi del repository, del registro, della porta XCA e di MHD; una ricerca dei documenti di un paziente in questo registro o in un altro della comunità (un registro ITI-18 o una porta ITI-38, con un token per esso); e la pubblicazione di un documento CDA a mano, con il tipo di struttura e l'impostazione della pratica che un documento non specifica. Vedi formati dei messaggi.

3.4.5 Direct

Messaggistica sicura diretta. Gli indirizzi Direct di questo server elenca ogni indirizzo che un canale invia o riceve, con il suo certificato, quando scade, gli anchor di trust e qualsiasi problema (un file mancante, un certificato scaduto). La Rubrica mantiene i corrispondenti e i certificati con cui la loro posta è crittografata: incolla uno dal loro HISP, o Salva con il certificato da DNS; un certificato che non è per l'indirizzo o il suo dominio viene rifiutato. Trova un certificato in DNS chiede senza salvare. Vedi formati di messaggio.

SMART Health Links e Cards, per CMS's *Kill the Clipboard*. Ricevere un link di salute SMART legge il link o il codice QR che un paziente mostra al check-in, verifica le carte di salute all'interno e le invia a un canale. Condividere un record di visita crea un link ospitato da questo server, opzionalmente con un codice di accesso, e un codice QR per il paziente; Utilizzare il riassunto del paziente lo riempie con il riassunto del paziente International Patient Summary dall'archivio FHIR di questo server. Link ospitati da questo server elenca i link con la frequenza di accesso, la data di scadenza e i tentativi di accesso rimanenti, e revoca uno di essi. Verificare una carta di salute SMART controlla la firma e l'emittente della carta in modo autonomo. Vedere CMS-0057 per le opzioni del server necessarie.

3.4.7 Immagini

L'archivio che questo server mantiene quando viene eseguito con -dicomweb-archive: conta degli studi, serie, istanze e spazio utilizzato, l'indirizzo DICOMweb e il blocco di dati di origine per un visualizzatore OHIF, e una ricerca di studio per nome del paziente, ID, accessione e data effettuata con la stessa richiesta QIDO-RS che effettua un visualizzatore. Uno studio si apre alle sue serie e istanze, e un'istanza viene scaricata come file DICOM. Nulla viene renderizzato: Perfuse sposta le immagini e un visualizzatore le visualizza. Senza un archivio, lo schermo indica come attivarne uno. Vedi DICOMweb.

3.4.8 TEFCA

La traccia di audit per lo scambio attraverso una Rete di informazioni sanitarie qualificata, e le regole di utilizzo che la governano.

Due trasporti, in fasi effettivamente diverse, e lo schermo dice quale è quale. Una bandiera che copre entrambi sarebbe errata in qualsiasi direzione fosse arrotondata.

FHIR facilitato è implementato e non ha mai parlato con un QHIN reale. Segue la Procedura operativa standard di Sequoia Project in vigore dall'8 marzo 2026: scopre i metadati UDAP del partner, li verifica, si registra dinamicamente, ottiene un token di accesso che trasporta lo scopo dell'uso e interroga. UDAP è un'infrastruttura a chiave pubblica su OAuth 2.0 — una comunità di fiducia rilascia certificati X.509 ai suoi membri, e un membro si autentica firmando JWT con la chiave privata e allegando la catena di certificati.

Il livello di sicurezza viene verificato contro l'implementazione di qualcun altro, che è l'unica verifica che valga la pena qui. Una registrazione firmata da questa build è stata inviata a un server di riferimento terzo live e rifiutata con unapproved_software_statement — Untrusted: Certificate is not a member of community. Per produrre quella risposta, il server ha decodificato la richiesta, analizzato l'affermazione del software come JWT, verificato la sua firma, percorso la catena di certificati e preso una decisione sulla membership. È la differenza tra essere respinti alla porta e ricevere una lettera illeggibile.

Ciò che rimane non può essere fatto da qui. Il certificato che prova la membership della comunità esce dal processo di onboarding QHIN e non è qualcosa che il software produce. Fino a quando non ne esiste uno, nessuno scambio con un partner reale si completa.

Come un canale chiede. Una destinazione di tipo tefca chiede all'insieme di partner FHIR facilitati nelle Impostazioni, TEFCA (tefca.partnerFHIRBase) per ogni messaggio del paziente: per identificatore quando il messaggio ne ha uno (PID-3, o un identificatore del paziente FHIR), altrimenti per cognome con data di nascita, e mai solo per nome, perché una corrispondenza errata su un nome restituisce il record di un'altra persona senza errore. La destinazione imposta lo scopo di utilizzo (trattamento, pagamento, operazioni, salute pubblica, accesso individuale); uno scopo che il partecipante non dichiara viene rifiutato prima che venga inviato qualcosa. Gli scopi vengono come codici di scambio 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), o con tefca.purposeCodes: hl7 come codici di utilizzo HL7 per le comunità che li utilizzano. Il Bundle trovato è la risposta della destinazione e può essere passato a un altro canale con results_to. Ogni query, incluse quelle rifiutate, è nella traccia su questo schermo, che nomina il partner.

L'intero percorso, dalla scoperta a un token che il server FHIR del partner accetta, viene testato contro il server di riferimento udap-dotnet (vedi verifica).

L'exchange QHIN-to-QHIN più vecchio costruito sui profili IHE non è implementato. Un tentativo viene rifiutato con un errore che lo dice, e il rifiuto viene registrato come un fallimento. Ciò è deliberato piuttosto che in attesa di una pulizia: un exchange stub che segnala il successo metterebbe voci nella traccia di audit per scambi che non sono mai avvenuti, e una traccia che non è d'accordo con ciò che è accaduto è peggiore di nessuna, perché la traccia è ciò che viene creduto.

In tutto, gli endpoint utilizzati per lo scambio provengono dalla parte firmata dei metadati di un partner, mai dal corpo del documento. Verificare una firma e poi leggere gli endpoint dalla copia non firmata sarebbe un modo elaborato per fidarsi della rete: un attaccante in grado di riscrivere la risposta lascia l'elemento firmato da parte, punta l'endpoint del token al proprio server e raccoglie affermazioni client da tutti coloro che hanno verificato la firma e poi ignorato ciò che copriva.

Un bundle di anchor di trust è richiesto e la sua assenza è rifiutata all'avvio. Verificare i metadati firmati di un partner contro il certificato che è arrivato all'interno di esso prova solo che una parte ha fatto entrambi — un errore che questo codicebase ha fatto in precedenza, in SAML, dove il verificatore ha preferito il certificato incorporato e ha autenticato un attaccante come amministratore mentre ogni test è stato superato. Includere gli intermedi in il bundle: un server UDAP ha bisogno di inviare solo il suo certificato foglia, e il server di riferimento pubblico fa esattamente questo.

3.5 Pagatori — richieste, autorizzazioni preventive, farmaci e regole del pagatore CMS

3.5.1 Richieste e autenticazioni

Crea un allegato di richiesta X12 275 nel formato 006020 adottato da CMS-0053-F, da un C-CDA incollato o un PDF, TIFF o JPEG caricato, e vedi come viene letto. Leggi un 275 e scarica il documento all'interno. Converte una decisione X12 278 in una risposta Da Vinci PAS ClaimResponse. Nulla in questa pagina viene memorizzato o inviato. Vedi formati di messaggio per cosa viene costruito il 275 e cosa non fa.

3.5.2 Farmaci

La formulary dei farmaci caricata con -formulary, e gli standard NCPDP risposti da essa. Formulary elenca i piani e i farmaci con il loro livello e requisiti, e dove si trovano l'API pubblica Da Vinci US Drug Formulary e gli endpoint NCPDP. Controllo del prezzo (RTPB) prezza un farmaco per un membro come richiesta di beneficio prescrittivo in tempo reale: lo stato di copertura, le restrizioni in parole con i loro codici, la quota del membro e del piano, e le alternative più economiche. Autorizzazione preventiva (ePA) invia un'inizializzazione SCRIPT all'endpoint di questo server, visualizza l'insieme di domande come un modulo, invia le risposte e visualizza la decisione; di seguito, ogni caso con dove si trova e se il prescrittor è stato informato, le risposte del caso, un pulsante per inviare nuovamente una decisione non inviata e le figure del farmaco che CMS-0062-P propone. Vedere CMS-0057.

3.5.3 CMS-0057

Il lato pagatore della regola di interoperabilità e autorizzazione preventiva CMS, come cinque strumenti:

e cosa ancora necessita ciascuna.

certificare meno unità. Vedi la coda di revisione.

Le conversioni non memorizzano nulla e non inviano nulla.

3.5.4 Rete allineata CMS

Prontezza per il CMS Interoperability Framework: ogni uno dei suoi 26 criteri, raggruppati come li raggruppa il CMS, con ciò che Perfuse fornisce, se è attivato qui, l'impostazione che lo attiva e cosa deve fare l'organizzazione. I conteggi in alto filtrano l'elenco. Vedere CMS-0057.

3.6 Amministra — chi può fare cosa, e come questo server è configurato

3.6.1 Utenti

Account, ruoli (monitor, viewer, operator, editor, admin) e gruppi di canali. I gruppi di canali di ogni persona vengono modificati direttamente nell'elenco; vuoto significa ogni canale e lab=editor, adt assegna un ruolo diverso in un gruppo. Un amministratore limitato a alcuni gruppi vede solo le persone di quei gruppi. L'intestazione mostra i tuoi gruppi accanto al tuo ruolo quando ne hai alcuni. Vedi security.

Credenziali di macchina sono anche qui. Un token è per una macchina piuttosto che per una persona: non scade e non è influenzato da qualcuno che si disconnette, il che è ciò di cui un server che interpella il suo vicino ha bisogno. Solo un hash viene memorizzato, quindi un token viene mostrato una volta quando viene creato e non può essere recuperato — un database rubato non produce alcun token utilizzabile. Assegnare un ruolo il più basso che faccia il lavoro.

Con MCP attivato, la sezione mostra anche l'indirizzo a cui un agente AI si connette, una configurazione del client da copiare e ogni strumento con il ruolo di cui ha bisogno; rilasciare un token con Lascia che un agente AI agisca con esso gli dà l'ambito mcp:write. Vedi sicurezza.

3.6.2 Tenant

Su un server condiviso, l'elenco dell'operatore della piattaforma di organizzazioni: per ognuna, il numero di canali e la dimensione archiviata accanto ai propri limiti (canali, messaggi al minuto, archiviazione), che sono impostati in posizione. Mostrato solo al ruolo della piattaforma. Vedere security per cosa fa ogni limite.

3.6.3 Certificati

I certificati TLS in uso e quando scadono. Le date di scadenza sono il punto: un certificato scaduto di domenica è una classe di guasto che è interamente prevenibile e di routine non è prevenuto.

3.6.4 Attività

Chi ha modificato cosa, e quando. Ogni modifica di configurazione viene registrata, il che è ciò che rende "ha iniziato a non funzionare martedì" rispondibile.

3.6.5 Protezione dei dati

Le richieste di una persona ai sensi del GDPR e del GDPR del Regno Unito, le richieste di blocco legale, il registro di cancellazione, la conservazione e il registro delle attività di elaborazione; solo amministratori. Vedi protezione dei dati.

3.6.6 Flotta

Ogni istanza Perfuse in una pagina.

Mirth vende questo come un prodotto separato; qui è un file di configurazione e un token di sola lettura. Il motivo per cui vale la pena averlo è limitato e importante: un server morto non sembra uno quieto. Il cruscotto di un'istanza singola non può dirti che un secondo sito ha smesso di segnalare e una vista flotta non può.

3.6.7 Migra

Inserisci un'esportazione di un canale Mirth o OIE e vedere quanti dei tuoi canali funzionerebbero qui senza modifiche. La stessa analisi di perfuse explain e perfuse translate, senza la necessità di un terminale. Vedi migration.

3.6.8 Impostazioni

Ogni impostazione del server, con un controllo per ognuna — comprese quelle che tradizionalmente vivono solo in un file. Ognuna indica se ha effetto immediato o richiede un riavvio e se è stata impostata esplicitamente o se è impostata sul valore predefinito.

Le impostazioni coprono ogni opzione perfuse serve che attiva una funzionalità: l'endpoint FHIR e la sua versione, le API dei pagatori, PAS e le regole CRD, il ponte X12 278, eCR, il server di autorizzazione SMART, TLS e firma, metriche, flotta e VPN. Sono raggruppati come FHIR, Payer, Sanità pubblica, SMART, Sicurezza e così via. Ognuno è visualizzato anche con la bandiera a cui corrisponde.

Riavvio dalla console. Un'impostazione contrassegnata *Richiede riavvio* viene salvata immediatamente ma letta solo quando il server si avvia. Finché alcune sono in attesa, una barra nella parte superiore delle Impostazioni elenca quelle con un pulsante Riavvia il server (l'editor di accesso e i file di impostazioni offrono lo stesso pulsante dopo un salvataggio). Chiede prima, perché ogni canale si ferma per alcuni secondi: ogni canale termina il messaggio che sta gestendo, come fa quando il servizio viene interrotto, e i mittenti rinvianno qualsiasi cosa arrivi nel frattempo. La console attende quindi che il server risponda di nuovo e legge le impostazioni di nuovo. Solo un amministratore può riavviare e ogni riavvio viene registrato nel registro delle attività come server.restart.

Su Linux e macOS, il processo si sostituisce con una copia fresca dello stesso programma e degli stessi argomenti, mantenendo il suo ID di processo, quindi systemd, launchd o un runtime del contenitore non nota nulla. Su Windows, il server si riavvia all'interno dello stesso processo, che mantiene un servizio Windows sotto il gestore dei servizi. Se il server non ha risposto dopo due minuti, la console lo dice; il motivo è nel log del server.

Flag e file di impostazioni. La prima volta che il server si avvia, le flag che gli sono state date vengono scritte nel file di impostazioni. Da allora in poi, il file vince sulle flag, quindi la modifica di un'impostazione viene eseguita nella console (o nel file), non modificando la riga di comando del servizio. Una flag che il file non menziona ancora viene registrata quando il server si avvia con essa. Rimuovere una flag dalla riga di comando in seguito non disattiva la funzionalità: disattivarla nelle Impostazioni.

SNMP ha un pannello sotto le impostazioni: se l'agente sta rispondendo e su quale indirizzo, le reti a cui risponde, quanti alert trap sono stati inviati o non sono riusciti e Scarica il MIB per l'OID di base in uso. I valori vengono impostati sotto Monitoraggio, SNMP.

Branding è qui anche: un sito può impostare il nome del prodotto, un tagline, un colore di accentuazione e caricare un logo. Il logo appare quindi nell'intestazione, nella pagina di accesso, nel cruscotto e negli schermi di reporting. Se non viene caricato, nulla viene sostituito — un'installazione non marchiata rimane non marchiata piuttosto che acquisire una decorazione.

3.7 Cosa significano i colori

Quattro registri e ognuno dice qualcosa di diverso. La distinzione vale la pena di essere dichiarata perché è la differenza tra uno schermo che puoi leggere a colpo d'occhio e uno in cui tutto compete per l'attenzione.

Testo normale è un fatto su come funziona Perfuse. La maggior parte dell'interfaccia. Nulla è colorato per dirti che è importante.

Verde significa che qualcosa è riuscito proprio adesso, a causa di qualcosa che hai fatto. Appare dopo un'azione e non persiste.

Arancione è un avvertimento: vale la pena di saperlo prima di agire e non è un errore. Una funzionalità che non è attivata, un'impostazione le cui modifiche sono registrate, una conversione che approssima piuttosto che riprodurre, un trasporto che Perfuse gestisce ma non può verificare completamente. L'arancione è il colore di "leggi questo prima di continuare".

Rosso significa che qualcosa è sbagliato in questo momento. Un valore che è stato rifiutato, una richiesta che non è riuscita, un certificato che è scaduto, un allarme critico che si sta attivando. Nulla altro lo utilizza.

Quell'ultima regola è il motivo per cui uno schermo non si apre rosso. Il rosso è l'unico colore che porta un'istruzione — fermati, e potrebbe essere qualcosa che hai fatto — e uno schermo che lo spende per la decorazione non ha nulla da dire quando l'input è effettivamente sbagliato. Ciò non è sempre stato vero: lo schermo degli utenti usava un tempo aprire con "il server ha inviato una risposta che non poteva essere letta" su ogni installazione che non aveva configurato le passkey, e lo schermo delle impostazioni contrassegnava i valori registrati con lo stesso colore di uno rifiutato. Un test in web/src/RedMeansWrong.test.ts ora fallisce se una frase che descrive qualcosa di assente o approssimativo viene data uno stile rosso.

All'interno di una casella di codice il vocabolario è diverso. Lì, il rosso è un tipo di token — un nome di segmento HL7, un elemento XML — e non porta alcun giudizio.

4 Canali

Un canale è un flusso di messaggi: da qualche parte arrivano, opzionali modifiche e uno o più posti in cui vanno. È l'unità di configurazione, l'unità di monitoraggio e l'unità di distribuzione. Tutto il resto in Perfuse esiste per servire i canali.

4.1 Anatomia

Un file di canale ha queste parti, nell'ordine in cui hanno effetto:

ParteChiaveObbligatorioCosa fa
IdentitànamesìNomina il canale. Deve essere unico.
Tipo di datidataTypenoCome analizzare i messaggi. Predefinito HL7 v2.
SorgentesourcesìDove arrivano i messaggi. Esattamente uno.
FiltrofilternoDecide quali messaggi accettare.
TrasformazionitransformationsnoModifiche ordinate al messaggio.
DestinazionidestinationssìDove vanno i messaggi. Uno o più.

Più diverse che si applicano all'intero canale: scripts, shadow, contract, tables, attachments, group e enabled. Ognuno è nel riferimento canale.

4.2 Una sorgente, molte destinazioni

Questa asimmetria è deliberata e vale la pena capirla presto, perché è la fonte di confusione più comune quando si proviene da un altro motore.

Un canale ha esattamente una sorgente. Se i messaggi arrivano da due posti, sono due canali. Tentare di esprimerlo come un canale produce una configurazione in cui un errore in uno dei trasporti sembra lo stesso dall'esterno e in cui il traffico dei due feed è mescolato insieme nelle statistiche — quindi una caduta in uno è nascosta dall'altro.

Un canale ha un numero qualsiasi di destinazioni e sono indipendenti. Uno che fallisce non ferma gli altri e ognuno ha la sua propia coda, la sua propia politica di ritentativi e il suo proprio record di consegna. Un messaggio che ha raggiunto tre delle quattro destinazioni è registrato come tale, non come un successo o un fallimento.

4.3 Le destinazioni non sono una catena

Ogni destinazione riceve il messaggio come stava dopo le trasformazioni del canale. Una destinazione non riceve l'output della destinazione precedente.

Ciò è importante quando una destinazione ha le sue propre trasformazioni, cosa che può fare. Queste si applicano solo alla copia di quella destinazione. Un errore comune è mettere un cambiamento sulla prima destinazione e aspettarsi che la seconda lo veda.

Se si ha veramente bisogno di una catena — l'output di un flusso che alimenta un altro — si utilizza una destinazione del canale, che invia a un altro canale per nome. Ciò è esplicito, appare nella storia del messaggio come due canali e può essere monitorato come due cose, cosa che una catena nascosta non può.

4.4 Denominazione

Il nome è l'identità del canale ovunque: nel file, nel message store, negli avvisi, nel registro di controllo e nell'URL. Cambiarlo non è un rinominamento; è un nuovo canale e la storia del vecchio canale rimane sotto il vecchio nome.

group è separato ed esiste per organizzare l'interfaccia. Un gruppo non ha effetto sul comportamento e raggruppare canali non li fa condividere nulla.

In una distribuzione multi-facility, mettere la facility nel nome invece di solo nel gruppo. Le distribuzioni Mirth su più siti tendono a diventare inconsistenti nella denominazione e il punto in cui ciò diventa doloroso è un incidente alle due del mattino in cui l'elenco dei canali ha quattro cose chiamate adt-inbound.

4.5 Abilitazione e disabilitazione

enabled: false ferma un canale senza eliminarlo. La sua configurazione, la sua storia e le sue statistiche rimangono.

Un canale disabilitato non è un canale in pausa. La sua sorgente non è in ascolto, quindi un mittente che tenta di connettersi ottiene una connessione rifiutata invece di una connessione bloccata. Per MLLP questo è il comportamento corretto — il mittente metterà in coda e ritenterà — ma significa che il registro degli errori del mittente si riempirà, quindi un canale disabilitato non è un sostituto per organizzare un'interruzione con chi sta inviando.

4.6 Dove vivono i canali

Un file YAML per canale, nella directory data da -channels. Il nome del file non è il nome del canale; la chiave name lo è. È fortemente consigliato mantenerli uguali e nulla li obbliga a farlo.

I file vengono riletto senza riavvio. Un file che non si analizza viene segnalato e la versione precedentemente caricata continua a funzionare, quindi un errore di sintassi non può interrompere un feed funzionante.

Un canale modificato nell'interfaccia web viene scritto nuovamente nel suo file. Se questi file sono in controllo di versione — il che è consigliato — si possono aspettare commit dalle modifiche di configurazione fatte attraverso l'interfaccia e non si deve modificare manualmente un file mentre qualcun altro lo ha aperto nel costruttore.

4.7 Cifrare l'ascoltatore proprio del canale

Un canale che ascolta su una porta è il suo proprio server e il suo TLS è separato dal TLS sull'interfaccia web di Perfuse. Impostare uno non imposta l'altro. Per una sorgente HTTP le impostazioni si trovano sotto TLS e limiti sulla sorgente.

Attivare il TLS richiede un certificato e una chiave privata. Richiedere un certificato client lo trasforma in TLS reciproco: il mittente deve presentare uno firmato da un'autorità che si nomina, che è un'autenticazione, quindi un listener con esso attivato non ha anche bisogno di un token condiviso — anche se avere entrambi non è sbagliato.

L'autorità viene richiesta solo una volta che viene richiesto un certificato client e viene omessa dal file fino ad allora. Un canale che nomina un'autorità che non viene mai consultata sembra come se i mittenti stessero venendo verificati quando in realtà non lo sono.

Un listener MLLP ha le stesse impostazioni sotto Cifrare questo listener, con una differenza degna di nota: su MLLP un certificato client è l'unica autenticazione disponibile. Non c'è token e non c'è intestazione, quindi un listener senza uno accetta messaggi da qualsiasi host che possa raggiungere la porta.

Due limiti si trovano accanto ad esso. Smettere di leggere dopo una durata, perché un mittente che apre una connessione e smette di scrivere altrimenti la tiene aperta. E messaggio più grande accettato, in byte, perché zero significa nessun limite e il limite è quindi la memoria — un mittente che invia un gigabyte viene rifiutato piuttosto che assorbito.

4.8 Convalida

Un canale viene verificato quando viene caricato e le verifiche sono rifiuti piuttosto che avvertimenti dove l'alternativa sarebbe un canale che funziona e fa la cosa sbagliata.

Esempi di cose rifiutate apertamente: una destinazione senza tipo, una trasformazione che indirizza un percorso che non può esistere nel tipo di dati dichiarato, una modalità di ack che il trasporto di origine non può consegnare e una prescrizione di classe II con riempimenti.

La distinzione che Perfuse cerca di mantenere è che qualsiasi cosa che potrebbe produrre un risultato errato plausibile viene rifiutata e qualsiasi cosa che sia semplicemente insolita viene consentita e segnalata. Un canale che non può essere errato è più prezioso di un canale che inizia.

5 Flusso di messaggi

Questo capitolo segue un messaggio dal momento in cui arriva al momento in cui viene consegnato o abbandonato. Sapere questo ordine è il modo più veloce per capire dove appartiene un cambiamento e perché qualcosa non sta accadendo.

5.1 L'ordine degli eventi

Arrival de-frame Parse Record as received Filter Transform Destination A Destination B Destination C unparseable filtered Filtered is a normal outcome, not an error. Unparseable is recorded and stops. The acknowledgement is sent after delivery by default, so a sender is not told "received" before it is true.
  1. Arrivo. La sorgente accetta i byte. Per un trasporto a flusso, ciò include la de-quadrazione — trovare dove termina un messaggio e inizia il successivo.
  2. Analisi. I byte diventano un albero in base al tipo di dati (dataType) del canale. Un messaggio che non può essere analizzato si ferma qui e viene registrato come fallimento di analisi.
  3. Registrazione. Il messaggio viene scritto nell'archivio dei messaggi così come ricevuto, prima che venga modificato. Ciò rende possibile la riproduzione e l'elaborazione nuovamente.
  4. Filtro. Se il canale ha un filtro (filter), decide se accettare il messaggio. Un messaggio rifiutato viene registrato come filtrato, il che è un esito normale e non un errore.
  5. Trasformazione. Le trasformazioni (transformations) del canale vengono eseguite in ordine, ciascuna contro il risultato dell'ultima.
  6. Distribuzione. Ogni destinazione riceve una copia del messaggio trasformato, applica le proprie trasformazioni se ne ha, e consegna.
  7. Registrazione dell'esito. Per ogni destinazione: consegnato, in coda, fallito o filtrato.
  8. Conferma. Se la sorgente si aspetta una conferma, viene generata e inviata. Di default, ciò avviene qui, dopo la consegna — vedi sotto.

5.2 Quando viene inviato l'ack

Questo è l'impostazione più importante in un canale, perché decide cosa viene promesso al mittente. È ack.when e ha due valori.

on_delivery è il valore predefinito. L'ack viene inviato solo dopo che ogni destinazione abilitata ha accettato il messaggio. Un ack positivo significa quindi che i dati sono effettivamente arrivati da qualche parte, il che è la promessa più forte che un motore in mezzo può onestamente fare.

on_receipt ack come appena il messaggio viene analizzato e messo in coda, prima che qualsiasi destinazione sia stata scritta.

Perfuse utilizza on_delivery di default perché promettere la consegna e poi perdere il messaggio è peggio che essere lento. Sotto on_receipt, un messaggio che è stato ack può comunque essere perso se il processo muore con lavoro in coda — il mittente crede che sia stato consegnato, nulla a monte lo rinvierebbe e l'unico record che esiste è nel negozio di messaggi di Perfuse.

5.3 Quando scegliere on_receipt

Il caso per esso è reale ed è i timeout. Un mittente MLLP che non riceve un ack entro pochi secondi di solito rinvierebbe, quindi una destinazione lenta sotto on_delivery produce duplicati piuttosto che ritardi. Se una destinazione è un archivio lento o un sistema che è regolarmente non disponibile, on_delivery accoppia il timeout del mittente al caso peggiore di quella destinazione.

Lo scambio è esplicito: on_receipt sposta il rischio dalle duplicazioni alla perdita. Sceglierlo significa accettare che un messaggio confermato possa essere perso in caso di crash, ed è consigliabile abbinarlo con un allarme sulla profondità della coda in modo che venga notata una coda che ha smesso di svuotarsi. Vedi alerting.

Sotto entrambi gli impostazioni, un ack positivo non è una promessa che l'applicazione ricevente abbia *elaborato* il messaggio — solo che ha accettato i byte. Se è necessario sapere che un risultato è stato archiviato, ciò deve provenire dal sistema ricevente e nessun motore di integrazione può fornirlo.

5.4 Dove viene registrato il messaggio

Prima del filtro e quindi prima di qualsiasi trasformazione. Tre conseguenze:

La forma trasformata viene registrata anche, per ogni destinazione, insieme all'esito. Quindi l'archivio contiene ciò che è arrivato, ciò che è stato inviato e cosa è successo — che è ciò di cui ha bisogno un'indagine.

5.5 Guasto a ogni stadio

FaseCome si presenta un erroreCosa succede
ArrivoErrore di strutturazione, connessione interrotta a metà messaggioRegistrato, connessione chiusa, mittente ritenta
AnalisiNon valido per il tipo dichiaratoRegistrato come errore di analisi, conferma negativa se la sorgente se lo aspetta
FiltroIl filtro stesso genera un erroreTrattato come un rifiuto, registrato con l'errore
TrasformazioneUn passaggio ha esito negativoDipende dal on_error del passaggio; vedere trasformazione
ConsegnaDestinazione irraggiungibile o rifiutaInserito in coda e ritentato secondo la politica del destinatario; vedere consegna

L'asimmetria importante: un fallimento di analisi è permanente e un fallimento di consegna di solito non lo è. Ritentare un messaggio non analizzabile non servirà a nulla, quindi non viene ritentato. Ritentare una destinazione irraggiungibile di solito servirà, quindi viene ritentato.

5.6 Ordinamento

All'interno di una sola destinazione, i messaggi vengono consegnati nell'ordine in cui sono arrivati, e un messaggio che fallisce e entra nella coda mantiene la sua posizione — i messaggi successivi aspettano dietro di esso invece di superarlo.

Questo è il comportamento predefinito giusto per i dati clinici, dove un ricovero seguito da una dimissione consegnati nell'ordine sbagliato è peggiore che se entrambi fossero in ritardo. Significa anche che un messaggio dannoso può bloccare una coda, ed è per questo che la profondità della coda vale la pena di essere segnalata.

Tra le destinazioni non c'è garanzia di ordinamento, perché sono indipendenti. Due destinazioni non riceveranno necessariamente lo stesso messaggio allo stesso tempo, e una destinazione veloce potrebbe essere diversi messaggi avanti rispetto a una lenta.

L'ordinamento tra canali non è garantito affatto. Se due flussi devono essere applicati in un ordine particolare l'uno rispetto all'altro, quell'ordinamento deve essere applicato dal sistema ricevente, perché nulla nel mezzo può sapere quale dei due messaggi indipendenti arrivati è arrivato per primo.

5.7 Concorrenza

Una sorgente può gestire più connessioni contemporaneamente, limitate da max_connections. I messaggi da connessioni diverse vengono elaborati contemporaneamente.

Ciò significa che l'ordine di arrivo di due messaggi inviati contemporaneamente su due connessioni non è definito e non può esserlo — sono effettivamente arrivati allo stesso tempo. Un mittente che necessita di ordinamento deve utilizzare una sola connessione, il che è ciò che fanno quasi tutti.

6 Trasformazione

Le trasformazioni modificano un messaggio. Sono una lista, vengono eseguite in ordine e ogni passaggio vede il risultato del passaggio precedente.

Le trasformazioni di Perfuse sono dichiarative: ogni passaggio nomina un'operazione e il campo a cui si applica. Non c'è un linguaggio di scripting nel percorso normale. Questa è una limitazione deliberata e la motivazione è in why not a script di seguito.

6.1 I passaggi

PassaggioCosa fa
setScrive un valore letterale in un percorso, creandolo se assente.
copyCopia un percorso in un altro, con un valore predefinito opzionale quando la sorgente è assente.
clearSvuota un campo, lasciandolo presente.
removeRimuove completamente un campo.
mapCerca il valore corrente in una tabella e lo sostituisce.
replaceSostituzione con espressione regolare all'interno di un campo.
padRiempe un valore fino a una larghezza fissa.
dateConverte una data o un timestamp tra formati.
trimRimuove gli spazi bianchi circostanti.
caseConverte in maiuscolo o minuscolo.

Ogni passaggio accetta anche description, che appare nella traccia e nell'interfaccia, e when, che rende il passaggio condizionale.

Un passaggio è scritto come il nome dell'operazione con il proprio blocco:

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 non sono fratelli. set prende un blocco contenente path e value. Scrivere set: PID-3.4 con value: accanto ad esso è l'errore più comune in un canale scritto a mano e produce un errore di caricamento invece di una configurazione silenziosa e errata.

6.2 Svuotamento, rimozione e la differenza

clear lascia il campo presente e vuoto. remove lo rimuove completamente.

Per HL7 questa distinzione è reale e raggiunge il ricevente. Un campo vuoto dice "ho questo campo e non ha valore". Un campo assente non dice nulla. Alcuni sistemi riceventi trattano il primo come un'istruzione per cancellare il valore memorizzato e il secondo come un'istruzione per lasciarlo invariato — che è la differenza tra l'eliminazione di un'allergia registrata del paziente e il non menzionarla.

Se non si sa quale il ricevente desidera, è necessario chiedere. Indovinare ha una probabilità del 50% di distruggere silenziosamente i dati sul lato opposto.

6.3 Condizioni

when prende un'espressione e il passaggio viene eseguito solo se è vera:

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

Un passaggio la cui condizione è falsa viene registrato come skipped e ciò viene segnalato separatamente da un passaggio che è stato eseguito e non ha modificato nulla. Questa distinzione è l'obiettivo del debugger passo-passo e viene trattata in debugging: una condizione falsa e un campo assente appaiono identici dall'esterno e significano cose opposte.

6.4 Percorsi

Un percorso si riferisce a un campo: PID-5 è il quinto campo di PID, PID-5.1 è il suo primo componente, PID-3(2) è la seconda ripetizione di PID-3 e OBX(3)-5 è il quinto campo del terzo segmento OBX.

Due comportamenti da conoscere:

6.5 Errori

La maggior parte dei passaggi non ha nulla che possa fallire. Impostare un valore, cancellare un campo o copiare da un percorso assente con un valore predefinito sono tutti definiti per ogni input.

date è l'eccezione, perché un valore che non è una data che riconosce non ha una conversione corretta. Accetta on_error:

Il valore predefinito è fail perché un timestamp che non si converte silenziosamente è peggiore di un messaggio che non arriva. Una data nel formato sbagliato appare comunque come una data, quindi supera la convalida del ricevitore e atterra nel record come il giorno sbagliato.

keep è legittimo quando il ricevitore tollera entrambi i formati e, quando utilizzato, la traccia segna il cambiamento come deliberato in modo che non appaia come un passaggio che è fallito silenziosamente.

6.6 L'ordine conta e la traccia lo mostra

Ogni passaggio vede l'output del passaggio precedente. Due conseguenze che colgono le persone:

Entrambi sono visibili nella visualizzazione passo-passo, che mostra l'intero messaggio dopo ogni passaggio piuttosto che solo il cambiamento. Vedi debugging.

6.7 Suggerire mapping e cosa fare con una suggerimento

L'AI Mapper propone mapping tra un set di campi sorgente e un set di destinazioni. Il suo comportamento caratteristico è che rifiuta: al di sotto della sua soglia di confidenza, si astiene piuttosto che indovinare, perché un mapping errato in un sistema clinico è peggiore di nessun mapping.

6.7.1 Dargli qualcosa di cui essere sicuri

Un nome da solo è una prova debole, anche quando corrisponde esattamente. PatientMRN contro PatientMRN punteggia 68, che si astiene alla soglia predefinita del 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.

Ciò ottiene un mapping per la maggior parte del percorso. Per finirlo, fornisci entrambe le metà:

Con quelli, il motore può vedere che i valori concordano con il tipo di destinazione e una suggerimento si basa su più di un nome.

6.7.2 L'approvazione avviene una mappatura alla volta

Ogni suggerimento ha la sua propia casella di approvazione. Non esiste un "accetta tutto sopra l'80%", deliberatamente: il motore ha già utilizzato la fiducia per decidere se offrire la mappatura e ciò che rimane è un giudizio su questo campo in questo feed. Un numero non è quel giudizio.

Un'astensione non può essere approvata affatto. Non ha una casella, nemmeno disabilitata, e lo schermo dice che il motore non conosce. Se conosci la risposta, mappa manualmente — è un atto diverso dall'accettare un suggerimento.

Un suggerimento al di sotto della tua soglia è mostrato senza una casella anche, contrassegnato come al di sotto di essa. Vale la pena leggerlo — una mancanza di poco è spesso la mappatura desiderata e nasconderla lascerebbe a chiedersi se il motore l'abbia considerata — ma non approvabile, perché la tua soglia è la linea che hai tracciato.

6.7.3 Due cose da fare con ciò che hai approvato

Aggiungerli a un canale trasforma ogni mappatura in un passaggio di copia. Ciò funziona solo dove la sorgente è un percorso nel messaggio, come ad esempio ZPI-1, perché un passaggio copia da un posto in un messaggio a un altro. I passaggi vanno nel file del canale e hanno effetto quando viene caricato nuovamente — nulla cambia nel traffico fino ad allora. La descrizione di ogni passaggio registra la fiducia con cui è stato suggerito e che una persona l'ha approvato, il che lo rende responsabile sei mesi dopo.

Scaricare come ricetta è la risposta giusta per il caso più comune: una mappatura da un nome di colonna, una chiave JSON o un nome di campo del fornitore. Sono mappature reali e un canale non può leggere direttamente un tale campo, quindi un passaggio non può esprimerle. La ricetta registra le mappature come approvate e può essere condivisa.

6.8 Perché non uno script

Mirth mette un trasformatore JavaScript al centro di ogni canale e rappresenta il design più flessibile disponibile. Perfuse offre la possibilità di scripting — vedere la chiave scripts nel riferimento al canale — ma non lo rende il percorso ordinario, per tre motivi che derivano da ciò che va storto nella pratica.

Un passaggio dichiarativo può essere ispezionato. Perfuse può dirti che un passaggio legge PID-5 e scrive PID-8, prima di eseguirlo, e può quindi mostrare una traccia a livello di campo, avvertire che un passaggio indirizza un percorso che il tipo di dati dichiarato non può contenere e generare una riproduzione per passaggio.

Un passaggio dichiarativo può essere ragionato dall'interfaccia. Il costruttore può offrire i campi che esistono nel traffico di questo canale e un cambiamento a un passaggio può essere verificato contro messaggi storici reali prima di essere salvato.

E un passaggio dichiarativo non può fare qualcosa di non correlato al messaggio. Uno script può chiamare la rete, leggere il file system o dipendere dall'orario del giorno. Quando un canale che ha funzionato per due anni inizia a produrre output errato, la causa che si trova al di fuori del messaggio è il caso più difficile da diagnosticare e rimuovere la possibilità vale più della flessibilità che costa.

Dove una trasformazione genuina non può essere espressa in modo dichiarativo, utilizzare uno script e accettare che la traccia lo mostrerà come un passaggio opaco.

6.9 Cosa è consentito a uno script

Uno script è rifiutato tutto ciò che si trova al di fuori del messaggio a meno che non gli sia concesso e le concessioni sono nella sezione Scripts del costruttore. Ciò è deliberatamente diverso da Mirth, che concede a ogni script tutti i diritti — quindi, lì, un trasformatore può iniziare a leggere il file system dopo un copia-incolla.

Ce ne sono tre.

Leggere e scrivere file richiede di nominare le directory che può utilizzare e un canale che concede l'accesso ai file senza di esse viene rifiutato al caricamento. Quella richiesta è l'unica differenza tra l'accesso ai file e l'accesso ai file non limitato: concederlo senza directory una volta raggiungeva l'intero file system, compreso il database di Perfuse, che contiene hash di password, la password del servizio account LDAP e il segreto client OIDC. La creazione di un canale richiede solo il ruolo di editore, quindi l'escalation si è completata nel momento in cui un amministratore ha avviato il canale.

Query su un database utilizza le connessioni configurate sul canale. Uno script con questo può leggere tutto ciò che queste credenziali possono.

Inviare messaggi ad altri canali consente a uno script di inviare un messaggio in un altro canale, il che è il modo in cui un ciclo tra due canali diventa possibile.

Concedere una capacità a un canale senza script non fa nulla e il file generato omette l'intero blocco in quel caso.

6.10 Gestione di una data che non corrisponde al suo formato

Un passaggio di data converte da un formato all'altro e la domanda interessante è cosa succede quando un valore non corrisponde al formato che afferma.

Il valore predefinito è interrompere il messaggio e rappresenta il valore predefinito giusto: un timestamp che non si converte silenziosamente è accettato a valle e poi letto male, il che è peggio di un messaggio che fallisce rumorosamente e si trova dove qualcuno può vederlo.

Lasciare il valore com'è lo passa attraverso nel suo formato originale. A valle, quindi, si vedono due formati in un campo, il che è il fallimento che il passaggio esisteva per prevenire — ma è la scelta giusta dove il campo è opzionale e un partner lo invia in modo non coerente.

Svuotare il campo è onesto e meglio di un formato errato, ma un ricevitore che richiede il campo rifiuta quindi il messaggio al suo posto.

6.11 I linguaggi di scripting

Se ne accettano tre e la scelta di quale utilizzare dipende principalmente dal fatto che si stia eseguendo una migrazione. Il valore va inserito nella chiave language di uno script:

ValoreCosa rappresenta
javascriptIl valore predefinito. Uno script non contrassegnato è JavaScript.
luaLa scelta migliore quando nessuno sta eseguendo una migrazione.
wasmI byte di un modulo WebAssembly compilato, non il codice sorgente.

JavaScript è il valore predefinito e uno script non contrassegnato viene trattato come JavaScript. È presente come obbligo di compatibilità piuttosto che come preferenza: gli script di Mirth sono JavaScript e un sito che si sposta ha migliaia di righe di codice. Ciò include il supporto per E4X, un'estensione obsoleta del linguaggio che gli script di Mirth utilizzano per XML e che deve essere tradotta prima che qualcosa possa essere analizzato.

Lua (lua) è la scelta migliore per chi non esegue una migrazione. Un runtime più piccolo, nessuna catena di prototipi da utilizzare in modo errato e tabelle con indici interi che corrispondono all'indirizzamento dei segmenti e dei campi in modo più naturale rispetto a JavaScript. La sua libreria standard è sufficientemente piccola da poter essere elencata, il che è ciò che rende più facile avere fiducia nella sua sandbox.

WebAssembly (wasm) non è un linguaggio, ma un modulo compilato, e il campo vuole i byte di un file .wasm invece del codice sorgente. Utilizzalo quando la trasformazione esiste già in un linguaggio compilato o quando è sufficientemente pesante da rendere importante il costo di runtime.

Il suo contratto è deliberatamente il più semplice disponibile: un modulo legge il messaggio sul canale di input standard e scrive il risultato sul canale di output standard. Byte in ingresso, byte in uscita — che è ciò che ogni strumento già fa e che qualcuno che testa un modulo sulla propria riga di comando già ha. L'alternativa era una funzione esportata su memoria lineare, che è più veloce e richiede che ogni autore di moduli concordi sull'allocazione, la codifica delle stringhe e su chi dealloca cosa; per qualcosa che viene eseguito una volta per messaggio, questo scambio non vale la pena.

Qualsiasi cosa un modulo scriva sul canale di errore standard diventa una riga di log, quindi può spiegarsi nel modo in cui uno script che chiama logger può.

Un codice di uscita diverso da zero significa che il modulo *è fallito*, il che non è lo stesso di un filtro che decide di rifiutare un messaggio. Un modulo filtro dice true o false sul canale di output standard. Confondere i due renderebbe un modulo che si blocca indistinguibile da uno che intenzionalmente rifiuta il traffico.

6.11.1 Cosa significa l'output

Le regole sono le stesse per tutti e tre i linguaggi piuttosto che nuove regole per ogni runtime, quindi il comportamento osservabile di uno script — cosa può vedere, cosa può fare, quanto tempo può impiegare, cosa significa un verdetto di filtro — è definito una volta.

Per un trasformatore, un preelaboratore o uno scrittore, un output vuoto significa che il messaggio non è stato modificato. Cadere alla fine di uno script lascia il messaggio invariato; trattare la mancanza di output come "il messaggio è ora vuoto" discarderebbe il traffico per una questione tecnica.

I moduli WebAssembly vengono compilati quando il canale viene caricato, non al primo messaggio. La compilazione non è gratuita — un modulo costruito da un linguaggio che porta il proprio runtime può richiedere centinaia di millisecondi — e pagare questo costo al momento del caricamento significa che il primo messaggio che passa attraverso un canale non è misteriosamente più lento degli altri.

6.12 Tabelle di mappatura condivise

L'altra metà dello stesso problema: i codici di sesso e le classi di pazienti di un sito vengono tradotti in modo identico in ogni canale che li tocca, e una tabella all'interno di un canale è una tabella che solo quel canale può utilizzare.

# 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

La provenienza è il punto. La maggior parte di ciò che rende un'interfaccia difficile da mantenere è che nessuno sa *perché* un mapping sia fatto in un certo modo, e la persona che lo sapeva se n'è andata. Un mapping con una ragione può essere discusso; uno senza diventa qualcosa che nessuno osa cambiare e nessuno osa eliminare.

Le tabelle vengono create e modificate in Build → Tabelle nonché nel file. Salvare una tabella in vigore riavvia i canali in esecuzione che caricano il suo file, in modo che il prossimo messaggio lo utilizzi; una bozza non riavvia nulla.

6.12.1 Versioni e date di efficacia

Un tableau può tenere diverse edizioni sotto un solo nome, ognuna con la sua versione version. L'edizione che un messaggio utilizza viene scelta quando il messaggio arriva: tra le edizioni approvate le cui date coprono quel giorno (UTC), quella che è iniziata più di recente. Quindi, un cambiamento del codice concordato per il primo giorno del prossimo mese viene inserito ora e diventa effettivo automaticamente.

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: [...]

(conservato per la registrazione, utilizzato da nulla).

che iniziano lo stesso giorno, vengono rifiutate quando il file viene caricato.

a partire da oggi, quindi sostituisce quella in vigore. Quella che era stata avviata solo oggi viene ritirata, poiché due edizioni che iniziano lo stesso giorno non lasciano alcuna regola.

altrimenti vengono utilizzati quelli della tabella.

chi l'ha salvata e chi l'ha approvata, e Confronta con la versione in vigore mostra cosa un'edizione aggiunge, rimuove e modifica.

6.12.2 Firma

Con Impostazioni → Dati → Tabelle di mapping "Le modifiche a una tabella di mapping richiedono l'approvazione di una seconda persona" (data.tableApproval) attivate, ogni salvataggio è una bozza e la persona che lo ha salvato non può approvarlo: qualcun altro lo fa, eventualmente fornendo il giorno in cui entra in vigore. Un'edizione approvata non può essere modificata sul posto; Nuova versione da questa la copia nella prossima versione. L'approvazione, il ritiro e la cancellazione di una bozza vengono scritti nel registro di controllo e l'approvazione riavvia i canali in esecuzione che caricano il file.

6.12.3 Valori senza tabella di mapping

Ogni valore che un passaggio di mappatura ha cercato e non ha trovato viene conteggiato, per tabella, con i canali attraverso cui è passato e quando è stato visto per la prima e l'ultima volta. Lo schermo delle tabelle elenca i valori, in ordine di frequenza. Mappa apre la tabella con quel valore già aggiunto come riga; Dismiss lo rimuove fino a quando non viene visto di nuovo. I valori più lunghi di 64 caratteri non vengono registrati (non sono codici) e l'elenco mantiene ciò che è stato visto all'interno del periodo di conservazione dei messaggi. L'elenco viene mantenuto in terminology.db accanto al database principale.

6.12.4 Sistemi di codici

I sistemi di codici pubblicati possono essere importati dai file dei loro editori, sotto Sistemi di codici sullo schermo Tabelle (amministratori) o con POST /api/terminology/import?format=… e il file come corpo:

FormatoFileSistema
loincLoinc.csv dalla tabella di rilascio LOINChttp://loinc.org
icd10cmil file di ordinamento CMS (icd10cm_order_*.txt) o il file dei codicihttp://hl7.org/fhir/sid/icd-10-cm
rxnormRXNCONSO.RRF dal rilascio completo RxNormhttp://www.nlm.nih.gov/research/umls/rxnorm
snomedlo snapshot delle descrizioni RF2 (sct2_Description_Snapshot-en_*.txt)http://snomed.info/sct
snomed-rf2un pacchetto di rilascio RF2 SNOMED CT completo (il file zip pubblicato da un centro di rilascio nazionale)http://snomed.info/sct, versione http://snomed.info/sct/{module}/version/{date}
clamlun file ClaML: ICD-10 dell'OMS, ICD-10-GM e OPS (BfArM), CIM-10 FR (ATIH)dal titolo del file o dal system fornito
icd11la tabulazione MMS semplice dell'ICD-11 dell'OMS (separata da tab, con colonne Code e Title)http://id.who.int/icd/release/11/mms
csvqualsiasi file delimitato, con system, codeColumn e displayColumn (CPT, HCPCS, codici locali, tabelle nazionali)il system fornito

Nessuno viene fornito con Perfuse: LOINC, SNOMED CT, RxNorm e CPT hanno ciascuno la propria licenza e lo schermo chiede all'importatore di confermare che l'organizzazione la possiede (registrata con l'importazione). I codici importati vengono utilizzati in tre modi:

viene salvata e i codici che non sono nel sistema vengono elencati nella versione;

per essi (vedere le opzioni del server FHIR). I codici ICD-10-CM vengono accettati con o senza il punto.

Edizioni e classificazioni nazionali. Un'edizione di SNOMED CT viene importata dal suo intero pacchetto RF2: concetti con il loro stato reale, ogni descrizione attiva e gli insiemi di riferimento linguistici. L'edizione viene trovata dal pacchetto (il modulo nazionale con il maggior numero di concetti; edition lo nomina invece) e diventa l'URI della versione. language sceglie il termine preferito per ogni concetto (sv, da, nl, de, fr, en-GB, en-US ...; inglese altrimenti) e ogni termine preferito e nome completamente specificato vengono mantenuti come designazioni: $lookup li restituisce e il suo displayLanguage ne sceglie uno (de-CH ricade su de). Le edizioni che Perfuse nomina (Internazionale, Regno Unito, Germania, Paesi Bassi, Svezia, Danimarca, Belgio, Irlanda, Norvegia, Svizzera, Estonia, Spagna) sono elencate da GET /api/terminology/editions, i cui ID modulo non vengono verificati contro una fonte pubblicata contrassegnata come tale; qualsiasi altra edizione viene importata anche, nominata dal suo modulo.

I file ClaML vengono letti in UTF-8, ISO-8859-1, ISO-8859-15 o Windows-1252, come dichiarato nella loro dichiarazione XML. Il titolo di ogni categoria è il suo rubrico preferito (termini annidati inclusi); un modificatore (un quinto carattere per il sito di una frattura, ad esempio) crea i codici che aggiunge, con il titolo del modificatore dopo quello della categoria, a meno che la categoria non lo escluda; blocks=true importa anche capitoli e blocchi. Le colonne della tabulazione ICD-11 vengono trovate per nome, poiché il loro ordine è cambiato tra le versioni, e i trattini che mostrano la profondità vengono rimossi dai titoli. Un file delimitato richiede delimiter (, ; | o tab), encoding (utf-8, iso-8859-1, iso-8859-15, windows-1252) e noHeader=true, con colonne numerate da 1. La console offre impostazioni per i file UK ICD-10 5a Edizione e OPCS-4 (TRUD), la tabella di etichette CIM-10 FR della Francia (ATIH) e un'esportazione ICD-10-BE; i loro editori non documentano tutte le colonne, quindi controllatele contro l'intestazione del file.

Date di efficacia. effective=YYYY-MM-DD importa una versione ora e la utilizza da quel giorno (ad esempio ICD-10-GM, ogni 1 gennaio): fino ad allora una ricerca che non nomina una versione viene risposta dalla versione già in vigore e lo schermo mostra la data.

ICD-11 dall'OMS. Con un client registrato su icd.who.int (Impostazioni → Dati → Sistemi di codici, serve -icd11-client-id e -icd11-client-secret; -icd11-release, 2025-01 per impostazione predefinita), i codici ICD-11 che non sono importati vengono cercati nell'API ICD dell'OMS (codeinfo, quindi il titolo dell'entità) e conservati per un giorno. Un codice postcoordinato (NC72.2&XK9K) viene verificato per intero, quindi una combinazione ICD-11 non consentita viene rifiutata, e i suoi nomi di visualizzazione ogni parte ("Frattura del collo del femore (Destro)").

ICD-11 senza inviare codici. L'OMS pubblica la stessa API come un contenitore (whoicd/icd-api, gratuito, Intel e Arm). Esegui su rete locale e fornisci l'indirizzo (serve -icd11-url http://icd-api.local, o Indirizzo API ICD nelle stesse impostazioni); nessun client è necessario e nessun codice lascia la rete. Testato contro quel contenitore (versione 2.6.0, rilascio 2025-01 in inglese e francese).

7 Filtraggio

Un filtro decide quali messaggi un canale accetta. È un'espressione sul canale, valutata dopo che il messaggio è stato analizzato e registrato, prima di qualsiasi trasformazione.

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

Un messaggio che il filtro rifiuta viene registrato con l'esito filtered. Ciò è un risultato normale, non un errore, e non genera un allarme o una conferma negativa.

7.1 Filtered non è fallito

Questa distinzione è importante perché confonderli può nascondere un problema reale.

Un messaggio filtrato è stato correttamente rifiutato: non era per questo canale. Un messaggio fallito è uno che questo canale avrebbe dovuto gestire e non ha potuto. Se entrambi fossero stati registrati allo stesso modo, un canale che inizia a fallire ogni messaggio sembrerebbe esattamente come un canale che sta filtrando la maggior parte del suo traffico, che è lo stato normale di molti canali.

Quindi le statistiche li contano separatamente, le regole di allarme li trattano in modo diverso e l'interfaccia li visualizza in colori diversi. Un aumento dei messaggi filtrati potrebbe significare che il mittente ha iniziato a inviare qualcosa di nuovo; un aumento dei fallimenti significa che qualcosa è rotto.

7.2 Ciò che un filtro può leggere

Qualsiasi campo nel messaggio analizzato, tramite gli stessi percorsi utilizzati dalle trasformazioni. Il filtro viene eseguito prima delle trasformazioni, quindi vede il messaggio come è arrivato — non come verrà inviato.

Quell'ordine è deliberato. Un filtro che legge valori post-trasformazione sarebbe in grado di decidere se accettare un messaggio in base alle modifiche apportate sull'ipotesi che fosse stato accettato, il che è circolare e produce canali il cui comportamento dipende dall'ordine di due cose che sembrano indipendenti.

7.3 Espressioni

Confronti: ==, != e per i numeri <, <=, >, >=.

Appartenenza: in ("A01", "A03"), che è più chiaro di una catena di || ed è la forma che il costruttore produce.

Combinazione: &&, || e parentesi. Negazione con !.

Assenza: un percorso che non è presente si confronta in modo diverso con qualsiasi valore, compresa la stringa vuota. Per testare l'assenza in modo esplicito, confrontare con absent. Ciò è importante perché un campo assente e un campo vuoto sono diversi, come descritto in transformation, e un filtro che li tratta nello stesso modo accetterà messaggi che era stato scritto per escludere.

7.4 Un errore nel filtro è un rifiuto

Se il filtro stesso non riesce a valutare — un'espressione malformata che è passata alla convalida, o un confronto che non può essere effettuato — il messaggio viene rifiutato e l'errore viene registrato contro di esso.

Rifiutare piuttosto che accettare è la scelta più sicura delle due, ma nessuna delle due è buona, e l'esito viene registrato in modo distinto da un rifiuto di filtro ordinario in modo che possa essere segnalato. Un filtro che si verifica un errore su ogni messaggio sta silenziosamente eliminando l'intero flusso di dati e non deve sembrare un filtro che funziona.

7.5 Filtra alla sorgente quando possibile

Un filtro viene eseguito dopo che il messaggio ha attraversato la rete e viene analizzato. Alcune sorgenti possono filtrare prima e più a buon mercato:

Il filtraggio alla sorgente è una decisione di prestazioni, non di correttezza, e ha un costo: un messaggio filtrato al broker non viene mai registrato da Perfuse, quindi non appare nel negozio dei messaggi e non può essere ispezionato in seguito. Se è necessario essere in grado di dimostrare cosa ha inviato il mittente, filtrare qui piuttosto che lì.

7.6 Test di un filtro

Un filtro può essere verificato contro il traffico storico reale prima di essere salvato. L'interfaccia segnala quanti dei messaggi registrati negli ultimi N il filtro accetterebbe, rifiuterebbe ed errore — che è il modo più veloce per scoprire che un'espressione che sembra giusta non accetta nulla.

La traccia mostra anche, per messaggio, quali campi il filtro ha letto e quali valori ha trovato. Un filtro che rifiuta inaspettatamente tutto è solitamente un percorso che non esiste in questo flusso di dati e la traccia lo nomina.

8 Formati di messaggio

Il dataType di un canale decide come i byte diventano un messaggio. Ciò influisce sull'analisi, su cosa significano i percorsi, su come il messaggio viene scritto di nuovo e su quali trasformazioni sono valide.

ValoreFormato
hl7HL7 v2, lo standard delimitato da pipe. Il valore predefinito.
hl7v3Documenti HL7 v3 e CDA, che sono XML.
x12ASC X12, utilizzato per l'idoneità e le richieste di rimborso.
ncpdpStandard di telecomunicazione NCPDP D.0 per le richieste di rimborso farmaceutiche.
scriptNCPDP SCRIPT, prescrizioni elettroniche. XML.
dicomOggetti di imaging DICOM.
delimitedCSV e altri testi delimitati.
rawNessun parsing. Byte in ingresso, byte in uscita.

8.1 HL7 v2

Il valore predefinito, e ciò che la maggior parte degli esempi di questo manuale utilizza. I segmenti terminati da ritorno a capo, i campi da |, i componenti da ^, le ripetizioni da ~.

Due cose sull'encoding sono degne di nota perché causano errori silenziosi.

I delimitatori non sono fissi. Vengono dichiarati in MSH-1 e MSH-2 di ogni messaggio, e Perfuse li legge da lì anziché supporre pipe. Un mittente che utilizza un separatore di campo diverso viene parsato correttamente.

La conseguenza è che un messaggio i cui separatori sono stati sostituiti — più spesso da un elaboratore di testi o un client di posta elettronica che sostituisce i caratteri con look-alike tipografici — viene parsato perfettamente in campi che sono tutti errati. Nessun errore si verifica. Questo è il motivo per cui il lettore di esempio descritto in testing segnala quale carattere di separatore ha trovato e rifiuta di esprimere fiducia quando è insolito.

Quando qualcuno ti invia un esempio e il canale costruito da esso produce nonsenso, controlla i separatori prima di tutto. Chiedi un allegato di testo semplice anziché un messaggio incollato nel corpo di un'e-mail.

8.2 HL7 v3 e CDA

XML anziché delimitato. I percorsi sono percorsi di elementi e attributi anziché posizioni di campo.

In v3 un valore è quasi sempre un attributo anziché testo di elemento. Un confronto che legge solo il testo di elemento segnalerà due documenti come identici quando la data di nascita, il genere e ogni identificatore differiscono. Il confronto di Perfuse legge entrambi, ed è per questo: l'alternativa ha successo silenziosamente.

Le opzioni hl7v3 sono nel format reference.

8.3 X12

I segmenti terminati da ~ per convenzione, con delimitatori dichiarati nel segmento ISA. Come HL7, vengono letti dal messaggio anziché supposti.

La struttura di X12 è costituita da buste all'interno di buste — scambio, gruppo funzionale, set di transazioni — e un singolo scambio può contenere molte transazioni.

Per default, uno scambio è un messaggio. L'intero file ottiene un record, un esito e una riga nell'interfaccia, indipendentemente da quante transazioni contiene.

8.3.1 L'X12 XML di Mirth

Mirth Connect e Open Integration Engine mostrano X12 come XML: una radice X12Transaction (o EDIMessage quando l'input non inizia con ISA) che trasporta i delimitatori come attributi, e un elemento per segmento ed elemento denominato ISA.01, NM1.03.1 e così via. I canali e i ricevitori costruiti per Mirth leggono e scrivono questa forma. Perfuse legge e scrive la stessa forma:

Il formato è stato scritto a partire dall'output osservato e dal formato pubblicato di Open Integration Engine 4.6, e viene verificato contro di esso: 25 scambi generati e 4 esempi conservati vengono fuori byte per byte come OIE li scrive, e viceversa (vedi verifica). Un DOCTYPE viene rifiutato, come in ogni XML che Perfuse legge.

8.3.2 Dividere uno scambio

Impostare split rende ogni set di transazioni un messaggio a sé stante, con il proprio record, le proprie metriche e la propria riga. Un operatore che cerca una richiesta di rimborso trova una richiesta di rimborso anziché un file di quattrocento.

È disattivato per default perché attivarlo moltiplica tutto ciò che si trova a valle — conteggi dei messaggi, righe, soglie di allarme — e una soglia tarata per i file che conta improvvisamente le richieste di rimborso non significherà più ciò che significava in precedenza. Ciò dovrebbe essere una decisione presa da qualcuno anziché un valore predefinito ereditato.

split e acknowledge non possono essere entrambi impostati, e un canale con entrambi viene rifiutato al caricamento. Un riconoscimento è una dichiarazione su un intero scambio, quindi la divisione invierebbe uno per set di transazioni, e un partner che riceve più 999 che nominano lo stesso gruppo funzionale non ha modo di riconciliarli.

8.3.3 Quando i conteggi non corrispondono

X12 dichiara i propri conteggi — quanti segmenti, quante transazioni — e la chiave envelope dice cosa fare quando essi non corrispondono a ciò che è effettivamente presente. Quei conteggi sono l'unico meccanismo che X12 ha per rilevare che metà di un file di richieste di rimborso è arrivata.

ValoreComportamento
requireRifiuta lo scambio. Il valore predefinito.
warnElaboralo, e registra il guasto contro il messaggio.
ignoreNon controllare affatto.

warn esiste per una situazione reale: alcuni software dei partner hanno generato conteggi errati per anni in file altrimenti completi, e un sito che deve elaborare quei file ha bisogno di un modo per dirlo a voce alta nella configurazione anziché disattivare la convalida nel suo complesso.

ignore è denominato per essere scomodo. Impostarlo getta via l'unico mezzo che X12 ti dà per notare un file troncato, e un file di richieste di rimborso troncato è indistinguibile da uno piccolo.

8.3.4 Transazioni Perfuse legge come dati strutturati

Ogni scambio X12 può essere instradato, filtrato e indirizzato per percorso. Queste transazioni vengono inoltre analizzate in campi denominati, in modo che un canale possa chiedere cosa abbia deciso un pagatore piuttosto che quale elemento si trova nella posizione quattro.

TransazioneCiò che trasporta
835Consiglio di rimborso: ciò che è stato pagato, ciò che è stato negato e i motivi di aggiustamento.
275Allegati di richiesta: documentazione clinica a supporto di una richiesta.
277Stato della richiesta, compresa la richiesta del pagatore di documentazione aggiuntiva.
278Autorizzazione preventiva: la richiesta di revisione e la decisione del pagatore.
999Conferma funzionale, che Perfuse genera anche.
271Eleggibilità: se un paziente è coperto e i relativi importi di co-pagamento, co-assicurazione, deducibile e fuori tasca, in rete e fuori rete.
834Iscrizione: membri aggiunti, modificati e terminati, con ogni linea di copertura e relative date.
837Richieste, professionali e istituzionali (leggi per la conversione CARIN di CMS-0057).

Perfuse costruisce anche la richiesta di eleggibilità 270 e la richiesta di stato della richiesta 276, sotto Payer → Richieste e autorizzazioni o attraverso POST /api/x12/eligibility/build e /api/x12/claimstatus/build. Entrambe sono le versioni HIPAA 5010 (005010X279A1, 005010X212), lette indietro e controllate prima di essere visualizzate, e nessuna delle due viene inviata da quella pagina: consegnare una di esse è un lavoro di canale, dove il partner commerciale e le relative credenziali sono.

8.3.5 Eleggibilità e regola di contenuto dei dati CAQH CORE

Un 271 è un elenco di segmenti EB, ognuno un singolo fatto: copertura attiva, o un co-pagamento di 25 dollari per tipo di servizio 30 in rete, o 800 dollari del deducibile individuale rimanente. Il lettore li assembla nella risposta che un banco desidera - "copertura attiva sotto Gold PPO 2000; co-pagamento in rete 25 dollari; deducibile individuale rimanente in rete 800 dollari" - e nomina un rifiuto (un segmento AAA) in parole, con cosa il pagatore dice di fare dopo.

Verifica anche la risposta contro la regola di contenuto dei dati di idoneità e benefici CAQH CORE: per un'indagine sulla copertura del piano di beneficenza sanitaria (tipo di servizio 30), una risposta attiva dovrebbe trasportare date di piano, nome del piano, co-pagamento, co-assicurazione, deducibile e deducibile rimanente sia in rete che fuori rete, e i tipi di servizio base (1, 33, 35, 47, 48, 50, 86, 88, 98, AL, MH, UC). Ognuno viene elencato come soddisfatto o mancante. Questa è la lettura di Perfuse della regola, utile per "perché questo pagatore non ci dice mai il deducibile?" - non è una certificazione CORE, che i vendor di test autorizzati da CAQH eseguono.

8.3.6 Autorizzazione preventiva

Perfuse implementa l'autorizzazione preventiva due volte, di proposito.

Il lato FHIR è ciò che CMS-0057-F richiede ai pagatori di esporre entro il 1° gennaio 2027. Il 278 è ciò che i pagatori accettano oggi, e la regola non lo sostituisce — Da Vinci PAS è in pratica un mapping su questa transazione, perché un 278 è ciò che un sistema di gestione dell'utilizzo parla. Un motore che legge solo la metà FHIR può parlare con i sistemi che esisteranno e non con quelli che esistono.

Una risposta 278 trasporta il numero di autorizzazione, e questo è il campo per cui esiste l'intera transazione. Senza di esso un servizio certificato non è fatturabile: la richiesta va in con nessun numero di autorizzazione e viene negata per la mancanza di esso, che legge a valle come una negazione clinica.

Un rifiuto e un rifiuto di considerazione non sono la stessa cosa

Questa è la confusione più costosa nella transazione, e Perfuse segnala le due separatamente.

Ciò che è arrivatoCiò che significaCiò che fare
HCR con azione A3Il pagatore ha considerato la richiesta e non la certificherà.Appellare, o cambiare il piano di cura.
Un segmento AAAIl pagatore non l'avrebbe considerata — paziente non trovato, richiedente non riconosciuto, revisione non coperta. Nessuna decisione è stata presa.Correggere la richiesta e inviarla nuovamente.

Entrambe vengono lette come "non approvate" da chiunque esegua la scansione e le azioni corrette sono opposte. Fare appello a qualcosa su cui nessuno ha preso una decisione non produce alcun risultato; rinviare un rifiuto produce lo stesso rifiuto. I nomi dell'esito parsificato che si sono verificati — denied contro not-considered — e AAA04 contiene il consiglio del pagatore stesso su se la richiesta sia recuperabile o meno.

La certificazione parziale viene segnalata come partially-certified anziché essere incorporata nell'approvazione. Esiste un numero di autorizzazione per addebitare, quindi conta come approvato, ma la quantità certificata non è la quantità richiesta — e uno studio che prenota sei sedute contro tre approvate lo scopre alla quarta richiesta di rimborso.

Un codice di azione che Perfuse non riconosce viene segnalato come unknown, non come pendente. Pendente si legge come "wait" e attendere è l'azione sbagliata per la maggior parte di ciò che potrebbe essere un codice non riconosciuto.

Un canale può instradare sulla decisione direttamente:

filter: HCR-1 == "A3"

Conversione tra i due

Perfuse converte un 278 analizzato in una risposta Da Vinci PAS ClaimResponse, e segnala ogni giudizio che la conversione ha richiesto piuttosto che solo il risultato. La conversione segue tre regole:

La riduzione a un vocabolario a tre stati — approvato, rifiutato, in sospeso — è disponibile ed esplicita su ciò che scarta. La riduzione di un rifiuto a considerare produce "rifiutato" e dice a parole che l'azione corretta è una risottomissione corretta piuttosto che un appello.

Verificato contro PAS 2.2.1, non solo contro se stesso

La ClaimResponse è modellata sul profilo Da Vinci PAS 2.2.1 e è stata verificata con il validator ufficiale HL7 caricato con il pacchetto PAS pubblicato. La prima versione era stata verificata solo con i test di Perfuse e il validator l'ha rifiutata con sei o otto errori per risorsa. Ognuno di essi è qualcosa che un endpoint PAS di un pagatore avrebbe anche rifiutato:

Cosa non andavaDove PAS lo mette
La decisione era in adjudication.category e reason.L'estensione reviewAction, su un adjudication la cui categoria è submitted.
Il codice di motivazione denominato elemento X12 1034.Elenco di codici esterni X12 886.
Una richiesta in sospeso ha risposto outcome: queued.outcome riguarda l'elaborazione e PAS consente solo complete, error e partial. Un rifiuto è complete, con azione di revisione A4.
processNote.type era un CodeableConcept.R4 ha un codice: print.
patient, created, insurer e request mancavano.Tutti e quattro sono obbligatori. Sono forniti come riferimenti di identificatore, perché la risposta si trova da sola piuttosto che in un bundle.

La risposta corretta valida senza errori per una certificazione, un rifiuto e un rifiuto. Gli avvertimenti che rimangono sono il validator che dice di non poter caricare i sistemi di codici X12, che X12 concede in licenza. Il numero di autorizzazione è riportato in reviewAction.number, dove l'esempio della guida lo mette, e in preAuthRef quando la risposta ha solo uno.

Il validator non fa parte di make check, perché richiede Java e un download della guida e delle sue dipendenze. Ciò che ha trovato è mantenuto da un test: ogni regola che ha applicato è affermata, quindi un cambiamento che reintroduce uno di quegli errori fallisce.

La vista Richieste e autorizzazioni converte un 278 incollato e mostra le decisioni, le note e la risorsa.

8.3.7 Allegati e perché richiedono un trattamento speciale

CMS-0053-F rende il 275 uno standard HIPAA per gli allegati alle richieste, con la conformità richiesta entro il 26 maggio 2028. Trasporta un documento — una nota operativa, un referto di imaging, un modulo scannerizzato — legato alla richiesta che supporta.

Il 277 è l'altra metà della stessa conversazione. Un pagatore riceve una richiesta, decide di aver bisogno di documentazione e invia un 277 per richiederla; il fornitore risponde con un 275.

Un canale può instradare direttamente sul codice di stato, perché STC01 è un composito e il suo secondo componente è lo stato. Scritto in forma canonica, perché un componente è indirizzato con un punto e le due notazioni non possono essere mescolate — STC-1.2 è l'elemento 1, componente 2:

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

Questi sono i codici che significano inequivocabilmente che un documento è richiesto. La categoria di stato in STC-1.1 non viene utilizzata da sola: R4 significa una richiesta di documentazione in alcune guide di implementazione e "inoltrato altrove" in altre, quindi un filtro sulla categoria sola metterebbe le richieste finalizzate nella coda per qualcuno da inseguire.

Due identificatori decidono se un allegato è mai associato alla sua richiesta e entrambi vengono segnalati: il numero di controllo dell'allegato, che il fornitore ha messo sulla richiesta originale per dire che la documentazione sarebbe seguita, e il numero di traccia, che corrisponde alla richiesta del pagatore. Un allegato che arriva senza nessuno dei due viene archiviato e mai collegato a nulla, mentre la richiesta invecchia.

Un documento all'interno di un 275 non viene interpretato. Perfuse segnala i suoi byte e ciò che il mittente dice che sono. Un allegato può essere un PDF, un TIFF, un documento CDA o un messaggio HL7 e un canale che necessita del contenuto può passare quei byte al formato che lo legge.

Il modulo 006020, che è quello adottato dal regolamento

CMS-0053-F adotta la versione 006020 e il suo 275 differisce dal modulo 005010 in due modi che contano.

Perfuse rimuove l'entità e segnala il documento al suo interno, con il suo tipo di contenuto e nome del file. I byte che segnala sono esattamente quelli che il mittente ha avvolto. Un'entità che non può essere rimossa lascia il payload grezzo al suo posto, con una nota che spiega il motivo.

Creazione di un 275. Perfuse costruisce anche allegati 006020X314: uno non sollecitato per accompagnare una richiesta di rimborso, o una risposta a una richiesta 277 di un pagatore. La differenza è BGN01 02 contro 11, e se TRN02 trasporta il PWK06 della richiesta di rimborso o il TRN02 della 277. Ogni scambio costruito viene analizzato nuovamente prima di essere restituito e la risposta indica se il documento all'interno è lo stesso che è stato inserito.

La struttura deriva dalle due guide compagne pubblicate per 006020X314: la guida esMD del CMS e quella di UnitedHealthcare. Non deriva dal rapporto tecnico X12, che X12 concede in licenza e che questo progetto non detiene.

Non esiste una convalida contro il rapporto tecnico. La guida compagna del partner governa.

8.3.8 Firme elettroniche sugli allegati

CMS-0053-F adotta anche uno standard di firma, al 45 CFR 162.2002(e): la guida di implementazione HL7 per CDA Release 2, firme digitali e delega di diritti, Release 1. Si applica alle firme apposte alle informazioni sugli allegati quando vengono inviate in una transazione di allegato HIPAA, a partire dal 26 maggio 2028. Un pagatore non può chiedere più di quanto previsto dalla guida.

Perfuse firma un C-CDA in quel modo mentre viene inserito in un 275, e controlla le firme su ogni C-CDA in un 275 che legge.

Se qualcosa di ciò non è disponibile, la firma viene comunque creata e mantiene la sua validità. Il risultato nomina la forma XAdES raggiunta e indica cosa l'ha fermata prima di raggiungere X-L: ad esempio un certificato autofirmato (nessun CA da interrogare) o nessun'autorità di timestamp.

La chiave è -signing-cert e -signing-key. Metti i certificati CA dopo quello del firmatario nello stesso file in modo che il percorso viaggi con la firma. Per una firma che significa ciò che significa DSDR, il certificato dovrebbe nominare il clinico, con il suo NPI, piuttosto che il server. La firma è un'azione amministrativa, come la firma di qualsiasi documento.

La guida non nomina uno spazio dei nomi per i suoi elementi. Perfuse mette digitalSignature, authorizedSigner e SignaturePurpose in urn:hl7-org:sdtc. Afferma anche lo scopo come un tipo di impegno XAdES con l'OID ASTM, che gli strumenti XAdES comprendono. La delega dei diritti, dove un delegato firma con un'asserzione SAML dall'autore autorizzato, non viene prodotta e una ricevuta viene segnalata come non verificata.

Il numero NPI del fornitore viene controllato contro il suo cifra di controllo. Un pagatore associa un allegato alla sua richiesta di rimborso in parte su quel numero e un numero errato lascia l'allegato non associato mentre la richiesta di rimborso viene negata per documentazione mancante.

La vista Richieste di rimborso e autenticazione costruisce un 275 da un C-CDA incollato o un file caricato, opzionalmente firmando il C-CDA, e legge uno con i risultati di ogni firma. Nulla su quella pagina invia nulla: lo scambio viene restituito per essere consegnato attraverso un canale, che è dove appartengono il partner, le credenziali e la traccia di audit.

8.3.9 Segmenti binari

Un segmento BIN trasporta byte grezzi e i byte grezzi contengono delimitatori. Ogni altro segmento X12 termina al terminatore di segmento, quindi un parser ordinario trova i segmenti cercando un byte; un allegato non può essere trovato in quel modo. Un PDF che contiene un ~ verrebbe diviso in pezzi e ogni pezzo è un segmento strutturalmente valido — quindi il documento viene troncato, ogni segmento dopo di esso è fuori allineamento e nulla segnala un errore.

Perfuse legge il conteggio dei byte che il segmento dichiara e prende esattamente quei byte. Due conseguenze degne di nota:

La guida esMD presenta un proprio esempio di scambio che dichiara 16 byte per lo stesso payload di 53 byte che la sua tabella conta correttamente come 53. Perfuse rifiuta quell'esempio, come dovrebbe. Un test mantiene sia l'esempio della tabella che l'errore di battitura dell'esempio, quindi un cambiamento in entrambe le direzioni viene notato.

8.4 FHIR

8.4.1 In cosa si trasforma un messaggio HL7 v2

Il tipo di messaggio decide cosa viene prodotto e ogni conversione segnala le decisioni che ha dovuto prendere come note accanto al bundle.

v2FHIR
ADTPaziente, un Incontro quando c'è una visita, una Condizione per ogni diagnosi DG1 (elencata anche nell'Incontro diagnosis, una di ammissione come AD), una Procedura per PR1 e un AllergyIntolerance per AL1. A28, A31, A29 e A24 riguardano la persona, quindi non producono Incontro o diagnosi, ma trasportano allergie.
ORUDiagnosticReport per OBR, con le sue Osservazioni e Campione, e l'ordine a cui risponde come ServiceRequest (il suo richiedente OBR-16 o ORC-12, il suo stato ORC-5); OBR-32 è l'interprete dei risultati, OBR-34 e OBR-35 i performer. I risultati sono raggruppati sotto l'OBR precedente in base alla posizione, perché OBX-4 non è affidabile.
ORM, OML, OMGServiceRequest.
SIUAppuntamento, con il paziente, i professionisti da AIP e le sedi da AIL.
MDMDocumentReference che trasporta il documento.
VXUImmunizzazione, una per RXA.

Qualsiasi altra cosa produce il Paziente e un avviso che nomina il tipo che non è stato mappato.

Prenotazione. Una prenotazione, una riprenotazione, una cancellazione e un no-show atterranano tutti sullo stesso Appuntamento. La sua identità deriva dai numeri dell'appuntamento in SCH-1 e SCH-2, mai dal messaggio, quindi una cancellazione aggiorna la prenotazione. L'alternativa sarebbe un secondo appuntamento cancellato accanto a uno vivo, il che mostra il paziente prenotato in uno slot che non esiste più.

Documenti. Le note di testo (TX, FT, ST) mantengono i propri a capo, comprese le righe vuote, perché una ripetizione vuota in una nota è una pausa di paragrafo.

Questo è ciò che il criterio 14 del CMS Interoperability Framework chiede: note di cartella clinica e documenti clinici restituiti come allegati FHIR.

Immunizzazioni. Una dose non viene mai segnalata come somministrata quando il messaggio dice il contrario.

Input scomodo. Ognuno di questi viene segnalato nelle note piuttosto che deciso silenziosamente:

8.4.2 Cosa aggiunge un sito: lo script del bundle

Un profilo nazionale spesso richiede ciò che un messaggio HL7 v2 non trasporta: il numero IK di un ospedale o il codice ODS, il livello di contatto di una visita (ISiK), se un nome è un nome proprio o un'iniziale (il nl-core olandese). Perfuse non indovina questi valori. La destinazione fhir ha uno script bundle_script dove un sito può scrivere questi valori: uno script JavaScript eseguito su ogni Bundle convertito, come bundle, prima della convalida e dell'invio. Ciò che lo script lascia è ciò che viene inviato, verificato come qualsiasi conversione, e uno script che genera un'eccezione fa fallire il messaggio come qualsiasi trasformatore. La console lo trova sotto la voce *Aggiungi ciò che i tuoi sistemi conoscono* della destinazione.

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 esegue lo stesso script, quindi un sito può provarlo sui propri messaggi per primo. Due esempi funzionanti sono nel repository: examples/isik/bundle-script.js (IKNR, Kontaktebene, numero di paziente MR, Diagnosetyp) e examples/nictiz/bundle-script.js (nomi propri e iniziali). Con essi i messaggi tedeschi e olandesi inventati in conformance/national passano da 18 a 42 risorse valide su 47 rispetto a ISiK e da 12 a 18 su 24 rispetto a nl-core; ciò che rimane è nei messaggi o nel server di terminologia, ed è elencato lì.

Il Bundle passa attraverso il modello di Perfuse sulla sua strada di ritorno, quindi le modifiche apportate da uno script vengono controllate e scritte nella versione FHIR della destinazione. I membri per i quali il modello non ha un campo vengono mantenuti come li ha scritti lo script, all'interno dei tipi di dati anche.

8.4.3 US Core 9.0.0 e USCDI v6

-us-core (e claim_us_core su una destinazione fhir) inserisce un profilo US Core in meta.profile, ma solo su una risorsa che è stata controllata contro quel profilo e trovata conforme. Una che non soddisfa è comunque convertita e inviata senza la pretesa, e una nota fornisce il motivo, come ad esempio "US Core richiede un tipo di incontro e questo Incontro non ne ha nessuno". I controlli sono trascritti da US Core 9.0.0, la versione che il processo di avanzamento delle norme 2026 di ONC approva per USCDI v6. Essi coprono Paziente, Incontro, l'osservazione e la relazione di laboratorio, Specimen, Operatore sanitario, Organizzazione, Località, Immunizzazione, DocumentReference, la diagnosi di incontro e AllergyIntolerance.

Ciò che il convertitore trasporta, per classe di dati USCDI v6:

USCDI v6DaCome
Dati demografici del pazientePIDNome, data di nascita, sesso, indirizzo, telefono e email, identificatori. Razza ed etnia (PID-10, PID-22) nelle estensioni di US Core quando codificate in CDC Razza ed Etnia. Lingua preferita (PID-15) come BCP 47
Informazioni sull'incontroPV1Incontro con tipo, classe, periodo, sede e partecipanti
Informazioni sulla strutturaPV1-3Sede, con la struttura come sua organizzazione di gestione
Problemi, data di insorgenzaDG1Condizione (diagnosi dell'incontro). DG1-5 è l'insorgenza, come mappato da HL7 v2 a FHIR
Allergie e intolleranze, reazioneAL1AlergiaIntolleranza con categoria, criticità e reazione
LaboratorioORUReferto diagnostico, Osservazioni, Campione (da SPM), Richiesta di servizio
OrdiniORM, OMLRichiesta di servizio
ImmunizzazioniVXUImmunizzazione
Note clinicheMDMRiferimento a documento
Membri del team di curaPV1, TXA, DG1Professionista

Non trasportati, poiché i messaggi v2 di questi tipi non li contengono o Perfuse non li mappa: Farmaci, Procedure, Obiettivi e Preferenze, Valutazioni dello stato di salute, Piano di cura, Storia sanitaria familiare, Dispositivi medici (UDI), Informazioni sull'assicurazione sanitaria, Segni vitali come profilo distinto e Provenienza.

8.4.4 R4 in entrambe le direzioni

Un server FHIR che dichiara R4 accetta R4. Ciò non era vero per gli Incontri fino a questa versione. Il server convertiva ciò che serviva in R4 ma leggeva ciò che riceveva come se fosse già nella sua forma interna, quindi un Incontro R4 veniva rifiutato con un 400. Lo stesso valeva per ogni bundle che la conversione ADT di Perfuse produceva, poiché ognuno trasporta Encounter.class, che R4 scrive come un singolo codice.

È stato scoperto la prima volta che qualcosa ha pubblicato un ADT convertito sul server R4 di Perfuse. Un test ora lo fa per ogni tipo di messaggio mappato e un altro controlla che tutto ciò che viene scritto come R4 venga letto indietro invariato.

8.4.5 Riepilogo internazionale del paziente

GET /fhir/Patient/{id}/$summary, or GET /fhir/Patient/$summary?identifier=system|value, returns an International Patient Summary (HL7 IPS 2.0.0): a FHIR document Bundle whose Composition lists the patient's active problems, allergies, medicines, immunizations, results, vital signs, procedures, devices, past illnesses, social history and care plans, each with a readable narrative. It is the short record a clinician who has never met the patient reads first, and the summary the European Health Data Space exchanges between countries from 2029.

È costruito da ciò che il negozio FHIR contiene e nulla viene inventato:

contiene il motivo codificato unavailable e indica che il server non dispone di informazioni, "il che non significa che non ce ne siano". Un elenco di allergie vuoto non deve mai essere interpretato come "nessuna allergia nota".

L'accesso segue $everything: un token limitato a un solo paziente ottiene un 403 per un altro, e un identificatore che corrisponde a due pazienti viene rifiutato piuttosto che indovinato. Viene costruito solo il profilo IPS; chiedere un altro profile viene rifiutato. Il documento che Perfuse produce dai suoi record di test valida contro il profilo IPS 2.0.0 Bundle con il validator HL7, senza errori. Un record costruito da feed reali può ancora fallire dove i codici del feed stesso falliscono (ad esempio, un nome visualizzato che il sistema di codici non utilizza), perché il riepilogo passa i dati come sono stati ricevuti.

Scambio → Collegamenti sanitari → Condividi riempie il contenuto con un riepilogo del paziente: digita l'ID FHIR del paziente e scegli Usa il suo riepilogo del paziente, quindi leggilo e crea il collegamento. La sua costruzione viene registrata come fhir.summary.

8.4.6 Riepiloghi di trasferimento per la cura post-acuta (PACIO)

When a patient leaves hospital for a nursing home, a rehabilitation unit or home health, the hospital's EHR sends a C-CDA: a transfer summary, a discharge summary or a CCD. Perfuse turns that document into the transfer summary PACIO's Transitions of Care guide describes (hl7.fhir.us.pacio-toc 1.0.0): one FHIR R4 document Bundle, US Core 8.0.1 inside, that the receiving facility's system can file without anyone reading XML.

Tre modi per crearne uno:

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

Verificato con il validator ufficiale FHIR contro il profilo Bundle TOC 1.0.0, sugli esempi C-CDA di HL7 (un sommario di trasferimento, un sommario di dimissione e un CCD). L'unico errore che segnala è nella guida: ogni segno vitale corrisponde sia alla sua voce simple-observation che alla sua voce vital-signs nel Bundle, quindi non può essere evitato da nessun mittente. Non ancora completato: la trasformazione delle voci delle sezioni di solo testo (stato funzionale, stato mentale, piano di assistenza, dispositivi) in risorse codificate e il DocumentReference della guida TOC che indice un sommario di trasferimento archiviato.

8.4.7 Abbonamenti

Con -fhir-subscriptions, l'endpoint FHIR invia notifiche quando viene creato o modificato un Incontro o un Appuntamento. Segue le linee guida FHIR Subscriptions R5 Backport IG per R4, che è ciò che il CMS Interoperability Framework criterion 15 e la roadmap FHIR di TEFCA utilizzano per le notifiche di appuntamento e incontro.

Un client crea una Subscription che nomina un argomento e, facoltativamente, un filtro come Encounter?patient=Patient/123. Gli argomenti sono elencati nella dichiarazione di capacità:

ArgomentoSi attiva inFiltri
https://perfuse.health/fhir/SubscriptionTopic/encounterIncontro creato o aggiornatopatient, status, class
https://perfuse.health/fhir/SubscriptionTopic/appointmentAppuntamento creato o aggiornatopatient, status

Un filtro che nomina qualsiasi altra cosa viene rifiutato, non ignorato. Un filtro ignorato è una sottoscrizione che notifica su ogni paziente quando il client ha chiesto informazioni su uno solo.

Le proprietà attorno alle quali è costruita l'implementazione:

Ciò che un client può far fare al server è limitato di proposito:

È disattivato a meno che non venga richiesto, perché una volta attivato, un client FHIR può far inviare a questo server i dati dei pazienti a un URL scelto dal client. Richiede un endpoint R4 che accetti scritture e si rifiuta di avviarsi altrimenti.

Non implementato, quindi nessuno deve scoprirlo provando:

La vista Sottoscrizioni mostra l'argomento di ogni sottoscrizione, il filtro e l'endpoint, quanti eventi ha avuto, quanti sono stati accettati e quanti sono in attesa, e l'ultimo motivo per cui uno è stato rifiutato. I valori dell'intestazione e la stringa di query dell'endpoint vengono trattenuti, poiché è lì che vivono le credenziali del sottoscrittore.

8.5 Standard di telecomunicazione NCPDP

Richieste di rimborso farmaceutico. Intestazione a larghezza fissa seguita da segmenti variabili.

Due dettagli che contano, entrambi facili da sbagliare e produrre risultati plausibili:

L'intestazione è esattamente di 56 byte e ha una larghezza fissa. Un'intestazione breve non può essere rilevata solo dalla lunghezza, perché un'intestazione troncata più i segmenti successivi supera comunque i 56 byte. La rilevazione avviene nel fatto che un'intestazione corretta non contiene mai un byte separatore, quindi l'intestazione viene scansionata per uno e un messaggio che ne contiene uno viene rifiutato con il numero di byte che mancano.

0x1E e 0x1C sono marker di inizio di gruppo e campo, non separatori. Trattarli come separatori sposta ogni campo di un posto a sinistra e la maggior parte dei valori risultanti rimane plausibile — una quantità si trova dove ci si aspettava una fornitura giornaliera e entrambi sono numeri.

I canali NCPDP e SCRIPT sono esclusi dal framing MLLP e ciò è imposto piuttosto che consigliato. Una richiesta legittima contiene 0x1C, che è il byte di fine blocco di MLLP, quindi inquadrare una richiesta la troncherebbe al primo marcatore di campo.

8.6 NCPDP SCRIPT

Ricette elettroniche, in XML. Il pacchetto interno si chiama eprescribe perché script era già stato preso dal motore JavaScript.

La principale preoccupazione di sicurezza è il flag di sostituzione e si legge al contrario dell'intuizione: sul filo, 0 significa che la sostituzione è consentita e 1 significa che la dispensazione deve essere eseguita come scritta.

Un flag di sostituzione assente viene rifiutato piuttosto che utilizzato come valore predefinito. Entrambi i valori predefiniti possibili raggiungono il paziente — uno potrebbe dispensare un generico dove il prescrittore richiedeva il marchio, l'altro potrebbe impedire una sostituzione che il prescrittore ha permesso — quindi non c'è un'ipotesi sicura e il messaggio si ferma.

Una prescrizione di classe II con confezioni è rifiutata e il costruttore non ne produrrà una.

I rifiuti e gli avvertimenti vengono mantenuti come elenchi separati piuttosto che come un elenco unico con tag di gravità, perché un lettore che deve controllare un campo di gravità per sapere se il messaggio è stato inviato alla fine non controllerà.

L'autorizzazione preventiva elettronica (PAInitiationRequest, PARequest, PAAppealRequest, PACancelRequest) e il beneficio della prescrizione in tempo reale vengono risposti dal lato del pagatore a /ncpdp/script e /ncpdp/rtpb, dal formulario del farmaco; vedere CMS-0057.

8.7 DICOM

Immagini. Perfuse può ricevere oggetti DICOM, richiedere un archivio remoto e memorizzarli in uno, tramite i servizi di rete DICOM classici o tramite DICOMweb, e può mantenere un archivio proprio per i visualizzatori.

DICOM non è un formato di messaggio nello stesso senso degli altri — gli oggetti sono grandi e la stretta di mano dell'associazione è più importante dell'analisi del payload. I titoli called_ae e calling_ae sono la ragione più comune per cui una prima connessione fallisce e il fallimento sembra un problema di rete piuttosto che di configurazione.

8.7.1 Ciò che un ascoltatore C-STORE accetta

Lasciato aperto, un ascoltatore DICOM accetta qualsiasi cosa da chiunque possa raggiungere la porta. Quattro impostazioni sotto Ciò che questo ascoltatore accetta restringono questo, e la prima è quella che vale la pena capire.

Accetta solo questi titoli AE chiamanti è la restrizione. Il titolo AE *chiamato* — quello accanto all'indirizzo — è il nome che un mittente compone, quindi identifica questo ascoltatore piuttosto che il mittente, e non è una restrizione. Chiunque possa raggiungere la porta può utilizzare il titolo AE chiamato corretto, perché è pubblicato per loro. Senza un elenco di chiamanti consentiti, qualsiasi host nella rete può spingere immagini in un canale clinico.

Accetta solo queste classi SOP e accetta solo queste sintassi di trasferimento accettano UID separati da virgole. Vuoto accetta ogni tipo di oggetto e negozia qualsiasi compressione offerta dal mittente, che include tipi che le destinazioni di questo canale non possono gestire. Rifiutare all'associazione è più chiaro per il mittente che accettare l'oggetto e fallire in seguito.

Oggetto più grande accettato è in byte e zero significa nessun limite. Le immagini a tutto schermo e le serie lunghe possono raggiungere i gigabyte, quindi il limite è altrimenti la memoria.

8.7.2 DICOMweb

DICOMweb è DICOM su HTTP: le ricerche QIDO-RS, WADO-RS e WADO-URI recuperano, STOW-RS archivia. I visualizzatori del browser come OHIF supportano solo DICOMweb, così come i servizi di imaging cloud (Google Cloud Healthcare, Azure Health Data Services, AWS HealthImaging). Perfuse lo utilizza in tre punti.

L'archivio di imaging. Avvia il server con -dicomweb-archive DIR (Impostazioni › Dati › Archivio di imaging) e mantiene oggetti nella cartella specificata, indicizzati in SQLite, e li serve a /dicomweb sull'indirizzo della console stessa: QIDO-RS ai livelli di studio, serie e istanza, WADO-RS per oggetti, metadati, frame e dati bulk, WADO-URI a /dicomweb/wado, e STOW-RS. La lettura richiede il ruolo di visualizzatore e l'archiviazione il ruolo di operatore, con una sessione o un token API; ogni lettura e archiviazione è registrata in Attività come dicomweb.read o dicomweb.store. Un account limitato a un tenant o a gruppi di canali viene rifiutato, poiché l'archivio appartiene all'intero server. Gli oggetti vengono mantenuti esattamente come ricevuti, quindi ciò che un visualizzatore recupera è byte per byte esattamente ciò che è stato archiviato. I frame vengono restituiti nella sintassi di trasferimento in cui sono stati archiviati; una richiesta che richiederebbe una trascodifica risponde con 406 anziché un'immagine convertita.

Una ricerca su un attributo che l'archivio non indicizza risponde con 400 anziché ignorare la condizione e restituire più studi di quanti richiesti. Indicizzati: nome del paziente (con caratteri jolly e corrispondenza fuzzy con fuzzymatching=true), ID del paziente, data di nascita, sesso, data e ora di studio (intervalli), numero di accesso, ID di studio, descrizione, medico di riferimento, studio, serie e istanza SOP UIDs (elenco), modalità, parte del corpo, numero e descrizione della serie, classe SOP, numero di istanza, righe, colonne e numero di frame.

La sorgente. type: dicomweb ascolta STOW-RS, a /dicom-web/studies per default (il percorso utilizzato da Orthanc e dcm4chee), e invia ogni oggetto attraverso il canale come messaggio DICOM. Il canale necessita di dataType: dicom. Imposta un token bearer o un nome utente e una password: senza uno di questi, chiunque possa raggiungere la porta può inviare immagini nel canale. La risposta elencare ogni oggetto come archiviato o fallito, con il motivo di fallimento DICOM, in modo che il mittente sappia quali inviare nuovamente.

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}

La destinazione si trova in delivery, sotto gli archivi DICOMweb.

Puntare OHIF all'archivio

Utilizza una sorgente di dati DICOMweb con qidoRoot e wadoRoot impostati sull'indirizzo dell'archivio (lo schermo Imaging lo mostra, con l'intero blocco di dati da copiare), wadoUriRoot su quell'indirizzo seguito da /wado, imageRendering e thumbnailRendering su wadors, e supportsFuzzyMatching su true. Un visualizzatore su un'altra origine necessita di quell'origine in -dicomweb-cors (Origin consentite a chiamarlo), e le sue richieste necessitano di un token API nell'intestazione Authorization, poiché un browser su un'altra origine non invia il cookie di sessione della console. La fornitura di OHIF dalla stessa origine attraverso un reverse proxy evita entrambi.

Testato contro Orthanc con il suo plugin DICOMweb, in entrambe le direzioni: la destinazione archivia in Orthanc, e il client DICOMweb di Orthanc cerca l'archivio di Perfuse e recupera uno studio byte-identico a quello archiviato. OHIF 3 elenca gli studi dell'archivio e visualizza i loro frame con le impostazioni sopra. OHIF e diversi altri client inviare type= non virgolettato nelle intestazioni Accept e Content-Type, il che RFC 2045 non consente; Perfuse lo accetta.

8.8 Condivisione di documenti IHE: XDS.b, XCA, XDR, MHD, PIXm e PDQm

Documenti clinici condivisi tra organizzazioni come fanno gli scambi di informazioni sanitarie, Carequality ed eHealth Exchange: un repository li conserva, un registro indice i loro metadati e una comunità risponde alle query di altre comunità attraverso un gateway. Avvia il server con -xds REPOSITORY-OID (Impostazioni › Dati › Condivisione di documenti) e sarà tutti e tre, nel database di questo servidor, agli indirizzi seguenti, ognuno dei quali accetta un token API come token bearer (il ruolo viewer per interrogare e recuperare, il ruolo operator per inviare; la maggior parte dei domini di affinità aggiunge TLS reciproco davanti)

IndirizzoAttoreTransazioni
/xds/repositoryDocument RepositoryITI-41 Fornire e registrare il set di documenti-b, ITI-43 Recuperare il set di documenti
/xds/registryDocument RegistryITI-18 Query di archiviazione del registro (tutte le tredici query di archiviazione), ITI-42 Registrare il set di documenti-b
/xca/gatewayXCA Responding GatewayITI-38 Query tra gateway, ITI-39 Recuperare tra gateway, con -xds-home-community urn:oid:...
/mhdMHD Document Recipient and ResponderITI-65 Fornire il bundle di documenti, ITI-66 Trovare elenchi, ITI-67 Trovare riferimenti a documenti, ITI-68 Recuperare documento
/mhd/PatientPDQm Supplier and PIXm ManagerITI-78 Query sui dati demografici del paziente, ITI-83 Patient/$ihe-pix, dal negozio FHIR dei Pazienti
/pixv3PIX Manager (HL7 v3)ITI-44 Feed di identità del paziente HL7 V3, ITI-45 Query PIXV3, dall'indice del paziente (-mpi)
/pdqv3PDQ Supplier (HL7 v3)ITI-47 Query PDQV3, con continuazione e annullamento, dall'indice del paziente

Le transazioni SOAP sono SOAP 1.2 con WS-Addressing, e MTOM/XOP dove i documenti viaggiano (un documento in linea come base64 è accettato anche). Una transazione fallita risponde con una RegistryResponse che trasporta i codici di errore IHE, non una fault SOAP: XDSDuplicateUniqueIdInRegistry, XDSNonIdenticalHash, XDSPatientIdDoesNotMatch, XDSMissingDocument, XDSRegistryMetadataError (con il campo mancante), XDSStoredQueryMissingParam, XDSUnknownStoredQuery, XDSUnknownRepositoryId, XDSUnknownCommunity, e UnresolvedReferenceException. Un sostituto (RPLC, XFRM_RPLC) deprecia il documento che sostituisce, che quindi risponde solo alle query che chiedono documenti deprecati; APND, XFRM e signs vengono mantenuti come associazioni. Hash e dimensione vengono calcolati dal repository e verificati contro ciò che la presentazione afferma. I documenti e i metadati su richiesta (ITI-57) non sono supportati, e una presentazione che li richiede viene rifiutata con il motivo.

MHD è lo stesso registro in FHIR: un documento fornito tramite MHD viene trovato da ITI-18 e tramite XCA, e uno fornito tramite XDS.b viene ritrovato da ITI-67. L'ID di un DocumentReference è l'UUID dell'elemento, il suo masterIdentifier è l'uniqueId, e l'URL dell'allegato è l'indirizzo ITI-68 del documento. I pazienti vengono risolti nell'identificatore del dominio di affinità dal negozio FHIR: il primo identificatore il cui sistema è urn:oid:, o il Paziente trasportato nel Bundle. PIXm risponde con ogni altro identificatore del Paziente con quello fornito (sourceIdentifier=system|value, ristretto da targetSystem), e 404 per uno che non conosce; PDQm cerca per identificatore, nome, data di nascita, genere, indirizzo e telecom.

Pubblicazione. Una destinazione xds di un canale pubblica ogni documento clinico che riceve, un documento CDA o uno trasportato in un messaggio HL7 v2, in qualsiasi repository XDS.b con ITI-41. I metadati vengono letti dal documento: il paziente (l'identificatore in patient_domain, l'autorità di assegnazione del dominio di affinità), titolo, tipo (come typeCode e, a meno che non sia impostato, classCode), creazione e tempi di servizio, autore, riservatezza, lingua e formato (corpo strutturato C-CDA 2.1 o 1.1, XDS-SD o mimeTypeSufficient, dai suoi modelli); e completato da ciò che un documento non dice: l'source_id del mittente, il facility_type e il practice_setting che ogni registro richiede. La risposta del registro decide la consegna: un fallimento o un errore in un PartialSuccess è una consegna fallita con i codici di errore del 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. Aggiungi direct_from (il tuo indirizzo Direct) e direct_to (quello dei destinatari) e lo stesso destinatario invia XDR come trasporto Direct, come descritto nel progetto Direct *XDR e XDM per Direct Messaging*: un blocco di indirizzamento Direct (urn:direct:addressing) nell'intestazione SOAP nomina il mittente e i destinatari e la intendedRecipient della presentazione nomina ogni destinatario (||^^Internet^address). Punta url all'endpoint XDR del destinatario o a un HISP che accetta XDR. XDR viaggia su TLS, di solito con un certificato client (tls), e non è S/MIME. Una sorgente direct accetta anche XDR (vedi Direct sotto).

    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 in HL7 versione 3. Con l'indice dei pazienti attivato (-mpi), /pixv3 è un gestore PIX e /pdqv3 un fornitore PDQ tramite SOAP 1.2, per gli ospedali e gli scambi che ancora utilizzano i profili v3 di IHE. Una sorgente alimenta i pazienti con ITI-44 (record aggiunto PRPA_IN201301UV02, rivisto PRPA_IN201302UV02, duplicati risolti PRPA_IN201304UV02): il primo identificatore del paziente è il suo record, gli altri e quelli in asOtherIDs sono identificatori che porta, e una fusione incorpora l'identificatore del record precedente in quello sopravvissuto, come fa un A40 di HL7 v2. ITI-45 (PRPA_IN201309UV02) risponde con gli altri identificatori della persona che detiene uno, limitati da dataSource, in Patient.id; l'identificatore richiesto torna indietro solo nella query ripetuta. ITI-47 (PRPA_IN201305UV02) abbina le informazioni demografiche (nome, genere, data di nascita, identificatore, indirizzo, telecom) con il matcher dell'indice, minimumDegreeMatch come punteggio su 100, otherIDsScopingOrganization limita i domini e initialQuantity impagina la risposta: il resto arriva con QUQI_IN000003UV01 per dieci minuti, o viene eliminato dal suo annullamento. Le risposte seguono i casi delle transazioni: un paziente o dominio sconosciuto è AE con errore 204 e la posizione del parametro, un paziente noto con nulla nei domini richiesti è NF. v3 nomina un'autorità solo con OID, quindi un identificatore il cui sistema è un URL senza OID (alcuni numeri nazionali) è lasciato fuori dalle risposte v3 ed è fornito tramite FHIR; impostare il sistema dell'identificatore aziendale su un OID (urn:oid:..., nelle impostazioni dell'indice) per l'EUID e il custode da visualizzare. Il ruolo del visualizzatore richiede e il ruolo dell'operatore alimenta; ogni transazione è registrata con un identificatore, mai un nome. Un messaggio v3 nudo inviato come application/xml è risposto allo stesso modo, il che è utile per i test manuali.

Scambio › Condivisione di documenti mostra cosa contiene il registro e dove può essere raggiunto, trova i documenti di un paziente in questo registro o in un altro (il registro ITI-18 o il gateway ITI-38), scarica uno, e pubblica un documento CDA manualmente con i metadati che una destinazione gli fornirebbe.

Verificato contro il NIST XDS Toolkit 7.13.0, l'implementazione di riferimento IHE: Perfuse's ITI-41, ITI-18 e ITI-43 contro il suo simulatore di Registro/Repository (accettato senza errori di convalida, il documento recuperato byte-identico), e il suo simulatore di Initiating Gateway che interroga e recupera da Perfuse's Responding Gateway su XCA, senza errori nel suo log. Ogni messaggio SOAP che Perfuse scrive convalida contro gli schemi ebXML Registry 3.0 e XDS.b, e il DocumentReference e SubmissionSet MHD contro IHE MHD 4.2.2 con il convalidatore HL7 FHIR. XDR da una destinazione xds con un blocco di indirizzamento Direct è stato accettato dal simulatore di Document Recipient dello strumento, la cui convalida dei metadati ha trovato il difetto descritto in docs/verification.md, e dal convalidatore XDR di ONC SITE, la checklist Direct XDR del test di certificazione (h)(2) applicato. Le risposte PIX e PDQ v3 convalidano contro gli schemi HL7 V3 IHE (NE2008 multicacheschemas) e i messaggi di esempio IHE (l'alimentazione ITI-44, unione, query ITI-45, query ITI-47, continuazione e annullamento) vengono risposti come mostrano le loro risposte pubblicate. Non ancora verificato contro un'implementazione PIX o PDQ v3 indipendente, Gazelle o un Connectathon.

8.9 Messaggistica sicura diretta

Direct è il modo in cui i fornitori di assistenza sanitaria statunitensi si inviano reciprocamente richieste di consulto, riassunti e risultati tramite posta elettronica sicura: ogni messaggio è firmato con il certificato del mittente e crittografato per il certificato del destinatario (S/MIME), e viaggia tra i fornitori di servizi di informazione sanitaria (HISP) che rilasciano gli indirizzi e garantiscono per essi. Perfuse è il sistema di bordo accanto al tuo HISP, non un HISP: il HISP rilascia il tuo indirizzo, il suo certificato e la sua chiave, e tu mantieni il suo bundle di trust (come DirectTrust). Segue la Dichiarazione di applicabilità Direct per il trasporto sanitario sicuro 1.2, la Guida all'implementazione per la notifica di consegna, IHE XDM (ITI TF-1 Allegato 15) per i documenti con metadati, la Guida all'implementazione della scoperta dei certificati per il progetto Direct (DNS e LDAP), e XDR e XDM per la messaggistica 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

Ricezione. Una sorgente direct è il server SMTP a cui il HISP consegna la posta dell'indirizzo del mittente. Accetta la posta solo per quell'indirizzo (qualsiasi altra cosa è rifiutata al RCPT), richiede STARTTLS quando viene fornito un certificato, e apre ogni messaggio prima che qualcosa lo legga: lo decrittografa con la chiave del mittente, verifica la firma contro gli anchor del mittente, e controlla che il certificato di firma sia per l'indirizzo del mittente o il suo dominio. Un messaggio che non è crittografato S/MIME, è firmato da un mittente che non si fida, o è firmato da un certificato per qualcun altro è rifiutato al DATA con il motivo, quindi il HISP lo mantiene e lo segnala al mittente; Perfuse non accetta mai ciò che poi rifiuta. Un pacchetto XDM diventa un messaggio (verificato contro gli hash nei suoi metadati); altrimenti ogni allegato diventa un messaggio, o il testo quando non ce ne sono. Con smtp_host impostato, ogni messaggio preso in carico è risposto con una notifica "elaborato" firmata e crittografata (MDN), e le notifiche in arrivo per ciò che è stato inviato sono registrate.

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

Dalla casella di posta del HISP. Un HISP che conserva la posta invece di consegnarla dà all'indirizzo una casella di posta IMAP: imap la legge (TLS o STARTTLS, ogni poll una sessione fresca), apre ogni messaggio come sopra, sposta ciò che è stato preso in move_to (o lo elimina) e ciò che non poteva essere aperto in error_folder, quindi nulla viene letto due volte. listen può quindi essere omesso. Un HISP il cui server di posta ha un certificato privato è considerato attendibile con tls.ca_file (il suo certificato, o quello della sua autorità) e tls.server_name; la verifica non può essere disattivata.

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

XDR. xdr accetta XDR su /xdr sul proprio indirizzo HTTPS, come un HISP invia Direct convertito in SOAP o un partner invia punto a punto: una richiesta ITI-41 Provide and Register il cui documento diventa un messaggio. Una presentazione il cui blocco di indirizzamento Direct nomina un altro indirizzo viene rifiutata e uno che il canale non accetta viene risposto con una risposta di Registro con un messaggio di fallimento che spiega il motivo. client_ca_file richiede un certificato client da quelle autorità. XDR è protetto da TLS, non da S/MIME, quindi una sorgente che accetta solo XDR necessita dell'indirizzo ma non del certificato, della chiave o degli anchor. Ogni documento diventa un messaggio del tipo di dati dataType del canale: i documenti CDA necessitano di raw (passati come sono) o hl7v3, poiché il valore predefinito, hl7, si aspetta HL7 v2 e li rifiuta.

    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 elenca gli indirizzi Direct che i canali inviano e ricevono, con i loro certificati, scadenze e anchor; mantiene il registro degli indirizzi dei corrispondenti (nome, organizzazione, note e certificato, incollato dal loro HISP o trovato in DNS o LDAP e rifiutato se non è per quell'indirizzo o dominio); e cerca i certificati di un indirizzo in DNS o LDAP senza salvarli. Il registro è la directory direct-certs accanto al database, un file PEM per ogni indirizzo o dominio, che una destinazione legge a meno che non specifichi la propria directory recipient_certs_dir.

Verificato contro OpenSSL 4.0 con cms e smime in entrambe le direzioni: ciò che Perfuse firma e crittografa OpenSSL verifica e decrittografa (trasporto di chiavi PKCS#1 v1.5 e OAEP), e Perfuse apre ciò che OpenSSL firma e crittografa (AES-128 e AES-256). Un messaggio creato con openssl smime e consegnato tramite SMTP viene ricevuto, aperto e archiviato da un canale, e uno inviato da Perfuse a un altro attraverso un sostituto HISP, che risponde con un MDN che il mittente apre. I certificati sono trovati in OpenLDAP 2.4 (associati a indirizzi e domini, scritti dal comando ldapadd di OpenLDAP); un messaggio Direct viene letto da una casella di posta IMAP GreenMail e aperto, e uno che non è Direct viene spostato nella cartella degli errori; XDR da una destinazione xds viene preso da una sorgente direct e rifiutato quando indirizzato a qualcun altro, e accettato dal toolkit di documenti NIST XDS e dal validator XDR del sito ONC; lo strumento di test Edge XDR Direct del sito ONC ha inviato sia il messaggio di metadati minimo che quello completo a una sorgente direct, che li ha accettati. Contro lo strumento di scoperta dei certificati Direct di ONC, una destinazione Direct sceglie il certificato giusto, o nessuno, in tutti e 18 dei casi di scoperta (D1 a D18: certificati scaduti, revocati e rilasciati AIA, priorità e peso SRV, directory non raggiungibile). Una sorgente Direct legge un messaggio dalla HISP del sito ONC (Apache James) tramite IMAP con STARTTLS. Non ancora testato: scambio SMTP con la HISP del sito ONC (AWS tiene la posta in uscita sulla porta 25 per i nuovi account) o con una HISP accreditata.

8.10 SQL su viste FHIR

Una ViewDefinition (HL7 SQL su FHIR v2) trasforma ogni risorsa FHIR di un tipo in righe di colonne nominate, ogni colonna un'espressione FHIRPath, in modo che i dati FHIR possano essere letti come tabelle da DuckDB, Athena, Spark, un data warehouse o un foglio di calcolo. Perfuse esegue queste operazioni con il suo own motore FHIRPath: column, select annidati, forEach, forEachOrNull, repeat e unionAll, where, constant (ogni tipo di valore[x]), colonne collection, %rowIndex, e le chiavi di join 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" }
  ]}]
}

Monitor › SQL on FHIR esegue una vista su questo server FHIR (un paziente, o tutti) o su risorse incollate (NDJSON da un'esportazione bulk, un Bundle, un array JSON), mostra le righe e le scarica come CSV, NDJSON o Parquet. Inizia con cinque viste di esempio (dati demografici del paziente, osservazioni con un valore, pressione sanguigna, condizioni, incontri) e salva le viste nella directory views accanto al database, un file JSON per ogni vista.

The FHIR endpoint answers the specification's $sql-run at the system level, by GET or POST, for a ViewDefinition subject given inline (subjectResource), by subjectReference (ViewDefinition/<name>, a saved view) or by subjectCanonical (a saved view's url), with _format (csv, ndjson (the default), json or parquet), header, patient, _since, _limit, and resource to run over resources sent with the request instead of the store. It is a read: a SMART token needs read scope for the view's resource type, a token bound to one patient gets that patient's rows only, and granular scopes narrow the resources read, as they do a search. More than a million rows needs _limit, patient or _since.

perfuse sof -view v.json [-format csv|ndjson|json|parquet] [-o out] files... esegue una vista su file FHIR senza un server: I file NDJSON di un'esportazione bulk, Bundles o array.

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"

I file Parquet hanno un gruppo di righe e pagine PLAIN non compressi; i booleani sono BOOLEAN, i tipi interi INT64, i decimali DOUBLE e tutto il resto stringhe UTF-8 (una colonna di raccolta come il suo JSON).

Verificato con la suite di test ufficiale SQL on FHIR (i 144 test del repository sql-on-fhir.js tests/, eseguiti su ogni build: tutti superati), e l'output Parquet letto nuovamente da DuckDB 1.5.6 con i tipi e i valori corretti. Non supportati: SQLQuery e SQLView Libraries (SQL sulle tabelle delle viste), $sql-export, _format=fhir e i parametri source e group; ogni uno viene rifiutato con il motivo.

8.11 Misure di qualità digitali

Una misura di qualità digitale conta i pazienti in ogni popolazione di una misura FHIR Measure su un periodo di misurazione (popolazione iniziale, denominatore, esclusioni e eccezioni del denominatore, numeratore, esclusioni del numeratore) e valuta il risultato. La risposta è un rapporto di misura FHIR MeasureReport, modellato come richiesto dalla guida Da Vinci Data Exchange per le misure di qualità (DEQM). È qui che si stanno dirigendo i programmi eCQM di CMS e le misure digitali HEDIS di NCQA.

In Perfuse i criteri di popolazione sono FHIRPath ("language": "text/fhirpath"), eseguiti dallo stesso motore di SQL on FHIR. Ogni criterio viene valutato una volta per paziente. Il suo focus è un Bundle del record del paziente (la compartment del Paziente), e ha queste variabili: %subject (il Paziente), %periodStart e %periodEnd (il periodo, come dateTimes) e %"Measurement Period". Un criterio restituisce true o false; un singolo valore esistente conta come true.

{
  "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()"
  }
}

Le popolazioni si annidano come specifica la specifica della misura. Un paziente è nel denominatore solo se è nella popolazione iniziale. Un'esclusione del denominatore rimuove il paziente prima che venga valutato il numeratore. Un'eccezione del denominatore conta solo per un paziente non nel numeratore. Il punteggio di una proporzione è (numeratore - esclusioni del numeratore) / (denominatore - esclusioni - eccezioni); il punteggio di un rapporto è numeratore / denominatore; un cohort ha conteggi e non ha punteggio. Gli stratificatori a singolo criterio dividono ogni popolazione in base al loro valore (sesso, ad esempio).

Perfuse non ha un motore CQL. Le misure eCQM di CMS e le misure digitali HEDIS pubblicate sono scritte in CQL, quindi non possono essere eseguite così come sono. Una misura il cui criterio è CQL viene rifiutata con quel motivo. Scrivere la logica come FHIRPath invece. Il punteggio di variabili continue, gli stratificatori multicomponente e i soggetti Gruppo o Operatore vengono rifiutati nello stesso modo.

Monitor → Misure di qualità valuta una misura su questo server FHIR o su risorse incollate, per un periodo. Offre tre rapporti: un riassunto, un riassunto con i pazienti in ogni popolazione o uno per paziente. Lo schermo mostra le popolazioni, il punteggio e gli strati e scarica il MeasureReport. Inizia da tre esempi: pressione sanguigna sotto controllo, diabete con un test HbA1c e pazienti visti nel periodo. Sono illustrativi, scritti per questo manuale e non sono misure eCQM di CMS o HEDIS. Salva nel negozio FHIR controlla la misura e la memorizza come risorsa Measure.

L'endpoint FHIR risponde a Measure/[id]/$evaluate-measure e Measure/$evaluate-measure?measure=<url>, tramite GET o POST di una risorsa Parameters. Parametri:

Il report viene restituito, non memorizzato. L'operazione è una lettura, quindi un token SMART necessita di accesso in lettura a Measure e a Patient. Un token legato a un paziente ottiene un report individuale su quel paziente e nessun altro.

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... valuta una misura su file FHIR (un'esportazione bulk in NDJSON, Bundles, array) senza un server. -measure example:example-bp-control esegue un esempio predefinito, e -examples li elenca.

Verificato. Il validatore HL7 FHIR controlla le misure fornite contro FHIR R4, senza errori. Controlla un riassunto, un individuale e un MeasureReport di elenco di soggetti contro i profili riassuntivi, individuali e di elenco di soggetti DEQM 5.0.0, anch'essi senza errori. Non verificato: equivalenza con qualsiasi eCQM pubblicato, poiché nessuno può essere eseguito qui senza CQL.

8.12 L'indice dei pazienti (MPI)

Un indice dei pazienti master collega i record che ogni sistema mantiene per una persona (il MRN dell'ospedale, quello della clinica, quello del laboratorio) in un unico identificatore aziendale, l'EUID. È disattivato fino a quando qualcuno decide di mantenerlo, poiché è una tabella dei nomi dei pazienti, delle date di nascita e degli identificatori: attiva Impostazioni → Dati → Indice dei pazienti (o serve -mpi) e riavvia. Vive in mpi.db accanto al database principale.

Alimentarlo. Aggiungi una destinazione di tipo mpi (L'indice dei pazienti nel costruttore) ai canali che trasportano le registrazioni. Legge il PID di ogni messaggio HL7 v2 o un paziente FHIR su un canale grezzo. L'identificatore del record è la ripetizione PID-3 di tipo MR (id_type lo modifica); gli altri, e PID-19, diventano i suoi altri identificatori. Un'autorità di assegnazione con un identificatore universale (PID-3.4.2 con tipo ISO) diventa urn:oid:...; uno con solo uno spazio dei nomi viene mappato da authorities, o diventa urn:perfuse:aa:<namespace>. Un A40, A34, A18 o A39 unisce la persona che detiene l'identificatore MRG-1 con la persona che detiene PID-3 (no_merge li ignora).

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

Abbinamento. Un nuovo record è collegato in questo ordine:

  1. Identificatori attendibili. Un record che condivide un identificatore da un sistema elencato come attendibile (un identificatore nazionale, un numero aziendale) è la stessa persona, senza punteggi. Non elencare mai un sistema condiviso da una famiglia, come un numero di abbonato di un'assicurazione.
  2. Punteggio. Altrimenti, le persone le cui registrazioni potrebbero corrispondere vengono trovate tramite blocco (lo stesso cognome e anno di nascita, la stessa data di nascita o lo stesso numero di telefono) e valutate con pesi Fellegi-Sunter su nome e cognome (Jaro-Winkler e Soundex, accenti e punteggiature ignorati, nomi scambiati notati), data di nascita (un giorno e un mese scambiati sono parzialmente concordi), sesso, codice postale, telefono e indirizzo. Solo i campi presenti in entrambi i record vengono conteggiati. Il punteggio è la prova trovata come percentuale della prova possibile. Il blocco utilizza cinque chiavi, quindi un errore non nasconde una persona: suono del cognome e anno di nascita, data di nascita, telefono, suono dei nomi (in qualsiasi ordine) e codice postale con il suono del nome.
  3. Decisione. Per impostazione predefinita, nulla viene collegato in base al punteggio solo. Un record con un punteggio pari o superiore alla soglia di revisione (60%) diventa una nuova persona e la possibile corrispondenza attende nella coda di revisione; quelli con un punteggio pari o superiore alla soglia automatica (90%) con cognome e data di nascita entrambi concordi vengono contrassegnati come *certi*. Collegare due persone in una (un sovrapposizione) mette i risultati di un paziente nel grafico di un altro, quindi il collegamento automatico è un interruttore che un amministratore attiva (Collega le corrispondenze certe senza chiedere a nessuno) una volta che la coda ha mostrato che le corrispondenze certe sono corrette. Con esso attivato, una corrispondenza certa si collega quando non c'è una seconda persona con un punteggio altrettanto alto. Al di sotto della soglia di revisione, il record è una nuova persona.

Numeri nazionali. Il numero NHS (e il CHI della Scozia e il numero sanitario e assistenziale dell'Irlanda del Nord), il PPSN e l'IHI dell'Irlanda, il KVNR della Germania, il SVNR dell'Austria, il numero AHV della Svizzera, il BSN dei Paesi Bassi, il numero di registro nazionale del Belgio, il matricule del Lussemburgo, l'INS (NIR e NIA) della Francia, il codice fiscale dell'Italia, il DNI/NIE e il CIP-SNS della Spagna, il numero SNS del Portogallo, i numeri personali nordici (Svezia, Danimarca, Norvegia con il numero D, Finlandia, Islanda), i codici baltici, il PESEL della Polonia, i numeri di nascita ceca e slovacca e i numeri ungheresi, rumeni, bulgari, croati, sloveni e greci sono noti all'indice. Ognuno viene memorizzato in un solo modo: sotto il sistema del proprio schema, spazi e punti rimossi, quindi il numero NHS inviato come urn:oid:2.16.840.1.113883.2.1.4.1|999 000 0018 da un sistema e come https://fhir.nhs.uk/Id/nhs-number|9990000018 da un altro è un solo identificatore. Una ripetizione PID-3 HL7 v2 il cui tipo di identificatore è NN e un codice di tre lettere di un paese (NNDEU, NNNLD) viene letto come il numero principale di quel paese, e il tipo NH dall'autorità NHS come il numero NHS. Il cifra di controllo di ogni numero viene verificato: uno che fallisce viene mantenuto nel proprio record, segnalato (mascherato) nella risposta e mai utilizzato per collegare o trovare qualcuno, poiché un errore di battitura di un solo cifra di solito crea il numero di un'altra persona. Il CPR della Danimarca viene verificato solo per la data, poiché i numeri emessi dal 2007 non devono superare l'antico modulo 11.

Le impostazioni elencano ogni schema con il proprio formato, il proprio controllo e il sistema in cui viene memorizzato. I sistemi presi dalla guida FHIR del paese (UK Core, fhir.de, Nictiz, CH Core, ANS, HL7 Italia, MedCom, i registri OID svedesi, norvegesi e finlandesi) sono contrassegnati come tali; gli altri sono impostazioni predefinite che possono essere modificate nel valore nazionale, che un sito può fare per schema (il vecchio viene ancora riconosciuto). L'attendibilità di uno schema è un solo segno di spunta. I numeri nazionali vengono mostrati per intero agli editor e agli amministratori per impostazione predefinita e mascherati (gli ultimi caratteri) a tutti gli altri; Chi vede i numeri per intero cambia questo, fino ai visualizzatori o fino agli amministratori soltanto. Dove la legge di un paese limita l'uso di un numero (Référentiel INS della Francia, PPSN dell'Irlanda, numero di registro nazionale del Belgio, §290 SGB V della Germania), le impostazioni lo dicono. GET /api/mpi/schemes elenca gli schemi e POST /api/mpi/check verifica un numero senza memorizzarlo. FHIR $match e PIXm rispondono ai client autorizzati con numeri per intero.

Una data scritta giorno- o mese-prima (08/15/1972) viene mantenuta come scritta e non corrisponde a una scritta anno-prima: gli ordini degli Stati Uniti e dell'Europa non concordano, e supporre sarebbe collegare le persone sbagliate.

La schermata dell'indice dei pazienti (Build) mostra i conteggi, trova le persone per nome, numero, EUID o data di nascita e apre ogni persona: i propri record, ogni identificatore e la storia di ciò che è accaduto loro e chi l'ha fatto. Gli editor decidono le revisioni (La stessa persona le collega; Persone diverse le mantiene separate per sempre), spostano un record in un'altra persona, rimuovono un record (Non questa persona) e fondono due persone. Gli amministratori impostano le soglie, i sistemi di identificatori attendibili, i numeri nazionali e il sistema EUID. Ogni ricerca e ogni persona letta vengono scritte nel registro di controllo.

Rispondere agli altri. POST /fhir/Patient/$match (l'operazione FHIR, come IHE PDQm utilizza ITI-119) accetta un Paziente e restituisce le persone che potrebbero essere, meglio in primo luogo, ogni Paziente il cui ID è l'EUID, con ogni identificatore, search.score e l'estensione del grado di corrispondenza (certain, probable, possible); onlyCertainMatches e count vengono onorati. PIXm (/mhd/Patient/$ihe-pix, ITI-83) risponde dall'indice: ogni identificatore di ogni record collegato alla persona e l'EUID. Lo fanno anche PIX e PDQ in HL7 v3 (/pixv3, /pdqv3; vedere la condivisione dei documenti IHE).

L'API è /api/mpi (riassunto e ricerca), /api/mpi/persons/{euid}, /api/mpi/find, /api/mpi/reviews, /api/mpi/records (registro, collegamento, scollegamento), /api/mpi/merge e /api/mpi/settings.

Pesi. I pesi predefiniti di Fellegi-Sunter provengono dalla letteratura sull'abbinamento dei record per i dati di registrazione ospedaliera. Stima dai nostri record (nelle impostazioni, amministratori; POST /api/mpi/estimate) li adatta all'indice del sito con la massimizzazione dell'attesa, senza richiedere coppie revisionate: m (accordo tra true match) dalle coppie che il blocco riunisce, u (accordo casuale) da 20.000 coppie estratte a caso, poiché le coppie bloccate concordano sui nomi e sulle date per costruzione. La stima è visualizzata accanto ai pesi in uso e non modifica nulla fino a quando non viene utilizzata e salvata. Un campo confrontato su troppo poche coppie mantiene il valore predefinito. L'adattamento presume che i campi siano indipendenti dato la classe, il che non è del tutto vero, quindi si deve trattare un grande cambiamento con sospetto.

Misurato. Sul set di dati FEBRL 3 (5.000 record sintetici di 2.000 persone, i duplicati con errori di digitazione, campi scambiati, valori mancanti e nomi abbreviati; PERFUSE_TEST_FEBRL), registrati in ordine di file con un revisore che risponde correttamente a ogni coppia in coda:

Collegati da soliInseriti davanti a un revisore con la persona giustaMancatiCollegamenti errati
Collegamento automatico disattivato (predefinito)02.649 di 3.0003510
Attivato, pesi predefiniti1.6371.0123510
Attivato, pesi stimati dai record1.6221.0703080

Nessun record è stato mai collegato alla persona sbagliata e nessuna delle 2.000 nuove persone è stata messa in coda inutilmente. Quelli mancanti differiscono quasi in ogni campo (una data di nascita e un indirizzo entrambi errati, ad esempio) e hanno un punteggio inferiore alla soglia di revisione. FEBRL è sintetico e ha pochi omonimi; un indice reale ne ha di più, quindi la sua coda di revisione sarà più lunga e questi numeri sono un limite inferiore per la cura, non una promessa.

8.13 Delimitato

CSV e i suoi parenti. Le opzioni sono sulla sorgente nel costruttore e la referenza del formato elenca le chiavi del file.

I percorsi indirizzano le colonne. Una colonna denominata è disponibile quando viene dichiarata una riga di intestazione o vengono forniti i nomi; altrimenti le colonne sono posizionali.

8.13.1 Denominazione delle colonne

Ci sono due modi e sono esclusivi. O la prima riga del file li denomina — la prima riga denomina le colonne — o li elenchi manualmente, in ordine. Dichiarare un'intestazione significa che la riga non viene trattata come dati.

Se nessuna delle due opzioni è impostata, le colonne possono essere indirizzate solo per posizione, quindi un filtro scritto contro un nome non ha nulla da confrontare. L'attivazione dell'intestazione rimuove l'elenco dei nomi invece di mantenerli entrambi: con un'intestazione i nomi provengono dal file, quindi un elenco lasciato indietro verrebbe ignorato e un canale che legge come se avesse scelto i nomi quando il file li ha scelti è più difficile da debuggare di uno che rifiuta.

8.13.2 Cosa vede un filtro o uno script

Un documento delimitato diventa molti messaggi, quindi questo deve essere dichiarato prima di scrivere entrambi.

Con la divisione attivata, tutto funziona per riga. I passaggi dichiarativi, il filtro e lo script di trasformazione vedono una riga, e un percorso significa *la colonna di questa* riga. Un filtro che rifiuta una riga rifiuta solo quella riga e il conteggio ricevuto è righe invece di documenti.

Con la divisione disattivata, il messaggio è l'intero documento e una scrittura che attraversa le righe viene rifiutata invece di essere applicata alla prima. Questo rifiuto è deliberato: scrivere silenziosamente sulla prima riga è il comportamento che produce un file che sembra trasformato e non lo è.

8.13.3 I tre che cambiano cosa conta come errore

Accetta righe con il numero di colonne errato è disattivato per impostazione predefinita. Una riga con troppe o troppe poche colonne è quindi un errore, il che è ciò che cattura un file il cui formato è cambiato senza preavviso. Attivarlo accetta la riga e lascia le colonne mancanti vuote.

Rimuovi gli spazi intorno a ogni valore risolve il caso comune di un valore riempito con una larghezza di colonna. Lascialo disattivato dove gli spazi finali sono significativi, il che a volte accade in un identificatore.

Mantieni le righe vuote come righe è disattivato per impostazione predefinita e di solito dovrebbe esserlo. Attivato, una riga vuota diventa una riga di colonne vuote, il che conta solo quando un conteggio deve corrispondere esattamente al file.

8.14 Grezzo

Nessun parsing. Il messaggio è byte.

Utilizza questo quando il contenuto non è qualcosa che Perfuse comprende e non ha bisogno di: un PDF spostato tra sistemi, un formato proprietario, un documento già formato inoltrato invariato.

Il costo è che nulla che dipende dalla struttura funziona — nessuna trasformazione a livello di campo, nessun filtro su un campo, nessun confronto a livello di campo nel controllo di parità. Un canale grezzo è una pipe e è onesto nel dire di esserlo.

8.15 Scegliere

Se il messaggio è HL7 v2, utilizza hl7, anche se si intende inoltrarlo invariato. L'analisi fornisce la traccia, le statistiche a livello di campo, la possibilità di filtrare in seguito e la possibilità di confrontare. raw su contenuti analizzabili non offre nulla e perde tutto ciò.

Utilizza raw quando l'analisi fallirebbe o sarebbe una menzogna sul contenuto.

*Kill the Clipboard* di CMS chiede ai fornitori di accettare i record di un paziente da un codice QR al momento del check-in e di restituire il record della visita allo stesso modo. Il codice QR contiene un SMART Health Link (shlink:/...): un indirizzo, una chiave a 256 bit e, opzionalmente, un'etichetta, una data di scadenza e una bandiera di passcode. Exchange → Health links legge uno.

Ricezione. Incolla il link o scansionalo con la fotocamera dove il browser può (Chrome e Edge). Perfuse recupera il manifesto, decrittografa ogni file con la chiave dal link, riassume eventuali bundle FHIR - chi è il paziente, quanti di ogni risorsa - e controlla eventuali SMART Health Card all'interno contro la chiave pubblicata dell'issuer. *Consegna al canale* consegna il contenuto FHIR a un canale come messaggio, che è come raggiunge il sistema di gestione sanitaria. La richiesta è limitata alla politica di uscita al momento della connessione, l'HTTP semplice è rifiutato e la risposta di un server che non è un server di manifesto non viene mai visualizzata, perché l'indirizzo proveniva da un codice QR di uno sconosciuto.

Condivisione. *Condividi* crittografa un bundle FHIR, lo ospita e visualizza il link e il suo codice QR una volta. Il server mantiene il testo cifrato e non la chiave - non può aprire ciò che ospita e non può visualizzare il link nuovamente. Un passcode viene hashato; dieci errori disabilitano il link. I link scadono dopo 30 giorni per impostazione predefinita, possono essere revocati e elencano quante volte e da chi sono stati recuperati. Avvia il server con -public-url impostato sull'indirizzo https raggiunto dai telefoni dei pazienti; l'URL del manifesto che costruisce deve adattarsi ai 128 caratteri della specifica.

Verifica di una carta. *Verifica una carta* prende un codice QR numerico shc:/ (un blocco o più), un file .smart-health-card o un JWS e dice se la firma corrisponde alla chiave dell'issuer.

8.17 UN/EDIFACT

dataType: edifact legge gli scambi UN/EDIFACT (ISO 9735): ORDERS, INVOIC, DESADV, IFTSTA e il resto, compresi i messaggi di assistenza sanitaria europei e di laboratorio. La stringa di servizio consiglia (UNA) è onorata, con il carattere di rilascio e, per la versione della sintassi 4, il separatore di ripetizione; i gruppi funzionali (UNG/UNE) sono opzionali. Lo scambio è consegnato esattamente come lo ha scritto il mittente.

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"'

La busta. Il conteggio dei segmenti UNT e il riferimento, il conteggio dei messaggi UNE e il riferimento e il conteggio UNZ e il riferimento sono confrontati con ciò che contiene lo scambio. Con require, il valore predefinito, una discrepanza rifiuta lo scambio (è come se un trasferimento interrotto mostrasse); warn accetta e registra un avvertimento; ignore non controlla.

Percorsi, per i filtri del canale e della destinazione, contano elementi e componenti a partire da 1 nell'ordine in cui il segmento è scritto, come le guide di implementazione li numerano: BGM-2 (il numero del documento), BGM-1.1, NAD(2)-2.1 (la seconda parte di NAD), LIN-3(2).1 (una ripetizione), UNB-2.1 (il mittente), UNH-2.1 (il tipo di messaggio). Un percorso senza un'occorrenza si riferisce a ogni occorrenza.

Dividere consegna uno scambio per messaggio, ognuno con l'UNB originale (e l'intestazione del gruppo) e trailer che contano uno, in modo che un ordine possa essere filtrato, cercato e ritentato da solo. I filtri di destinazione visualizzano ogni pezzo. Una destinazione del file nomina i file per tipo di messaggio (ORDERS_INVOIC-20261017.edi), e ${control_id} è il riferimento dello scambio.

CONTRL. Con acknowledge: contrl, un mittente che invia tramite HTTP riceve una risposta con sintassi CONTRL e rapporto di servizio: azione UCI 7 quando lo scambio è stato letto e consegnato, 4 quando è stato rifiutato o non poteva essere deliverato (allora HTTP 400 o 502). Non può essere combinato con split, poiché un CONTRL risponde a un intero scambio. Su AS2 la ricevuta del partner è l'acknowledgement.

Non offerto: i directory dei messaggi (che segmenta ORDERS D.96A consente), quindi la struttura è controllata, non il contenuto; le trasformazioni, che riscriverebbero un documento del partner; e script di filtro o trasformatore (un preelaboratore esegue, prima dell'analisi). Controllato contro pydifact 0.1.8, un parser indipendente, in entrambe le direzioni.

9 Conferme

Una conferma dice al mittente cosa è successo. Per HL7 v2 su MLLP è un messaggio di conferma; il mittente non invierà il prossimo messaggio fino a quando non arriva, e di solito lo rinvierebbe se non arriva.

Sbagliare le conferme è il modo più comune in cui un'integrazione perde silenziosamente i dati, perché un mittente che sta ricevendo conferme non ha motivo di lamentarsi.

9.1 Temporizzazione

Coperto in flusso di messaggi, e il riassunto è: ack.when è on_delivery per impostazione predefinita, il che significa che la conferma viene inviata solo dopo che ogni destinazione abilitata ha accettato il messaggio. on_receipt la invia non appena il messaggio viene analizzato e messo in coda.

9.2 Cosa invia Perfuse

Un AA quando il messaggio è stato accettato, un AE quando è stato rifiutato per un motivo per cui il mittente poteva agire, e un AR quando è stato rifiutato per un motivo per cui il mittente non poteva.

La distinzione tra AE e AR è chi deve fare qualcosa. AE significa che il messaggio aveva un problema - un campo che non poteva essere analizzato come data, un segmento richiesto mancante - e il mittente può correggerlo e rinviarlo. AR significa che Perfuse non poteva accettarlo indipendentemente dal contenuto, il che di solito significa un problema di configurazione o di disponibilità a questo livello. Un mittente che rinvierebbe dopo un AR otterrebbe la stessa risposta.

9.3 Identificazione di questo motore

ack.application e ack.facility popolano MSH-3 e MSH-4 dell'acknowledgement.

Quando entrambi sono vuoti, l'acknowledgement riflette il ricevitore originale — utilizza ciò che il messaggio in entrata aveva in MSH-5 e MSH-6. È ciò che la maggior parte dei mittenti si aspetta e rappresenta il valore predefinito per questo motivo.

Impostarli esplicitamente quando il mittente li valida, o quando più istanze di Perfuse gestiscono lo stesso feed e è necessario sapere quale di esse ha risposto.

9.4 L'evento trigger

ack.include_trigger_event invia ACK^A01 anziché un semplice ACK.

Alcuni ricevitori lo richiedono e altri lo rifiutano, il che è il motivo per cui rappresenta un'opzione esplicita senza un valore predefinito intelligente. Se un mittente sta rifiutando le vostre acknowledgement e il contenuto sembra corretto, questa è la prima cosa da provare.

9.5 Le acknowledgement negative non sono fallimenti da nascondere

Un NACK trattato come un successo rappresenta una delle configurazioni più dannose possibili e si verifica abbastanza frequentemente da essere degno di essere menzionato. Si verifica quando un destinatario invia un'acknowledgement negativa e il lato di invio registra la *trasmissione* come riuscita perché i byte sono stati inviati e qualcosa è tornato.

Perfuse legge l'acknowledgement che riceve da un destinatario MLLP e registra l'esito di conseguenza. Un AE o AR da un sistema a valle rappresenta un fallimento di consegna, viene ritentato in base alla politica del destinatario e contribuisce al tasso di fallimento che attiva gli avvisi.

Se si sta eseguendo la migrazione da un altro motore, vale la pena verificarlo esplicitamente sul proprio traffico anziché supporlo. Il controllo di parità lo mostrerà: un destinatario che il vecchio motore ha registrato come consegnato e Perfuse registra come fallito solitamente significa che il vecchio motore stava ignorando un NACK.

9.6 Timeout

L'attesa di un'acknowledgement è limitata. Quando non arriva in tempo, la consegna rappresenta un fallimento e viene messa in coda per il ritento.

Un timeout non è lo stesso di un rifiuto e viene registrato in modo diverso. Un rifiuto significa che il lato remoto ha considerato il messaggio e lo ha rifiutato; un timeout significa che non si sa se sia stato elaborato. Quella distinzione decide se un ritento sia sicuro: ritentare dopo un rifiuto è inutile, e ritentare dopo un timeout rischia di generare un duplicato. Perfuse ritenta dopo un timeout, perché un messaggio clinico mancante è generalmente peggiore di un duplicato e il sistema di ricezione è generalmente in grado di rilevare un ID di controllo del messaggio ripetuto.

Se quel compromesso sia giusto per un determinato feed rappresenta un giudizio e vale la pena di effettuarlo deliberatamente per tutto ciò che ha una conseguenza clinica per un duplicato — un ordine, un'amministrazione di farmaci — anziché accettare il valore predefinito in silenzio.

9.7 Sorgenti che non inviano acknowledgement

Non tutti i trasporti hanno il concetto. Una sorgente file non ha dove inviare un'acknowledgement; una sorgente broker la invia al broker anziché al mittente originale; una sorgente HTTP risponde con un codice di stato.

Quando la sorgente non può consegnare la modalità di acknowledgement richiesta da un canale, il canale viene rifiutato al caricamento anziché avviarsi e non inviare acknowledgement in silenzio. Un canale che crede di inviare acknowledgement e non lo fa è peggiore di uno che non si avvia.

9.8 Acknowledgement X12

Tutto ciò che precede riguarda HL7 v2. X12 ha le proprie acknowledgement, e a differenza di v2 sono disattivate per impostazione predefinita: un'impostazione vuota significa nessuna.

Quel valore predefinito è il più sicuro, perché un partner commerciale che non si aspetta un'acknowledgement e la riceve potrebbe trattarla come un'intercambio non sollecitato. La chiave acknowledge su un canale X12 può avere uno dei quattro valori:

ValoreCosa viene inviato
noneNiente. Il valore predefinito.
999Acknowledgement di implementazione. Sostituisce il 997 per le transazioni HIPAA.
997Acknowledgement funzionale. Più vecchio e ancora ciò che molti collegamenti dei pagatori si aspettano.
ta1Acknowledgement di interscambio, relativo alla busta piuttosto che al suo contenuto.

Quale inviare è una proprietà della relazione del partner commerciale piuttosto che del messaggio, il che è il motivo per cui deve essere configurato e non può essere dedotto. Un 999 sostituisce un 997 per le transazioni HIPAA, ma molti partner — soprattutto le connessioni dei pagatori più vecchie — sono configurati per aspettarsi un 997 e tratteranno un 999 come un file non riconosciuto.

Inviare l'acknowledgement sbagliato è peggiore che non inviarne nessuno. Risponde a una domanda che nessuno ha posto mentre lascia aperta la vera domanda, e il mittente non ha modo di distinguere la differenza.

9.9 Acknowledgement HL7 v3

Un canale HL7 v3 invia un'acknowledgement per impostazione predefinita, il che è l'opposto di X12 e vale la pena conoscerlo.

La ragione è il trasporto piuttosto che lo standard: un'interazione v3 arriva generalmente su una connessione sincrona con l'applicazione di invio in attesa di una risposta, e un mittente che non riceve nulla riproverà solitamente. È così che un paziente viene registrato tre volte.

Disabilitarlo è possibile e deve essere fatto esplicitamente — "non impostato" e "impostato su false" sono deliberatamente diversi, quindi l'impostazione predefinita rimane a meno che qualcuno non dica diversamente.

10 Consegna, messa in coda e ritentativo

Una destinazione che non può essere raggiunta è il caso normale, non l'eccezione. I sistemi si riavviano, le reti si interrompono e un motore di interfaccia ospedaliera è indisponibile durante la propria finestra di manutenzione. La consegna è costruita intorno a questo.

10.1 Coda per destinazione

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

Ogni destinazione ha la sua coda. Una destinazione che sta fallendo non influisce sulle altre e ognuna ha la sua profondità, età e stato di ritentativo.

La messa in coda è per destinazione piuttosto che per canale perché il fallimento è per destinazione. Una coda a livello di canale bloccerebbe la consegna a tre sistemi funzionanti perché un quarto è disattivato, e le due situazioni — una destinazione non disponibile, tutte e quattro non disponibili — sembrerebbero le stesse nelle statistiche.

10.2 Impostazioni coda

queue on a destination:

ChiaveCosa fa
enabledSe i messaggi non riusciti sono messi in coda.
max_attemptsQuante volte provare prima di desistere.
backoffAttendere prima del primo ritentativo.
max_backoffLimite massimo dell'attesa crescente.
max_depthNumero massimo di messaggi da mantenere. Non impostato significa nessun limite.
retain_hoursQuanto a lungo un messaggio consegnato viene mantenuto. Non impostato lo mantiene indefinitamente.

Gli ultimi due mancavano da questa tabella e dal costruttore, e sono la coppia che impedisce al disco di riempirsi. Una coda senza entrambi cresce fino a quando il file system non è pieno, e quel fallimento arriva come qualcosa di non correlato che si rompe — un write che fallisce da qualche altra parte — piuttosto che come un problema di coda.

Il backoff cresce tra i tentativi fino a max_backoff. Cresce piuttosto che fisso, perché una destinazione che è disattivata è solitamente disattivata per minuti piuttosto che secondi, e ritentare ogni secondo per dieci minuti produce diverse centinaia di voci di log che seppelliscono quella che conta.

10.3 L'ordinamento è preservato

All'interno di una destinazione, i messaggi sono consegnati nell'ordine di arrivo, e un messaggio che fallisce mantiene la sua posizione. I messaggi successivi aspettano dietro di esso piuttosto che superarlo.

Questo è il default giusto per i dati clinici — un'ammissione e una dimissione applicate nell'ordine sbagliato è peggio che entrambi essere in ritardo — e ha una conseguenza degna di essere compresa: un messaggio che fallisce sempre bloccherà tutto ciò che lo segue.

È per questo che la profondità della coda e l'età della coda sono condizioni di allarme separate. Una coda profonda che si sta svuotando è un sistema impegnato. Una coda il cui messaggio più vecchio continua a invecchiare è bloccata, e i tipi di allarme queue-depth, queue-age e queue-stuck li distinguono.

Un messaggio velenoso — uno che non riuscirà mai a prescindere da quante volte viene ritentato — è il fallimento specifico a cui questo design è vulnerabile. max_attempts è ciò che limita i danni: dopo di esso, il messaggio viene registrato come non riuscito e la coda si sposta. Impostare max_attempts molto alto nella speranza di un successo eventuale converte un singolo messaggio non riuscito in un feed bloccato.

10.4 Quando la messa in coda è disabilitata

Con queue.enabled false, una consegna non riuscita è una consegna non riuscita. Viene registrata e non ritentata.

È la scelta giusta quando i dati in ritardo sono peggiori dei dati mancanti — un display in tempo reale, un sistema di paging, qualsiasi cosa in cui un messaggio consegnato quaranta minuti dopo l'evento sarebbe fuorviante piuttosto che semplicemente ritardato.

È la scelta sbagliata per qualsiasi cosa che vada in un record, dove il messaggio è altrettanto valido un'ora dopo.

10.5 Ritentativo versus coda

Ci sono due meccanismi e operano a livelli diversi.

retry su una destinazione governa i tentativi immediati all'interno di una consegna — una connessione che fallisce viene ritentata dopo una breve pausa, senza lasciare il percorso di consegna. Ciò gestisce i guasti transitori: una connessione interrotta, un rifiuto momentaneo.

queue governa cosa succede una volta che i tentativi immediati sono esauriti. Il messaggio lascia il percorso di consegna e viene ritentato più tardi su una programmazione più lunga.

Entrambi esistono perché i due fallimenti sono diversi. Un reset di connessione nel primo tentativo è solitamente scomparso nel secondo, e passare attraverso la coda per esso aggiungerebbe minuti di latenza a un guasto che è durato millisecondi. Una destinazione che è stata disattivata per la manutenzione non tornerà online entro tre tentativi immediati, e martellare è inutile.

10.6 Cosa un endpoint HTTP considera consegnato

Un endpoint HTTP ha tre impostazioni che decidono se un messaggio è trattato come inviato e tutte e tre sono sull'endpoint nel costruttore.

Codici di stato che significano consegnato. Vuoto significa qualsiasi 2xx. Alcuni endpoint rispondono 202 Accepted per qualcosa che non hanno ancora elaborato, e alcuni rispondono 200 con un errore nel corpo — il secondo è ciò per cui *Tratta come fallito se la risposta contiene* è previsto. Impostare un elenco esplicito vale la pena di farlo quando un partner ha detto quale codice significa cosa, perché l'alternativa è scoprire la differenza da un messaggio che non è stato consegnato e non è stato messo in coda.

Segui reindirizzamenti. Disattivato per impostazione predefinita e intenzionalmente. Un reindirizzamento può puntare a un host diverso, quindi seguirlo invia il messaggio da qualche parte che nessuno ha configurato e segnala il successo.

Token Bearer. Inviato come intestazione Authorization. Viene archiviato con il canale e non viene più visualizzato, quindi lasciare la casella vuota durante la modifica di un canale esistente mantiene il token già salvato anziché cancellarlo.

10.7 Denominazione e potatura di una cartella di archiviazione

Una destinazione del file aggiunge a un file per giorno e tipo di messaggio per impostazione predefinita (20261012-ADT_A01.hl7), inquadrato MLLP in modo che il file possa essere riprodotto con perfuse send. Quattro impostazioni sulla destinazione modificano questo.

Nome del file (file_name) crea un file per messaggio invece, nominato da ${date}, ${timestamp}, ${control_id}, ${message_type} e ${destination}. Un nome che è già stato preso (lo stesso ID di controllo due volte) ottiene un suffisso univoco invece di sovrascrivere il messaggio lì.

Aggiungi (append: true) scrive ogni messaggio nel file Nome file denominato, quindi ${date}.hl7 è un file al giorno per ogni tipo.

Suffix durante la scrittura (temp_suffix, un file per messaggio solo) predefinito su .part e rimosso da un rename una volta che il file è completo. Chiunque raccoglie questi file non dovrebbe raccogliere uno scritto a metà, e un rename all'interno di una cartella è atomico. Cambiarlo solo se il collector filtra un'estensione diversa.

Elimina dopo (retain_hours) pota i file nella cartella più vecchi del numero di ore dato, controllato al massimo ogni dieci minuti mentre arrivano messaggi. Solo i file semplici direttamente nella cartella vengono eliminati, mai una sottocartella. Vuoto o zero li mantiene per sempre, che è il valore predefinito ed è una decisione piuttosto che un errore — ma un archivio che nessuno pota riempie il disco e un disco pieno ferma il canale piuttosto che l'archiviazione.

10.8 Invio a un server FHIR

Tre impostazioni decidono quanto viene verificato prima che un bundle parta.

Dichiara la conformità US Core aggiunge il profilo a ogni risorsa. Dichiara solo quando la risorsa trasporta ciò che il profilo richiede, perché un ricevente può convalidare contro la dichiarazione e rifiutare un bundle che altrimenti sarebbe stato accettato.

Convalida prima dell'invio controlla ogni risorsa qui anziché apprendere dal ricevente. Un rifiuto all'estremità remota ti dice meno, più tardi e spesso solo in un registro che non puoi leggere.

Tratta gli avvertimenti come rifiuti ha effetto solo quando la convalida è attiva e il controllo non è disponibile fino ad allora. È abbastanza rigoroso da fermare un bundle che un ricevente accetterebbe, quindi appartiene a un feed che sta venendo avviato piuttosto che a uno in servizio.

10.8.1 Servizi FHIR ospitati

Un endpoint fhir con il blocco auth si connette ai servizi ospitati, dove un token bearer incollato smette di funzionare entro un'ora:

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 firma ogni richiesta per AWS HealthLake con Signature Version 4, con la regione letta dall'URL. azure ottiene un token Microsoft Entra ID per Azure Health Data Services da tenant_id, client_id e client_secret - una registrazione dell'app che detiene il ruolo di contributore dei dati FHIR - con l'URL del servizio FHIR come pubblico. client_credentials fa lo stesso contro qualsiasi URL del token OAuth 2.0 token_url. I token vengono riutilizzati fino a un minuto prima della loro scadenza. Le stesse opzioni sono disponibili sotto il Servizio di accesso ospitato della destinazione nel costruttore del canale.

10.8.2 Segnalazione dei casi di salute pubblica

Selezionare Segnalare le condizioni segnalabili alla sanità pubblica su una destinazione FHIR e invierà rapporti di casi invece di bundle. Ogni messaggio viene controllato per un codice di attivazione della condizione segnalabile: una diagnosi, un test di laboratorio o un risultato codificato. Se ne ha uno, il messaggio diventa un eICR HL7 eCR 2.1.2, avvolto in un messaggio eCR e inviato all'URL $process-message. Se non ne ha nessuno, nulla viene inviato e nulla fallisce; la destinazione lo conta come non segnalabile.

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 è il set di codici di attivazione delle condizioni segnalabili, come un ValueSet FHIR o il bundle eRSD. Richiede una licenza UMLS, quindi non è incluso; senza di essa, viene utilizzato un campione di esempio breve integrato, solo per test. source è dove l'agenzia invia la sua risposta alla segnalazione. La struttura sanitaria è obbligatoria perché eCR richiede il suo numero di telefono e l'indirizzo, e un messaggio v2 non li ha.

Un rapporto indica cosa mancava nel messaggio piuttosto che inventarlo, e ogni lacuna viene registrata. Provare un messaggio nel pannello Rapporto di casi di sanità pubblica del laboratorio FHIR prima di puntare un flusso live a un'agenzia.

10.8.3 Risultati di laboratorio alla salute pubblica: ELR

perfuse elr -config elr.yaml results.hl7 trasforma i risultati di un laboratorio nei messaggi ELR HL7 2.5.1 che i dipartimenti di sanità statale ricevono, uno per ogni messaggio con un risultato segnalabile, e solo gli ordini che ne trasportano uno: un esame del sangue completo accanto a un test SARS-CoV-2 positivo non è affare della sanità pubblica. I codici di attivazione sono gli stessi della segnalazione dei casi, il RCTC che si carica o il campione integrato.

ELR nomina tutti con OID o numero CLIA, che nessun feed di laboratorio trasporta per il mittente e il destinatario, quindi questi provengono dal file:

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}

La struttura che effettua l'ordine, il laboratorio che esegue e le autorità di assegnazione vengono utilizzate solo dove il messaggio del laboratorio le omette, e ogni utilizzo è una nota. Ciò che solo il laboratorio sa non viene mai compilato: un risultato senza tipo di campione va con SPM-4 vuoto e una nota che lo dice, perché un campione ipotizzato in un rapporto alla sanità pubblica è peggiore di una lacuna che lo stato può chiedere. Iniziare con processing: T mentre il team di onboarding dello stato testa il flusso.

Ciò che il laboratorio ha fatto correttamente viene mantenuto com'è stato inviato. Un ordine figlio (un pannello di sensibilità o un test di riflessione il cui OBR-29 nomina il genitore e che non ha un ORC proprio) va come ricevuto, senza ORC o campione inventato, e un figlio senza risultato segnalabile proprio va con quello del genitore, poiché una sensibilità non significa nulla senza la coltura a cui appartiene. Una nota dopo il PID rimane con il paziente, e ORC-14, il numero di telefono di richiamo, viene copiato da OBR-17 quando il laboratorio lo mette solo lì. Tutti i 28 messaggi di esempio che ONC pubblica per il suo strumento di certificazione ELR escono validi senza errori.

MSH-2 viene scritto come ^~\&#, i cinque caratteri richiesti dall'errata di ELR Release 1 e verificati dallo strumento di certificazione di ONC. Se la guida del tuo stato mostra i quattro caratteri più vecchi, aggiungere encoding_characters: "^~\\&" al file.

Per inviarli da un canale invece che dalla riga di comando, dare alla destinazione che raggiunge lo stato un blocco elr che nomina lo stesso file. Ogni risultato del laboratorio viene riorganizzato durante l'invio, e uno con nulla di segnalabile non viene inviato affatto, il che viene conteggiato come consegnato, non fallito: lo stato ha chiesto solo risultati segnalabili.

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

Il blocco si applica a un canale HL7 v2, alle destinazioni che consegnano il messaggio stesso (mllp, http, tcp, file, sftp, ftp, S3, Azure Blob, soap, i broker di messaggi o un altro canale); il canale rifiuta di caricare altrimenti, e quando il file è mancante o manca della struttura di invio, dell'applicazione ricevente o della struttura ricevente. Le note vengono scritte nel log con l'ID di controllo del messaggio.

Il file ELR è il compagno del canale, non un canale: perfuse check e lo schermo dei canali lo saltano invece di segnalare un canale che non verrà caricato. Nel costruttore di canali, le stesse due impostazioni sono sotto la destinazione, in Segnalazione del laboratorio (ELR 2.5.1); il campo dei codici di attivazione si apre una volta che viene nominato un file ELR, e il salvataggio rifiuta un file che non si trova accanto al canale.

10.8.4 Archivi DICOMweb

type: dicomweb archivia ogni oggetto con STOW-RS: Orthanc, dcm4chee, i servizi di imaging cloud o l'archivio di un server Perfuse. Fornire la radice del servizio (https://pacs.example/dicom-web); /studies viene aggiunto, e un URL che termina già con /studies viene rifiutato invece di essere inviato a /studies/studies. Autenticare con token (un token bearer) o username e password; headers aggiunge altri, come l'intestazione del progetto di un servizio cloud. Il canale necessita di dataType: dicom.

La risposta del server decide l'esito, non solo il suo codice di stato. Un oggetto che la risposta elenca come fallito è una consegna fallita con il motivo di fallimento DICOM, e lo è anche un 202 che non elenca nulla come archiviato: il server ha preso la richiesta e non ne ha mantenuto nessuna. Il timeout predefinito è di due minuti, perché una serie grande è lenta.

10.8.5 Repository di documenti (IHE XDS.b)

type: xds pubblica ogni documento clinico in un repository XDS.b con ITI-41 Provide and Register: un documento CDA o un messaggio HL7 v2 (MDM, ORU) che lo trasporta. I metadati provengono dal documento e dalle impostazioni del destinatario (source_id, patient_domain, facility_type, practice_setting), e la risposta del repository RegistryResponse decide la consegna. Vedi condivisione di documenti IHE.

10.8.6 Registry di immunizzazione

Ogni registro di immunizzazione statale (IIS) accetta messaggi HL7 2.5.1 sulla stessa interfaccia SOAP, quella pubblicata dal CDC nel 2011 (namespace urn:cdc:iisb:2011). Ha due operazioni: connectivityTest, che verifica l'endpoint, e submitSingleMessage, che trasporta il messaggio. Un VXU^V04 segnala un vaccino e torna come un ACK; un QBP^Q11 chiede la storia e la previsione di un paziente e torna come un RSP^K11.

Scegliere Registry di immunizzazione (servizio web CDC IIS) come servizio di un destinatario SOAP, o scrivere 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 costruisce la busta, quindi non c'è corpo da scrivere. Il nome utente e la password vanno all'interno della richiesta, dove il CDC WSDL li posiziona, non nell'autenticazione HTTP. La versione è SOAP 1.2, il binding del WSDL, a meno che non si imposti version: "1.1" per un registro che richiede una guida specifica. Dove un registro richiede un certificato client, impostare il tls del destinatario come per qualsiasi chiamata HTTPS.

L'acknowledgement del registro decide se il messaggio è stato consegnato, non lo stato HTTP. Un registro risponde a un rifiuto con HTTP 200 e un AR all'interno, quindi una destinazione che si fidava dello stato segnalerebbe un'immunizzazione persa come consegnata.

Il registro rispondeRegistri di Perfuse
AA (o CA)Consegnato.
AE con tutti i segmenti ERR di warning (ERR-4 W o I)Consegnato. I warning sono nella risposta.
AE con qualsiasi ERR-4 E, o un ERR senza gravitàFallito, con la posizione, il codice e il testo di ogni ERR nell'errore.
AR o CRFallito, nello stesso modo.
Una fault SOAP (password errata, messaggio troppo grande)Fallito, con il motivo del registro.
Qualcosa che non è un messaggio HL7Fallito.

warnings_are_errors: true (Tratta i warning come fallimenti) fa attendere ogni AE a una persona. La risposta, che gli script di risposta e un chiamante HTTP in attesa sul canale leggono, è il messaggio HL7 del registro: l'ACK o la RSP con la storia e la previsione. examples/iis contiene tre canali da cui partire: VXU da un EHR su MLLP, query QBP su HTTP e un sostituto locale per un registro.

La dashboard Connessioni chiede a un registro il suo connectivityTest quando non è stato inviato nulla per sette giorni. Quell'operazione esiste a questo scopo e non invia nulla, quindi è il solo controllo a livello di applicazione che Perfuse esegue. Dimostra l'indirizzo, il TLS e il binding SOAP, non il nome utente e la password; solo una reale invio li testa.

Una sorgente SOAP può rispondere allo stesso modo: Rispondi come un registro di immunizzazione, o profile: cdc-iis sulla sorgente. Ripete connectivityTest, prende il messaggio da submitSingleMessage, restituisce l'acknowledgement del canale in return e serve il WSDL del CDC a ?wsdl. Un nome utente e una password, quando impostati, vengono verificati contro quelli nella richiesta, e una coppia errata ottiene la SecurityFault del WSDL. Un messaggio che il canale rifiuta torna indietro come un NAK, mai come una fault, come dice la guida del CDC. Usalo come doppio di test o per ricevere invii nel modo in cui li riceve un registro.

Non coperto: le parti specifiche dello stato del processo di onboarding. Ogni registro ha il proprio endpoint, processo di account e profilo locale della guida 2.5.1 (campi RXA e OBX richiesti, idoneità VFC, codici di rifiuto). Quelli sono il contenuto dei messaggi, che le trasformazioni del canale plasmano; nessun endpoint di stato è integrato. Perfuse è stato testato contro se stesso e contro risposte di registro registrate, non contro un registro di stato live.

10.9 Quando il trasporto dice sì e il messaggio non è arrivato

"È arrivato questo" è spesso una domanda che il trasporto non può rispondere. Un ricevitore MLLP restituisce un acknowledgement di applicazione il cui significato è nel testo. Un ricevitore HTTP restituisce 200 con un documento di errore. In entrambi i casi il trasporto è riuscito e il messaggio non è arrivato.

Ispeziona la risposta su una destinazione prende uno script dato dalla risposta del ricevitore. Restituisci false, o lancia un'eccezione, e la consegna viene contrassegnata come fallita — il che significa che si ritenta, si mette in coda e appare nel conteggio degli errori invece di essere conteggiato silenziosamente come consegnato.

Viene offerto solo sulle destinazioni che ricevono una risposta. Su una che non può, viene rifiutato al caricamento invece di essere lasciato in esecuzione.

10.10 Cosa significa l'esito di una consegna

EsitoSignificato
DeliveredLa destinazione ha accettato il messaggio. Per MLLP, è stato ricevuto un acknowledgement positivo.
QueuedLa consegna ha avuto esito negativo e il messaggio sarà ritentato.
FailedLa consegna ha avuto esito negativo e non sarà ritentato, sia perché la coda è disabilitata sia perché i tentativi sono esauriti.
FilteredLa destinazione ha rifiutato il messaggio in base al proprio filtro. Non è un errore.

Questi vengono registrati per destinazione per messaggio, quindi un messaggio che ha raggiunto tre delle quattro destinazioni viene registrato esattamente come tale. Non c'è un "successo" a livello di canale, perché non significherebbe nulla.

10.11 Consegna lenta

Una destinazione che sta accettando messaggi ma ci mette molto tempo è un problema distinto da uno che sta fallendo, ed è facile perderlo di vista perché ogni esito è un successo.

Esiste un tipo di allarme slow-delivery per questo. Vale la pena impostarlo su tutto ciò per cui l'acknowledgement del mittente attende la consegna, perché una destinazione il cui tempo di risposta è aumentato silenziosamente raddoppierà alla fine e inizierà a produrre ritardi — e a quel punto il sintomo appare a monte, in un sistema che potresti non amministrare.

10.12 Scrittura su un database

type: database esegue uno statement per messaggio con valori vincolati dal messaggio.

I segnaposto sono propri del driver — $1 per postgres, ? per mysql e sqlite, @p1 per sqlserver — e Perfuse non li riscrive. È deliberato: uno strato di traduzione che sbagliasse un segnaposto li leggerebbe come dati validi invece di un errore.

Uno statement scritto nel dialetto sbagliato viene rifiutato quando viene salvato, nominando lo stile che il driver vuole. Prima che esistesse questo controllo, l'errore emergeva come syntax error at or near "," dal server quando arrivava un messaggio, che nomina uno statement che hai scritto e quindi ti fa cercare un refuso invece di guardare al dialetto.

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

Un parametro tra virgolette è una costante piuttosto che un percorso, che è come un canale scrive il proprio nome o un codice di sistema sorgente in una riga accanto ai dati del messaggio.

I valori vengono sempre vincolati come parametri. Un riferimento ${...} all'interno dello statement viene rifiutato: un nome che contiene un apostrofo romperebbe lo statement, e un valore ostile lo riscriverebbe.

10.13 Invio a un socket grezzo

type: tcp scrive su un socket con framing scelto dall'utente, che è ciò che un dispositivo o uno strumento di laboratorio vuole solitamente. MLLP è uno dei framing disponibili; questa destinazione offre anche gli altri.

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

Il framing non ha un valore predefinito, intenzionalmente. Scrivere con il framing errato non fallisce. Il sistema di ricezione legge i messaggi divisi nei punti sbagliati o attende un terminatore che non arriva mai, e il sintomo appare nel sistema di ricezione piuttosto che qui.

framingCiò che scrive
mllp0x0b prima, 0x1c 0x0d dopo. Lo stesso framing utilizzato da una destinazione MLLP.
delimitedUn delimiter dopo ogni messaggio, e un start_block opzionale prima di esso.
fixedRecord padding o troncati a record_length.
lengthUn prefisso length_bytes. big_endian e length_includes_header hanno entrambi due convenzioni nel mondo reale e la differenza è silenziosa.
wholeUn messaggio per connessione, chiuso per contrassegnare la fine.

Vengono accettate solo le impostazioni utilizzate dal framing scelto. Una lunghezza di record in un flusso delimitato viene rifiutata piuttosto che ignorata, perché un'impostazione ignorata silenziosamente è una impostazione che qualcuno ritiene essere in vigore.

expect_reply modifica ciò che significa recapitato. Senza di esso, il successo significa che i byte hanno raggiunto il buffer di invio del sistema operativo — che un peer crashato un attimo dopo non ha mai letto.

10.14 Amazon S3, SQS e SNS

Un canale può leggere da una coda SQS o da un prefisso di bucket S3 e consegnare a SQS, SNS o S3. Tutti e cinque utilizzano HTTP firmato senza SDK AWS nel binario e tutti e cinque accettano le stesse impostazioni di accesso: region, access_key_id, secret_access_key (scrivere ${AWS_SECRET_ACCESS_KEY} per leggere l'ambiente), un facoltativo session_token e endpoint per LocalStack, MinIO o un endpoint VPC. Sotto Canali → Nuovo canale, scegliere *Leggiamo da una coda Amazon SQS*, *Raccogliamo oggetti da un bucket Amazon S3* o i tipi di destinazione SQS, SNS e S3.

Nessun messaggio viene confermato ad AWS fino a quando il canale non lo ha gestito. Un messaggio SQS viene eliminato successivamente e altrimenti riappare quando il timeout di visibilità termina, quindi una politica di riavvio della coda è ciò che sposta un messaggio che continua a non riuscire in una coda di lettere morte. Un oggetto S3 si sposta in processed/ successivamente, o in error/ se non poteva essere gestito, quindi un singolo file non blocca gli altri.

In una coda o un argomento FIFO, i messaggi sono raggruppati per paziente per impostazione predefinita - SQS mantiene l'ordine all'interno di un gruppo e da nessun'altra parte - e deduplicati per contenuto, quindi un retry non viene consegnato due volte.

Un archivio S3 può essere scritto direttamente su Glacier con storage_class, e come JSON linee per Amazon Athena con format: ndjson; perfuse athena stampa la tabella. Il riferimento contiene ogni impostazione.

10.15 AMQP 1.0 e Azure

AMQP 1.0 è ciò che Azure Service Bus e Event Hubs parlano, e RabbitMQ 4, ActiveMQ e Artemis oltre ai loro altri protocolli. Un' origine amqp riceve da una coda o una sottoscrizione e accetta ogni messaggio solo una volta che il canale lo ha gestito; uno che non poteva essere gestito viene rilasciato come consegna non riuscita, quindi il broker lo ridistribuisce e, oltre il limite della coda, lo invia alla coda di lettere morte. Una destinazione amqp segnala il successo solo quando il broker accetta il messaggio. Per Service Bus: addr è <namespace>.servicebus.windows.net:5671 con tls, username il nome della politica di accesso condiviso, password la sua chiave, e address il nome della coda, o <topic>/subscriptions/<name> per ricevere.

Azure Blob Storage: una destinazione azure_blob scrive un blob per messaggio nel livello di accesso scelto - Hot, Cool, Cold o Archive - e un'origine azure_blob raccoglie i blob da un prefisso, spostandoli in processed/ o error/ come l'origine S3 fa. Preferire un token SAS generico limitato al contenitore piuttosto che la chiave dell'account.

10.16 MQTT

Un'origine mqtt si iscrive a un filtro di argomento (+ corrisponde a un livello, # a tutti i livelli inferiori) su qualsiasi broker MQTT 3.1.1: Mosquitto, EMQX, HiveMQ, AWS IoT Core, Azure Event Grid. Con QoS 1, il valore predefinito, ogni messaggio viene confermato solo una volta che il canale lo ha gestito. MQTT non ha modo di rifiutare un singolo messaggio, quindi uno che non poteva essere gestito rimane non confermato e la connessione viene stabilita nuovamente; il broker mantiene la sessione sotto l'ID client (perfuse-<channel> a meno che client_id non specifichi diversamente) e lo invia nuovamente, per primo in linea. QoS 0 è al massimo una volta: qualsiasi cosa inviata mentre Perfuse è disconnesso è persa. Una destinazione mqtt pubblica e, con QoS 1, segnala il successo quando il broker ha il messaggio.

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}

AWS IoT Core vuole un certificato client: fornire tls.cert_file e tls.key_file.

10.17 IBM MQ

ibm_mq legge e scrive code IBM MQ attraverso l'API REST di messaggistica del gestore di code (mqweb), che IBM MQ 9.1.5 e successive forniscono su ogni piattaforma, incluso z/OS, quindi non è necessario installare un client MQ accanto a Perfuse. L'utente necessita del ruolo MQWebUser e dell'autorità di inserimento, recupero e navigazione sulla coda. Una sorgente esamina il primo messaggio, lo passa al canale e lo rimuove in base al suo ID messaggio solo una volta che è stato gestito; un messaggio che ha esito negativo rimane in cima alla coda. Eseguire un lettore per coda. Una destinazione inserisce messaggi persistenti (a meno che non_persistent non sia impostato), con l'ID di controllo HL7 come ID di correlazione.

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 per MQ 9.3 e successivi (il valore predefinito), v2 per 9.1.5 a 9.2. Un gestore di code con un canale AMQP può essere raggiunto anche con il connettore amqp.

10.18 Google Cloud Pub/Sub e Cloud Storage

Una sorgente pubsub recupera da un abbonamento e conferma ogni messaggio una volta gestito; uno che ha esito negativo viene restituito immediatamente (la sua scadenza di conferma è impostata su zero), con il resto del suo batch, quindi Pub/Sub lo consegna nuovamente e, oltre alla politica di dead-letter dell'abbonamento, lo invia alla coda di dead-letter. Una destinazione pubsub pubblica con il tipo di messaggio HL7 e l'ID di controllo come attributi; order_by: patient imposta la chiave di ordinamento da PID-3.1, quindi un abbonamento con ordinamento dei messaggi mantiene i messaggi di ogni paziente in ordine.

Una destinazione gcs scrive un oggetto per messaggio, denominato come una chiave S3, nella classe di archiviazione scelta (STANDARD, NEARLINE, COLDLINE, ARCHIVE). Una sorgente gcs recupera oggetti da un prefisso e li sposta in processed/ o error/ come fa la sorgente S3.

Entrambe si connettono come account di servizio: credentials_file è la sua chiave JSON. Lasciarla vuota su Google Cloud (una VM, GKE o Cloud Run) per utilizzare l'account di servizio collegato lì. endpoint nomina un emulatore (l'emulatore Pub/Sub, fake-gcs-server), che non richiede credenziali.

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

10.19 Lettura di una casella di posta (IMAP e POP3)

Una sorgente email legge una casella di posta elettronica e trasforma ciò che trova in messaggi: ogni allegato (take: attachments, il valore predefinito, limitato da modelli attachment_names), il testo dell'email (take: body) o l'intera email (take: raw) per un script che li smonti. Laboratori, centri di imaging e piccole strutture sanitarie inviano ancora i risultati in questo modo.

Ogni controllo si collega, legge la posta non letta più vecchia per prima, e si disconnette. Su IMAP, un'e-mail viene recuperata senza essere contrassegnata come letta, consegnata al canale, e solo una volta ogni messaggio da essa accettato viene spostata in move_to (Elaborata), contrassegnata come letta (after_read: flag) o eliminata. La posta che non è riuscita o che non è stata presa (un mittente al di fuori di allowed_senders, nessun allegato che corrisponda a attachment_names, più grande di max_message_size), si sposta nella cartella error_folder (Errore) con il motivo nel log. Entrambe le cartelle vengono create quando mancano. POP3 non ha cartelle o flag, quindi elimina: le eliminazioni vengono confermate dal QUIT alla fine del controllo, quindi una sessione che si interrompe non elimina nulla e un'e-mail gestita potrebbe essere letta di nuovo (mai persa). La posta POP3 che non è stata presa rimane sul server e viene segnalata una volta.

La connessione è una password (${MAIL_PASSWORD}; una password dell'app per Gmail) o OAuth 2.0 tramite SASL XOAUTH2, che Microsoft 365 richiede (ha disattivato la connessione con password) e Gmail preferisce:

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]

Con client_secret e senza refresh_token, viene utilizzato l'accesso app-only di Microsoft 365 (la concessione di credenziali client, ambito https://outlook.office365.com/.default): un amministratore registra l'app, gli concede l'accesso IMAP.AccessAsApp e lo limita a una sola casella di posta con un principale di servizio Exchange. Con un refresh_token (un consenso di una persona), viene utilizzato l'ambito delegato IMAP.AccessAsUser.All o POP.AccessAsUser.All, e un token di aggiornamento ruotato viene mantenuto per la durata del processo. Gmail richiede un refresh_token: Google non offre l'accesso app-only a una casella di posta.

allowed_senders accetta indirizzi e domini. La riga From di un'email può essere contraffatta, quindi tiene fuori gli incidenti e la posta vagante, non un attaccante; un feed che deve essere considerato attendibile appartiene a Direct (S/MIME firmato), SFTP o una VPN. security è tls (993 o 995, il valore predefinito), starttls (143 o 110) o none, che è consentito solo a localhost. I controlli sono separati da almeno 10 secondi (60 per impostazione predefinita), perché i servizi di posta elettronica limitano gli account che controllano più velocemente.

Testato contro GreenMail 2.1.3 (IMAPS, IMAP, POP3S e POP3: rifiuto di accesso con password errata, recupero senza contrassegnare come letto, SPOSTA, flag, eliminazione, un'email troppo grande rifiutata prima di essere letta) e contro l'IMAP di Gmail con una password dell'app (creazione di una cartella, aggiunta, recupero, SPOSTA, eliminazione). OAuth è stato testato contro un endpoint di token di sostituzione solo: non contro Microsoft o Google.

10.20 AS2

AS2 (RFC 4130) è il modo in cui molti pagatori, centri di smistamento e fornitori scambiano EDI: un POST HTTP il cui corpo è firmato con il certificato del mittente e crittografato per il ricevente, risposto con una ricevuta (un MDN) che nomina un digest di ciò che è arrivato. Il S/MIME è lo stesso codice utilizzato dalla messaggistica Direct. Entrambe le estremità sono sul costruttore di canali: I partner commerciali ci inviano EDI su AS2 come sorgente, Un partner commerciale su AS2 come destinazione.

# 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"

Ricezione. Un messaggio a qualsiasi altro AS2-To, o da un mittente non in partners, viene rifiutato con 403 e senza ricevuta. Il messaggio di un partner deve essere firmato e crittografato a meno che la sua voce non imposti allow_unsigned o allow_unencrypted. Il payload viene decrittografato, la sua firma verificata contro il certificato del partner (i partner di solito scambiano certificati autofirmati, che va bene: il certificato è la fiducia), e consegnato al canale come dice il formato del messaggio. Il partner riceve la ricevuta che ha richiesto: nella risposta, o inviata all'URL della sua Receipt-Delivery-Option; firmata quando ha richiesto una firmata. Un messaggio che non riesce ottiene una ricevuta che nomina il motivo (decryption-failed, authentication-failed, insufficient-message-security, unexpected-processing-error).

Invio. Ogni messaggio è firmato (SHA-256) e crittografato (AES-256-CBC). Con receipt: sync, il valore predefinito, viene considerato consegnato solo quando la ricevuta verifica contro partner_cert_file, dice processed e contiene lo stesso digest (MIC) di quello inviato; qualsiasi altra cosa è una consegna fallita e viene ritentata. receipt: async richiede la ricevuta a receipt_url, che deve essere una sorgente AS2 su questo server che elenchi il partner: il messaggio viene considerato consegnato una volta che il partner accetta la richiesta e una ricevuta che in seguito non è d'accordo viene registrata come errore. receipt: none non richiede nulla. unsigned, unencrypted e unsigned_receipt rilassano ogni parte per un accordo che lo dice; username e password aggiungono l'autenticazione di base HTTP per le porte che lo richiedono. Il tipo di contenuto segue il formato del canale (application/edi-x12 per X12) a meno che content_type non ne imposti uno.

Triple DES, AES-128 e AES-192 vengono letti così come AES-256, poiché i partner li inviano ancora, e anche il flusso BER (lunghezze indefinite) che le porte Java scrivono.

Compressione (RFC 5402). Un messaggio compresso viene letto in qualsiasi modo sia stato costruito: compresso prima della firma o della crittografia, o un messaggio firmato compresso interamente. Il MIC del ricevuto segue la RFC: su ciò che è stato firmato quando è firmato, sul contenuto non compresso quando non è firmato. Un messaggio che si espanderebbe oltre dieci volte la dimensione massima del messaggio della sorgente (max_message_size) viene rifiutato con decompression-failed, in modo che pochi kilobyte non possano richiedere gigabyte di memoria. Una destinazione comprime con compress: true, prima della firma e della crittografia, come fanno la maggior parte delle porte di accesso; chiedere al partner per prima.

Un messaggio inviato due volte. Un partner che non ha mai ricevuto la nostra ricevuta invia nuovamente il messaggio con lo stesso Message-ID (RFC 4130 sezione 7.5). La sorgente ricorda ogni Message-ID del partner per duplicate_window (predefinito 720h, 30 giorni; almeno un'ora) e risponde a una rinviata con una ricevuta processed senza passarla di nuovo. Il record viene mantenuto nel database, quindi un riavvio non lo dimentica. Un messaggio il cui elaborazione è fallita non viene ricordato, quindi il retry del partner passa. Le copie che arrivano allo stesso momento si attendono a vicenda e solo la prima viene passata. Se il record non può essere letto, il messaggio viene rifiutato con unexpected-processing-error e il partner ritenta più tardi, piuttosto che rischiare una copia seconda. Un messaggio senza Message-ID non può essere riconosciuto e viene registrato come tale.

L'interoperabilità è testata contro pyas2lib 1.4.3 in entrambe le direzioni, con Triple DES e AES-256, compressi e non, ricevute firmate sincrone incluse.

10.21 OpenPGP

I pagatori, le casse di compensazione e le agenzie statali spesso accettano e inviano file solo sotto OpenPGP. Un blocco pgp su una sorgente apre ciò che arriva; uno su una destinazione protegge ciò che esce. Entrambi sono sul costruttore di canali: Messaggi crittografati con Open PGP sotto la sorgente, Crittografare con OpenPGP su ogni destinazione.

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}

I file delle chiavi vengono letti relativamente al file del canale e vengono letti e sbloccati quando il canale viene caricato: una chiave mancante o una passphrase errata ferma il canale lì, non sul primo file.

aperto per primo e quindi diviso in messaggi, quindi un batch crittografato come un file funziona. Uno che non può essere aperto viene rifiutato: una sorgente file lo sposta nella sua cartella degli errori, un inviante HTTP risponde 400 con il motivo. require_signature rifiuta un messaggio non firmato da uno di verify_with; allow_unencrypted accetta uno che è solo firmato; pass_plain lascia passare un messaggio che non è PGP affatto invariato, per una cartella che riceve entrambi.

encrypt_to) e firmato (con sign_with), dopo ogni altro passaggio. Una destinazione file, SFTP, FTP, S3, Azure Blob o GCS nomina ancora il file dal messaggio piano, quindi ${control_id} funziona, e qualsiasi cornice è all'interno della crittografia. armor: true scrive .asc testo invece di binario; no_compress disattiva la compressione; file_name è il nome trasportato all'interno del messaggio.

I messaggi vengono scritti con AES-256 nel formato RFC 4880 che i ricevitori più vecchi leggono, e il formato RFC 9580 più recente viene letto anche. La crittografia è ProtonMail/go-crypto; Perfuse non implementa alcun primitivo. L'interoperabilità è testata contro GnuPG in entrambe le direzioni: gpg decripta e verifica ciò che Perfuse scrive, e Perfuse apre e verifica ciò che gpg scrive.

10.22 Consegna a un altro canale

Una destinazione del canale consegna il messaggio a un altro canale per nome. Il canale ricevente lo tratta come qualsiasi altra arrivata: lo registra, lo filtra, lo trasforma e lo diffonde.

Questo è il modo supportato per costruire una catena. È deliberatamente visibile — due canali, due set di statistiche, due voci nella cronologia del messaggio — perché una catena nascosta all'interno di un canale è una catena che nessuno può monitorare.

Il messaggio viene consegnato in memoria piuttosto che su una rete, quindi non c'è cornice, non c'è ack e non c'è timeout tra i due.

10.23 Cosa succede quando il processo viene ucciso

La domanda che chiunque abbia eseguito un motore di interfaccia chiede per primo, e quella che raramente viene risposta, perché la risposta onesta è di solito imbarazzante.

È stata risposta uccidendo il processo con SIGKILL a metà di un batch — che è ciò che un guasto di alimentazione, un kill out-of-memory e un reset dell'ipervisore sembrano all'interno — e contando ciò che è sopravvissuto contro ciò che era stato promesso.

La proprietà in prova non è "nulla va perso". Ciò non è realizzabile e affermarlo sarebbe una bugia. È la promessa più stretta su cui un mittente fa effettivamente affidamento: un messaggio che è stato positivamente confermato è un messaggio che è arrivato.

Con ack.when: on_delivery, che è il valore predefinito, ogni destinazione viene scritta prima che venga inviata la conferma, quindi un AA è una dichiarazione sulla destinazione piuttosto che sulla coda. Un messaggio eliminato prima della sua conferma potrebbe essere perso e ciò è corretto: il mittente non ha mai ricevuto alcuna promessa e lo invierà di nuovo.

10.23.1 Conferma alla consegna

Cinque esecuzioni, eliminate dopo 5, 25, 40, 75 e 110 messaggi su 120.

ConfermatoPresente a valle in seguitoConfermato ma mancante
2552550

La promessa è mantenuta in ogni punto di eliminazione e nulla è stato duplicato. Una duplicazione sarebbe stata accettabile e una perdita no: un A08 rinviato è un fastidio che i ricevitori assorbono e un risultato di laboratorio che non arriva silenziosamente è un evento di sicurezza per il paziente.

10.23.2 Conferma alla ricezione

on_receipt risponde non appena il messaggio viene messo in coda, prima che qualsiasi destinazione sia stata scritta. Questo capitolo ha sempre detto che un messaggio confermato può ancora essere perso in questo modo. Ecco la dimensione di esso.

Eliminato dopoConfermatoPresente a vallePerso
5514
2525124
7575273
1101102108

Praticamente tutto ciò che è in volo. L'impostazione non è un difetto e ci sono feed in cui è la scelta giusta, ma dovrebbe essere scelta sapendo che un crash scarta ciò che è stato confermato e non ancora scritto, e che ciò è quasi tutto di un burst.

Nessun recupero al riavvio, perché perfuse run non ha un archivio duraturo. Una destinazione che non deve perdere messaggi durante un'interruzione richiede queue.enabled, che richiede il database che perfuse serve fornisce — e perfuse run ora rifiuta un tale canale invece di avviarlo senza la coda.

10.23.3 Un mittente che muore a metà di un messaggio

Il più pericoloso di questi difetti, perché un messaggio HL7 troncato di solito è comunque parsabile. I segmenti prima del taglio sono completi e ben formati, quindi un ricevitore non ha modo di sapere che PID e PV1 sono arrivati e i segmenti OBX che trasportano i risultati non sono arrivati.

Un frame è stato aperto, sei decimi di un messaggio inviati e la connessione resettata invece di chiusa. Il messaggio parziale non è stato consegnato, l'ascoltatore è sopravvissuto e un messaggio ben formato inviato subito dopo è stato accettato normalmente, quindi il frammento non è stato portato nel messaggio successivo.

Il registro di connessione segnala ora quanti byte di un frame non completato sono stati abbandonati, per ogni modalità di errore e non solo per una chiusura pulita. In precedenza, un mittente crashato, un processo interrotto e un cavo estratto segnalavano tutti messages=0 e nulla altro, il che non consente di distinguere un controllo di salute vuoto da un risultato di laboratorio scartato nove decimi del percorso.

10.23.4 Un disco pieno

L'esaurimento dello spazio viene rilevato e registrato invece di essere inghiottito. Due cose su di esso valgono la pena di essere conosciute.

Il mittente non riceve un rifiuto immediato. La consegna ritenta secondo il solito programma — un secondo, due, quattro, otto — e la conferma negativa arriva circa quindici secondi dopo. Un mittente il cui timeout è più breve di quello vede una connessione bloccata invece di un AE e concluderà che la rete è in errore invece del disco.

E un volume che segnala zero byte liberi può ancora accettare piccoli aggiornamenti per un po' di tempo, because l'aggiunta di un paio di centinaia di byte a un file il cui ultimo blocco ha spazio non richiede una nuova allocation. Il primo errore di scrittura si verifica più tardi del momento in cui il disco si è riempito.

10.23.5 Ciò che non è stato testato

Una directory di destinazione che perde l'autorizzazione di scrittura. Non poteva essere iniettato con chmod: il motore tiene aperto il file di output e il cambio della modalità di un file non influenza un descrittore già aperto su di esso. Testarlo correttamente richiede il volume rimontato in sola lettura o rimosso sotto il processo, il che non è stato fatto. È nominato qui invece di essere omesso, perché una lacuna che nessuno menziona legge come una lacuna che nessuno ha cercato.

11 Allarme

Niente al di fuori di Perfuse ti dirà che un flusso si è interrotto. Il mittente sta ricevendo conferme e ne è soddisfatto; il ricevitore non ha modo di sapere che un messaggio è stato inviato. L'allarme è l'unica cosa che si trova tra un'interfaccia rotta e qualcuno che se ne accorge settimane dopo.

11.1 I tipi di allarme

TipoSi attiva quando
error-rateI fallimenti superano una proporzione del traffico.
queue-depthUna coda ha più di N messaggi in attesa.
queue-ageIl messaggio più vecchio in coda è più vecchio di una durata.
queue-stuckUna coda non si sta svuotando affatto.
no-trafficNulla è arrivato per un periodo fisso.
below-rhythmIl traffico è ben al di sotto di ciò che questo flusso di lavoro fa normalmente *in questo momento della settimana*.
channel-downUn canale che dovrebbe essere in esecuzione non lo è.
script-errorsUno script sta fallendo.
rows-quarantinedUna sorgente del database sta mettendo da parte le righe.
slow-deliveryLe consegne stanno avendo successo ma stanno impiegando troppo tempo.
contractUn messaggio viola il contratto dichiarato del canale.
phi-volumeUn canale trasporta diverse volte la sua tariffa abituale per l'ora.
phi-after-hoursUn canale che trasporta solo traffico diurno trasporta alcuni di notte.
phi-new-destinationUn canale consegna a un indirizzo a cui non ha inviato prima.
phi-bulk-readsUna persona legge più di N record di pazienti diversi all'interno di un minuto.

Gli ultimi quattro controllano l'accesso ai dati dei pazienti e vengono descritti di seguito.

11.2 Il silenzio è la cosa più difficile da rilevare

Un canale che ha smesso di ricevere non produce errori. Non c'è nulla da contare. È per questo che esiste no-traffic e perché non è sufficiente da solo.

no-traffic è una soglia fissa: allerta se nulla è arrivato per, ad esempio, due ore. Su un feed che non si ferma mai, funziona. Su un feed di laboratorio di una clinica è inutile — il feed è silenzioso ogni notte e durante tutto il fine settimana, quindi una soglia di due ore allerta qualcuno alle 1 del mattino ogni notte, e una soglia abbastanza lunga da superare il fine settimana non noterà un guasto del martedì mattina fino al pomeriggio del martedì.

Non esiste un numero singolo che sia entrambi. Non è un problema di regolazione; è che la domanda "questo feed si è fermato" non può essere risposta da una costante quando il feed normale varia di un fattore di cento durante la settimana.

11.3 Rilevamento consapevole del ritmo

below-rhythm confronta il traffico attuale con ciò che questo canale fa normalmente in quest'ora di questo giorno della settimana.

Perfuse apprende la settimana di ogni canale dalla sua storia registrata: 168 bucket orari, lunedì per primo in modo che la settimana lavorativa sia contigua. Per ogni bucket, tiene un valore mediano, un valore basso e un valore alto, un minimo e quante osservazioni è basato su.

La soglia è una quota del normale, che di default è 0.8 (80 per cento nella console) — allerta quando il traffico scende al di sotto di quattro quinti di ciò che è normale per quest'ora.

11.3.1 Mediana, non media

Un singolo scarico di backlog di quarantamila messaggi contro un normale di trecento sposta la media abbastanza lontano da far sì che il feed possa andare completamente silenzioso senza mai scendere al di sotto di essa. La mediana non è influenzata da un'ora straordinaria, che è esattamente la proprietà necessaria.

11.3.2 Il minimo è un percentile, non il minimo

Se il ritmo di un canale è abbastanza affidabile da allertare è deciso dal suo estremo inferiore, non dal suo estremo superiore. Un allarme di carenza si attiva quando il traffico è *basso*, quindi solo l'estremo inferiore può dirti se produrrà falsi positivi. Una versione precedente di questo confrontava l'alto con la mediana e si sbagliava in entrambe le direzioni contemporaneamente: disqualificava un feed perfettamente stabile per un mese dopo un backlog e passava un feed genuinamente erratico che oscillava tra due e novecento messaggi nella stessa ora perché il suo alto era solo tre volte la sua mediana.

Il minimo è il ventesimo percentile piuttosto che il minimo, perché il minimo è trascinato a zero da una sola festa nazionale. E il percentile non è interpolato — ogni numero in un allarme alle 2 del mattino dovrebbe essere un conteggio che il feed ha effettivamente prodotto, non una media di due conteggi che non ha prodotto.

11.3.3 Dirà quando non può dire

Un canale senza storia alcuna è omesso completamente piuttosto che trattato come uno che si è fermato. Un nuovo canale non deve sembrare rotto.

Dove la storia è troppo sottile o troppo erratico per supportare un giudizio, la regola rifiuta di attivarsi piuttosto che indovinare. "Non posso onestamente dire" è una risposta di prima classe qui, e viene preferita a un allarme che è giusto leggermente più spesso del caso.

Le ore assenti all'interno della finestra di apprendimento sono registrate come zero reali, non come dati mancanti. La metà del segnale in un feed di clinica è *quando è legittimamente silenzioso*, e trattare quelle ore come sconosciute lo getterebbe via.

11.4 Impostazione degli allarmi

Dall'interfaccia, sotto Avvisi, per canale o per tutti. Ogni regola ha un tipo, una soglia e dove inviare l'avviso. Le regole vengono salvate in alerts.yaml accanto al database (o il file -alerts nomina) e hanno effetto immediato; fino al primo salvataggio le regole predefinite si applicano. Il file può anche essere modificato manualmente: il cambiamento viene raccolto entro trenta secondi e un file che non carica più viene segnalato nel log e le regole in vigore vengono mantenute.

Vale la pena farlo prima che un feed vada live piuttosto che dopo il primo incidente. L'insieme specifico di allarmi che vale la pena avere su qualsiasi feed clinico:

  1. below-rhythm — il feed si è fermato quando non dovrebbe essere silenzioso.
  2. error-rate — i messaggi stanno arrivando e fallendo.
  3. queue-age — qualcosa è bloccato piuttosto che semplicemente occupato.
  4. channel-down — il canale non sta funzionando affatto.

Il primo è quello che cattura il guasto che nessun altro segnalerà.

11.5 Controllare l'accesso ai dati dei pazienti

Una violazione raramente si annuncia. Sembra un flusso che trasporta più del solito, traffico alle tre del mattino su un canale che funziona solo durante le ore di ufficio, una destinazione che nessuno ha impostato o una persona che apre un paziente dopo l'altro. Perfuse controlla questi quattro aspetti, abilitati per default (serve -watch-access=false li disabilita), e segnala ciò che vede attraverso le regole di allarme sopra, in modo che sia configurato, confermato e consegnato come qualsiasi altro allarme.

Nessun canale viene giudicato fino a quando non ha trasportato 200 messaggi, perché "insolito" non significa nulla senza un modello. Il modello viene appreso dall'ultimo fortnight del negozio di messaggi quando il server si avvia, quindi un riavvio non fa sì che ogni canale diventi nuovamente nuovo. Tutto ciò che viene visto viene conservato per quindici minuti, poi l'allarme si cancella da solo.

Esso controlla e segnala solo. Non trattiene mai un messaggio o rifiuta una lettura: queste sono euristiche e un flusso fermato a causa di un'ipotesi errata è un problema clinico. Ogni allarme dice ciò che è stato visto e cosa potrebbe essere innocente, perché la maggior parte di essi sarà innocente.

Gli amministratori vedono ciò che il monitor ha appreso sullo schermo degli allarmi, sotto Controllo dell'accesso ai dati dei pazienti: il modello di ogni canale (ancora in fase di apprendimento, solo diurno o sia diurno che notturno), quanti destinatari conosce e tutto ciò che è stato visto negli ultimi quindici minuti, compreso ciò che è al di sotto della soglia di una regola.

11.6 Dove vanno gli allarmi

Gli avvisi possono essere inviati come JSON a un webhook (-alert-webhook: Slack, Teams, Mattermost, PagerDuty, Alertmanager o qualsiasi cosa che accetti un POST), inviati come trappole SNMPv2 a gestori SNMP (-snmp-traps, vedere SNMP), o scritti nel registro per un collector. Non c'è una consegna di posta elettronica di per sé: puntare il webhook a un relay se gli avvisi devono arrivare come posta elettronica.

Un allarme che è scritto solo nel log che nessuno legge non è un allarme. Se Perfuse è l'unica cosa che noterà un feed fermato, l'allarme deve raggiungere una persona.

12 L'archiviazione dei messaggi

Ogni messaggio che Perfuse riceve viene registrato, così come ricevuto, prima che venga modificato. Viene registrato anche ciò che è stato inviato a ogni destinazione e cosa gli è successo. L'archivio è un file SQLite specificato da -db.

12.1 Cosa viene conservato

Per messaggio: i byte grezzi così come sono arrivati, quando sono arrivati, quale canale, il tipo di messaggio parsato e l'evento di trigger, e l'esito del filtro.

Per destinazione per messaggio: i byte inviati, l'esito, il tempo impiegato e eventuali errori o risposte negative ricevute.

Questa è la forma che un'indagine richiede. "Cosa ci hanno inviato", "cosa abbiamo inviato loro" e "cosa hanno detto al riguardo" sono tre domande diverse e ognuna di esse viene posta.

12.2 Ricerca

Per canale, per intervallo di tempo, per esito, per tipo di messaggio e evento di trigger, e per valore di campo.

La ricerca per campo funziona sul messaggio parsato, quindi la ricerca di un numero di record lo trova ovunque nel messaggio che vive quel campo, piuttosto che corrispondere ai numeri in qualsiasi punto del testo. Una ricerca di testo per 12345 in un messaggio che contiene una quantità di 12345 trova un messaggio che non ha nulla a che fare con il paziente che si sta cercando.

12.3 Riproduzione e riprocessamento

Poiché l'originale viene conservato, un messaggio può essere eseguito nuovamente con la configurazione attuale.

Traccia prende un messaggio registrato e mostra cosa farebbe il canale con esso ora, senza inviare nulla. Coperto in debugging.

Riprocessa esegue effettivamente nuovamente il messaggio, compresa la consegna. Questo è ciò che risolve un batch di messaggi che non sono riusciti a causa di una destinazione configurata in modo errato: correggere la configurazione, selezionare i messaggi interessati, riprocessare.

Il riprocessamento consegna nuovamente. Se i messaggi sono stati parzialmente consegnati la prima volta, il riprocessamento produrrà duplicati nelle destinazioni che li hanno già ricevuti. Perfuse registra quali destinazioni sono state consegnate con successo, quindi il riprocessamento può essere limitato a quelle che non sono riuscite — fare questo invece di riprocessare tutto, a meno che il sistema di ricezione non deduplichi in base all'ID di controllo del messaggio.

12.4 Stagnazione

Una traccia di un messaggio vecchio contro la configurazione attuale risponde a un'ipotesi: cosa *sarebbe* successo ora. Quello è solitamente ciò che si vuole, ma non sempre — se si sta indagando su cosa è andato storto l'ultima volta, il canale potrebbe essere cambiato da allora.

Perfuse rileva questo e lo segnala. Una traccia di un messaggio che è arrivato prima dell'ultima modifica del canale è contrassegnata come tale, in modo che la risposta non venga scambiata per una ricostruzione di ciò che è effettivamente successo.

12.5 Ritenzione

L'archivio cresce. cleanup.periodDays controlla per quanto tempo vengono conservati i messaggi.

Due cose da considerare. I messaggi clinici possono essere soggetti a requisiti di ritenzione più lunghi di quelli che si sceglierebbero per motivi operativi, e l'archivio non è il sistema di registrazione — il sistema di ricezione lo è. La copia di Perfuse esiste per diagnosticare e riprocessare, e entrambe queste esigenze diminuiscono drasticamente dopo alcune settimane.

La ritenzione decide anche quanto storia il ritmo dell'apprendimento abbia a disposizione. Vedi alerting: una finestra di ritenzione più breve di alcune settimane lascia che non sia in grado di distinguere una domenica tranquilla da un flusso interrotto.

12.6 L'archivio contiene dati clinici

Questa è la parte di Perfuse che contiene informazioni sui pazienti e dovrebbe essere trattata come tale: su archiviazione crittografata, backup come dati clinici e accesso controllato. Vedi security.

I messaggi di test generati descritti in testing esistono in parte in modo che questi dati non debbano lasciare l'ambiente per riprodurre un problema altrove.

13 Debugging

La domanda è quasi sempre la stessa: questo messaggio è arrivato, qualcosa è andato storto, dove è cambiato? Perfuse risponde riproducendo un messaggio registrato attraverso la configurazione attuale e mostrando ogni passaggio.

Nessun messaggio viene inviato durante la tracciatura. Il canale continua a funzionare senza modifiche e non è necessario ridistribuire.

13.1 Tracciare un messaggio

Selezionare qualsiasi messaggio registrato e tracciarlo. Il risultato mostra, in ordine:

13.2 Passo dopo passo

La visualizzazione passo-passo esegue ogni trasformazione singolarmente e cattura l'intero messaggio dopo di essa. Una guida numerata dei passaggi, colorata in base a cosa è successo, e il messaggio come si presentava in ogni punto.

L'intero messaggio piuttosto che solo il cambiamento, perché il cambiamento spesso non è dove si trova il problema — un passaggio che ha modificato correttamente il campo a cui era destinato, in un messaggio in cui un passaggio precedente aveva già inserito la cosa sbagliata, sembra perfettamente corretto in isolamento.

13.3 Quattro esiti e la distinzione che conta

EsitoSignificato
changedIl passaggio è stato eseguito e ha modificato il messaggio.
no-effectIl passaggio è stato eseguito e il messaggio non è stato modificato.
skippedLa condizione when del passaggio era falsa, quindi non è stato eseguito.
failedIl passaggio ha generato un errore.

no-effect e skipped vengono segnalati separatamente, ed è questo il punto di tutta la funzionalità.

Dall'esterno sono identici: il messaggio è lo stesso dopo di che in entrambi i casi. Significano cose opposte. skipped significa che la condizione funziona come scritta e questo messaggio non è uno a cui si applica — di solito corretto. no-effect significa che il passaggio è stato eseguito e non ha trovato nulla da fare, il che di solito significa che è destinato a un campo che non c'è.

Un motore che segnala entrambi come "non è successo nulla" ti lascia incapace di distinguere una condizione funzionante da un percorso rotto, e questo è il bug di trasformazione più comune che esista.

Un passaggio che segnala no-effect su ogni messaggio è quasi sempre un percorso errato. L'intestazione del passo-passo conta quanti passaggi non hanno trovato nulla, che è il modo più veloce per individuarlo: un canale con tre passaggi e tre risultati no-effect non sta trasformando nulla.

13.4 Testare una modifica prima di salvarla

Il costruttore può eseguire una configurazione candidata contro il traffico registrato e segnalare cosa sarebbe diverso. Questo è il modo più sicuro per modificare un canale live: apportare la modifica, vedere cosa fa ai primi pochi messaggi reali, quindi salvare.

È anche il modo per scoprire che una modifica che sembra ovviamente corretta influisce su messaggi che non avevi pensato — un passaggio condizionato su un evento di trigger, su un flusso di dati che si scopre trasportare quattro.

13.5 Cosa la tracciatura non può dirti

Esegue la configurazione attuale. Se il canale è stato modificato dal momento in cui il messaggio è arrivato, la traccia è ipotetica piuttosto che una ricostruzione, e Perfuse la segnala come tale piuttosto che lasciare che la distinzione passi inosservata.

Non esercita anche il trasporto. Una traccia mostra cosa verrebbe inviato, non se la destinazione lo accetterebbe — un messaggio corretto e una destinazione che rifiuta le connessioni producono una traccia pulita e una consegna fallita. Quelli sono visibili nel record di consegna invece.

13.6 Script

Uno script è un passaggio opaco nella traccia. Perfuse può mostrare cosa è entrato e cosa ne è uscito, e non può mostrare cosa è successo nel mezzo o quali campi sono stati letti.

Questo è il costo concreto dell'utilizzo di uno script invece di passaggi dichiarativi, e vale la pena di valutarlo quando si sceglie. Vedere transformation.

14 Test

Il consiglio standard per testare un'interfaccia è costruire messaggi di esempio che riflettono il proprio ambiente — i codici del proprio laboratorio, la miscela di casi, le abitudini del mittente — e rimuovere i dati dei pazienti manualmente. Questo è lento, e farlo in modo incompleto è il risultato normale.

Perfuse offre tre cose al posto di questo: traffico generato che corrisponde alla forma di un flusso di dati senza il suo contenuto, un canale proposto da un esempio che qualcuno ti ha inviato, e un confronto con il motore che stai sostituendo.

14.1 Traffico di test generato

Se un canale ha gestito messaggi, Perfuse può produrre più messaggi simili

Cosa è fedele:

Cosa non è fedele, e questo è affermato piuttosto che implicito: coerenza clinica. Un paziente generato ha un numero di record non correlato, una stringa a forma di nome e una diagnosi senza alcuna relazione con l'osservazione. Questi messaggi esercitano un'interfaccia. Non sono un set di test clinici e non possono essere utilizzati per convalidare la logica clinica.

14.1.1 Perché non contiene dati reali

L'argomento è strutturale piuttosto che una pretesa di sforzo. L'unico input del generatore è il profilo del canale, e un profilo contiene tassi di riempimento, forme, lunghezze, conteggi di ripetizione e frequenze di segmenti. Non contiene valori.

L'unica eccezione sono i campi delle tabelle di codici, e un codice non identifica nessuno.

Questa è una garanzia più forte rispetto all'anonimizzazione dei messaggi reali, che è un processo che può essere eseguito in modo incompleto e di solito lo è. Qui non c'è alcun percorso attraverso il quale un nome potrebbe raggiungere l'output, perché il nome non era mai nell'input.

Ogni messaggio generato viene analizzato prima di essere restituito — un corpus non analizzabile manderebbe qualcuno a caccia di un bug nella propria interfaccia che in realtà è un bug del generatore — e ogni uno è contrassegnato con T in MSH-11, con un'applicazione e una struttura di invio sintetiche deliberate.

Un messaggio di test che non è contrassegnato come tale alla fine verrà trovato in un sistema di produzione da qualcuno che non ha modo di sapere che non era reale. Il T e il mittente sintetico non sono cosmetici.

14.2 Creazione di un canale da un campione

Incolla il messaggio che un laboratorio, un ospedale o un fornitore ti ha inviato per posta elettronica e Perfuse propone un canale per esso. Nulla deve essere in esecuzione prima.

Gestisce ciò che le persone effettivamente incollano: più messaggi in un blocco, qualsiasi terminazione di riga, framing MLLP che ha superato la copia e la nota di copertura sopra il messaggio. Rifiutare un campione perché è arrivato con terminazioni di riga Windows sarebbe un ostacolo piuttosto che un controllo.

14.2.1 Tre elenchi

La proposta viene con ciò che il campione mostra, ciò che è stato indovinato, e ciò che il campione non può dirti — tre elenchi separati, ponderati equamente nell'interfaccia.

Sono separati perché un lettore che non può dire quale è quale deve verificare tutto o fidarsi di tutto, e entrambi sono peggio che sapere dove cercare.

Da un singolo messaggio i limiti sono nominati specificamente piuttosto che in generale: quali campi sono opzionali, quali segmenti si ripetono, quali codici esistono oltre a quelli qui, se il mittente invia mai un evento di trigger diverso. Un avvertimento generale è qualcosa che le persone scorrono.

La fiducia è una parola — bassa, moderata, ragionevole — mai una percentuale. Una percentuale implica un calcolo, e questo è un giudizio su quanti campioni ci sono.

I segmenti Z vengono chiamati per nome, perché un segmento locale è la cosa che nessuna specifica menziona e la ragione più comune per cui un canale costruito da un modello standard non funziona.

14.2.2 L'avvertimento del separatore

Se il separatore di campo del campione non è il solito |, questo appare primo, e la fiducia scende a bassa.

Il motivo è un vero fallimento silenzioso. HL7 prende il separatore di campo dal messaggio stesso, quindi un campione i cui pipe sono stati sostituiti da look-alike tipografici — che è ciò che fa un elaboratore di testi — viene analizzato perfettamente in campi che sono tutti sbagliati. Nessun errore si verifica da nessuna parte.

Rifiutare un tale campione sarebbe sbagliato, perché un mittente può legittimamente utilizzare un altro separatore. Quindi viene segnalato, il carattere viene nominato e viene suggerito di chiedere un allegato di testo semplice.

14.3 Confronto con il vecchio motore

Prima di spostare un flusso live, la domanda è se Perfuse produce lo stesso output della cosa che è stata in esecuzione per anni. Nessuna quantità di qualità del design risponde a ciò. Vedi migration.

14.4 Verificare contro la cosa reale, nei contenitori

Tre controlli vengono eseguiti contro implementazioni reali piuttosto che contro l'idea di Perfuse di un protocollo. Essi vivono al di fuori di make check perché richiedono un runtime di contenitori e un controllo che richiede Docker è un controllo che le persone smettono di eseguire.

scripts/interop-up.sh avvia tutti e stampa cosa ognuno sblocca.

ContenitoreControlliCosa ha trovato
Keycloak 26web/e2e-saml/, e fixture internal/samlUn difetto. La forma canonica di una firma copre era calcolata con prefissi di namespace eliminati, quindi nessun vero fornitore di identità avrebbe potuto firmare qualcuno
Microsoft EntraTest e fixture internal/saml liveDue difetti, entrambi in ciò che circonda il protocollo. Un account è stato creato sotto l'ID non trasparente di Entra, perché la logica del nome leggibile desiderava una richiesta di posta elettronica e Entra non invia nulla. E un account SAML è stato registrato come OIDC, perché l'archivio derivava il protocollo da un emittente che sembra identico per entrambi
HAPI FHIRgo test ./internal/engine/ -run HAPIUn difetto. Un'autorità di assegnazione non mappata ha prodotto un sistema di identificatore che annuncia un OID e trasporta una parola, che HAPI ha accettato senza lamentarsi
ActiveMQgo test ./internal/engine/ -run RealBrokerCorretto, compreso il caso di framing con byte nulli. Affermato tramite l'interfaccia di gestione del broker stesso piuttosto che attraverso una funzione che restituisce nil
nginx, certificati clientgo test ./internal/engine/ -run ClientCertificateCorretto
Orthanc (un vero PACS)go test ./internal/engine/ -run RealPACSCorretto. Un C-STORE arriva e il nome del paziente, l'identificatore, la data di studio, la modalità e la classe SOP sopravvivono
PostgreSQLgo test ./internal/engine/ -run RealPostgresCorretto, e ha sollecitato un miglior errore: una dichiarazione nello spazio dei segnaposto del dialetto sbagliato è ora rifiutata quando salvata piuttosto che diventare un errore di sintassi nel server quando arriva un messaggio
OpenSSH sftp-servergo test ./internal/engine/ -run OpenSSHServerCorretto. I test SFTP esistenti utilizzano la stessa libreria Go su entrambi i lati; OpenSSH è un'altra implementazione e quella all'estremità opposta di quasi ogni flusso reale
Mirth 4.5.2go test ./internal/mirth/ -run RealMirthCorretto ora. L'unico fixture utilizzato in precedenza era scritto a mano e Mirth non lo caricava; scripts/mirth-author-channel.sh ha Mirth che ne crea uno invece, e Perfuse lo legge

Ognuno salta piuttosto che fallire quando il suo contenitore è assente, quindi make check passa su una macchina senza Docker.

Perché questo è separato dal resto della suite. Ogni altro test di queste funzionalità aveva entrambe le metà scritte qui: un documento che questo codice firmava, letto nuovamente dal codice che lo firmava. Questo è un accordo con se stessi, e vale meno di quanto sembri.

Il canonicalizzatore SAML è il caso che dimostra il punto. Portava mille righe di test, cinque di loro specificamente sulla canonicalizzazione, e tutti passavano mentre nessun vero fornitore di identità avrebbe potuto firmare qualcuno — la forma canonica che una firma copre era calcolata con prefissi di namespace eliminati, e l'unico modo per scoprirlo era consegnargli un documento che Perfuse non aveva scritto.

Due dei otto controlli hanno trovato difetti diretti, e un terzo ha sollecitato un miglioramento reale. Tre non hanno trovato nulla di sbagliato. Questa proporzione è l'argomento per mantenere tutti: un controllo che passa ha detto qualcosa che non si sarebbe potuto sapere altrimenti, e non c'era modo di sapere in anticipo quali sarebbero stati.

Un modello degno di nota, perché è apparso in entrambi i difetti: l'accettazione non è verifica. HAPI ha accettato il sistema di identificatore malformato e lo ha archiviato; il difetto è apparso solo leggendo la risorsa nuovamente. Un ricevitore che tollera qualcosa non è una prova che sia giusto, solo che questo ricevitore era indulgente.

Due affermazioni catturate sono state commitate, in internal/saml/testdata/keycloak-assertion.xml e entra-response.xml, con test su entrambi — quindi quella particolare regressione viene catturata senza un contenitore.

Entrambi sono necessari piuttosto che uno essere di riserva. Keycloak antepone il suo assert e la firma, Entra no, e questi sono i due casi opposti nella canonicalizzazione — che è esattamente dove si trova il difetto. Un test afferma che ogni documento copre ancora il proprio caso, perché una cattura di sostituzione che è accaduta per caso è stata prefissata e avrebbe dimezzato la copertura senza fallire nulla. La lezione generale non si generalizza così a buon mercato: per qualsiasi altra cosa, il contenitore è il controllo.

14.5 Diagnosi di un test che fallisce una volta e non più

Un test che fallisce in un'esecuzione completa e passa sedici volte da solo non è un test instabile. È un test che condivide qualcosa con l'esecuzione, e il modo per scoprire cosa è misurare la cosa condivisa piuttosto che il test.

Due strumenti esistono per questo, e entrambi sono destinati a essere eseguiti accanto a una suite 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

Ognuno scopre i porti dell'esecuzione dal file di stato della configurazione e campiona ogni 500 millisecondi fino a quando il server esce. Registrano ogni campione piuttosto che solo i fallimenti, che è ciò che li rende utili: un picco si verifica in un'esecuzione in cui nulla è fallito, quindi un difetto che appare una volta in tre esecuzioni diventa misurabile in ognuna.

Impostare PERFUSE_E2E_KEEP=1 per mantenere la directory temporanea, che contiene il database così come è stato lasciato e il log del server per l'intera esecuzione. Il log del server è di solito la risposta. In un caso investigato, ha registrato l'arresto di un canale e la riassociazione del suo listener 421 millisecondi dopo, e la connessione rifiutata della sonda è caduta all'interno di quella finestra.

Leggere la traccia invece di error-context.md, che è stato vuoto in più di un'occasione in cui la traccia conteneva il messaggio reale.

Copiare gli artefatti prima di eseguire nuovamente qualsiasi cosa. Un'esecuzione superata cancella test-results, quindi la traccia del fallimento che si sta indagando scompare nel momento in cui si tenta di riprodurlo. Una volta perso, la domanda che avrebbe risposto non può essere più risposta.

Fermare i contenitori di interop prima. Fermarli prima di un'esecuzione completa del browser e avviarli con ./scripts/interop-up.sh in seguito se sono ancora necessari.

Otto contenitori occupano circa 9,8 GB di memoria e su una macchina senza molto più di quello c'è troppo poco spazio per i processi di Chromium, node e la catena di strumenti Go insieme. Ciò che produce non è un errore di memoria esaurita, ma un renderer che smette di essere pianificato: una traccia registrata mostra un intervallo di 60,2 secondi senza frame, durante il quale Playwright ha atteso che un pulsante diventasse "visibile, abilitato e stabile" e non ha potuto ottenere due frame di animazione consecutivi da confrontare. Il server era sano durante l'intera esecuzione, la richiesta più lenta dell'intera esecuzione essendo di 154 millisecondi.

Quel fallimento si legge come un difetto nel test che è capitato di eseguire. Vale la pena conoscere la forma di esso: ogni richiesta veloce, la pagina visivamente congelata, il ciclo di ritentativi che non raggiunge mai una seconda iterazione e l'intera cosa che passa in isolamento.

Una sola esecuzione alla volta. La suite condivide un server, una sessione di accesso in web/e2e/.auth/admin.json e un file di stato che nomina il processo del server. Nessuno di questi è per esecuzione, quindi una seconda esecuzione che inizia mentre la prima è in corso sovrascrive il file di stato e qualsiasi teardown che finisce per primo uccide il server dell'altra esecuzione e cancella la sua sessione.

Ciò che sembra non è affatto la causa. Ha prodotto un'esecuzione di 279 fallimenti il cui primo messaggio era ENOENT: no such file or directory, open './e2e/.auth/admin.json', un'esecuzione che si è fermata presto segnalando 217 passati e due test falliti con bind: address already in use — nessuno di questi suggerisce due esecuzioni in lotta. La suite ora prende un lucchetto e rifiuta di avviarsi, nominando il processo che lo detiene. Un lucchetto lasciato da un'esecuzione interrotta è preso in carico piuttosto che bloccare per sempre, perché una misura di sicurezza che blocca la suite è una cosa che qualcuno cancella insieme alla sicurezza.

Una trappola correlata, ora risolta: due specifiche hanno nominato i loro porti di ascolto direttamente, quindi un server lasciato indietro da un'esecuzione interrotta li ha fatti fallire su qualcosa con cui non avevano nulla a che fare. I porti sono ora richiesti al sistema operativo.

Non rispondere a nessuna di queste con ritentativi. Un test che passa al secondo tentativo ha trovato una vera corsa e l'ha nascosta, e playwright.config.ts imposta retries: 0 per questo motivo.

Un'avvertenza: campionare ogni 100 millisecondi ha generato venti processi al secondo, allungato un'esecuzione della metà e fallito due test su timeout che non avevano nulla di sbagliato. Uno strumento che cambia ciò che misura produce risultati su se stesso.

14.6 Ciò che ancora necessita di infrastrutture reali

Diverse parti di Perfuse sono implementate e non sono mai state esercitate contro la cosa reale. Sono elencate qui piuttosto che lasciate alla scoperta:

Le funzionalità in questo capitolo e nel prossimo esistono in modo che possiate raccogliere le vostre prove piuttosto che prendere la parola di qualcun altro.

14.7 Misurato contro corpora di conformità pubblici

Una suite di test il cui fixture è stato scritto qui dimostra l'accordo con se stessi. Questi sono i dati di altre persone.

14.7.1 FHIR R4, gli esempi della specifica

Tutti i 2.912 file di esempio pubblicati con la specifica FHIR R4 — ogni esempio che gli autori dello standard hanno scritto.

RisultatoConteggio
Risorse convalidate senza riscontri13.723
Risorse segnalate non valide0
File rifiutati come tipo di risorsa non implementato753
Voci del bundle saltate come tipo non implementato1.348

Nessuna risorsa è stata convalidata in modo errato. Ogni fallimento è un rifiuto esplicito che nomina il tipo che non può leggere — 672 ValueSet, 80 ConceptMap e un Parameters. Un convalidatore che passa silenziosamente ciò che non capisce è peggiore di uno che lo dice.

Il corpus ha trovato un difetto, che è il motivo per cui viene eseguito. La convalida di un bundle ha stampato "La convalida del bundle da un file non è ancora supportata" e ha continuato. Ciò era falso in entrambe le direzioni: i bundle le cui voci sono casualmente dei tipi che il parser può tenere sono già stati convalidati e un bundle che era genuinamente non valido ha prodotto la stessa riga, non ha contato nulla e ha uscito zero — compreso sotto -strict, che esiste in modo che questo possa bloccare una build. Quarantadue dei bundle della specifica stessa sono stati saltati.

I bundle sono ora convalidati voce per voce, con tre risultati tenuti separati: una voce che è errata fallisce e nomina il campo, una voce di un tipo che questa build non può leggere è contata come saltata e segnalata e un bundle che trasporta nessun corpo di risorsa non è né. Lo stesso corpus è passato da 2.100 risorse controllate a 13.723.

14.7.2 HL7 v2, il corpus di test HAPI

I fixture di messaggio da HAPI, l'implementazione Java di riferimento HL7 v2 — materiale deliberatamente scomodo, compresi payload uuencoded, delimitatori sfuggiti e gruppi ripetuti.

59 messaggi, 59 parsati, nulla rifiutato. Sette tipi di messaggio in un corpus che ogni singolo sistema descriverebbe come una cosa, che è il punto perfuse profile esiste per fare.

14.7.3 Ciò che non è stato eseguito

DICOM contro un set di conformità pubblico e X12 contro un corpus pubblicato. Nessuno dei due è stato fatto e nessuno dei due dovrebbe essere inferito dai due precedenti.

15 Migrazione da Mirth

Due cose sono necessarie per sostituire un motore funzionante: i canali devono essere trasferiti e qualcuno deve essere in grado di dimostrare che il sostituto produce lo stesso output. Perfuse esegue la prima importando le esportazioni di Mirth e la seconda confrontando i due motori con il proprio traffico.

Tutto ciò che è contenuto in questo capitolo si applica ugualmente a Open Integration Engine e BridgeLink. Mirth Connect ha smesso di essere open source alla versione 4.6 nel marzo 2025; OIE (ospitato dalla Eclipse Foundation) e BridgeLink (Innovar Healthcare) sono le fork che continuano la linea open-source e entrambi scrivono gli stessi formati di esportazione. L'importatore è testato contro tutti e tre, di seguito.

15.1 Importazione dei canali

Perfuse legge ogni esportazione scritta da questi motori:

EsportazioneDall'amministratoreCiò che viene trasferito
Un canaleEsporta canaleIl canale
Un gruppo di canaliEsporta gruppoOgni canale in esso, ciascuno che mantiene il gruppo
Modelli di codiceEsporta modelli di codiceOgni libreria come un file di script
Un backup del serverBackup configurazione o GET /api/server/configurationTutti i precedenti contemporaneamente

Puntare perfuse translate su uno di essi o rilasciarne uno su Amministra → Migra:

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

Una libreria di modelli di codice diventa lib/<library>.js accanto ai canali e ogni canale per cui Mirth aveva abilitata la libreria ottiene scripts.include: [lib/<library>.js] — quindi un trasformatore che chiama una funzione del sito come formatMRN() la trova ancora. Un canale per cui la libreria non era abilitata non la include, perché i suoi script non potevano vederla in Mirth. I frammenti di trascinamento e rilascio vengono esclusi: Mirth li incolla solo manualmente in un passaggio, quindi non sono codice che viene eseguito autonomamente. Nel browser, l'importazione di un canale salva prima le librerie che include.

Un Channel Writer nomina il canale a cui consegna per id. In un gruppo o in un backup, l'obiettivo è nello stesso documento, quindi diventa una destinazione channel che nomina quel canale; da un'esportazione a canale singolo viene segnalato per essere compilato. Gli script globali a livello di server non hanno un equivalente in Perfuse e vengono segnalati anziché eliminati.

La relazione dice, per canale, se è stato tradotto correttamente, tradotto con avvisi o non può essere letto.

Il titolo è una frazione con il denominatore — "37 di 40 pronti" — perché "37 pronti" non dice nulla su ciò che si deve ancora fare.

Un canale che non può essere letto è un problema diverso da uno che non può essere tradotto. Il primo significa che il XML stesso non è stato analizzato e di solito è un'esportazione troncata o parziale; il secondo significa che il contenuto del canale ha qualcosa senza un equivalente in Perfuse. L'importazione li separa.

15.2 Ciò che si traduce e ciò che richiede una decisione

Le sorgenti, le destinazioni, i filtri e i passaggi del trasformatore ordinario si traducono direttamente. I connettori che si traducono: TCP/MLLP (e TCP grezzo con il framing), HTTP, File, Database, JavaScript, DICOM, Web Service (SOAP), SMTP e Channel Reader/Writer. JMS e il Document Writer non si traducono e sono segnalati come blocchi.

Un passaggio Mapper che imposta una variabile la inserisce nella mappa con il nome del suo ambito — channelMap per default — esattamente come fa Mirth, in modo che passaggi successivi che la leggono con $('name') la trovino.

I trasformatori JavaScript non lo fanno in generale. I canali Mirth contengono spesso codice sostanziale in un trasformatore e non c'è una conversione automatica da JavaScript arbitrario a passaggi dichiarativi. L'importatore li segnala piuttosto che tentare una traduzione che potrebbe essere sottilmente errata: un trasformatore mal tradotto è peggiore di uno segnalato per un essere umano, perché verrà eseguito.

Dove uno script deve effettivamente rimanere uno script, Perfuse può eseguirlo — vedere la chiave scripts nel riferimento canale — al costo della traccia a livello di passaggio descritta in debugging.

15.3 Ciò che l'importatore è stato testato

Cinque motori, ognuno che scrive i propri documenti: 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 un piccolo programma contro i jar di ogni motore e utilizza il proprio serializzatore per scrivere tre canali ordinari — un flusso MLLP con un mapper, uno script che chiama una libreria di modelli di codice e un filtro; un flusso HTTP in un database; un sondaggio file su MLLP — più la libreria e un gruppo di canali. Li carica nel motore in esecuzione e scarica il backup del server del motore. I risultati vengono commitati in internal/mirth/testdata/engines/, e la suite di test controlla l'importatore per ognuno di essi in ogni build: ogni backup viene letto, tradotto, caricato e il canale ADT viene eseguito con due messaggi per verificare che la libreria riempia il numero di record e il filtro scarti il risultato.

Le esportazioni di Perfuse vanno nell'altro senso — i canali Perfuse importati in ogni motore in esecuzione e verificati che il motore non li memorizzi come non validi. Tutti e cinque accettano ogni trasporto esportato da Perfuse. Open Integration Engine 4.7.0 ha aggiunto due impostazioni HTTP senza equivalente qui: un mittente HTTP legato a un indirizzo locale scelto viene segnalato come avvertimento, e un limite di intestazione di richiesta dell'ascoltatore HTTP solo quando è superiore al 1 MB accettato da Perfuse.

La prima esecuzione contro questo corpus ha trovato quattro difetti, tutti risolti: il traduttore rifiutava le sorgenti HTTP e File come "solo MLLP è supportato" molto tempo dopo che Perfuse aveva entrambi; leggeva l'indirizzo di un mittente HTTP da un campo che nessuno dei motori scrive; traduceva la dimensione del buffer di socket di Mirth come un limite di messaggio di 64 KB; e una variabile di un Mapper diventava una globale JavaScript che $('mrn') non vedeva mai, quindi la libreria riempiva una stringa vuota.

La fixture a canale singolo che ha iniziato questo è stata esportata anche da Mirth 4.5.2, autore di Mirth stesso e non scritta qui. Questa distinzione ha guadagnato il suo posto: l'unica fixture in questo repository utilizzata era scritta a mano e un vero Mirth non la caricherà - l'API accetta il POST e quindi archivia il canale come This channel is invalid. Verify all required extensions are loaded correctly, con ogni connettore di destinazione scartato.

Scrivere a mano non avrebbe mai funzionato, e il motivo vale la pena di conoscerlo se si stanno producendo esportazioni proprie. Il serialiser di Mirth ignora gli elementi che non riconosce, quindi un nome di elemento errato non produce alcun errore - il connettore semplicemente non c'è dopo.

scripts/mirth-author-channel.sh costruisce uno utilizzando le classi di modello di Mirth e il suo own serialiser, poi lo invia a un server in esecuzione e fallisce se il server lo rifiuta. L'importatore di Perfuse legge il risultato: nome, trasporto di origine e destinazioni tutte sopravvivono.

15.4 Dimostrare che corrisponde

Questa è la parte che decide se una migrazione avviene, e ha bisogno di prove piuttosto che di fiducia.

Perfuse confronta la sua own uscita contro quella del vecchio motore, messaggio per messaggio, sul traffico. Ciò di cui ha bisogno sono coppie: il messaggio come è arrivato, e il messaggio che il vecchio motore ha prodotto da esso. Entrambi sono nel message store di Mirth e possono essere esportati dal browser dei messaggi.

Perfuse non può raggiungere Mirth, e questo manuale non pretenderà di farlo. Uno strumento che afferma di verificare una migrazione senza mai vedere l'uscita effettiva del vecchio motore starebbe verificando nulla. Fornire le coppie è l'onesto aspetto dell'esercizio.

15.4.1 Quattro numeri, non una percentuale di passaggio

RisultatoSignificato
IdenticoByte per byte lo stesso.
Solo cosmeticoDifferisce in modi che non portano informazioni - campi vuoti alla fine, un terminatore finale.
DifferenteIl valore di un campo è diverso.
Non eseguibilePerfuse non poteva elaborare il messaggio affatto.

Sono quattro numeri perché significano quattro cose diverse e collassarli nasconde quelli che hanno bisogno di una decisione.

Identico significa byte per byte, non equivalente. Un test più debole permetterebbe differenze nell'ordine dei segmenti o separatori alla fine, e quelli sono esattamente ciò che un sistema a valle pignolo rifiuta.

Le differenze cosmetiche sono contate separatamente piuttosto che piegate nella colonna dei buoni. Portano veramente informazioni, quindi trattarle come fallimenti seppellirebbe le scoperte reali sotto migliaia di nulla - ma non sono identiche nemmeno, e un ricevitore che fa la sua own analisi rigorosa può non essere d'accordo.

"Non eseguibile" è separato da "diverso" perché è solitamente una lacuna di configurazione che l'importatore non poteva riempire, non una decisione di mappatura. Se tutto è in quella colonna, il verdetto dice così e dice di guardare la configurazione prima di leggere qualsiasi altra cosa.

15.4.2 Le differenze sono raggruppate per campo

Un'esecuzione su cinquantamila messaggi che segnala quattromila differenze non ha detto nulla che si possa agire. La stessa esecuzione che segnala che PID-8 differisce in ogni messaggio perché il vecchio motore scriveva Male dove Perfuse scrive M ha detto esattamente una cosa da decidere.

Quindi ogni scoperta è un campo, con un conteggio, e dice se la differenza è sistematica - la stessa coppia di valori ogni volta - o se il contenuto del campo differisce.

Quella distinzione è la cosa più utile nel report. Una coppia di valori distinti su quattromila messaggi è una singola decisione di mappatura. Quattromila coppie di valori distinte è il contenuto che differisce, che è un problema diverso e molto peggiore, e i due non devono leggere allo stesso modo.

Le scoperte sono ordinate per quanti messaggi influenzano, quindi la causa singola più grande è prima.

15.4.3 Il verdetto non arrotonda

Fornisce conteggi esatti: 49.993 su 50.000, non "oltre il 99%". I sette sono il punto di eseguire.

È scritto per essere citabile in una richiesta di modifica, perché è lì che finisce il numero.

15.5 Una sequenza suggerita

  1. Importare i canali e risolvere tutto ciò che viene segnalato come illeggibile.
  2. Per ogni canale, esaminare gli avvisi. La maggior parte saranno script.
  3. Esportare alcune migliaia di coppie di messaggi da Mirth per il canale più trafficato e eseguire il confronto.
  4. Lavorare sui risultati. Quelli sistematici sono una decisione ciascuno.
  5. Eseguire nuovamente fino a quando le sole differenze sono quelle che si sono deciso siano corrette.
  6. Eseguire Perfuse in modalità ombra accanto a Mirth su traffico live, consegnando da nessuna parte, e confrontare nuovamente su un periodo che include un fine settimana e una fine mese.
  7. Passare a un canale, non a tutti.

15.6 Ciò che funziona solo sul software di un fornitore

La schermata di migrazione risponde a una seconda domanda, e vale la pena chiederla prima di avere un'opinione su Perfuse: quanto della logica di integrazione può funzionare solo sul software che si possiede.

Ogni canale ottiene un verdetto di Portabilità, dalla stessa scansione che produce le note di migrazione. Esegue contro un'esportazione del canale, quindi non richiede nulla installato e non modifica nulla.

15.6.1 La distinzione è l'intero punto

La maggior parte del Java nei script di Mirth non è di blocco. SimpleDateFormat, HashMap, Apache Commons — tutto funziona intorno a un motore JavaScript del 2009, tutto è ordinario, tutto ha equivalenti diretti. Un canale con trecento di quelle referenze è completamente portabile, e uno strumento che riporta "300 referenze Java, siete intrappolati" starebbe mentendo.

Il blocco è specificamente le chiamate che necessitano del server del fornitore: com.mirth.connect.* e jar del fornitore. Cinque di quelle e si è bloccati. Cinquecento dell'altro tipo e si è liberi.

Quindi il verdetto inizia con il numero che conta e dice nella stessa frase che il numero più grande non è quello. Dove ci sono chiamate del fornitore, sono elencate per nome — un conteggio è un'asserzione, e un elenco è qualcosa che il proprio ingegnere può andare a controllare.

Una terza categoria è tenuta separata: capacità che esiste ma non da uno script. Avviare un canale da JavaScript non ha equivalente qui, e c'è un endpoint API che fa esattamente la stessa cosa. Chiamare quel blocco sarebbe esagerare il risultato.

15.6.2 Chiamate Java che funzionano invariati

Le classi Java più comuni vengono eseguite come sono scritte. Perfuse non ha un runtime Java, quindi queste sono classi JavaScript con gli stessi nomi e metodi, sufficienti per il modo in cui gli script del canale li utilizzano; importPackage(java.util) e importClass(...) li portano nell'ambito dei loro nomi brevi, come in Rhino (i Date, Map, Set, Math, String e Boolean di JavaScript non vengono mai sostituiti: quelli Java sono ancora lì con il nome completo). Il rapporto di migrazione conta ogni chiamata a questi come già supportata.

PacchettoClassi
java.utilArrayList, LinkedList, Vector, List, Collection, HashMap, LinkedHashMap, Hashtable, TreeMap, Properties, HashSet, LinkedHashSet, TreeSet, Arrays, Collections, Date, Calendar, GregorianCalendar, UUID, Base64, regex.Pattern (con Matcher), concurrent.ConcurrentHashMap
java.langString, StringBuilder, StringBuffer, Integer, Long, Short, Byte, Double, Float, Boolean, Math, System (solo tempo e separatore di riga)
java.text, java.math, java.net, java.nioSimpleDateFormat e DateFormat (lettere del modello di Mirth), BigDecimal (come un double), URLEncoder, URLDecoder, StandardCharsets
Apache Commonslang3.StringUtils e lang.StringUtils (circa sessanta metodi), StringEscapeUtils, codec.binary.Base64

Si comportano come Java dove gli script dipendono da esso: Integer.parseInt("x") lancia NumberFormatException, String.replaceAll e split accettano espressioni regolari mentre replace è letterale, le mappe chiave stringhe per valore, TreeMap e TreeSet iterano in ordine, e SimpleDateFormat.parse restituisce una data getTime() funziona su. Un metodo che uno script chiama che l'equivalente manca fallisce in quella riga, nominandolo; qualsiasi altra classe Java fallisce per nome, come prima. BigDecimal è un doppio qui, quindi non mantiene l'aritmetica decimale esatta di Java: controllare gli script che lo utilizzano per il denaro.

15.6.3 Gli script esterni vengono segnalati come sconosciuti

Un passaggio che esegue un file di script esterno fa riferimento a un percorso sul vecchio server, e il file non è nell'esportazione. Non si può dire nulla su cosa contenga, quindi viene conteggiato come sconosciuto piuttosto che assunto in un modo o nell'altro. Recuperare quei file prima di concludere qualcosa — in entrambe le direzioni.

15.6.4 Il blocco di Perfuse, dichiarato nella stessa frase

Questa sezione sarebbe disonesta senza di esso.

Perfuse è Apache 2.0, che è irrevocabile per il codice già rilasciato. È possibile forkare ciò che esiste oggi e nessuno può revocare quello. I canali sono file YAML e gli script sono JavaScript ordinari, quindi non c'è una superficie proprietaria da chiamare — il sapore di Java di Mirth è structuralmente non disponibile qui, che è il posto in cui una limitazione è genuinamente una funzione.

Ciò che non promette: che una versione futura rimanga aperta, che un servizio ospitato esista a un prezzo che si desidera, o che la migrazione da Perfuse non costi nulla. Spostare qualsiasi livello di integrazione significa ritestare ogni canale contro traffico reale. Ciò che si sta scegliendo è se gli artefatti che si costruiscono sono leggibili e portabili, e se l'uscita dipende da una licenza che qualcun altro controlla.

15.6.5 Impostazione del passaggio 6

One message real traffic Live channel unchanged Candidate the version you are testing Receiver delivers nothing Comparison field by field The candidate sees the same real messages as the live channel and delivers none of them. Only the live channel reaches the receiver. What you read afterwards is where the two disagreed, field by field — not a pass or a fail.

La sezione Shadow avvia un confronto. Scegliere il canale che è in esecuzione, scegliere il candidato da confrontare contro dall'elenco e avviare.

Tre cose su di esso valgono la pena di sapere prima di affidarsi ai numeri.

Il candidato è scelto da un elenco, non digitato. Un'ombra nomina un file di canale e un nome che non si risolve rende il canale *live* non valido — Perfuse rifiuta un canale nel suo complesso quando qualcosa a cui fa riferimento è rotto. Quindi un errore di digitazione non produce un avvertimento, ma fa scomparire il canale in esecuzione.

La quota è una percentuale. Ridurla solo su un feed occupato e conoscere i costi: il campionamento riduce il lavoro e la fiducia nella stessa proporzione, e il messaggio che avrebbe mostrato la differenza è quello insolito.

I campi da ignorare sono solitamente necessari. Un canale che stampa un timestamp o un numero di sequenza differisce in ogni singolo messaggio, che segnala un tasso di differenza del 100% e non ti dice nulla. MSH-7 e MSH-10 sono la coppia comune.

Un confronto viene scritto nel file del canale non appena lo si avvia e inizia l'osservazione quando il canale viene caricato nuovamente — lo schermo lo dice invece di affermare che è già in esecuzione. Interrompere un confronto lascia il canale candidato al suo posto, perché il candidato è la cosa destinata a essere messa in linea.

Il passo 6 è quello che non può essere abbreviato. Le differenze che contano sono solitamente nel traffico che appare solo occasionalmente — un evento di trigger raro, un batch di fine mese, un mittente che si comporta diversamente a mezzanotte — e un campione preso nel pomeriggio non le conterrà.

15.7 Tornare indietro dall'altra parte

Un canale può essere esportato come file di canale Mirth, dal browser: Canali, quindi A Mirth sul canale desiderato.

Ciò esiste perché l'obiezione a sostituire un motore funzionante raramente riguarda se il sostituto sia buono. È ciò che accade se la decisione si rivela sbagliata, e un'esportazione che torna indietro dal modo in cui è arrivata è la risposta più economica a ciò.

Leggere ciò che il dialogo ti dice prima di prendere il file. Il formato di Mirth non ha posto per un filtro Perfuse, una catena di trasformazione, un contratto o un confronto di ombra, quindi un canale esportato fa meno di quello da cui proviene. I trasporti e i loro indirizzi si convertono; la logica no. Ogni perdita è elencata per nome prima che il file venga offerto, e la stessa lista viene inserita nella descrizione del canale in modo che chi lo importa lo veda anche.

Un canale che Mirth non può esprimere viene rifiutato piuttosto che approssimato. Una destinazione S3 non ha un equivalente Mirth, e un canale che importa pulito mentre consegna da qualche altra parte oltre al bucket sarebbe peggiore di nessun file affatto. Il rifiuto nomina la destinazione in colpa.

Le definizioni dei connettori non vengono scritte da una lettura del formato di Mirth. scripts/mirth-dump-connector-templates.sh ha il serializzatore di Mirth che produce i valori predefiniti per ogni classe di connettori, e Perfuse sostituisce i valori in quei documenti — rifiutando ogni impostazione che il modello non contenga già. Ciò conta a causa di come Mirth risponde a un canale che non può analizzare: non rifiuta l'importazione. Memorizza un canale la cui descrizione è stata sostituita con "Questo canale non è valido. Verificare che tutte le estensioni richieste siano caricate correttamente" e le cui destinazioni sono state eliminate silenziosamente. Un esportatore verificato contro la sua stessa uscita piuttosto che contro un server supera ogni test mentre produce documenti che vengono scartati, che è esattamente ciò che è successo qui prima che le esportazioni venissero provate contro un Mirth in esecuzione.

Ciò che attraversa oggi: MLLP e TCP in entrambe le direzioni, HTTP in entrambe le direzioni, lettura e scrittura di file, lettura e scrittura di database, DICOM in entrambe le direzioni, e destinazioni SMTP, SOAP e JavaScript. Ogni coppia viene verificata importando in un Mirth 4.5.2 reale e verificando che il server non abbia sostituito silenziosamente il canale.

16 CMS-0057 per i pagatori

La regola finale di interoperabilità e autorizzazione preventiva del CMS (CMS-0057-F) richiede ai pagatori interessati — organizzazioni Medicare Advantage, programmi Medicaid e CHIP statali e i loro piani di assistenza sanitaria gestita, e gli emittenti QHP sui mercati federali — di eseguire quattro API FHIR a partire dal 1° gennaio 2027, e di pubblicare le metriche di autorizzazione preventiva sul loro sito web pubblico ogni anno a partire dal 2026.

Perfuse fornisce le quattro API nel suo endpoint FHIR e le conversioni che le riempiono: reclami liquidati come CARIN Blue Button, autorizzazioni preventive come Da Vinci PDex, e le metriche annuali nel layout del modello del CMS. La vista CMS-0057, sotto Exchange, dice quali delle quattro questa istanza può rispondere e cosa ogni ancora necessita, e esegue tutte e tre le conversioni nel browser.

I farmaci sono fuori dall'ambito in tutto, come lo sono nelle disposizioni di autorizzazione preventiva della regola: nessuna richiesta di farmaci, nessun formulari, e una riga di metriche che nomina un farmaco viene rifiutata piuttosto che conteggiata.

16.1 Le quattro API

APIChe serveGuideAttivato da
Accesso pazienteLe richieste, i dati clinici e le autorizzazioni precedenti di un membro, a un'app che sceglieCARIN Blue Button 2.2.0, PDex 2.2.0, US Core, SMART App Launch-fhir e un emittente SMART (-smart-issuer)
Accesso fornitoreLo stesso per i membri attribuiti a un fornitore, in bloccoPDex 2.2.0, Da Vinci ATR 2.1.0, Bulk Data-fhir-payer-apis e -fhir-bulk-export
Payer-to-PayerIl record di un membro a un altro pagatore, dopo averlo abbinatoHRex 1.2.0 $member-match, PDex 2.2.0-fhir-payer-apis
Autorizzazione preventivaCiò di cui un ordine ha bisogno, la documentazione, quindi la richiesta e la decisioneDa Vinci CRD, DTR e PAS 2.2.x (2.2.1, 2.2.0, 2.2.1) e 2.1.0, con traduzione X12 278-fhir, scrivibile, e -crd-rules

L'API di accesso ai pazienti non richiede un'operazione propria: si tratta del normale lettura e ricerca dell'endpoint FHIR, protetto da SMART, con risorse CARIN e PDex nel negozio. La ricerca di ExplanationOfBenefit supporta i parametri con nomi CARIN — patient, identifier, type, service-date, billable-period-start, provider, insurer, coverage — e Coverage supporta subscriber-id, identifier e payor.

16.1.1 Due versioni delle guide: 2.1.0 e 2.2.x

CMS-0057-F raccomanda CRD, DTR e PAS 2.0.1 e 2.1.0. Le versioni 2.0.1 si basano su US Core 3.1.1, che è scaduto il 1° gennaio 2026, quindi la versione 2.1.0 è la versione che un sistema di registrazioni elettroniche sanitarie costruito per la regola probabilmente parlerà; le più recenti sono CRD 2.2.1, DTR 2.2.0 e PAS 2.2.1. Perfuse risponde in entrambe. Determina quale versione parla il chiamante, più specifica per prima:

  1. dalla richiesta: estensione CDS Hooks di CRD davinci-crd.requestedVersion ("2.1"), o la versione su un profilo Da Vinci di un input DTR o PAS (profile-pas-request-bundle|2.1.0);
  2. dalla registrazione del chiamante: davinci_version: "2.1" su un client SMART (-smart-clients) o un client CDS (-cds-clients);
  3. dal server: serve -davinci-version 2.1; il valore predefinito è 2.2.
clients:
  - issuer: https://ehr.example.org
    jwks_url: https://ehr.example.org/.well-known/jwks.json
    davinci_version: "2.1"

Ogni risposta è decisa e mantenuta nella forma 2.2.x e riscritta per un chiamante 2.1.0 come viene inviata, quindi le regole, la coda di revisione, il collegamento X12 278 e le metriche sono le stesse per entrambi. La riscrittura copre ciò che le versioni scrivono in modo diverso: CRD 2.1.0 non ha indeterminate (Perfuse dice condizionale, con il motivo) e non ha una categoria in un dettaglio di copertura; DTR 2.1.0 nomina il pacchetto PackageBundle e lascia la risposta del questionario all'app; PAS 2.1.0 risponde con un solo Bundle alla richiesta $inquire e manca delle estensioni del revisore e della trasmissione. L'elenco completo e il controllo con ogni guida 2.1.0 è in conformance/davinci21. Una notifica PAS segue -davinci-version, poiché un abbonamento non specifica quale versione il suo proprietario legge.

16.2 Requisiti e documentazione di copertura: CRD e DTR

L'API di autorizzazione preventiva è in pratica tre guide Da Vinci insieme. CRD dice al clinico, mentre l'ordine è ancora uno schema, se è coperto, se necessita di autorizzazione preventiva e quale documentazione è richiesta. DTR consegna all'EHR il questionario che raccoglie quella documentazione. PAS invia la richiesta e restituisce la decisione. Perfuse serve tutti e tre come pagatore.

-crd-rules rules.yaml serve CRD tramite CDS Hooks all'indirizzo /cds-services: tutti e sei degli hook di CRD, order-sign, order-select, order-dispatch, appointment-book, encounter-start e encounter-discharge, ciascuno con un prefetch per la copertura attiva del paziente. I due hook di encounter prefetchano anche l'incontro e rispondono riguardo all'incontro stesso, abbinato per tipo e tipo di servizio, come appointment-book risponde riguardo a un appuntamento. Le regole sono le politiche del pagatore, mantenute in un file perché cambiano senza rilasci 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

Ogni ordine riceve un aggiornamento systemActions che trasporta l'estensione delle informazioni di copertura del CRD - che il sistema EHR memorizza sull'ordine e invia successivamente con l'autorizzazione preventiva - e una carta che il clinico legge. Un ordine il cui codice non ha regole viene risposto come conditional, mai assunto come coperto; una richiesta senza copertura alcuna riceve una carta che lo indica. La cartella examples/crd/ contiene un file di regole e un questionario corrispondente.

Una regola può anche trasportare il resto di ciò che CRD consente a un pagatore di dire:

Ciò che il registro elettronico dei pazienti (EHR) non ha prelevato in anticipo, Perfuse legge dal fhirServer dell'EHR con il token che ha inviato. Se fallisce, la risposta è indeterminate con il motivo technical di CRD, mai un'ipotesi. Una Copertura che è terminata o non è attiva viene risposta come not-covered, no-active-coverage.

members: fhir nel file di regole risolve la copertura contro i propri record del pagatore in questo server FHIR (avviarlo con -fhir), gli stessi record che $member-match legge:

con quel numero.

La discovery dichiara davinci-crd.version e un'opzione di configurazione coverage-info. Quando un client disattiva l'opzione, la risposta è vuota. I JWT EHR vengono verificati come li definisce CDS Hooks, con iss, aud, exp, iat e jti e senza sub, e un jti ripetuto viene rifiutato.

Le chiamate si autenticano con il JWT che un EHR firma per ogni chiamata, da un emittente nominato in -cds-clients con il suo URL JWKS - che è come CDS Hooks lo descrive - o con un token API Perfuse. La scoperta è aperta, come richiede CDS Hooks.

DTR: caricare i questionari nel punto di terminazione FHIR e POST /fhir/Questionnaire/$questionnaire-package li restituisce come bundle di pacchetti DTR, con le librerie CQL che nominano. La richiesta può nominare il questionario o inviare l'ordine e lasciare che le informazioni di copertura dicano quale.

Provarlo: Payers → Claims & auth → Coverage requirements (CRD) invia un ordine alle regole di questo server o all'URL del servizio CDS di un pagatore e mostra le carte e le informazioni di copertura.

16.3 Reclami come CARIN Blue Button

perfuse cms0057 carinbb accoppia ogni reclamo in un 837 con il suo pagamento in un 835, in base al numero di account del paziente che l'835 è richiesto di restituire, e scrive una transazione FHIR per ciascuno: l'ExplanationOfBenefit con il paziente, la copertura, le organizzazioni e i professionisti che fa riferimento.

perfuse cms0057 carinbb -system https://fhir.your-plan.org/identifier -network innetwork \
    claims.837 remittance.835

Il profilo segue il reclamo: i reclami professionali (837P) diventano C4BB-ExplanationOfBenefit-Professional-NonClinician, e quelli istituzionali (837I) inpatient o outpatient in base al tipo di fattura. Ogni voce è un PUT con un id preso dagli identificatori di origine, in modo che caricare due volte lo stesso reclamo lo aggiorna invece di crearne una seconda copia.

Tre cose non sono presenti in nessuno dei file X12 e ciascuna viene gestita dicendo che non ci sono invece di ipotizzare:

Le diagnosi vengono scritte con il loro punto decimale (J02.9, non J029), perché è così che il sistema di codici li pubblica e un server di terminologia chiesto sulla grafia diversa dice che non esiste. L'identificatore del membro di un dipendente è quello dell'iscritto, che è ciò che l'837 trasporta, e le note lo dicono. Un NPI il cui cifra di controllo è errata viene segnalato prima che US Core lo rifiuti.

16.4 Autorizzazioni preventive come PDex

perfuse cms0057 priorauth converte una risposta Da Vinci PAS ClaimResponse — o il bundle di risposta PAS che la trasporta — in una spiegazione PDex di autorizzazione preventiva ExplanationOfBenefit, che è ciò che servono tutti e tre i dati API.

perfuse cms0057 priorauth pas-response.json pas-claim.json

La richiesta PAS è opzionale e quasi sempre necessaria. Un ExplanationOfBenefit deve indicare quale copertura è stata utilizzata per la decisione e solo la richiesta la trasporta; senza di essa la conversione si ferma e lo segnala. L'azione di revisione — approvata, rifiutata, sospesa, con il suo numero di autorizzazione e motivo — si sposta dall'estensione PAS a PDex, e il tipo di servizio X12 mantiene il suo codice sotto l'URI a cui PDex lo associa.

16.5 Le API di accesso ai fornitori e di comunicazione tra pagatori

Con -fhir-payer-apis l'endpoint FHIR risponde a tre operazioni aggiuntive:

Le esportazioni applicano le esclusioni della regola in uscita. Le pretese perdono il pagamento e ogni importo di condivisione dei costi e rimborso, e mantengono i servizi, i codici, le date e i fornitori; il profilo CARIN viene rimosso da meta.profile perché la risorsa non soddisfa più tale profilo. La comunicazione tra pagatori esclude anche le autorizzazioni preventive rifiutate. I membri che detengono un consenso attivo di opt-out PDex Provider Access sono esclusi dall'esportazione del fornitore e il registro indica quanti. Il parametro patient può restringersi solo ai membri del gruppo; il nome di chiunque altro viene rifiutato.

L'accesso all'esportazione di un Gruppo è deciso dall'autenticazione dell'endpoint. Gli ambiti SMART dicono quali tipi di risorsa un token può leggere, non quale Gruppo, quindi ogni fornitore necessita di un token che possa raggiungere solo la propria lista di attribuzione. Un token API può essere limitato ai Gruppi quando viene creato — perfuse token create -label riverside-provider-access -fhir-groups riverside-attributed, o il campo Limita ai Gruppi FHIR sotto Utenti → Credenziali macchina — e sul punto di terminazione FHIR può quindi leggere quei Gruppi, eseguire $davinci-data-export o $export su di essi e recuperare ciò che l'esportazione ha prodotto, e nulla altro. Un token di un altro fornitore risponde non trovato piuttosto che vietato, quindi un token non apprende quali altre liste di attribuzione esistono; ogni altra richiesta, inclusa la corrispondenza dei membri e la ricerca ordinaria, viene rifiutata. Il limite si applica ai token API; un token da un emittente SMART non porta alcun limite di Gruppo. Quando SMART è configurato anche, i token API vengono rifiutati a meno che Impostazioni → FHIR → Accetta token API Perfuse accanto ai token SMART non sia attivato (vedere Sicurezza, *Chi può chiamare il punto di terminazione FHIR*); un token del Gruppo di un fornitore limitato necessita di esso.

16.6 Un elenco dei fornitori: Plan-Net

CMS-0057 chiede anche ai pagatori un elenco dei fornitori e il punto di terminazione FHIR serve uno a Da Vinci Plan-Net 1.1.0 senza opzione per attivarlo: caricare i Practitioners, PractitionerRoles, Organizations, OrganizationAffiliations, Locations, HealthcareServices, InsurancePlans e Endpoints, e le app dei membri possono cercarli. Ogni parametro di ricerca Plan-Net è indicizzato - il ruolo di rete e servizio, l'area di copertura di un piano, l'organizzazione partecipante di un'affiliazione, l'organizzazione partof - insieme agli include e alle catene inverse (_has) che le query della guida utilizzano, e la CapabilityStatement elenca i profili Plan-Net.

La suite Plan-Net di Inferno supera 199 test. I 10 test che non supera sono catene di collegamento in cui il kit prende il valore di ricerca dal primo organizzazione che ha visto invece che da una delle risorse cercate; ciò è stato segnalato al kit (problema 34) e il server risponde correttamente a quelle query quando viene fornito un valore che i dati contengono.

16.7 Metriche di autorizzazione preventiva

perfuse cms0057 metrics legge un file CSV di decisioni esportate dal sistema di gestione dell'utilizzo e produce la pagina pubblica richiesta da CMS, nel layout della sua *Rapporto e modello di metriche di autorizzazione preventiva*.

perfuse cms0057 metrics -year 2025 -org "Springfield Health Plan" -services services.csv \
    decisions.csv > prior-authorization-metrics-2025.html

Le colonne vengono trovate per intestazione: priority, received, decided e decision sono obbligatorie, e request_id, line_of_business, extended, appealed, appeal_decision, service_code e service_description vengono letti quando presenti. Una richiesta appartiene all'anno in cui è stata decisa; una richiesta ancora in sospeso viene elencata come esclusa, mai conteggiata. Ogni riga che non può essere letta viene segnalata con il suo numero di riga.

L'aritmetica segue il modello: per richieste standard ed accelerate separatamente, la quota approvata e rifiutata, approvata e rifiutata entro il termine di decisione, approvata dopo l'estensione del tempo di revisione e approvata dopo appello — su appelli, non su richieste — con la media e la mediana del tempo da ricezione a decisione. Una mediana inferiore a un giorno viene scritta in ore anziché arrotondata a "0 giorni", che il modello chiede esplicitamente. Le richieste parzialmente approvate vengono conteggiate come approvate, poiché il modello non ha una categoria per esse, e la pagina indica quante ce ne sono state. Le metriche vengono segnalate per linea di business, che è il livello richiesto da CMS.

La pagina è autonoma — nessuno script, nessun foglio di stile esterno o font — perché è pubblicata su un sito web pubblico da chiunque lo mantenga, e qualsiasi cosa carichi da altrove è qualcosa che può rompersi o tracciare un visitatore. -format csv e -format json forniscono gli stessi numeri per altri usi. Senza -services la pagina riporta un avviso che l'elenco di elementi e servizi che richiedono autorizzazione preventiva è mancante, perché CMS lo richiede sulla stessa pagina.

16.8 Farmaci: il prontuario, il beneficio prescrittivo in tempo reale e l'autorizzazione preventiva elettronica

CMS-0062-P (proposto il 14 aprile 2026) introdurrebbe i farmaci nell'autorizzazione preventiva: i pagatori interessati supporterebbero l'autorizzazione preventiva elettronica NCPDP SCRIPT, lo standard NCPDP Formulary & Benefit e il beneficio prescrittivo in tempo reale NCPDP a partire dal 1 ottobre 2027, deciderebbero le richieste di farmaci entro 24 ore (accelerato) e 72 ore (standard), fornirebbero una ragione specifica per ogni diniego e segnalerebbero le metriche dei farmaci a partire dal 2028. Medicare Part D richiede già l'autorizzazione preventiva elettronica SCRIPT. Un file, il formulario, risponde a tutte queste richieste:

perfuse serve -fhir -pas -crd-rules payer-rules.yaml -formulary formulary.yaml

examples/formulary/formulary.yaml è un esempio il cui farmaci sono concetti RxNorm reali con NDC elencati in RxNav. Un file nomina il pagatore, i suoi piani (ognuno con il formulario che utilizza, i suoi ID di gruppo e le sue quote di costo per beneficio farmaceutico e fascia) e i suoi formulari. Ogni farmaco è un RxNorm SCD o SBD con il suo gruppo RxNorm (lo SCDG o SBDG richiesto dall'API Drug Formulary), i suoi NDC, una fascia e i suoi limiti: prior_authorization, step_therapy, quantity_limit (una quantità in un numero di giorni scorrevole e una quantità massima giornaliera), not_covered, alternatives (codici RxNorm, più preferiti per primi), notes e questionnaire, l'URL canonico del questionario FHIR per l'autorizzazione preventiva. cost_30_day è il costo del piano per una fornitura di 30 giorni, che è una percentuale della copertura assicurativa; senza di esso, la copertura assicurativa è indicata come una percentuale, mai come un importo inventato. L'intero file viene verificato quando viene caricato, ogni problema viene elencato contemporaneamente. Un membro viene trovato dall'elenco members del file, per gruppo o attraverso il negozio FHIR: una Coverage il cui subscriberId è l'ID del membro e il cui class di tipo plan è l'ID del piano. Payers › Drugs visualizza il formulario, prezza un farmaco ed esegue un'autorizzazione preventiva dall'inizio alla fine.

16.8.1 L'API Da Vinci US Drug Formulary

Pubblicato in /formulary/fhir come Da Vinci US Drug Formulary 2.1.0: ogni piano è un PayerInsurancePlan, ogni formulario è un Formulary (entrambi InsurancePlan), ogni farmaco è un FormularyDrug (MedicationKnowledge) e ogni voce è un FormularyItem (Basic). Le ricerche della guida vengono servite (Basic?code=formulary-item&formulary=...&drug-tier=...&pharmacy-benefit-type=...&period=..., subject:MedicationKnowledge.code, InsurancePlan?formulary-coverage=..., coverage-type, MedicationKnowledge?code=...&doseform=...) con _include=Basic:subject, Basic:formulary e InsurancePlan:formulary-coverage. È pubblico, senza credenziali, come richiesto da CMS per il formulario di un pagatore: viene servito da un negozio dedicato, in memoria, che contiene solo il formulario e non può quindi accedere al record di un paziente. È di sola lettura. Un farmaco escluso non viene pubblicato, poiché l'API elenca ciò che il formulario copre; RTPB e ePA rispondono comunque come non coperto. Verificato con il validatore HL7 FHIR contro il pacchetto 2.1.0 della guida con terminologia verificata: ogni risorsa generata dal campione non contiene errori.

16.8.2 Beneficio prescrittivo in tempo reale

POST /ncpdp/rtpb accetta un RTPBRequest (NCPDP RTPB v13) con un token API del ruolo operatore e risponde con un RTPBResponse dal formulario: lo stato di copertura, lo stato del formulario, la quota stimata del membro e del piano, e le restrizioni di copertura, con fino a cinque alternative coperte prezzate allo stesso modo. I codici di restrizione e lo stato a cui ogni codice si riferisce seguono le Raccomandazioni di implementazione RTPB pubbliche di NCPDP: 75 autorizzazione preventiva richiesta, 608 terapia a gradini, 76 limiti del piano superati, 7X giorni di fornitura oltre il limite del piano (un farmaco non disponibile per posta, ad esempio), 70 non coperto, tutti *coperti con restrizioni* (CR) tranne 70 (NC). Un membro con un'autorizzazione preventiva approvata in archivio ottiene CC e AB8, come richiesto dalla guida Surescripts, in modo che il prescrittore non debba chiedere di nuovo. Una richiesta che non può essere prezzata è NotProcessed con un codice di rifiuto NCPDP: 52 per un membro non trovato, E7 e 19 per una quantità o fornitura mancante. Il beneficio farmaceutico viene letto dalla richiesta: una fornitura superiore a 34 giorni è una fornitura di tre mesi e il tipo di farmacia M è la posta.

16.8.3 Autorizzazione preventiva elettronica (NCPDP SCRIPT)

POST /ncpdp/script accetta PAInitiationRequest, PARequest, PAAppealRequest e PACancelRequest con un token API del ruolo operatore e risponde a ciascuno con la sua risposta:

RichiestaRisposta
PAInitiationRequestClosed quando non è necessario: CC nessuna autorizzazione preventiva richiesta, FN all'interno del limite di quantità, FM non coperto o non nella formulary, FQ un'autorizzazione approvata in archivio, CD nessun membro trovato, CG una già in corso. Altrimenti Open, con un ID di caso e l'insieme di domande.
PARequestDeciso come una richiesta PAS: Approved con il numero di autorizzazione e il periodo, Denied con il motivo, o Open in revisione.
PAAppealRequestUn caso respinto deciso di nuovo, sul motivo in PANote (un appello senza uno viene richiesto).
PACancelRequestApproved mentre il caso è aperto o in revisione, e la richiesta PAS viene cancellata; Denied una volta che è stata decisa.

L'insieme di domande è il questionario FHIR del farmaco dal negozio FHIR, lo stesso utilizzato da DTR per compilare: un valore booleano diventa una scelta sì/no, una scelta una scelta, un numero un valore numerico, una data una data e qualsiasi altra cosa un testo libero; i gruppi vengono appiattiti in ordine e enableWhen non viene mantenuto, poiché SCRIPT ramifica in base alla scelta e non alle condizioni. Un farmaco senza questionario viene chiesto tre domande a testo libero: la diagnosi, cosa è stato provato e perché questo farmaco. Una PARequest diventa una richiesta Da Vinci PAS: una Claim per il farmaco (RxNorm e NDC), la MedicationRequest che richiede, il paziente, il prescrittore, il pagatore e la copertura, e le risposte come una QuestionnaireResponse, con eventuali allegati come DocumentReference. Viene quindi deciso come ogni autorizzazione preventiva su questo server: il file delle regole, un servizio di decisione (-pas-decider-url), o la coda del revisore, dove viene contrassegnato Farmaco e mantenuto all'interno dei tempi del farmaco. Un servizio di decisione vede una richiesta di farmaco esattamente come vede una richiesta da un client PAS di un sistema di cartella clinica elettronica. Consigliamo Vaglio, il motore di decisione open source (PolyForm Shield) di BioDream, che dispone di politiche per farmaci con terapia a gradini; il motore di un pagatore si collega attraverso lo stesso -pas-decider-url e non ne è necessario uno per il file delle regole e i revisori per decidere.

Una decisione presa dopo che la richiesta è stata risposta (di un revisore, di un appello) viene inviata al prescrittore come un PAResponse o PAAppealResponse non sollecitato, instradato al canale denominato da -epa-reply-channel, che lo consegna alla rete. Senza di esso, o quando la consegna fallisce, il caso afferma che il prescrittore non è stato informato e lo schermo lo invia nuovamente.

Payers › Drugs › Prior authorization invia i messaggi che il sistema di un prescrittore invierebbe al proprio endpoint del server (inizia, risponde alle domande, visualizza la decisione), elenca ogni caso con ciò che il prescrittore è stato informato e visualizza le cifre dei farmaci che CMS-0062-P propone: richieste approvate, negate e in sospeso, appellate e approvate o negate in appello, la media e la mediana delle ore dalla richiesta alla decisione e quanti sono stati decisi in ritardo. I farmaci a beneficio medico richiesti attraverso PAS (un codice HCPCS J con un MedicationRequest o un articolo codificato in RxNorm o NDC) sono conteggiati come farmaci nelle cifre PAS anche.

Cosa si basa questo, espresso chiaramente. Gli schemi e le guide di implementazione di NCPDP sono concessi in licenza. I nomi degli elementi e l'ordine seguito qui seguono le guide companion pubbliche di Surescripts ePA e RTPB e i loro esempi, e le raccomandazioni pubbliche di NCPDP per RTPB. Due elementi che il materiale pubblico non mostra mai sono scritti nel modello SCRIPT utilizzato altrove e dovrebbero essere verificati contro una copia concessa in licenza prima della certificazione: Closed/ReasonCode e Denied/DenialReason. Nessun messaggio è stato verificato contro lo XSD di NCPDP o la certificazione di una rete. Il file di formulari e benefici di NCPDP non viene prodotto: il suo layout completo è nella guida concessa in licenza di NCPDP e un file parziale verrebbe rifiutato dalla rete che lo carica.

16.9 Cosa è stato verificato e contro cosa

Le uscite CARIN e PDex sono state convalidate con il validator ufficiale HL7 FHIR, caricato con i pacchetti pubblicati (hl7.fhir.us.carin-bb#2.2.0, hl7.fhir.us.davinci-pdex#2.2.0): professionale, ricoveri e degenze, e due decisioni PAS, senza errori. Gli input PDex sono stati gli esempi della guida PAS stessa invece delle forme scritte qui per concordare con il convertitore. Il validator ha trovato cinque difetti al primo ciclo — tra cui il fatto che CARIN richiede la versione del profilo in meta.profile e la versione del codice di sistema del tipo di richiesta sulle richieste istituzionali — e ognuno è stato corretto e coperto da un test.

La costruzione di questo ha trovato un difetto più vecchio di esso: il negozio FHIR eliminava ogni elemento che il suo modello interno non dichiarava, quindi una ExplanationOfBenefit perdeva i suoi elementi, le diagnosi, l'addebito e il pagamento durante il percorso di ingresso. Il negozio ora mantiene qualsiasi risorsa che trasporta e un test carica una richiesta CARIN attraverso il server e la legge nuovamente intera.

L'output di CRD - l'ordine aggiornato e la risposta CDS Hooks contro il modello logico di CRD - e l'output del pacchetto DTR convalidano nel validatore ufficiale HL7 contro CRD 2.2.1 e DTR 2.2.0 senza errori.

DTR qui è il lato del pagatore di 2.2.0. $questionnaire-package prende i questionari denominati, quelli denominati da CRD in un ordine, o l'ID di affermazione di copertura restituito da CRD (context, mentre lo stesso processo serve CRD), e restituisce ogni questionario come un pacchetto bundle con una QuestionnaireResponse da compilare, le Libraries che il suo CQL necessita e le loro dipendenze. I set di valori che le sue risposte utilizzano viaggiano nel pacchetto quando vengono caricati (PUT /fhir/ValueSet/{id}), e $expand elenca i loro codici. $log-questionnaire-errors scrive cosa un'app DTR segnala al log del server.

Questionari adattivi: scrivere l'intero questionario una volta, con l'estensione questionnaireAdaptive di SDC e enableWhen sulle domande che si applicano solo a volte. Il pacchetto consegna all'app un guscio vuoto, e ogni chiamata $next-question aggiunge la prossima domanda che si applica alle risposte finora, fino a quando non c'è più nulla da chiedere e la risposta è segnata come completata. L'ordine e la ramificazione sono le regole del pagatore; le domande che non si applicano non vengono mai visualizzate.

Accedere come client: i client DTR e PAS raggiungono il pagatore con i servizi SMART Backend - un JWT firmato scambiato per un token sul server di autorizzazione del pagatore. Puntare Perfuse su quel server con -smart-issuer (e -smart-jwks se il suo indirizzo non si risolve da Perfuse), e passare -smart-backend-services in modo che il documento di scoperta lo dica. La suite Inferno DTR passa in questo modo con Keycloak come server di autorizzazione.

Perfuse può essere quel server di autorizzazione stesso: serve -fhir -smart-clients clients.yaml emette token Backend Services a /auth/token ai client elencati, ogni token con le chiavi pubbliche che utilizza per firmare le sue affermazioni e gli ambiti di sistema che può essere concesso, e l'endpoint FHIR accetta tali token. Non è necessario un server di identità separato per i client machine-to-machine del pagatore.

Con -smart-users users.yaml inoltre, i membri e i clinici si accedono lì per autorizzare le app, che l'API di accesso del paziente necessita: l'app invia la persona a /auth/authorize, si accede, un clinico sceglie il paziente e entrambi visualizzano cosa l'app chiede e possono deselezionare qualsiasi parte di esso. Un membro riceve solo il proprio record, qualsiasi cosa l'app chieda. Ogni persona nel file nomina la risorsa FHIR che è, Patient/… o Practitioner/…, e un hash della password da perfuse smart hash; la password stessa non viene mai scritta.

Le persone possono accedere all'organizzazione del proprio fornitore di identità invece: -smart-oidc oidc.yaml nomina il fornitore (emittente, ID client e dove si trova il segreto), e la pagina di accesso offre "Accedi con" accanto alla password. Ogni persona è collegata dal soggetto del fornitore, oidc_subject nel file degli utenti, quindi il file decide ancora chi può autorizzare le app e quale risorsa FHIR è; un account collegato a nessuno viene rifiutato. I codici, i token di aggiornamento e le revocazioni vengono conservati nel database, quindi un riavvio non disconnette nessuno.

Utenti → App SMART nella console elenca le app registrate e le persone, e aggiunge, modifica e rimuove gli elementi. Ogni salvataggio viene verificato come i file all'avvio, scritto su di essi e utilizzato subito. Un'app confidenziale salvata senza un segreto riceve uno, mostrato una volta; una password viene impostata lì e non viene più mostrata. La rimozione di un'app o di una persona interrompe i token di accesso già emessi per essa o concesso da essa subito, non quando scadono, e i token di aggiornamento con essi.

Gli ambiti possono essere granulari, come SMART App Launch 2 e US Core li definiscono: patient/Observation.rs?category=laboratory legge solo le Observations che la ricerca troverebbe. Una concessione filtrata per un tipo applica il suo filtro a ogni ricerca e a ogni lettura di quel tipo; una concessione non filtrata per il tipo, o per *, la solleva. Un filtro che non può essere letto non concede nulla invece di tutto.

16.10 Decidere le richieste di autorizzazione preventiva: PAS

serve -fhir -pas -crd-rules rules.yaml risponde a Da Vinci PAS 2.2.1 a POST /fhir/Claim/$submit e POST /fhir/Claim/$inquire. Le decisioni provengono dallo stesso file di regole delle risposte di CRD, quindi l'ordine in cui un clinico viene informato che è necessaria l'autorizzazione è deciso dalla regola che lo ha detto:

  - 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

Ogni elemento ottiene un'azione di revisione X12: A1 certificato, A3 non certificato, A4 sospeso, A6 modificato, C annullato (tipo di certificazione 3). Una riga che non nomina un servizio non viene decisa ma risponde con un errore (X12 901 AG, correggere e rinviare). La risposta ripete ciò che una risposta 278 ripete — numeri di tracciamento degli elementi, le date dei servizi richiesti, le date dell'incontro, gli identificatori di trasmissione con mittente e destinatario scambiati — e fornisce a ogni riga il numero di riferimento amministrativo del pagatore. Un servizio che non viene nominato da alcuna regola viene sospeso e non approvato: una decisione che nessuno ha scritto è una decisione per una persona.

Richieste sospese attendono un revisore, che risponde con 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 può anche essere modify: certificato, ma non come richiesto, con quantity (valueDecimal, le unità certificate) e/o alternative (valueCoding, il servizio approvato al posto). La risposta dice quindi A6 Modificato, con il dettaglio certificato o l'alternativa come elemento aggiunto, e un numero di autorizzazione. item (valueInteger, ripetibile) limita la decisione a determinate righe. La decisione diventa una nuova versione della risposta, contrassegnata come esaminata da una persona, e con -fhir-subscriptions viene consegnata sul topic PAS (PASSubscriptionTopic, filtrato per org-identifier, l'identificatore dell'organizzazione richiedente) come il bundle di risposta PAS completo, nella stessa transazione che la registra. $inquire restituisce la risposta corrente a ogni richiesta che il fornitore ha fatto su quel membro; un'altra richiesta di un fornitore non trova nulla. $decide richiede un ambito di scrittura; $inquire è una lettura.

Le richieste e ogni versione delle loro risposte vengono mantenute in pas_requests e pas_responses nel database del server.

16.10.1 La coda del revisore

Nella console web, Payers → CMS-0057 → Reviewer queue elenca le richieste sospese in scadenza più vicina per prime: una richiesta accelerata (Claim.priority stat) scade 72 ore dopo il suo arrivo, una standard 7 giorni. La scelta di una di esse mostra il membro, il fornitore, ogni servizio con le unità richieste e il suo stato, ciò che la risposta ha richiesto e ogni documento ricevuto per esso, con documenti in testo semplice visualizzati in linea. Un editor registra la decisione lì: approvare, rifiutare o modificare (unità certificate o un altro servizio approvato al posto), con un motivo e il numero NPI del revisore. Una modifica deve certificare meno unità di quelle richieste; altrettante o più sono un'approvazione e vengono rifiutate come modifica. Un servizio approvato al posto inizia nel sistema di codici di quello richiesto. È la stessa decisione che $decide prende, quindi la sottoscrizione del fornitore la consegna. La lettura di una richiesta e la decisione su di essa vengono scritte entrambe nel registro di controllo.

Monitor → Team dashboards → Prior authorization mostra, per gli ultimi 30 giorni, quanti richiesti standard e accelerati sono stati decisi entro i tempi previsti dal CMS-0057, decisi in ritardo, ancora in attesa di tempo e scaduti adesso, con il tempo mediano per decidere, e come sono state risposte le richieste di servizi: approvate, modificate, negate o ancora pendenti. Queste due piastrelle vengono lette dalle richieste stesse, quindi non sono nell'esportazione Grafana del dashboard, che lo specifica nella sua descrizione.

16.10.2 Ricezione dei documenti richiesti da una richiesta pendente

Una risposta pendente richiede documenti con un Task e una CommunicationRequest per ogni documento. Un questionario è richiesto come descritto da PAS: una CommunicationRequest con il singolo codice LOINC 102089-0, sotto il numero di traccia della riga per cui è richiesto (itemTraceNumber, che la ClaimResponse echeggia; una riga inviata senza uno ne riceve uno). Quel numero di traccia è il contesto DTR: $questionnaire-package con solo context impostato su di esso restituisce il questionario. Il fornitore invia ciò che è stato richiesto con Da Vinci CDex $submit-attachment (POST /fhir/$submit-attachment): il TrackingId è il numero di traccia della richiesta (il primo identificatore della ClaimResponse, che è anche il Task), o un identificatore della CommunicationRequest, AttachTo è preauthorization, e MemberId deve essere il membro della richiesta. Ogni allegato DocumentReference o QuestionnaireResponse è mantenuto con la richiesta e mostrato al suo revisore; un documento in arrivo decide nulla.

16.10.3 Decisione in un sistema di gestione dell'utilizzo X12

La maggior parte dei pagatori decide le autorizzazioni preventive in un sistema UM che parla X12 278. Con -pas-278-url, Perfuse è il front-end FHIR di quel sistema: ogni $submit viene inviato come una richiesta 278 (005010X217), ogni elemento un evento del paziente. Ognuno trasporta ciò che PAS chiama per esso: il tipo di revisione (extension-serviceItemRequestType, UM01: servizi sanitari, ammissione o assistenza specialistica), il tipo di certificazione (extension-certificationType, UM02), il tipo di servizio, il luogo di servizio (UM04), il livello di servizio (extension-levelOfServiceCode, UM06: elettivo, urgente o di emergenza; una priorità stat sostituisce l'urgente), la data, le date di ammissione e dimissione di una revisione di ammissione, le diagnosi, il fornitore del team di assistenza che eseguirà il servizio e la procedura e la quantità, come servizio professionale (SV1) o, in una richiesta di rimborso istituzionale, una linea di servizio dell'ospedale (SV2). Il codice di azione e il numero di autorizzazione della risposta 278 diventano l'azione di revisione dell'elemento: certificato, in parte o modificato, rifiutato, sospeso, annullato o non considerato (sospeso per un revisore, con i motivi di rifiuto). Le regole locali non vengono consultate.

perfuse serve -fhir -pas -pas-278-url https://um.example/x12/278 -pas-278-receiver ACMEUM \
  -pas-278-token-env UM_TOKEN

Un sistema di gestione dell'assistenza sanitaria che sospende inizialmente e decide in seguito pubblica la sua risposta 278 successiva a POST /fhir/Claim/$decide-278; ogni evento viene abbinato alla sua richiesta dal numero di tracciamento inviato da Perfuse e viene deciso come $decide lo deciderebbe. Se il sistema di gestione dell'assistenza sanitaria non può essere raggiunto o risponde con qualcosa che non è una risposta 278, ogni elemento viene sospeso per un revisore e il fornitore viene informato solo di ciò; il motivo è nel registro del server.

Richieste a cui risponde il sistema UM

Un fornitore di $inquire deve trovare un'autorizzazione però sia stata richiesta: per fax, attraverso il portale del pagatore, per telefono o in un 278 che un altro mittente ha inviato. Perfuse conserva solo le richieste che sono state inviate attraverso di esso; il sistema UM le conserva tutte. Quindi con un sistema UM che risponde in tempo reale (ogni trasporto tranne sftp), ogni $inquire viene anche inviato lì come una richiesta di autorizzazione 278 (005010X215: BHT02 28, il membro, il fornitore, il numero di autorizzazione dal insurance.preAuthRef della richiesta quando è presente e le date di evento da billablePeriod o le date di servizio degli elementi, altrimenti un anno prima o dopo oggi). Ogni autorizzazione che la risposta contiene che Perfuse non ha (abbbinata ai numeri di traccia che ha inviato e ai numeri di autorizzazione che ha già fornito) torna come un'altra raccolta di risposte di richiesta di autorizzazione: la decisione del sistema UM per ogni linea di servizio, il numero di autorizzazione e il periodo e una nota che indica dove è stata trovata. Nessuna richiesta di autorizzazione viene creata per un'autorizzazione che nessuno ha inviato in FHIR: la sua ClaimResponse.request contiene un motivo di assenza di dati, come consente il profilo PAS. Una richiesta di autorizzazione legge solo; nulla nei registri di Perfuse cambia. Se il sistema UM è disattivato o risponde con un TA1 o 999, il fornitore ottiene ciò che Perfuse conserva e lo stato del collegamento indica il motivo. La forma segue le guide di accompagnamento della richiesta 278 che UnitedHealthcare, Cigna e Blue Cross Blue Shield of Massachusetts pubblicano; non è stato provato contro un sistema UM reale.

Come i 278 raggiungono il sistema UM

La guida alla connettività del sistema UM dice come accetta i 278 e -pas-278-transport (Impostazioni, Payer, Collegamento gestione dell'utilizzo) lo segue:

TrasportoCosa viene inviatoAutenticazione
x12 (predefinito)La 278 inviata come application/edi-x12; la risposta è il corpo della rispostaUn token bearer, OAuth, HTTP Basic, un certificato client
core-soapLa busta CAQH CORE real-time SOAP 1.2 (COREEnvelopeRealTimeRequest, tipo di payload X12_278_Request_005010X217E1_2 o X12_278_Request_005010X215 per una richiesta di autorizzazione): Regola di connessione vC2.2.0 con il payload nella busta, che la maggior parte dei pagatori e dei sistemi CMS esMD esegue, o -pas-278-core-version C4.0.0 con il payload come allegato MTOMvC2.2.0: un nome utente e una password (WS-Security UsernameToken) o un certificato client. vC4.0.0: un certificato client e un token OAuth
core-mimeLa busta CAQH CORE vC2.2.0 HTTP MIME multipart, il payload come parte del fileIl nome utente e la password della busta o un certificato client
sftpOgni 278 inserito in una cartella sul server SFTP del sistema UM (-pas-278-sftp, -pas-278-sftp-outbound); le risposte vengono raccolte da un'altra (-pas-278-sftp-inbound, ogni -pas-278-sftp-every)Una chiave SSH o una password; la chiave del server deve essere in -pas-278-sftp-known-hosts

Un certificato client è -pas-278-cert e -pas-278-key; -pas-278-ca si fida di un'autorità di certificazione del payer. OAuth è -pas-278-oauth-token-url, -pas-278-oauth-client-id e il segreto, recuperato con la concessione client-credentials e mantenuto fino a un minuto prima della scadenza. Le password, i token e i segreti non sono mai flag: ogni nome è un nome di variabile d'ambiente (-pas-278-password-env, -pas-278-token-env, -pas-278-oauth-secret-env, -pas-278-sftp-password-env), o digitato nello schermo delle impostazioni, dove viene mantenuto nel file delle impostazioni (leggibile solo dall'account del server) e non viene più mostrato.

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

Su SFTP ogni richiesta viene messa in attesa fino all'arrivo della risposta: la risposta 278 decide gli elementi e Perfuse mette un 999 di accettazione nella cartella in uscita. Un file che non può essere letto rimane nella cartella in entrata per una persona e viene offerto nuovamente alla prossima lettura.

Quando il sistema UM non può leggere una richiesta

Un sistema UM che non può leggere un 278 risponde con un TA1 (la busta) o un 999 (la transazione) invece di una decisione. Perfuse legge quale e cosa dice, mette in attesa ogni elemento ("la gestione dell'utilizzo non può leggere la richiesta") e lo registra. Payer, CMS-0057, coda del revisore mostra il collegamento: cosa è stato inviato negli ultimi sette giorni, ogni scambio con il suo numero di controllo e cosa ne è stato (risposto; riconosciuto, risposta in arrivo; rifiutato, con il segmento, l'elemento e il codice del 999; non raggiunto). Ogni scambio ha il proprio numero di controllo, uno più dell'ultimo, che è ciò che un TA1 o un 999 nomina quando risponde.

16.10.4 Decisione sulla base delle prove cliniche, con un servizio di decisione

Un file di regole decide in base al codice di servizio: un codice non richiede autorizzazione, non è coperto o va a un revisore. Se questo paziente soddisfa i criteri per esso è una domanda diversa, risposta dalle condizioni, dalle risposte ai questionari e dai documenti che il fornitore ha inviato con la richiesta. Con -pas-decider-url, ogni elemento che le regole lasciano a un revisore viene inviato a un servizio di decisione, come Vaglio, che legge lo stesso bundle di richiesta PAS attraverso il pacchetto pas pubblicato da Perfuse. Un Vaglio pubblico, su richieste inventate solo, viene eseguito accanto all'istanza di test di Perfuse all'indirizzo https://vaglio.perfuse.health:8443 (accedi come demo, password try-vaglio-demo; può guardare tutto e non modificare nulla): ogni decisione lì ha la sua prova, una lettera in linguaggio semplice e una ricevuta che chiunque può verificare.

perfuse serve -fhir -pas -crd-rules payer-rules.yaml -pas-decider-url https://vaglio.example/api/pas/decide \
  -pas-decider-token-env VAGLIO_TOKEN

L'URL deve essere https o http semplice per questa macchina (localhost, 127.0.0.1), poiché trasporta il record di un paziente e il token. Vaglio stesso risponde solo su https; quando utilizza un certificato dalla propria autorità, passare quell'autorità con -pas-decider-ca DATA/tls/ca.crt (o qualsiasi autorità interna del pagatore da cui proviene il certificato del servizio). Il servizio riceve la richiesta Bundle come l'ha inviata il fornitore, POST <url>?item=<sequence> (application/fhir+json), e risponde con {"decision": "approve" | "deny" | "pend", "why": "...", "requested": ["..."]}, o 404 quando non decide nulla per quell'elemento, il che lascia la risposta delle regole in piedi. why è la nota di processo della risposta e è obbligatoria per un rifiuto, che altrimenti è rinviato; requested è detto al fornitore come informazione di cui ha bisogno una richiesta rinviata. Un rinvio può anche trasportare "questionnaire": "<canonical>" e "attachments": ["<LOINC>", ...], che vengono richiesti nella risposta CDex Task e CommunicationRequests oltre a qualsiasi questionario o allegato DTR richiesto dalla regola (il questionario della regola vince, poiché un Task ne richiede uno; un codice che non ha la forma di LOINC viene scartato e registrato). Una regola che approva o rifiuta è la politica di copertura del pagatore e non viene inviata al servizio. Un errore, un timeout o una risposta che non è una delle tre decisioni rinviato l'elemento per un revisore, con il motivo nel registro del server: nulla qui trasforma un errore in un'approvazione. Non può essere combinato con -pas-278-url, dove il sistema di gestione dell'utilizzo risponde a ogni elemento.

Consiglio prima di inviare. Con -crd-advisor-url accanto a -crd-rules, CRD chiede anche a un servizio di decisione cosa sarebbe detto a una richiesta di autorizzazione preventiva per ogni ordine che ne ha bisogno, e mostra la risposta come un'altra carta: "Prima di inviare: una richiesta per questo avrebbe bisogno di: ...", o "sarebbe approvata", con ciò che è ancora necessario, il questionario che lo chiede e cosa lo approverebbe. Vaglio risponde a /api/pas/advise, con lo stesso token e autorità di sopra:

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 invia POST <url> con {"service": {"system": "...", "code": "..."}, "resources": [ ... ]}, le risorse essendo il prefetch dell'uncino (il paziente per primo, la copertura omessa), e legge {"decides": true, "answer": "approve" | "pend" | "deny", "summary": "...", "missing": [...], "questionnaire": "...", "toApprove": [[...]], "policyTitle": "..."}. È un consiglio e non modifica nulla: le informazioni sulla copertura, le altre carte e la decisione del PAS sono ciò che dicono le regole. Aspetta al massimo tre secondi e nessuna risposta, un errore o "decides": false lascia la risposta esattamente com'è senza di essa. Perfuse non ha mai bisogno di un servizio di decisione.

La richiesta trasporta X-PAS-Request-Id, l'id per cui la risposta è conosciuta. Un servizio con i propri revisori che rinviato un elemento può inviare la propria decisione in seguito come quella di qualsiasi revisore: Claim/$decide con quell'id come claimResponse, la sequenza dell'elemento e la decisione e il motivo. La sottoscrizione del fornitore lo consegna come se fosse stato fatto nella coda del revisore.

Una sottoscrizione con contenuto id-only dice al fornitore quale risposta è cambiata senza dire cosa sia: il focus della notifica è Bundle/<id>. GET /fhir/Bundle/<id> restituisce l'ultimo bundle di risposta PAS, GET /fhir/Bundle/<id>/_history/<n> la versione di una notifica inviata, e GET /fhir/ClaimResponse/<id> il ClaimResponse solo. Un token legato a un paziente viene detto che non esiste, come per qualsiasi record al di fuori del suo paziente.

Verificato con la suite ufficiale Inferno PAS Server v2.2.1 (vedi verifica). Non inviato, anche se PAS lo segna come supporto obbligatorio: ClaimResponse.adjudication con un'azione di revisione, ClaimResponse.extension:authorizedProvider e ClaimResponse.item.extension:communicatedDiagnosis, perché le estensioni di cui hanno bisogno non sono consentite lì dal proprio contesto in PAS 2.2.1 e il validator rifiuta una risposta che le trasporta; e request.extension:DataAbsentReason, perché Perfuse sa sempre la richiesta. I 278 inviati a un sistema di gestione dell'utilizzo (sopra) vengono verificati contro gli esempi di richiesta di PAS 2.2.1, gli esempi di esMD 278 pubblicati da CMS e un controllore 278 scritto da guide di accompagnamento pubbliche, e ogni trasporto contro un sistema UM sostitutivo scritto dalle Regole di connettività CAQH (vedi verifica); non ancora contro un sistema UM reale o un clearinghouse, e non certificato CORE. Non implementato: allegati inviati indietro con CDex.

Un file di regole viene controllato contro le invarianti di CRD quando viene caricato: un questionario necessita di documentazione, un servizio che non è coperto non può necessitare di autorizzazione, satisfied appartiene a un caso e non a una regola, e qualsiasi cosa condizionale deve fornire un motivo.

Non verificato: le esportazioni e l'abbinamento dei membri contro l'implementazione di un altro pagatore, le metriche contro le figure pubblicate di un pagatore, e CRD contro un client CDS Hooks di un EHR reale.

16.11 Invio di richieste di autorizzazione preventiva a un pagatore (per i fornitori)

Tutto ciò che è stato detto sopra risponde alle richieste, come un pagatore. Il lato di un fornitore è l'opposto: un'app EHR o un'app DTR costruisce un bundle di richiesta Da Vinci PAS e qualcosa deve inviarlo al pagatore, conservare la risposta e passarla. Una destinazione pas fa questo.

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

Ogni messaggio deve essere una richiesta PAS completa Bundle su un canale grezzo. Perfuse la invia invariata a {payer}/Claim/$submit: il pagatore decide sulla richiesta di rimborso insieme al paziente, alla copertura e alle risorse di supporto nel Bundle, e una richiesta di rimborso ricostruita da un riassunto perderebbe queste informazioni. Fuori da questa macchina l'indirizzo del pagatore deve essere https.

Una decisione è una richiesta consegnata, indipendentemente da cosa dice. Un'approvazione, un rifiuto e una sospensione sono tutti registrati e nessuno di essi viene ritentato, perché ritentare un rifiuto sottopone due volte la stessa richiesta. Ciò che fallisce la consegna e viene ritentato è un pagatore che non ha preso una decisione: uno stato di errore, un OperationOutcome (il cui testo è l'errore) o un ClaimResponse il cui esito è error. La decisione viene letta voce per voce dai codici di azione di revisione del PAS (X12 306: A1 approvato, A2 parzialmente, A3 rifiutato, A4 sospeso, A6 modificato); una risposta senza codice viene elencata come "nessun codice di decisione" piuttosto che considerata come un'approvazione. Un rifiuto senza motivo in nessun luogo viene rifiutato in quanto non soddisfa CMS-0057.

La risposta del pagatore è la risposta della destinazione, quindi Ispeziona la risposta può giudicarla e results_to la consegna a un altro canale. Ogni richiesta è elencata in CMS-0057, Richieste inviate ai pagatori: quando è stata inviata, il paziente, il servizio, la decisione e il riferimento del pagatore (preAuthRef), che un'indagine successiva nomina. L'elenco viene conservato in prior-auth.json accanto al database (al massimo 10.000 richieste; le decisioni più vecchie vengono eliminate per prime, una richiesta in sospeso non lo fa mai) e ogni tenant vede solo il proprio.

Verificato contro l'implementazione di riferimento HL7 Da Vinci PAS per pagatori (immagine docker hlseven/davinci-prior-auth): una richiesta inviata attraverso un canale in esecuzione viene messa in attesa da esso con il suo riferimento e la risposta appare sullo schermo (vedi verifica). Non ancora provato contro un pagatore di produzione. Non costruito: seguire una richiesta in attesa con $inquire, o ricevere la risposta successiva del pagatore tramite abbonamento; un canale può fare entrambe le cose oggi con una destinazione http o fhir.

16.12 Reti allineate con CMS

Il CMS Interoperability Framework (CMS Health Technology Ecosystem) chiede alle reti di dati sanitari di auto-attestare a 26 criteri e di essere elencate come reti allineate CMS; EHR, fornitori, pagatori e app si connettono a loro. I criteri dal 13 al 16 sono in vigore dal 4 luglio 2026: API FHIR su US Core con un CapabilityStatement completo e Bulk Data, documenti come allegati FHIR leggibili dall'uomo, notifiche di appuntamento e incontro tramite FHIR Subscription, e un localizzatore di record.

Amministra › Rete allineata CMS elenca ogni criterio con ciò che Perfuse fornisce per esso e dove si trova questo server: letto da ciò che è attivato qui:

StatoSignificato
Pronto quiPerfuse lo fornisce e è attivato.
Pronto, con un divarioÈ attivato e parte del criterio è al di fuori di esso (nominato sullo schermo).
Costruito, non attivatoPerfuse lo fornisce; lo schermo nomina l'impostazione o il flag che lo attiva.
Da fareLa parte dell'organizzazione: un accordo, una certificazione, pubblicazione nell'elenco dei fornitori nazionali.
Non costruitoIl software lo farebbe e Perfuse no.

Ciò di cui hanno bisogno i quattro in vigore da questo server:

CriterioIn PerfuseAttiva
13 API FHIR, US Core, Bulk DataL'endpoint FHIR con il suo CapabilityStatement e $export-fhir, -fhir-bulk-export
14 Documenti come allegati FHIRDocumentReference con Binary e IHE MHD sul registro XDS-fhir (MHD anche -xds)
15 Notifiche di incontro e appuntamentoSottoscrizioni basate su argomento (R5 Backport per R4) dai feed ADT e SIU-fhir-subscriptions
16 Indicatore di registrazioneIl registro XDS.b, XCA per altre comunità, PIXm-xds, -xds-home-community

Lo schermo è un foglio di lavoro per l'attestazione, non una certificazione: CMS esamina le reti che sospetta non soddisfino i criteri, e il testo del framework stesso è l'autorità. Non costruito oggi: query di lacune di qualità aperte (criterio 8), query di un pagatore per i dati di incontro di una richiesta di rimborso (9), segnalazione delle metriche delle query al National Provider Directory (19), controllo dei fornitori contro quel directory (6), lettura delle patenti di guida mobili o delle carte di assicurazione digitali (3, 23), e applicazione di una politica di consenso generale su ogni lettura (5). L'identificazione IAL2 è del servizio di identità; Perfuse accetta i token di quello che si sceglie.

17 Sicurezza

Perfuse gestisce dati clinici. Questo capitolo descrive cosa fa al riguardo e cosa lascia a voi.

17.1 Sicurezza del trasporto

TLS sull'interfaccia web è configurato con -tls-cert e -tls-key. Senza di essi l'interfaccia è HTTP semplice, che è accettabile su un indirizzo di loopback per un primo sguardo e da nessun'altra parte — trasporta credenziali e contenuto del messaggio, entrambi leggibili sul filo.

TLS sui trasporti del canale è per sorgente e per destinazione, sotto un blocco tls. Le impostazioni disponibili sono nelle sorgenti e destinazioni di riferimento.

insecure_skip_verify accetta qualsiasi certificato. Esiste perché i sistemi ospedalieri presentano regolarmente certificati che non verificano e rifiutare di connettersi significherebbe rifiutare di integrare. È denominato per essere vistoso e utilizzarlo significa che la connessione è crittografata ma non autenticata — si ha protezione contro l'intercettazione passiva e nessuna contro un server interposto.

Una connessione TLS non verificata non è la stessa di una verificata e la distinzione vale la pena di registrarla da qualche parte dove i vostri revisori la troveranno. La soluzione migliore è quasi sempre ottenere il certificato dell'estremità remota e fidarsi esplicitamente di esso invece di fidarsi di tutto.

17.2 Autenticazione e ruoli

Gli utenti sono memorizzati nel database. Ognuno ha uno dei cinque ruoli e ogni ruolo include tutto ciò che è incluso nei ruoli sopra di esso:

RuoloPuò
MonitorVedere se le cose funzionano: stato del canale, conteggi, mappa di flusso, avvisi, dashboard, metriche e profondità della coda. Nessun contenuto di messaggio, file di canale o messaggi in coda.
ViewerLeggere anche i messaggi, file di canale, tracce e registro di attività.
OperatorRinviare anche: riprocessare un messaggio, riprodurre un canale e ritentare le consegne in coda.
EditorCreare e modificare anche i canali e eseguire confronti.
AdminAvviare e interrompere anche i canali, svuotare le code e gestire le persone, i token e le impostazioni del server.

Un sesto ruolo, Piattaforma, appartiene a chi esegue un server condiviso: crea tenant e imposta i loro limiti e non possiede canali propri.

Monitor è per un help desk o per uno schermo operativo su un muro: tutto ciò che è necessario per vedere che un feed si è interrotto e nulla che nomina un paziente. Viewer può leggere il contenuto dei messaggi, che sono dati clinici; è un ruolo a basso privilegio per la *configurazione*, non per la privacy. Operator separa la correzione di una consegna fallita di notte dal cambiamento di ciò che un feed fa: la persona che rinviene non deve essere in grado di riscrivere il canale.

17.2.1 Password errate ripetute

Le password errate e i tentativi di accesso con passkey falliti vengono conteggiati per l'indirizzo da cui proviene la connessione, e dopo alcuni tentativi consecutivi quell'indirizzo deve attendere prima di poter riprovare (la risposta è 429, con Retry-After). Gli account non vengono bloccati per nome, perché ciò permetterebbe a chiunque di bloccare un amministratore di proposito.

L'indirizzo è quello della connessione stessa, mai quello che una richiesta afferma in X-Forwarded-For, che il mittente scrive. Dietro un proxy inverso sulla stessa macchina Perfuse utilizza l'ultimo elemento X-Forwarded-For invece, quello aggiunto dal proxy, in modo che ogni client venga ancora conteggiato separatamente. Un proxy su un'altra macchina raggiunge Perfuse da un solo indirizzo e tutti i suoi client condividono un solo conteggio: è necessario limitare la frequenza degli accessi anche a quel proxy.

17.2.2 Gruppi di canali

Una persona (o un token API) può essere limitata a alcuni gruppi di canali: possono quindi visualizzare e agire solo sui canali il cui group è uno dei loro. Questo è l'assetto di un gruppo ospedaliero su un server, gli analisti di ogni struttura che si occupano dei propri feed e un team centrale, senza limiti, che si occupa di tutti. Rhapsody lo chiama un locker.

Il limite si applica ovunque contemporaneamente, perché è applicato alla richiesta piuttosto che ricordato da ogni schermo: l'elenco dei canali, il dashboard e la mappa di flusso, i messaggi e la loro ricerca, i conteggi e i grafici, la coda, gli avvisi, le metriche, i certificati, i contratti e l'utilizzo dei set di codici. Un canale al di fuori dei gruppi di una persona non esiste per loro; chiedere il suo nome risponde *non trovato*, quindi il suo nome non è confermato. Un canale senza gruppo è visibile solo alle persone senza limite.

Salvare un canale lo mantiene all'interno dei gruppi di una persona: non possono creare un canale in un altro gruppo o spostarlo fuori dal proprio. Ciò che ogni struttura condivide - tabelle di codici, librerie di script, decisioni di autorizzazione preventiva - possono leggerle ma non modificarle. Le cifre a livello di server (autorizzazione preventiva, utilizzo di token, tunnel) sono mostrate solo alle persone senza limite e così sono le metriche e gli avvisi relativi all'intero server piuttosto che a un canale.

Un amministratore limitato ai gruppi è l'amministratore della struttura stessa. Gestisce le persone e i token dei propri gruppi, avvia e ferma i canali e svuota le code. Un collega che aggiunge ottiene i gruppi a meno che non ne specifichi alcuni, non può dare un gruppo che non possiede e non vede mai o modifica nessuno senza limite. Tutto il resto che un amministratore può fare cambia l'intero server - impostazioni, accesso, riavvio, regole di avviso, branding, flotta, il server SMART - e gli viene rifiutato.

I gruppi sono impostati in Utenti (e per i token in Token), come elenco separato da virgole. Ogni modifica è registrata nel registro di attività e ha effetto alla prossima richiesta della persona.

Un ruolo diverso in ogni gruppo

Una persona può avere un ruolo diverso in ogni gruppo: lab=editor, adt in Utenti modifica i canali del laboratorio e ha il ruolo scelto accanto ad esso - ad esempio visualizzatore - in quelli delle ammissioni. Vedono i canali di entrambi i gruppi su ogni schermo. Salvare, avviare o rinviare uno in un gruppo in cui il loro ruolo è troppo basso viene rifiutato con il ruolo che detengono lì; non finge che il canale sia mancante, poiché possono vederlo. Il loro ruolo in alto sullo schermo è il più forte che detengono, che apre gli schermi che quel ruolo utilizza, e ogni azione su quegli schermi è ancora limitata ai gruppi in cui lo detengono.

Solo le persone limitate ai gruppi di canali possono averne uno. Qualcuno che vede ogni canale ha un solo ruolo, perché "editore dei canali del laboratorio" per una persona senza limite sarebbe editore di tutto ciò che appartiene a nessun gruppo e delle pagine a livello di server. Un amministratore della struttura può dare un ruolo per gruppo solo nei gruppi che amministra e mai al di sopra del proprio ruolo lì.

17.3 Chi può chiamare l'endpoint FHIR

L'endpoint FHIR (serve -fhir) controlla uno di due tipi di token:

limitato ai Gruppi FHIR. Questo è l'impostazione predefinita quando non è configurato un server di autorizzazione SMART.

trasporta ambiti, e l'endpoint tiene ogni richiesta ad essi.

Con SMART configurato, vengono accettati solo token SMART, quindi ogni chiamante è soggetto ai suoi ambiti. Un token API ha un ruolo e non ha ambiti: un token viewer può leggere il record di ogni paziente. Un pagatore che ha attivato SMART per limitare ogni app a ciò che è stato concesso non dovrebbe avere un modo per accedere che non sia limitato.

Alcuni siti necessitano di entrambi - un feed di richieste interne che tiene un token API e non ha un client SMART, accanto ad app di membri che si connettono tramite SMART. Per quelli, Impostazioni → FHIR → Accetta token API Perfuse accanto ai token SMART (-fhir-api-tokens all'avvio) consente ai token API di accedere anche. È disattivato per default, ha effetto sulla prossima richiesta in entrambe le direzioni e il cambio è scritto nel registro di audit. Un token è distinto dalla sua forma: un token SMART è un JWT firmato, e un token API non lo è mai, quindi uno non viene mai controllato come l'altro. Dove possibile, fornire a un tale sistema un client SMART Backend Services con solo gli ambiti di sistema di cui ha bisogno.

17.3.1 Un endpoint FHIR aperto a sconosciuti

Un server di test pubblico fornisce credenziali che possono scrivere, poiché il test della precedente autorizzazione o delle iscrizioni richiede scritture. Due limiti impediscono a un client di rovinare tutto per tutti, entrambi sotto Impostazioni → FHIR e entrambi disabilitati per impostazione predefinita:

scrittura viene risposta 429 con Retry-After: 60. Le letture e le ricerche, incluse le ricerche tramite POST, non vengono mai conteggiate.

L'endpoint di un ospedale non necessita di nulla di tutto ciò.

17.4 Agenti di intelligenza artificiale: il server MCP

Con Impostazioni › Sicurezza › Agenti AI (MCP) attivato (o serve -mcp), Perfuse serve il Model Context Protocol a /mcp, in modo che un agente AI come Claude, ChatGPT o un assistente IDE possa chiedergli cosa sta succedendo. È disattivato per default e spegnendolo si ferma ogni agente alla sua prossima chiamata.

Un agente si connette con un token API da Amministra › Utenti › Credenziali macchina come token bearer, mai con una sessione del browser di una persona (questo viene rifiutato, quindi un agente non agisce mai con l'accesso completo di una persona). Una configurazione del client sembra:

{ "mcpServers": { "perfuse": { "type": "http", "url": "https://perfuse.example/mcp",
    "headers": { "Authorization": "Bearer <token>" } } } }
StrumentoRuoloFunzionalità
server_status, list_channels, queue, alertsmonitorVerifica se tutto funziona, senza contenuti dei messaggi
get_channel, search_messages, get_message, find_patient, fhir_searchviewerCanali, messaggi (con contenuti), messaggi di un paziente su più formati, ricerca FHIR
retry_delivery, reprocess_messageoperator, e mcp:writeRitenta la consegna in coda, invia nuovamente un messaggio attraverso il suo canale
start_channel, stop_channeladmin, e mcp:writeAvvia o interrompi un canale

Ogni strumento risponde alla stessa route o alla ricerca FHIR di uno schermo di una persona, chiamata con il token dell'agente, quindi il ruolo del token, i gruppi di canali e l'inquilino decidono cosa vede, esattamente come fanno nella console; e fhir_search ottiene l'accesso del token sul endpoint FHIR (che potrebbe rifiutare i token API; vedere la sezione FHIR sopra). Un agente viene offerto solo gli strumenti che il suo token può utilizzare. La lettura è l'impostazione predefinita: uno strumento che modifica qualcosa richiede anche l'ambito mcp:write del token ("Consenti a un agente AI di agire con esso" quando si rilascia il token), quindi un token rilasciato per un agente di reporting non può essere indotto ad agire da un prompt. Le risposte di un token di monitoraggio hanno i contenuti dei messaggi rimossi, qualunque cosa restituisca una route.

Ogni chiamata è registrata in Activity come mcp.tool con il nome del token, lo strumento, i suoi argomenti e l'esito (ok, refused, invalid, rate-limited o lo stato HTTP); mcp.connect registra quale client si è connesso. Ogni token può effettuare 60 chiamate di strumenti al minuto (Chiamate di strumenti al minuto da un token); superato questo limite, una chiamata restituisce un errore che l'agente può leggere e nulla viene eseguito. Una richiesta da una pagina del browser su un'altra origine viene rifiutata, che MCP chiede a un server di interrompere il rebinding DNS. Il trasporto è lo Streamable HTTP di MCP, risposto come JSON senza stream di eventi; sono accettate le versioni del protocollo 2025-06-18, 2025-03-26 e 2024-11-05. I messaggi e le risorse FHIR contengono dati dei pazienti: le risposte di un agente vanno al modello su cui viene eseguito, quindi assegnare un token a un agente solo dove quel modello è autorizzato a visualizzarli e assegnargli il ruolo più basso che svolge il lavoro.

17.5 Un account di dimostrazione

serve -demo-account demo:PASSWORD crea un account condiviso per un server di dimostrazione pubblica, e la pagina di accesso mostra il suo nome utente e la password con un pulsante che si accede con essi. L'account è un visualizzatore, quindi può visualizzare tutto e modificare nulla. A differenza di qualsiasi altro visualizzatore, può anche aprire gli schermi degli amministratori (utenti, token macchina, impostazioni, protezione dei dati, i peer della flotta), in modalità sola lettura: una dimostrazione è giudicata dai suoi schermi. Li legge come un visualizzatore legge i canali, con ogni credenziale mostrata come impostata o meno, mai il suo valore, e ogni modifica rifiutata. Può anche premere i controlli che non modificano nulla e non raggiungono nulla all'esterno del server: un controllo di script e convalida e analisi dell'editor di canale. Non può modificare la sua password o aggiungere una chiave di accesso, perché il primo visitatore a farlo bloccerebbe tutti gli altri dopo di lui. Ogni avvio lo ripristina come visualizzatore con la password pubblicata. La password deve essere di almeno 12 caratteri, come qualsiasi altra. Utilizzarlo solo su un server che contiene dati di test: chiunque legge la pagina di accesso può leggere ogni messaggio sul server.

17.6 Registro di controllo

I cambiamenti di configurazione, gli accessi e l'accesso al contenuto dei messaggi vengono registrati con chi, cosa e quando.

Il registro di controllo si trova nello stesso database dei messaggi. Ciò è comodo ed è una limitazione: qualcuno che può modificare il database può modificare il registro di controllo. Se le tue esigenze includono un registro di controllo a prova di manomissione, il registro deve essere inviato da qualche parte in modalità solo aggiunta, e l'output del registro di Perfuse è il modo per farlo.

17.7 Segreti nella configurazione

Le password, i codici di accesso e le chiavi appaiono nella configurazione del canale, il che significa che sono presenti nei file YAML.

Due conseguenze. I file necessitano di autorizzazioni del file system che riflettono il loro contenuto e, se sono sotto controllo versione — il che è comunque consigliato — il repository contiene credenziali e deve essere trattato di conseguenza.

Quando un valore è un segreto, l'interfaccia lo visualizza come segreto e l'API non lo restituisce una volta salvato. Ciò lo protegge dall'essere letto sulla spalla di qualcuno o divulgato in uno screenshot. Tuttavia, non protegge il file.

17.8 Ciò che è nel database

Il message store conserva i messaggi come ricevuti, il che per un flusso clinico significa dati identificativi dei pazienti. Dovrebbe essere su un archiviazione crittografata, salvato come dati clinici con la conservazione che ne consegue e controllato dall'accesso al livello del file system nonché attraverso i ruoli propri di Perfuse.

cleanup.periodDays limita quanto a lungo viene conservato. Vedere il message store per la tensione tra questo e avere abbastanza storia per l'avviso ritmico.

17.9 Protezione dei dati (GDPR e UK GDPR)

Lo schermo Protezione dei dati (Amministra, solo amministratori) risponde alle richieste di una persona ai sensi del GDPR e del GDPR del Regno Unito. Non decide nulla per conto del titolare del trattamento: se una richiesta deve essere accolta e se si applica un'esenzione, è una decisione del titolare del trattamento, registrata con la richiesta.

Trovare cosa è memorizzato. Una persona è identificata da identificatori: system|value (un numero NHS, un MRN con l'autorità di assegnazione) o un numero da solo. Con un indice dei pazienti, questi si estendono a ogni numero di ogni record collegato alla stessa persona, quindi una richiesta che cita un numero di ospedale trova i record archiviati con gli altri. Visualizzare cosa è memorizzato cerca quindi in ogni archivio che memorizza dati dei pazienti:

ArchiviazioneTrovato da
Messaggil'indice di identità (Impostazioni → Dati → Indice degli identificatori dei pazienti); senza di esso, i messaggi non possono essere trovati per identificatore
La coda di consegnaleggendo gli identificatori di ogni messaggio in coda
L'archiviazione FHIRle risorse Paziente che contengono un identificatore e ogni risorsa le cui referenze indicizzate puntano a uno
Richieste di autorizzazione preventivagli identificatori del paziente della richiesta
L'indice dei pazientil'identificatore o l'EUID

Cosa non può raggiungere dice: tracce inviate a un collector (-trace-endpoint), il log di audit (conservato: è il record di chi ha fatto cosa, inclusa questa richiesta), e le copie di backup.

Richieste. Una richiesta è registrata con il suo tipo (accesso, Articolo 15; portabilità, Articolo 20; cancellazione, Articolo 17; limitazione, Articolo 18), chi la fa in base ai record del controller, gli identificatori e una nota (come è stata confermata l'identità, un'estensione e il suo motivo). Deve essere eseguita entro un mese dalla ricezione (Articolo 12(3)); una richiesta in ritardo è mostrata in rosso.

Una richiesta chiusa conserva solo gli ultimi caratteri dei numeri della persona: rimane come record di una risposta senza essere un'altra copia di essi. Ogni passaggio è nel log di audit con i numeri mascherati.

Blocco legale. Un blocco nomina una persona tramite identificatori, con il suo motivo e una data di fine opzionale. Finché è in vigore, una cancellazione viene rifiutata direttamente, e la finestra di conservazione dell'archivio dei messaggi risparmia i messaggi della persona (record e corpi) fino a quando il blocco non viene revocato.

Copie di backup e registro di cancellazione. Una copia di backup creata prima di una cancellazione conserva ancora ciò che è stato cancellato fino a quando non scade. Ogni cancellazione viene scritta in un registro: quando, da chi, approvata da chi, quanto è stato rimosso da ogni archivio, e gli identificatori della persona come hash SHA-256 salati invece che in chiaro. Dopo aver ripristinato una copia di backup, Applica nuovamente le cancellazioni hash gli identificatori che gli archivi ripristinati contengono con ogni voce del sale ed elimina ogni persona che il registro nomina. I numeri brevi possono essere trovati dai loro hash provando ogni valore, quindi il registro è esso stesso un dato personale e viene conservato con la protezione del database.

Ritenzione. Lo schermo elenca per quanto tempo ogni tipo di record viene conservato qui e cosa lo modifica: record e corpi dei messaggi in base alle loro finestre di ritenzione, la coda fino a quando non viene consegnata o rimossa, l'archivio FHIR, richieste di autorizzazione precedenti e l'indice dei pazienti fino a quando non vengono cancellati (i record clinici non vengono eliminati secondo una programmazione), il registro di controllo conservato.

Record di elaborazione (Articolo 30). Record di elaborazione scarica, in formato Markdown o CSV, cosa questo server sa di esso: il controller, l'ufficiale per la protezione dei dati e dove i dati vengono conservati (Impostazioni → Dati → Protezione dati), la conservazione di ogni tipo di record, e un'attività di elaborazione per canale con cosa riceve, da dove, a quali destinazioni, e gli host a cui invia. Gli scopi, le basi giuridiche e le categorie di soggetto dei dati vengono lasciati al controller per compilarli, e dirlo. Una cella CSV che inizia con =, +, - o @ viene scritta con un apostrofo iniziale, in modo che una cartella di lavoro non lo esegua.

Dove vengono conservati i dati. Dove vengono conservati i dati (Impostazioni → Dati → Protezione dei dati) afferma, in parole che un regolatore può verificare, dove il server, il suo database e i suoi backup vengono eseguiti; lo schermo di protezione dei dati e il record lo mostrano. Un progetto di accordo di elaborazione dei dati per le organizzazioni BioDream che ospita si trova in docs/legal/dpa-template.md; è un progetto per un avvocato, non un consiglio legale.

L'API è /api/privacy (riassunto), /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 Tenant

Un tenant è un limite di isolamento: canali, messaggi, utenti e impostazioni appartengono a uno e nulla li attraversa.

Esiste per un fornitore di servizi che esegue feed per più studi. Non utilizzarlo per separare i dipartimenti all'interno di un'organizzazione che devono vedere il traffico degli altri: l'isolamento è reale e non esiste una visualizzazione tra inquilini. Per questo, utilizzare i gruppi di canali (sopra), che dividono le persone di un'organizzazione consentendo a un team centrale di vedere tutto.

17.10.1 Limiti

Un operatore di piattaforma imposta i limiti di ogni tenant in Tenants, in modo che un cliente non possa occupare tutto lo spazio di un server condiviso. Lasciare un limite vuoto per non impostarne nessuno.

Nessuno di loro perde un messaggio. Oltre la velocità o il limite di archiviazione, un messaggio ricevuto viene rifiutato nel modo in cui un ricevitore occupato rifiuta uno, prima che qualcosa venga archiviato o consegnato: MLLP non riceve un acknowledgement (non un rifiuto, che alcuni mittenti considerano come "non rinviare"), HTTP riceve 429 con Retry-After, SOAP riceve 503, DICOM riceve uno stato ripetibile e una coda, un bucket o un file rimane dove si trovava. Il mittente rinvia, come fa ogni motore di integrazione e ogni sistema di cartella clinica. Nulla di ciò che è già stato archiviato viene cancellato per fare spazio. Un limite aumentato ha effetto entro un minuto e ogni modifica dei limiti viene registrata nel registro di attività.

17.11 Dati di test

I messaggi generati descritti in testing esistono in parte come controllo della privacy. Riprodurre un problema altrove, inviare un esempio a un fornitore o popolare un ambiente di test sono tutte cose che altrimenti vengono fatte con messaggi reali.

L'output del generatore non contiene dati del paziente per costruzione piuttosto che per oscuramento. Preferirlo ai messaggi reali sfrondati a mano, che è un processo che può essere fatto in modo incompleto e di solito lo è.

17.12 Accesso singolo

Tre meccanismi e account locali accanto a tutti loro.

OpenID Connect (-oidc), un directory su LDAP (-ldap) e SAML 2.0 (-saml). Ognuno di essi è configurato da Amministra → Accesso e scritto nel file che il flag nomina, quindi lo schermo e il file sono due visualizzazioni di una sola cosa piuttosto che due posti da mantenere allineati.

Gli account locali sono sempre disponibili e non possono essere disattivati. Ciò è deliberato: un motore di integrazione locale il cui unico modo di accesso è un fornitore di identità diventa irraggiungibile proprio quando il fornitore di identità è irraggiungibile, e un'interfaccia clinica non è un buon posto per imparare che. Lo schermo di accesso ti dice quanti amministratori locali esistono prima di incoraggiarti a dipendere da qualcos'altro.

17.12.1 Cosa decide un mapping di gruppo

Tutti e tre mappano gruppi dal directory ai ruoli di Perfuse e qualcuno in gruppi che corrispondono a più di uno ottiene il più privilegiato. Ciò è l'unica direzione sicura per risolverlo — l'alternativa è una persona che perde l'accesso a cui ha diritto perché è anche in un gruppo inferiore.

Uno dei sei ruoli può essere concesso: monitor, visualizzatore, operatore, editore, amministratore e piattaforma.

Un gruppo può anche essere limitato a alcuni gruppi di canali, nella seconda casella della sua riga (channel_groups nel file). Una volta che un gruppo ne nomina uno, ogni accesso imposta i gruppi di canali della persona dai gruppi che hanno concesso il loro ruolo: qualcuno in un gruppo che modifica i canali del laboratorio e in un altro che visualizza ogni canale è un editore dei canali del laboratorio e nulla altro. Il ruolo più forte non viene mai unito alla portata più ampia, perché nessun gruppo concede questo. Un gruppo con una casella vuota concede ogni canale. Finché nessun gruppo ne nomina uno, l'accesso lascia i gruppi di canali come li ha impostati un amministratore in Utenti.

Quando ogni gruppo a cui una persona appartiene nomina gruppi di canali, ogni gruppo di canali ottiene il ruolo più forte tra i gruppi che lo nominano: con Lab-Interfaces (editore, laboratorio) e Clinical-IT (visualizzatore, laboratorio e adt), la persona modifica i canali del laboratorio e visualizza quelli delle ammissioni, come se fosse stato impostato manualmente. Quando uno dei loro gruppi concede ogni canale, non c'è una lista per tenere un ruolo per gruppo, e si applica la regola sopra.

roles:
  editor: [Lab-Interfaces]
  operator: [Night-Desk]
  viewer: [Clinical-IT]
  channel_groups:
    Lab-Interfaces: [lab, pathology]
    Night-Desk: [adt]

Questo è il file OpenID Connect e SAML. Il file della directory mappa ogni gruppo a un ruolo (roles: {Lab-Interfaces: editor}), e channel_groups si trova accanto a roles lì.

Una mappatura che non concede nulla a nessuno viene rifiutata invece di essere salvata. Una configurazione che autentica le persone e le respinge tutte sembra identica a un prodotto rotto dall'esterno: il round trip si completa e tutti vengono negati senza nulla che spieghi il motivo.

La creazione di un account al primo accesso è disabilitata per default. Con essa disabilitata, qualcuno deve esistere in Perfuse prima di poter accedere, quindi la directory decide chi sono e Perfuse decide chi è autorizzato ad accedere.

17.12.2 SAML, in particolare

Le parti importanti da conoscere prima di configurarlo:

17.12.3 Cosa invia ogni provider

L'attributo di gruppo è dove gli accessi vanno storti, e i tre provider comuni lo nominano in modo diverso.

ProviderDi solito inviaNote
KeycloakgroupsRichiede un mapper di appartenenza al gruppo aggiunto al client.
Entra IDun URI di attestazione che termina /claims/groupsInvia oggetti ID di gruppo a meno che l'applicazione non sia configurata per inviare nomi. Mappa gli ID o modifica il provider.
Oktaciò che l'applicazione è stata configurata per inviareDi solito groups, con un filtro che decide quali vengono inviati.
ADFSun URI di attestazioneFirma la Risposta invece dell'Attestazione, che Perfuse accetta.

Un URI di attestazione può essere immesso dal suo segmento finale: digitare groups trova http://schemas.microsoft.com/ws/2008/06/identity/claims/groups. Un nome che termina semplicemente con la parola non corrisponde — excluded_groups non è groups.

L'appartenenza al gruppo che arriva come un solo valore separato da virgole viene trattata come un singolo nome di gruppo e non corrisponde a nulla. Questa è la lettura corretta dello standard, e dividere le virgole significherebbe che un gruppo che legittimamente contiene uno è diventato silenziosamente due. Se questo è ciò che il tuo provider invia, modificalo lì.

Test sulla schermata di accesso controlla tutto ciò che può essere controllato senza una persona: le impostazioni, il certificato e se una richiesta di accesso può essere costruita. Dice chiaramente che non può provare che qualcuno possa accedere, perché ciò richiede un'asserzione reale su una persona reale e l'unico modo per ottenerla è che provino.

17.13 Account provisionati dal provider di identità: SCIM

Con -scim (Impostazioni → Accesso → Account automatici), un provider di identità come Okta, Microsoft Entra ID o Google Workspace crea, aggiorna e rimuove account Perfuse da solo in /scim/v2/Users, quindi una persona che lascia l'organizzazione perde l'accesso quando il suo account del directory viene disabilitato, non quando qualcuno se ne ricorda. Il provider si autentica con un token API che detiene il ruolo di amministratore, creato sotto Utenti → Credenziali macchina, inviato come token di portatore.

*viewer* (o *solo lettura*) o *monitor* assegna quel ruolo, quindi APP-Perfuse-Editor e Perfuse Operators funzionano come sono denominati. Tutto il resto ottiene -scim-default-role, viewer a meno che non sia impostato diversamente. La piattaforma non può essere concessa in questo modo.

risultati. Le operazioni bulk, l'ordinamento e le ETag non sono supportate.

17.14 Cosa Perfuse non fa

Non crittografa il database a riposo. Utilizzare la crittografia del file system o del volume.

Non gestisce i propri certificati o il loro rinnovo. Indicarlo ai file e gestire quei file con ciò che già si utilizza.

SAML è stato verificato contro due provider indipendenti, ciascuno con un accesso al browser reale, un'asserzione reale e una sessione reale: Keycloak 26 e Microsoft Entra. Due questioni più del doppio di una, perché i due sono in disaccordo in un modo che si è rivelato fondamentale — Keycloak scrive la sua asserzione con prefissi di namespace e Entra scrive gli stessi elementi senza di essi, e il difetto che questa area ha avuto è stato nella gestione dei prefissi.

Iniziare leggendo i metadati del provider. Impostazioni, quindi Accesso, quindi la scheda SAML: fornire l'URL dei metadati o incollare il documento, e l'indirizzo di accesso e il certificato di firma sono compilati automaticamente. Ogni provider SAML pubblica uno di questi — Okta, Entra, AWS IAM Identity Center, Keycloak, ADFS — ed è la differenza tra la configurazione di un provider e la trascrizione di uno. Farlo manualmente significa trovare il certificato all'interno del XML, rimuovere le interruzioni di riga dalla base64 e avvolgerlo in intestazioni PEM, dove uno spazio isolato produce un errore di firma che non dice nulla sulla formattazione.

Ciò che torna è descritto piuttosto che scaricato: il soggetto di ogni certificato, la scadenza e l'impronta SHA-256, in modo che sia possibile verificarlo con ciò che mostra la console del provider. Un certificato scaduto è indicato come scaduto piuttosto che lasciato come data da confrontare ad occhio. Nulla è salvato leggendo — applicarlo al modulo è un clic separato, perché un documento che qualcuno ha incollato non è ancora una decisione su cosa fidarsi.

Un URL dei metadati è recuperato solo su https e l'indirizzo è verificato contro la stessa politica che governa le destinazioni dei canali, quindi questo non può essere utilizzato per far leggere al server le credenziali delle istanze cloud. Le reindirizzamenti non sono seguiti, perché un indirizzo consentito che reindirizza a uno bloccato passerebbe direttamente oltre quel controllo.

Se si sta configurando Entra, cinque cose non corrisponderanno a ciò che mostrano gli esempi. Non invia alcuna richiesta di posta elettronica. Il suo NameID è un identificatore opaco piuttosto che un indirizzo. Non invia alcuna richiesta di gruppo a meno che l'applicazione non sia configurata esplicitamente per emetterne una, quindi un mapping di ruolo scritto contro i gruppi rifiuta ogni accesso. Quando i gruppi vengono emessi, sono GUID di oggetto piuttosto che nomi, a meno che il tenant non sincronizzi da Active Directory locale. E i nomi delle sue richieste vivono sotto schemas.microsoft.com/identity dove la maggior parte della documentazione mostra schemas.xmlsoap.org. Perfuse gestisce tutti e cinque; sono elencati perché i primi quattro altrimenti sembrerebbero difetti in Perfuse quando sono Entra che è Entra.

Quella distinzione non è teorica qui. La prima asserzione Keycloak genuina è fallita del tutto, perché la forma canonica della firma coperta stava venendo calcolata con prefissi di namespace rilasciati. Nessun provider di identità reale avrebbe potuto firmare qualcuno, e i cinque test di canonizzazione del pacchetto sono passati in tutto — ciascuno di essi firmato e verificato con lo stesso codice, quindi hanno dimostrato solo che era d'accordo con se stesso. Se si è i primi a puntare un provider diverso su questo, aspettarsi di trovare qualcosa, e il registro del server nomina la fase che è fallita.

18 Operazioni

18.1 Distribuzione

Un binario e due percorsi: una directory di file di canale e un file di database. Non c'è un server di applicazioni, nessun livello web separato e nessun broker di messaggi richiesto.

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

Eseguirlo sotto qualsiasi cosa supervisioni i servizi sull'host — systemd, launchd, un runtime del contenitore. Si aspetta di essere riavviato se esce.

18.2 Dove i dati possono andare (residenza dei dati)

serve -residency (Impostazioni → Dati → Dove i dati possono andare) nomina le regioni cloud in cui i dati di questo server possono essere inviati o letti: aree (eea, uk, ch) e codici di regione (eu-central-1, uksouth, europe-west2), separati da virgole. eea sono le regioni AWS, Azure e Google Cloud nell'Area Economica Europea (Frankfurt, Irlanda, Parigi, Stoccolma, Milano, Spagna; Paesi Bassi, Germania, Francia, Svezia, Norvegia, Italia, Polonia, Spagna; Belgio, Paesi Bassi, Germania, Italia, Francia, Finlandia, Spagna, Polonia), uk quelle nel Regno Unito, ch quelle in Svizzera.

Con esso impostato, un canale viene rifiutato quando viene salvato e quando viene caricato, se un connettore nomina una regione al di fuori dell'elenco: una sorgente o destinazione S3, SQS o SNS con region (o il suo endpoint, quando è un hostname AWS), o qualsiasi destinazione il cui indirizzo è un hostname AWS che trasporta una regione (sqs.us-east-1.amazonaws.com, un URL dell'API Gateway). Il server rifiuta di avviarsi con un collector di tracce o un webhook di allarme in un'altra regione. Un connettore puntato a un host che non nomina una regione (un sistema di un ospedale, MinIO nella rete del sito) non viene giudicato: il record dell'elaborazione sullo schermo di protezione dei dati elenca ogni host a cui ogni canale invia, per il controllore di verificarlo. Il cruscotto e lo schermo di protezione dei dati dicono dove i dati possono andare.

Hosting nell'UE e nel Regno Unito. deploy/hosted contiene OpenTofu (o Terraform) per un server ospitato per organizzazione a Francoforte, Irlanda o Londra: il server, il suo database PostgreSQL e i backup, un bucket di backup, log e record di sessioni di supporto, tutto criptato con una chiave nella Regione, nulla replicato in un'altra Regione, supporto tramite Session Manager solo, e Perfuse eseguito con -residency. Il suo README dice cosa costruisce, cosa non copre, cosa è stato verificato (validato e pianificato contro un account reale; non ancora applicato) e cosa costa al prezzo di lista in ogni Regione.

18.3 Configurazione come file

I canali sono file, il che significa che possono essere in controllo di versione, esaminati prima della distribuzione e confrontati dopo un incidente.

I file vengono riletto senza riavvio. Un file che non si analizza viene segnalato e la versione precedentemente caricata continua a funzionare, quindi un errore di sintassi non può interrompere un feed funzionante.

Un canale modificato nell'interfaccia web viene scritto nuovamente nel suo file. Se questi file sono in controllo di versione, si prevedono commit dalle modifiche di configurazione apportate tramite l'interfaccia, e non si modifichi manualmente un file mentre qualcun altro lo ha aperto nel costruttore.

18.4 Backup

Due cose da eseguire il backup, e hanno caratteristiche diverse.

La directory del canale è piccola, cambia raramente e è ciò di cui hai bisogno per ricostruire il servizio. Eseguire il backup come configurazione; il controllo di versione è di solito sufficiente.

Il database contiene messaggi, utenti e storia di audit. È grande, cambia costantemente e contiene dati clinici — quindi ha bisogno di essere eseguito il backup come dati clinici, con la conservazione e la crittografia che ne conseguono. La perdita di esso non interrompe il servizio, ma perde la capacità di indagare su tutto ciò che è già accaduto e la storia di cui dipende l'apprendimento del ritmo.

18.5 Comportamento di riavvio

Al riavvio, i canali vengono caricati e le sorgenti iniziano ad ascoltare. Le consegne in coda riprendono.

La cosa da capire è cosa succede al lavoro in volo. Con l'acknowledgement predefinito on_delivery, un messaggio che non era stato ancora confermato non viene confermato, quindi il mittente lo rinviará — che è l'esito corretto. Con on_receipt, un messaggio che era stato confermato ma non ancora consegnato è nella coda e riprende; se la coda è disabilitata, viene perso. Vedi flusso di messaggi.

18.6 Aggiornamento

Sostituire il binario e riavviare. Lo schema del database viene migrato in avanti automaticamente all'avvio.

Le migrazioni sono solo in avanti. Non c'è downgrade, quindi un rollback a un binario precedente dopo che lo schema è stato spostato richiede il database precedente. Prendere una copia prima di eseguire l'aggiornamento — questa è l'unica precauzione operativa per cui vale la pena essere disciplinati.

18.7 Monitoraggio

L'allertamento all'interno di Perfuse è coperto in allertamento e sarà ciò che ti dirà che un feed si è fermato.

Dall'esterno, monitorare il processo, il disco su cui si trova il database e se l'interfaccia web risponde. Il database cresce e un disco pieno interrompe la registrazione dei messaggi, che è una modalità di guasto senza altri avvisi.

18.7.1 SNMP

Per strumenti di monitoraggio che parlano SNMP (Nagios, Zabbix, PRTG, SolarWinds, LibreNMS), Perfuse esegue un agente SNMPv2c in sola lettura e invia una trappola quando un allarme si attiva o si risolve. Impostalo sotto Impostazioni → Monitoraggio → SNMP, o con flag:

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

BASE.1 (canali, in esecuzione, interrotti, ricevuti, consegnati, non riusciti, in coda) e una tabella dei canali sotto BASE.2.1 (nome, in esecuzione o interrotto, ricevuti, consegnati, non riusciti, in coda, età del messaggio più vecchio in coda). I numeri sono quelli visualizzati dal cruscotto e /metrics.

gravità, canale, destinazione e riassunto. Mai il contenuto del messaggio. Un allarme riconosciuto non invia trappole.

numero di impresa. Scarica il MIB nella pagina Impostazioni (o GET /api/snmp/mib) fornisce un MIB per la base in uso; lo stesso pannello indica se l'agente sta rispondendo e quanti allarmi sono stati inviati.

18.7.2 Un inventario di ogni interfaccia

-inventory interfaces.md (Impostazioni → Monitoraggio → Inventario) scrive un documento Markdown che elenca ogni canale - il suo formato, se è in esecuzione, cosa riceve da e cosa invia a - seguito dalla descrizione di ogni canale, e lo riscrive ogni -inventory-every (un giorno per default). È destinato a essere commitato accanto ai file del canale, o consegnato a un revisore, e letto senza che l'applicazione sia in esecuzione.

18.8 Capacità

Il soffitto di throughput di Perfuse non è stato misurato su hardware reale in traffico reale, e questo manuale non stampa un numero che non possa supportare.

Ciò che può essere detto: l'architettura è un goroutine per connessione con code per destinazione, quindi il throughput scala con le destinazioni piuttosto che essere serializzato attraverso un solo lavoratore; la registrazione dei messaggi è una scrittura SQLite per messaggio, che rende il disco la limitazione più probabile; e l'archiviazione dei messaggi cresce linearmente con il traffico, quindi la conservazione è l'impostazione che governa l'utilizzo del disco a lungo termine.

Se si sta dimensionando questo per un grande feed, misurarlo con il proprio traffico utilizzando il corpus di test generato descritto in testing. Questa è la risposta onesta, ed è anche una risposta migliore di un numero proveniente da hardware di qualcun altro.

18.9 Dove questa installazione si è bloccata

L'attività porta un pannello, visibile agli amministratori, che mostra cosa Perfuse ha rifiutato di fare — raggruppato per messaggio, più frequente per primo — e quanto l'installazione ha progredito verso un canale funzionante.

Esiste perché ogni altra affermazione sulla facilità d'uso di questo software proviene dalle persone che lo hanno scritto. Un rifiuto non è così: qualcuno voleva qualcosa, il server ha detto no e nessuna delle due parti stava indovinando. È l'unica prova nel prodotto che non proviene da BioDream LLC.

Il funnello nomina il passaggio che non è ancora avvenuto piuttosto che lasciare i timestamp da confrontare. Lo stato degno di essere osservato è i messaggi arrivano e nessuno è stato consegnato a una destinazione — un canale può gestire il traffico per settimane e non consegnare nulla, e da ogni altro schermo sembra che funzioni.

Nessuno di ciò che qualcuno ha digitato è registrato. La tabella contiene il percorso della richiesta con gli identificatori sostituiti da {id}, lo stato e la frase del server. Un messaggio di convalida nomina un campo e una regola, che è la parte utile; il valore che ha violato la regola è molto spesso un dato del paziente e una tabella di questi sarebbe una responsabilità peggiore della frizione che misura.

Due esclusioni deliberate. Un 5xx è un errore in questo software e viene già registrato come tale — mescolare i due seppellirebbe i casi in cui qualcuno non poteva capire cosa digitare sotto i casi in cui nulla di ciò che hanno digitato avrebbe aiutato. E una sessione scaduta produce una serie di 401 che non dicono nulla sulla facilità d'uso e sommergerebbero ogni scoperta che lo fa.

La lettura del report tronca anche la tabella alle sue ultime cinquemila righe. I rifiuti sono risposte 4xx quindi cresce lentamente, e la lettura è un momento naturale per sistemare: nessun timer e nulla che funzioni quando nessuno sta guardando.

GET /api/friction restituisce la stessa cosa per chi preferisce leggerla come JSON.

18.10 Registri

Perfuse registra l'output standard, che è dove un supervisore o un runtime del contenitore lo raccoglierà.

I dettagli a livello di messaggio vanno al message store invece del registro, intenzionalmente. Una riga di registro per messaggio in un feed attivo è rumore che nasconde le righe che contano, e il negozio è ricercabile in modi che un file di registro non è.

Il registro porta ciò che il negozio non può: avvio e arresto, risultati del caricamento della configurazione, modifiche dello stato del canale e errori che non sono attribuibili a un messaggio specifico.

18.11 Esecuzione di due istanze

Due o più server possono essere eseguiti come un cluster: quando il server che esegue un feed si ferma, un altro lo assume entro pochi secondi, e il prossimo tentativo del mittente lo raggiunge. Condividono un database PostgreSQL invece di ogni server che mantiene un file SQLite, e si accordano tra loro, attraverso di esso, su quale di loro esegue cosa.

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

Avvia ogni server allo stesso modo con il proprio nome e indirizzo. L'account del database deve creare tabelle e, una volta, la estensione citext (o un amministratore esegue CREATE EXTENSION citext prima). Ogni server mantiene i propri file in -data: il proprio log, il proprio ID di nodo e le proprie copie della configurazione.

Due modi di condividere il lavoro.

altri aspettano. Il più semplice da capire, e ciò che un sito con un server occupato e uno di riserva vuole.

agli altri; uno che si unisce prende la propria quota man mano che i canali sono liberati, uno alla volta. I canali che instradano l'uno all'altro (una destinazione del canale) vengono eseguiti su un server e si spostano insieme, perché l'instradamento avviene all'interno di un server. Un amministratore può spostare un canale manualmente da Monitor → Fleet; rimane dove è stato messo finché quel server vive.

Chi esegue cosa, e nessun momento con due. Ogni pezzo di lavoro è un lease nel database, rinnovato ogni quinto di -cluster-lease (15 s per impostazione predefinita). Un server che non può rinnovarlo (si è bloccato, la sua rete è fallita, il database non è raggiungibile) ferma quel lavoro da solo una volta che il proprio orologio dice che il lease è quasi finito, con un terzo del lease di riserva. Un altro server prende il lease solo dopo che il proprio orologio ha osservato il contatore del lease rimanere fermo per un intero lease. Nessun orologio viene confrontato con un altro, quindi gli orologi dei server e del database non devono essere coerenti; devono solo funzionare più o meno alla stessa velocità, il che ogni orologio fa. Tra la fine del vecchio detentore e l'inizio del nuovo c'è un breve intervallo con nessuno in ascolto, che un mittente vede come una connessione rifiutata e ritenta; non c'è mai un momento con due in ascolto su un feed o due lavoratori che svuotano una coda.

Un server che si spegne in modo pulito, o un amministratore che sceglie Ritira sul leader, passa il testimone subito invece di aspettare il lease.

Cosa ogni server condivide. I messaggi, la coda di consegna, gli account e le sessioni, il log di audit, l'archivio FHIR, le tabelle di terminologia e l'indice dei pazienti sono nel database, quindi qualunque server esegua un canale trova la coda che l'ultimo ha lasciato. I file del canale, il file di impostazioni, le regole di allarme, i file di accesso singolo, il logo, i certificati Direct e le viste salvate vengono mantenuti uguali su ogni server attraverso il database: ogni server mantiene la propria copia sul proprio disco, una modifica su qualsiasi server (nella console, a mano, tramite git pull) raggiunge gli altri entro due secondi, e un canale modificato su un altro server si riavvia con il nuovo file. Lo stesso file modificato su due server contemporaneamente mantiene la versione che ha raggiunto il database per prima, e l'altro accanto come NAME.conflict-SERVER. Le impostazioni che si applicano solo al riavvio (il database dei messaggi, le porte che la console ascolta) vengono applicate da ogni server al prossimo riavvio, e il log lo dice. Cosa nomina qualcosa su una macchina rimane sulla riga di comando del server e fuori dal file condiviso: il certificato e la chiave (-tls-cert, -tls-key), l'indirizzo di ascolto SNMP e il nome del server nelle tracce. Le impostazioni li visualizzano come impostati su ogni server.

Avvio e arresto. L'avvio o l'arresto di un canale su qualsiasi server si applica al cluster: il server che lo esegue lo avvia o lo arresta entro un secondo, e la risposta indica quale server lo fa.

Il bilanciatore di carico davanti. L'indirizzo di un feed deve raggiungere il server che lo esegue. Puntare il mittente a un indirizzo virtuale (un bilanciatore di carico, un IP galleggiante, un nome DNS con un TTL breve) e fare in modo che il bilanciatore di carico controlli /readyz?channel=NAME, che risponde 200 solo sul server che esegue quel canale, e 503 sugli altri. Per la console, /readyz è 200 su ogni server attivo; /readyz?role=leader solo sul leader.

Su un AWS Network Load Balancer, utilizzare un gruppo di destinazione per feed con un controllo di salute HTTPS su /readyz?channel=NAME, un intervallo di 5 secondi e una soglia di 2, e attivare il bilanciamento di carico tra zone. Con esso disattivato, il nodo del bilanciatore di carico in una zona in cui nessun server esegue il feed vede solo destinazioni non sane, invia comunque a tutte loro, e un mittente che ha risolto quel nodo attende fino a quando il feed non torna nella sua zona (95 secondi in un test). Impostare il ritardo di deregistrazione su 0, poiché un server che smette di eseguire un feed non ha nulla da drenare.

Ciò che è stato testato. Due server su PostgreSQL 16, un mittente che invia 300 messaggi, rinviando fino a quando non riceve una risposta, e il server che esegue il feed ucciso con SIGKILL due volte (la prima, poi la seconda dopo che la prima è tornata). Ogni messaggio riconosciuto ha raggiunto il ricevente, in entrambe le forme provate: consegnato prima dell'ack, e in coda nell'archivio condiviso mentre il ricevente rifiutava (185 messaggi riconosciuti in coda al momento dell'uccisione; il superstite li ha consegnati tutti). Il failover ha richiesto da 3 a 4 secondi su un lease di 3 secondi. Una copia è possibile e si è verificata una volta su 600: un messaggio che il server morente ha consegnato e non ha potuto riconoscere, che il mittente ha rinviato. I test del coordinatore coprono un crash, un server tagliato fuori dal database mentre è in esecuzione, step-down, diffusione, spostamenti e configurazione condivisa con conflitti. Vengono eseguiti in CI contro PostgreSQL con il rilevatore di gare, con l'intera suite.

Lo stesso è stato fatto su AWS: due server Linux (ARM) e un server Windows Server 2022 in tre zone di disponibilità, Amazon RDS PostgreSQL 16 su TLS con il certificato verificato (sslmode=verify-full), un bilanciatore di carico di rete interno in fronte, e mittenti che rinviavano fino a quando non ricevevano una risposta:

TestMessaggiConfermati ma persiCopieTempo più lungo atteso da un mittente
Attivo-passivo, il server che esegue il flusso ucciso due volte (Linux, poi Windows), destinatario che rifiuta nel frattempo2.0000015 s
Un leader Linux tagliato fuori dal database (firewall), il suo processo lasciato in esecuzione3.0000116 s
Un leader Windows tagliato fuori dal database3.0000020 s
Il leader ucciso mentre un orologio del server correva 2 minuti avanti e un altro 90 secondi indietro2.0000018 s
Attivo-attivo, quattro flussi su tre server, uno ucciso e riportato6.0000224 s

Con il lease predefinito di 15 secondi, un server tagliato fuori dal database ha fermato il suo feed 10 secondi dopo l'ultima rinnovazione, e il prossimo server lo ha avviato 6-8 secondi dopo: mai entrambi contemporaneamente. Gli orologi distorti non hanno cambiato nulla, poiché nessun orologio viene confrontato con un altro.

Non ancora. Un cluster serve un'organizzazione: -cluster con -multi-tenant viene rifiutato. Gli ascoltatori si spostano con il loro canale, quindi il bilanciatore di carico è di competenza del sito.

Un server da solo continua a funzionare come sempre, su SQLite, senza cluster.

18.12 Più di un server

Un sito con due istanze ha una domanda a cui nessuna console singola può rispondere: è tutto in esecuzione? Mirth addebita per la risposta. Questa è la visualizzazione della flotta.

Un'istanza è designata come il luogo in cui si guarda. Interroga le altre e visualizza ogni canale su ogni server in una tabella, con un riepilogo su tutti loro.

18.12.1 Aggiungere un peer

Impostazioni → Flotta, o PUT /api/fleet/peers. Un peer necessita di un nome, un URL e un token rilasciato dal peer stesso.

Il nome è obbligatorio e non è l'URL, perché un URL non è qualcosa che chiunque riconosca alle tre del mattino.

Il token deve essere creato sul peer, sotto Utenti, e dovrebbe avere un ambito di visualizzazione. L'aggiunta di un peer senza uno di questi token viene rifiutata, con queste istruzioni, piuttosto che essere accettata e poi fallire silenziosamente ad ogni poll. La lettura dello stato di salute di un'altra istanza è il privilegio minimo che esiste, ed è l'unico di cui ha bisogno la visualizzazione della flotta.

18.12.2 Controllo di un peer, che è spento

allow_control consente di avviare e fermare i canali di quel peer da qui. È disattivato per default e ogni utilizzo viene registrato per nome.

I due privilegi sono deliberatamente separati. Leggere la salute di un altro server è una questione minore; fermare i suoi canali durante una trasfusione non lo è, e il secondo non dovrebbe mai arrivare silenziosamente allegato al primo.

18.12.3 Cosa dice il report

Ogni server segnala il numero totale di canali, quanti sono in esecuzione, fermi o in errore, la profondità della coda e l'età del messaggio più vecchio in attesa, quanti allarmi sono attivi, e se sta drenando per lo spegnimento.

Il riepilogo conta i server in tre modi: raggiungibile, irraggiungibile e indeterminato. Il terzo copre i peer di cui nessuno conosce la salute — non ancora interpellati, rifiutanti il token, o in esecuzione di una versione che questo non può leggere. Viene tenuto separato dall'irraggiungibile perché "non sappiamo" non è "è giù", e fondere i due insieme è come iniziare a mentire su una pagina della flotta.

Per lo stesso motivo, il rollup riporta knownFrom: quante istanze i dati del canale e della coda sono stati effettivamente letti. Dodici canali in esecuzione su una flotta significano qualcosa di diverso quando due dei cinque server non hanno risposto e il totale da solo non può dirlo.

Un peer irraggiungibile dice perché in termini che un operatore può utilizzare. Una connessione rifiutata viene segnalata come l'host che è attivo senza nulla in ascolto su quella porta, che è un problema diverso da un host che non risponde affatto.

18.12.4 Differenza di orologio

Il rollup riporta la maggiore differenza tra gli orologi dei server in esso. Vale la pena di un numero proprio: la correlazione di un incidente tra due istanze le cui ore non concordano di quattro minuti produce una sequenza di eventi che non è avvenuta.

18.12.5 Cosa un peer apprende da te

Conteggio e tassi. Il report che un'istanza fornisce a un'altra non contiene identificatori di messaggio, dettagli a livello di canale e nessun dato paziente di alcun tipo.

È ciò che impedisce a una visualizzazione della flotta di essere una centralizzazione dei dati clinici: l'istanza aggregante apprende quanti canali sono in esecuzione e nulla riguardo a ciò che è stato trasmesso attraverso di essi. Se si desiderano i messaggi, si apre la console del server stesso, dove il registro di audit registra che lo si è fatto.

18.12.6 Un peer puntato a se stesso

Rifiutato. Un'istanza che interpella il proprio indirizzo attraverso il proprio stack HTTP appare due volte nella propria visualizzazione della flotta e conta due volte ogni canale che possiede.

18.12.7 TLS nelle reti interne

insecure_skip_verify accetta il certificato di un peer senza verificarlo. Esiste perché l'infrastruttura ospedaliera funziona con autorità di certificazione private e rifiutare di funzionare affatto spingerebbe le persone verso HTTP semplice, che è peggiore. È denominato in modo che non possa essere scambiato per una buona idea.

19 La riga di comando

Tutto ciò che Perfuse fa a un sistema in esecuzione è raggiungibile dall'interfaccia web, e ciò è deliberato: una funzionalità che necessita di un terminale è trattata come un difetto piuttosto che come una scelta di progettazione. I comandi qui sono per il lavoro che avviene *intorno* a un sistema in esecuzione — prima che esista, mentre si decide se fidarsi di esso e quando è necessario consegnare qualcosa a qualcun altro.

Molti di essi non toccano affatto un server. perfuse explain, perfuse profile, perfuse deident e perfuse translate leggono file e scrivono file, quindi sono utili su un laptop contro un patrimonio che ancora funziona interamente con qualcos'altro.

Eseguire qualsiasi comando con -h per le sue opzioni. Questo capitolo dice a cosa serve ogni comando.

Le opzioni mostrate qui sono illustrative, non esaustive. -h è generato dal codice e non può essere obsoleto; un elenco copiato nella prosa può.

19.1 Esecuzione dei canali

19.1.1 perfuse serve

Esegue l'interfaccia web e l'API e, per default, esegue anche i canali. Questo è il comando utilizzato da un'installazione.

Ogni opzione che accetta è elencata in Opzioni del server, generata dal programma. Rifiuta di servire HTTP non crittografato a tutto tranne che al loopback a meno che non si passi -insecure. Ciò non è una configurazione di cortesia: il traffico clinico e un cookie di sessione su una connessione LAN non crittografata è un evento segnalabile e la bandiera esiste in modo che dire sì sia una decisione presa da qualcuno piuttosto che un'impostazione predefinita ereditata. Vedi sicurezza.

19.1.2 perfuse run

Esegue i canali da YAML senza interfaccia web e senza database. Utile in un contenitore che dovrebbe fare esattamente una cosa e utile quando si desidera vedere il comportamento di un canale senza che nulla altro sia in esecuzione.

19.1.3 perfuse check

Convalida le definizioni dei canali e stampa cosa fanno, senza eseguirle. La seconda metà è il punto: un canale che si carica non è necessariamente il canale che si intendeva e la lettura di un riassunto in inglese chiaro di cosa farà un file coglie un errore che la convalida non può vedere.

Esci con un codice diverso da zero in caso di errore, quindi appartiene a qualsiasi controllo della configurazione prima che raggiunga un server. -quiet non stampa nulla in caso di successo, per questo utilizzo.

-allow-metadata-egress consente ai destinatari di puntare agli indirizzi dei metadati delle istanze cloud. Tali indirizzi contengono le credenziali della macchina stessa, quindi un canale che può essere convinto a inviare lì è una perdita di credenziali; il controllo rifiuta tali indirizzi a meno che non si specifichi diversamente.

19.1.4 perfuse test

Esegue i test scritti contro le definizioni dei canali. Un test invia un messaggio attraverso il filtro reale del canale, le trasformazioni reali e gli script reali, nell'ordine reale, con solo la rete sostituita — quindi ciò che passa qui è ciò che il canale fa.

I test si trovano in *_test.yaml o *.test.yaml accanto ai canali. Vedi testing.

19.2 Migrazione da un altro motore

Questi tre sono quelli da eseguire per primi, prima di decidere qualsiasi cosa. Vedi migration.

19.2.1 perfuse explain

Legge le esportazioni di Mirth, Open Integration Engine e BridgeLink — un canale, un gruppo di canali o un backup di un intero server — e descrive cosa fa ogni canale e cosa bloccerebbe una migrazione. Non modifica nulla e non richiede un'installazione di Perfuse, il che lo rende il passo più economico possibile: puntarlo a un'esportazione del proprio patrimonio e leggere cosa viene restituito.

-strict esci con un codice diverso da zero se qualcosa è bloccato, quindi può essere utilizzato per controllare una pipeline. -json emette gli stessi risultati per una macchina.

19.2.2 perfuse translate

Converte le esportazioni di Mirth, Open Integration Engine e BridgeLink in file di canali Perfuse: un canale, un gruppo di canali, un'esportazione di una libreria di modelli di codice o un backup di un intero server.

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

Le librerie di modelli di codice vengono scritte nella cartella lib/ accanto ai canali e ogni canale di Mirth include la libreria abilitata per esso. Vedi migration.

Nessuna parte di un canale viene silenziosamente eliminata. Ogni parte di un canale viene tradotta, portata come uno script che esegue invariato o segnalata come necessitante di un intervento umano. L'ultima categoria è quella onesta — un traduttore che produce un file pulito per ogni input starebbe nascondendo le decisioni che più si necessitano di prendere.

19.2.3 perfuse compare

Esegue lo stesso traffico attraverso due motori e segnala dove sono in disaccordo, raggruppati per campo.

Questo è il comando che risponde alla domanda "perché dovrei fidarmi di questo con i dati dei pazienti", e risponde con le prove che hai raccolto piuttosto che con un'affermazione fatta qui. È il passo finale consigliato prima di effettuare il cut-over e il primo passo consigliato in qualsiasi discussione su se Perfuse è pronto.

19.3 Comprendere un feed

19.3.1 profilo di Perfuse

Legge i messaggi e segnala cosa contiene effettivamente: quali campi sono sempre popolati, quali mai, i set di valori reali dei campi codificati, i contatori di ripetizione e quali segmenti Z appaiono.

I valori vengono segnalati solo per i campi il cui valore forma un piccolo set di codici, in modo che un profilo del traffico reale non diventi un file pieno di dati dei pazienti.

Salvare un profilo e confrontarlo in seguito è il modo per scoprire che un mittente ha cambiato qualcosa:

perfuse profile -save last-month.json corpus/ perfuse profile -against last-month.json new/

19.3.2 contratto di Perfuse

Trasforma l'output di quel pensiero in qualcosa di applicabile. Un contratto dice come deve essere un feed, in modo che il giorno in cui cambia, tu venga avvisato, piuttosto che scoprirlo settimane dopo da un ricevitore che è caduto — i messaggi sono ancora validi HL7 quando un campo scompare, quindi nulla altro si accorge.

perfuse contract promote -o adt.contract.yaml corpus/ perfuse contract check adt.contract.yaml today/

promote genera un punto di partenza, non una risposta. Leggilo e cancella la maggior parte di esso: ogni riga registra se è stata misurata o decisa, che è ciò che ti dice quali righe tenere.

19.4 Produzione di messaggi

19.4.1 perfuse generate

Produce messaggi sintetici HL7 v2. Tutto è inventato — nomi ovviamente fittizi, identificatori sequenziali, indirizzi inventati — quindi l'output è sicuro da inviare, inviare e allegare a un ticket.

Può inviare direttamente a un canale invece di scrivere un file, che è il modo più veloce per dimostrare che un listener funziona:

perfuse generate -n 100 -send 127.0.0.1:6661

19.4.2 perfuse deident

Legge messaggi reali e scrive un corpus che mantiene la loro struttura, i loro codici e i loro intervalli, e nessuno di ciò che identifica un paziente. Questa è la differenza tra essere in grado di inviare a qualcuno una riproduzione e non.

Non è lo stesso strumento di perfuse generate e la distinzione è importante. I messaggi generati sono inventati e quindi sicuri ma irrealistici; un corpus de-identificato è *derivato dal traffico reale*, quindi riproduce le stranezze che effettivamente rompono le interfacce.

Due proprietà degne di nota prima di utilizzarlo:

-keep-local-segments passa i segmenti Z invariati e non è sicuro. I segmenti Z sono esattamente dove i siti mettono i nomi, le note e il testo libero, quindi mantenerli sconfigge lo scopo dello strumento. Esiste perché un problema strutturale è talvolta *in* un segmento Z, e allora hai bisogno di un corpus che non puoi condividere.

19.5 Spostamento dei messaggi manualmente

19.5.1 perfuse listen

Accetta HL7 v2 su MLLP e lo conferma. Un ricevitore che esiste per tutto il tempo necessario, per dimostrare che un mittente può raggiungere questa macchina.

19.5.2 perfuse invia

Invia messaggi HL7 v2 su MLLP da file.

MLLP non ha autenticazione e non ha crittografia, in Perfuse o altrove. Entrambi questi comandi sono soggetti a ciò, così come ogni origine e destinazione MLLP: l'accesso è limitato a livello di rete o non è limitato.

19.6 FHIR

19.6.1 perfuse fhir

Converte HL7 v2 in FHIR, convalida FHIR o lo serve, a seconda del sottocomando.

Il sottocomando di convalida è utile di per sé: ti dirà se una risorsa che qualcuno ti ha inviato soddisfa US Core, che è il profilo contro cui è scritta la regolamentazione americana. Essere in grado di rispondere a ciò senza adottare un motore è l'obiettivo.

19.6.2 perfuse x12

Converte X12 (o altri EDI delimitati) in XML Mirth Connect e Open Integration Engine scrive per esso e viceversa: perfuse x12 xml FILE e perfuse x12 from-xml FILE, input standard quando non è specificato un file. L'output è esattamente ciò che OIE 4.6 scrive, byte per byte, in modo che possa essere confrontato con ciò che un server Mirth ha prodotto o alimentato a un sistema costruito contro di esso. Un canale fa la stessa cosa con x12.arrives_as: xml e x12_as: xml di una destinazione; vedere X12.

19.6.3 perfuse sof

Esegue un SQL su FHIR ViewDefinition su file FHIR (il NDJSON di un'esportazione bulk, Bundles o array JSON; - per stdin) e scrive la tabella: -view FILE (obbligatorio), -format csv|ndjson|json|parquet (csv per default), -header=false e -o FILE (obbligatorio per Parquet). Vedi SQL on FHIR views.

19.6.4 perfuse misura

Valuta una misura di qualità con criteri FHIRPath su file FHIR (il NDJSON di un'esportazione bulk, Bundles o array JSON; - per stdin) e scrive il MeasureReport. Flag:

Vedi misure di qualità digitali.

19.6.5 Flag FHIR su perfuse serve

FlagEffetto
-fhirServire l'endpoint FHIR a /fhir. Attivato per default.
-fhir-versionLa versione servita. R4 per default.
-fhir-read-onlyRifiutare le scritture.
-fhir-api-tokensCon SMART configurato, accettare i token API Perfuse oltre ai token SMART (disattivato per default; anche sotto Impostazioni → FHIR).
-fhir-bulk-exportAbilitare $export. Disattivato per default.
-fhir-subscriptionsAbilitare le sottoscrizioni ai topic: notifiche di encounter e appuntamento agli endpoint scelti dai client FHIR. Disattivato per default; necessita di R4 e di un endpoint scrivibile.
-fhir-subscriptions-allow-httpConsentire alle sottoscrizioni di consegnare a http semplice. Per un ricevitore di test, mai per i dati dei pazienti su una rete.
-fhir-patient-directory-searchConsentire a un token limitato a un paziente di cercare la directory (operatori sanitari, organizzazioni, località), all'interno dei suoi ambiti. Disattivato per default.
-fhir-declaresGuide che questo server dichiara nella sua dichiarazione di capacità, separate da virgole: l'indirizzo CapabilityStatement di una guida, o Type=profile indirizzo. Una dichiarazione per i client e i kit di test; non cambia nulla che l'archivio accetta.

Il negozio mantiene documenti nonché risorse: un documento, raccolta o messaggio Bundle PUT su /fhir/Bundle/{id} viene mantenuto integro, letto nuovamente con ogni voce nella versione servita e trovato per type, identifier, timestamp e composition. Una transazione PUT lì viene mantenuta come record e non applicata; un POST su /fhir ne applica uno.

Le risposte sono in JSON a meno che il client non chieda XML (Accept: application/fhir+xml, o _format=xml). Perfuse legge solo JSON: un corpo inviato come XML ottiene 415. Un documento Bundle POSTato a /fhir viene mantenuto quando questo server tiene, per identificatore, il paziente e l'incontro che la sua Composizione nomina, e rifiutato con 422 altrimenti. Una lettura Binaria con Accept impostato sul suo tipo di contenuto risponde con il contenuto stesso.

19.7 Impostazione e funzionamento

19.7.1 perfuse init

Crea la struttura delle directory, un canale di esempio e una definizione di servizio per il sistema operativo su cui viene eseguito. Nulla di esistente viene sostituito a meno che non si passi -force.

perfuse init -dir /opt/perfuse -service systemd

19.7.2 perfuse servizio

Registra Perfuse come servizio Windows, lo rimuove o segnala se è installato e in esecuzione. Solo Windows; su Linux l'equivalente è il file unitario perfuse init che può scrivere per te. Vedi operazioni.

19.7.3 perfuse token

Rilascia credenziali per macchine anziché persone. Un token non scade e non è influenzato da chiunque si disconnetta, il che è ciò di cui un server che interpella il suo vicino ha bisogno e ciò che una sessione del browser non è intenzionalmente.

perfuse token crea -db perfuse.db -etichetta flotta-da-sito-a -ruolo visualizzatore perfuse token elenca -db perfuse.db perfuse token revoca -db perfuse.db -etichetta flotta-da-sito-a

Viene memorizzato solo l'hash, quindi un token viene visualizzato una volta quando viene creato e non può essere recuperato in seguito. Un database rubato non produce quindi alcun token utilizzabile. Assegna a un token il ruolo più basso che faccia il lavoro: una visualizzazione a livello di flotta richiede viewer e nulla che legga solo deve avere nulla di più.

-fhir-groups riverside-attributed,riverside-north limita un token a quei gruppi FHIR, per un'esportazione del fornitore CMS-0057 Provider Access: sull'endpoint FHIR può leggere quei gruppi ed esportarli, e nulla altro. Vedi CMS-0057 per i pagatori.

19.7.4 Perfuse Athena

Stampa la tabella esterna di Amazon Athena CREATE EXTERNAL TABLE per un archivio S3 scritto con format: ndjson, utilizzando la proiezione di partizione sulla parte dt=YYYY-MM-DD della chiave, in modo che non debba essere eseguito alcun crawler man mano che vengono aggiunti giorni.

Perfuse Athena -bucket hospital-archive -destination archive

Viene stampato anziché eseguito, poiché la creazione di una tabella richiede autorizzazioni Athena e Glue che questo programma non dovrebbe possedere.

19.7.5 Perfuse SBOM

Elenca tutto ciò che è collegato al binario, letto dal build stesso anziché da go.mod — quindi descrive il binario di fronte a te e non ciò che qualcuno ha richiesto in precedenza.

-json emette CycloneDX e -spdx emette SPDX tag-value, che è generalmente ciò che una revisione di approvvigionamento o di sicurezza sta effettivamente richiedendo. Il codice del browser incorporato nel binario è incluso, poiché un revisore che confronta un binario con gli avvisi di sicurezza deve sapere che contiene un'applicazione React.

19.7.6 Perfuse versione

Stampa la versione e il commit da cui è stato costruito. Vale la pena inserirlo in un ticket: "l'attuale" non è una versione, e due macchine che sono state installate a una settimana di distanza spesso non eseguono lo stesso build.

20 Opzioni del server

Ogni opzione perfuse serve accetta, generata dal programma stesso, quindi questa lista non può nominare un'opzione che non esiste o ometterne una. La maggior parte di esse sono anche un'impostazione nell'interfaccia web, denominata nell'ultima colonna: un valore salvato lì vince sul flag al prossimo avvio, e il flag rimane il modo per impostarlo da una definizione di servizio. L'indirizzo di ascolto, il database e la directory del canale rimangono flag solo, poiché dicono al server dove trovare ciò che starebbe modificando.

I segreti non sono mai flag. Un'opzione che richiede una password o un token nomina una variabile d'ambiente che la contiene.

20.1 Tutte le opzioni

OptionTakesDefaultWhat it doesIn the console
-addrstring127.0.0.1:8080, or 127.0.0.1:8443 with -tls-certaddress to serve the interface on—
-alert-severitystringwarningminimum severity to send to the webhook: warning or criticalSettings › Alerts › Delivery: Only send alerts at least this serious
-alert-webhookstring—POST alerts to this URL as JSON. Works with Slack, Teams, Mattermost, Alertmanager or anything that accepts a webhook. The payload carries channel names, counts and thresholds; never message contentSettings › Alerts › Delivery: Send alerts to this address
-alertsstring—YAML file of alert rules. Default: alerts.yaml beside the database, written when the rules are first saved in the console; until then a conservative default set is used—
-allow-metadata-egresson/off—permit destinations pointed at cloud instance metadata addresses, which hold this machine's credentialsSettings › Security › What may leave: Allow destinations at cloud instance metadata addresses
-cds-clientsstring—the EHRs trusted to call the CDS services with signed JWTs (issuer and jwks_url)Settings › Payers › Prior authorization: EHRs trusted to call the CDS services
-channelsstring./channelsdirectory holding channel files—
-clusterstring—share the work with other servers on the same PostgreSQL -db: active-passive (one runs everything, another takes over when it stops) or active-active (channels spread over all)—
-cluster-leaseduration15show long a crashed server holds its work before another takes it over; renewed five times as often—
-crd-advisor-castring—a PEM file of certificate authorities to trust for -crd-advisor-url beside the system's (Vaglio's is its DATA/tls/ca.crt)Settings › Payers › Decision service: Certificate authorities to trust for the advice service
-crd-advisor-token-envstring—name of an environment variable holding a bearer token for -crd-advisor-url (the token itself is never a flag)Settings › Payers › Decision service: Environment variable holding the advice service's token
-crd-advisor-urlstring—with -crd-rules, ask the decision service at this URL (such as Vaglio's /api/pas/advise) what a prior authorization request for each order needing one would be told as the record stands, shown as one more CRD card; the prefetched record is POSTed to it. No answer, or any failure, leaves the cards as they are without itSettings › Payers › Decision service: Advice before submitting (CRD)
-crd-rulesstring—a Da Vinci CRD rules file: serve coverage requirements over CDS Hooks at /cds-servicesSettings › Payers › Prior authorization: Coverage rules file (Da Vinci CRD)
-dashboardsstring—a file mapping directory groups and roles to the dashboard each opens onSettings › Monitoring › Dashboards: Which dashboard each group opens on (file)
-datastring—directory for this server's own files (settings, alerts, sign-in configuration, the log): default beside -db when it is a file, the current directory when it is a PostgreSQL URL—
-davinci-versionstring2.2the Da Vinci CRD, DTR and PAS release answered when neither a request nor its client's registration says: 2.2 (CRD 2.2.1, DTR 2.2.0, PAS 2.2.1) or 2.1 (2.1.0)—
-dbstring./perfuse.dbdatabase for users, messages and stored resources: a file, or a postgres:// URL for servers that share one store (a cluster)—
-demo-accountstring—for a public demonstration server: username:password of a shared viewer account shown on the sign-in page—
-dicomweb-archivestring—keep imaging objects in this directory and serve them over DICOMweb (QIDO-RS, WADO-RS, WADO-URI, STOW-RS) at /dicomwebSettings › Data › Imaging archive: Keep images in this folder and serve them over DICOMweb
-dicomweb-corsstring—comma-separated browser origins, such as an OHIF viewer's, allowed to call /dicomwebSettings › Data › Imaging archive: Browser origins allowed to call it
-drain-forduration—after SIGTERM, report not-ready for this long before shutting down (for rolling deploys)Settings › Engine › Shutdown: Wait for in-flight messages on shutdown
-ecr-agencystring—play a public health agency for testing eCR: answer case reports at $process-message with a Reportability Response, using the agency YAML file given (name, phone, address, endpoint; optional rctc, reply)Settings › Public health › Case reporting: Act as a test public health agency
-ecr-responseson/off—accept eCR Reportability Responses at the FHIR endpoint's $process-message, storing each as DocumentReference/<id> derived from the eICR it answersSettings › Public health › Case reporting: Receive Reportability Responses
-engineon/offtruerun the channel engine in this process, so the interface can start, stop and monitor channels—
-epa-payer-idstring—this payer's identifier on the prescribing network, the From of every RTPB and ePA response (default: the formulary's payer id)Settings › Payers › Drug formulary: Payer ID on the prescribing network
-epa-reply-channelstring—route ePA decisions made after the request was answered (a reviewer's, an appeal's) to this channel, which delivers them to the prescriber's networkSettings › Payers › Drug formulary: Channel that sends later ePA decisions
-fhiron/offtrueserve a FHIR endpoint at /fhirSettings › FHIR › The FHIR server: Serve a FHIR endpoint at /fhir
-fhir-api-tokenson/off—with SMART configured, accept Perfuse API tokens on the FHIR endpoint as well (unscoped; the console's FHIR settings can switch it)Settings › FHIR › Access: Accept Perfuse API tokens beside SMART tokens
-fhir-bulk-exporton/off—enable $export, which produces a file holding every record the FHIR endpoint servesSettings › FHIR › Bulk data: Bulk Data export ($export)
-fhir-declaresstring—guides this FHIR server declares in its capability statement, comma-separated: a CapabilityStatement address, or Type=profile addressSettings › FHIR › Capability statement: Guides this server declares
-fhir-max-resourcesint—for a public server: refuse new FHIR resources once this many are held (0: no limit)Settings › FHIR › Access: Most resources held
-fhir-member-match-without-consenton/off—let $member-match answer without an active Consent; the Payer-to-Payer API is opt-in, so only for testingSettings › Payers › CMS-0057-F: Answer $member-match without the member's consent
-fhir-openon/off—serve the FHIR endpoint with no authentication at all, exposing every stored recordSettings › FHIR › Access: Let anyone read the FHIR endpoint without signing in
-fhir-patient-directory-searchon/off—let a token limited to one patient search the directory (practitioners, organisations, locations) within its scopesSettings › FHIR › Access: Let a patient's app search the directory
-fhir-payer-apison/off—enable the CMS-0057 payer operations: $member-match (Payer-to-Payer) and Group $davinci-data-export (Provider Access); the Group exports also need -fhir-bulk-exportSettings › Payers › CMS-0057-F: The CMS-0057-F payer APIs
-fhir-read-onlyon/off—refuse writes to the FHIR endpointSettings › FHIR › Access: Refuse writes to the FHIR endpoint
-fhir-subscriptionson/off—enable topic-based subscriptions, which send encounter and appointment notifications to URLs FHIR clients chooseSettings › FHIR › Notifications: FHIR subscriptions (encounter and appointment notifications)
-fhir-subscriptions-allow-httpon/off—let subscriptions deliver to plain-http endpoints; for a test receiver, never for patient data on a networkSettings › FHIR › Notifications: Allow subscriptions to notify plain-HTTP addresses
-fhir-versionstring4.0.1FHIR release to serve: R4, R4B or R5Settings › FHIR › The FHIR server: FHIR version clients see
-fhir-writes-per-minuteint—for a public server: writes one client address may make to the FHIR endpoint a minute (0: no limit)Settings › FHIR › Access: Writes a minute from one client
-fleet-labelstring—how this instance names itself in a fleet view (default: hostname)Settings › Fleet › This server: Name for this server
-formularystring—publish this drug formulary over the Da Vinci US Drug Formulary API at /formulary/fhir and answer NCPDP Real-Time Prescription Benefit and SCRIPT electronic prior authorization from itSettings › Payers › Drug formulary: Drug formulary file
-icd11-client-idstring—a WHO ICD API client: ICD-11 codes not imported are looked up thereSettings › Data › Code systems: WHO ICD API client ID
-icd11-client-secretstring—the WHO ICD API client's secretSettings › Data › Code systems: WHO ICD API client secret
-icd11-releasestring2025-01the ICD-11 MMS release the WHO ICD API is asked aboutSettings › Data › Code systems: ICD-11 release to ask for
-icd11-urlstring—the ICD API's address when it is not the WHO's: the WHO's ICD-API container on your network needs no clientSettings › Data › Code systems: ICD API address
-index-identityon/offtrueindex patient identifiers from message contents so a message can be found by MRN, name or accession in any format; has no effect when -store-payloads is offSettings › Data › What is kept: Index patient identifiers
-insecureon/off—serve over plain HTTP on a non-loopback address (not recommended)—
-inventorystring—write a Markdown inventory of every interface to this file, and keep it currentSettings › Monitoring › Inventory: Write an interface inventory to
-inventory-everyduration24h0m0show often to rewrite the interface inventorySettings › Monitoring › Inventory: Rewrite the inventory every
-json-logson/off—emit structured JSON logsSettings › Monitoring › Logging: Write logs as JSON
-ldapstring—YAML file configuring directory (LDAP) sign-in (default: ldap.yaml beside the database, once saved in the console)—
-log-filestring—append the log, and the first administrator's one-time password, to this file (mode 0600) instead of the console. A Windows service has no console, so there it defaults to perfuse.log beside the database—
-mcpon/off—serve the Model Context Protocol at /mcp, so AI agents with an API token can read status, messages, the queue, alerts and the FHIR store with that token's own accessSettings › Security › AI agents (MCP): Let AI agents connect over MCP
-measure-reporterstringPerfusethe reporting organisation's name on MeasureReports from $evaluate-measure when the request names no reporter—
-metrics-openon/off—serve /metrics to anybody who can reach the port. Only safe where that port is genuinely private: metric labels name your channels, and on a multi-tenant server they name every tenant'sSettings › Security › Metrics: Serve /metrics without a token
-metrics-tokenstring—credential the Prometheus scrape endpoint requires. Give the scraper the same value in bearer_token_file. Without this, only a signed-in operator can read /metricsSettings › Security › Metrics: Token a metrics scraper presents
-mpion/off—keep a patient index (master patient index) in mpi.db beside the database: patient records from every system linked into one enterprise identifier per person, fed by mpi destinations and the PIX v3 identity feed, answering Patient/$match, PIXm, PIX v3 (/pixv3) and PDQ v3 (/pdqv3)Settings › Data › Patient index: Keep a patient index
-multi-tenanton/off—keep each tenant's channels in their own subdirectory of -channels, so one server can run integration for several organisations without them being able to see each other—
-node-addressstring—this server's console URL as the other servers and a load balancer reach it—
-node-namestring—this server's name in the cluster (default: an id kept in -data)—
-oidcstring—YAML file configuring OpenID Connect sign-in (default: oidc.yaml beside the database, once saved in the console)—
-pason/off—serve Da Vinci PAS 2.2.1 and 2.1.0 (Claim/$submit, $inquire, $decide) on the FHIR endpoint; decisions come from -crd-rules, and what no rule decides is pended for a reviewer. With -fhir-subscriptions, the PAS topic delivers each pended request's resultSettings › Payers › Prior authorization: Da Vinci PAS prior authorization server
-pas-278-castring—a PEM file of certificate authorities to trust for the UM system beside the system'sSettings › Payers › Utilization management link: Certificate authorities to trust for the UM system
-pas-278-certstring—a PEM client certificate for X.509 mutual TLS with the UM system (CORE's authentication)Settings › Payers › Utilization management link: Client certificate file
-pas-278-core-receiverstring—the CORE envelope's ReceiverID, as the UM system's connectivity guide gives it (default: -pas-278-receiver)Settings › Payers › Utilization management link: CORE envelope ReceiverID
-pas-278-core-rule-versionstring—what to write in the CORE envelope's CORERuleVersion when the UM system's guide asks for something other than the version itself (CMS esMD's sample says v2.2.0)Settings › Payers › Utilization management link: CORERuleVersion written in the envelope
-pas-278-core-senderstring—the CORE envelope's SenderID, as the UM system's connectivity guide gives it (default: -pas-278-sender)Settings › Payers › Utilization management link: CORE envelope SenderID
-pas-278-core-versionstring2.2.0the CAQH CORE Connectivity Rule the UM system runs, for core-soap and core-mime: 2.2.0 (payload in the envelope) or C4.0.0 (payload as an MTOM attachment; SOAP only)Settings › Payers › Utilization management link: CAQH CORE Connectivity Rule
-pas-278-keystring—the private key (PEM) for -pas-278-certSettings › Payers › Utilization management link: Client certificate key file
-pas-278-oauth-client-idstring—the OAuth client ID for -pas-278-oauth-token-urlSettings › Payers › Utilization management link: OAuth client ID
-pas-278-oauth-scopestring—the scope asked for with the OAuth token, when the UM system wants oneSettings › Payers › Utilization management link: OAuth scope
-pas-278-oauth-secret-envstring—name of an environment variable holding the OAuth client secret (the secret itself is never a flag)Settings › Payers › Utilization management link: Environment variable holding the OAuth client secret
-pas-278-oauth-token-urlstring—an OAuth 2.0 token endpoint: a token got with the client-credentials grant is sent as a bearer token (CORE vC4.0.0's authorization)Settings › Payers › Utilization management link: OAuth token endpoint
-pas-278-password-envstring—name of an environment variable holding the password for -pas-278-user (the password itself is never a flag)Settings › Payers › Utilization management link: Environment variable holding the password
-pas-278-payer-idstring—the UMO's payer ID (NM1*X3) when the request's insurer carries no identifierSettings › Payers › Utilization management link: Payer ID for the 278s
-pas-278-productionon/off—mark the 278s sent as production (ISA15 P) rather than testSettings › Payers › Utilization management link: Mark the 278s as production
-pas-278-receiverstring—ISA08/GS03 receiver ID on the 278s sent to the UM systemSettings › Payers › Utilization management link: Receiver ID on the 278s
-pas-278-senderstringPERFUSEISA06/GS02 sender ID on the 278s sent to the UM systemSettings › Payers › Utilization management link: Sender ID on the 278s
-pas-278-sftpstring—host:port of the UM system's SFTP server, for -pas-278-transport sftpSettings › Payers › Utilization management link: SFTP server
-pas-278-sftp-everyduration1m0show often the SFTP inbound folder is readSettings › Payers › Utilization management link: Read the SFTP inbound folder every
-pas-278-sftp-inboundstring—the SFTP folder the UM system's 278 responses, 999s and TA1s are collected fromSettings › Payers › Utilization management link: SFTP inbound folder
-pas-278-sftp-keystring—an OpenSSH private key file for the SFTP user, instead of a passwordSettings › Payers › Utilization management link: SFTP key file
-pas-278-sftp-known-hostsstring—an OpenSSH known_hosts file holding the SFTP server's key; required, so requests never go to whoever answersSettings › Payers › Utilization management link: SFTP known_hosts file
-pas-278-sftp-outboundstring—the SFTP folder the 278 requests (and the 999s for the answers) are put inSettings › Payers › Utilization management link: SFTP outbound folder
-pas-278-sftp-password-envstring—name of an environment variable holding the SFTP password (the password itself is never a flag)Settings › Payers › Utilization management link: Environment variable holding the SFTP password
-pas-278-sftp-userstring—the SFTP user nameSettings › Payers › Utilization management link: SFTP user
-pas-278-token-envstring—name of an environment variable holding a bearer token for the UM system (the token itself is never a flag)Settings › Payers › Utilization management link: Environment variable holding the token
-pas-278-transportstringx12how the 278s reach the UM system: x12 (POSTed as application/edi-x12), core-soap (a CAQH CORE SOAP envelope), core-mime (CAQH CORE HTTP MIME multipart), or sftp (batch files over -pas-278-sftp, answers collected from its inbound folder)Settings › Payers › Utilization management link: How the 278s travel
-pas-278-urlstring—forward every PAS request to the payer's utilization management system as an X12 278 request sent to this URL (by -pas-278-transport), and answer with its 278 response; later 278 responses go to Claim/$decide-278Settings › Payers › Utilization management link: Send PAS requests on to the UM system at
-pas-278-userstring—user name for the UM system: CORE's UserName (WS-Security UsernameToken in SOAP), or HTTP Basic for x12Settings › Payers › Utilization management link: User name
-pas-decider-castring—a PEM file of certificate authorities to trust for -pas-decider-url beside the system's, such as the payer's own authority or the decision service's (Vaglio's is its DATA/tls/ca.crt)Settings › Payers › Decision service: Certificate authorities to trust for the decision service
-pas-decider-token-envstring—name of an environment variable holding a bearer token for -pas-decider-url (the token itself is never a flag)Settings › Payers › Decision service: Environment variable holding the decision service's token
-pas-decider-urlstring—ask the decision service at this URL (such as Vaglio) to decide each PAS item on the request's clinical evidence, when -crd-rules leave it to a reviewer; the PAS request Bundle is POSTed to it. Cannot be combined with -pas-278-urlSettings › Payers › Decision service: Decision service URL
-passkey-allowed-modelsstring—comma-separated authenticator AAGUIDs that may enrol; requires -passkey-attestation-roots—
-passkey-attestation-rootsstring—a PEM file of authenticator vendor certificates; passkey attestation is verified against these—
-passkey-domainstring—the bare domain passkeys are registered for, such as perfuse.example.org. No scheme, no port, no path. Setting it turns passkeys on; leaving it empty leaves them offSettings › Sign-in › Passkeys: Domain passkeys are bound to
-passkey-namestringPerfusethe name an authenticator shows a person when they register a passkeySettings › Sign-in › Passkeys: Name shown on the device
-passkey-originsstring—comma-separated origins the console is reached at, with scheme and port: https://perfuse.example.org. Defaults to https:// plus the domainSettings › Sign-in › Passkeys: Other origins passkeys are accepted from
-peersstring—YAML file listing other Perfuse instances to show in a fleet viewSettings › Fleet › Fleet: Other Perfuse servers to show (file)
-public-urlstring—the https address patients' phones and other organisations reach this server at, for the SMART Health Links it hosts (default: the listen address)Settings › FHIR › The FHIR server: Address others reach this server at
-rctcstring—eCR trigger codes for the case report preview: a FHIR ValueSet or Bundle of them, such as the eRSDSettings › Public health › Case reporting: Trigger codes file (RCTC or eRSD)
-residencystring—cloud regions this server's data may go to or come from: areas (eea, uk, ch) and region codes (eu-central-1), comma-separated; channels with connectors elsewhere are refusedSettings › Data › Data protection: Where data may go (cloud regions)
-retention-daysint30how long to keep recorded messages; 0 keeps them for ever, which will eventually fill the diskSettings › Data › How long it is kept: Delete records after
-samlstring—YAML file configuring SAML 2.0 sign-in (default: saml.yaml beside the database, once saved in the console)—
-scimon/off—accept SCIM 2.0 provisioning from an identity provider at /scim/v2. Okta, Entra ID and Google Workspace use it to create accounts and, more importantly, to disable them when somebody leavesSettings › Sign-in › Automatic accounts: Let the identity provider manage accounts
-scim-default-rolestringviewerrole for an account the identity provider does not describe. Defaults downward on purpose: an account whose role could not be determined should be able to read and nothing else—
-settingsstring—settings file the web interface may edit (default: perfuse-settings.yaml beside the database)—
-shl-allow-httpon/off—let a received SMART Health Link point at plain HTTP; for testing onlySettings › Public health › Health links: Allow SMART Health Links over plain HTTP
-signing-certstring—certificate for signing documents (defaults to -tls-cert)Settings › Security › Document signing: Certificate for signing documents
-signing-keystring—key for signing documents (defaults to -tls-key)Settings › Security › Document signing: Key for signing documents
-smart-audiencestring—the audience a SMART token must be issued for, normally the FHIR base URLSettings › SMART › Authorization: Audience tokens must name
-smart-authorizestring—the authorization endpoint to advertise to SMART appsSettings › SMART › Authorization: Authorization endpoint
-smart-backend-serviceson/off—advertise that the SMART authorization server issues backend-services (client_credentials, signed JWT) tokensSettings › SMART › Built-in server: Backend Services (system-to-system tokens)
-smart-clientsstring—run Perfuse's own SMART authorization server at /auth for the apps registered in this YAML fileSettings › SMART › Built-in server: Registered apps file (turns on the built-in server)
-smart-issuerstring—accept SMART on FHIR access tokens from this authorization serverSettings › SMART › Authorization: Accept SMART access tokens from this authorization server
-smart-jwksstring—where to fetch the SMART issuer's signing keys, when not from its published metadata (split DNS, a private address)Settings › SMART › Authorization: Key set file
-smart-jwks-uristring—the authorization server's public key set URL, advertised to SMART apps (needed to claim OpenID Connect sign-in)Settings › SMART › Authorization: Key set address
-smart-keystringsmart-signing.keythe built-in authorization server's RSA signing key (PEM, mode 0600), created if missingSettings › SMART › Built-in server: Signing key file
-smart-oidcstring—with -smart-users, let people sign in at this OpenID Connect provider (YAML: issuer, client_id, client_secret_file or client_secret_env, label); each is linked by oidc_subjectSettings › SMART › Built-in server: Sign people in through the OpenID Connect provider
-smart-tokenstring—the token endpoint to advertise to SMART appsSettings › SMART › Authorization: Token endpoint
-smart-usersstring—with -smart-clients, the people who may sign in to authorize apps (YAML: username, password_hash, fhir_user)Settings › SMART › Built-in server: People who sign in to authorize apps (file)
-snmp-allowstring—comma-separated networks or addresses the SNMP agent answers, such as 10.0.5.0/24; required with -snmp-listenSettings › Monitoring › SNMP: Networks that may ask
-snmp-base-oidstring1.3.6.1.4.1.8072.9999.9999.16, Net-SNMP's experimental spacewhere Perfuse's values sit, under your enterprise numberSettings › Monitoring › SNMP: Base OID
-snmp-communitystring—the SNMPv2c community (a password sent in clear: at least 6 characters, not public or private)Settings › Monitoring › SNMP: SNMP community
-snmp-contactstring—sysContact the SNMP agent reportsSettings › Monitoring › SNMP: Contact (sysContact)
-snmp-listenstring—answer SNMPv2c GET/GETNEXT/GETBULK on this UDP address, such as :161 (off when empty). Read-only: channel states, counts and queue depthsSettings › Monitoring › SNMP: Answer SNMP on this address
-snmp-locationstring—sysLocation the SNMP agent reportsSettings › Monitoring › SNMP: Location (sysLocation)
-snmp-trapsstring—comma-separated managers (host or host:port, default port 162) that receive an SNMPv2 trap when an alert fires or resolvesSettings › Monitoring › SNMP: Send traps to
-store-messageson/offtruerecord every message handled, which is what makes the message browser workSettings › Data › What is kept: Keep a record of each message
-store-payloadson/offtruestore message contents as well as their outcomes; turn this off where PHI must not be held at restSettings › Data › What is kept: Keep message contents
-tls-certstring—TLS certificate fileSettings › Security › Encryption: TLS certificate file
-tls-keystring—TLS private key fileSettings › Security › Encryption: TLS private key file
-trace-endpointstring—OTLP/HTTP base URL to export message traces to, for example http://localhost:4318Settings › Monitoring › Tracing: Send traces to
-trace-instancestring—name for this instance in traces; defaults to the hostname, which is what distinguishes replicasSettings › Monitoring › Tracing: This instance's name in traces
-trace-samplefloat1fraction of traces to record, 0 to 1—
-tsa-urlstring—RFC 3161 time-stamping authority for DSDR signatures on claims attachmentsSettings › Security › Document signing: Time-stamping authority
-vpnstring—partner VPN tunnels to report on the Connections dashboard (YAML: AWS Site-to-Site VPN, Azure VPN Gateway or strongSwan, and both sides' settings); see examples/vpn.yamlSettings › Monitoring › Connections: VPN tunnels to watch (file)
-watch-accesson/offtruewatch traffic and reads of patient data for what a breach looks like (bursts, night traffic, new destinations, bulk reads) and raise alerts—
-xdsstring—keep clinical documents here as an IHE XDS.b registry and repository with this repository uniqueId (an OID), answering ITI-41, ITI-42, ITI-18 and ITI-43 at /xds/repository and /xds/registrySettings › Data › Document sharing (IHE XDS): Keep documents here as an XDS registry and repository
-xds-home-communitystring—this community's home community id (urn:oid:...), so /xca/gateway answers XCA ITI-38 and ITI-39 for itSettings › Data › Document sharing (IHE XDS): Home community id, for XCA

21 Riferimento canale

Ogni chiave che può apparire nel file di canale di livello superiore. Queste vengono estratte dalla sorgente, quindi questo capitolo non può descrivere un'opzione che non esiste o omettere una che esiste.

21.1 Canale

Un canale è un flusso di messaggi configurato: da qualche parte arrivano i messaggi, un filtro opzionale e uno o più posti in cui vanno.

Definito come Channel in internal/config.

ChiaveTipoObbligatorioPredefinito
nametestosì—
descriptiontestono—
grouptestono—
attachmentsAllegati (un blocco, omesso per non includerlo)no—
delimitedDelimitato (un blocco, omesso per non includerlo)no—
tableselenco di testono—
contractContractRef (un blocco, omesso per non includerlo)no—
enabledtrue o false (un blocco, omesso per non includerlo)no—
dataTypeDataTypenohl7
hl7v3HL7v3Options (un blocco, omesso per non includerlo)no—
x12X12Options (un blocco, omesso per non includerlo)no—
ncpdpNCPDPOptions (un blocco, omesso per non includerlo)no—
edifactEDIFACTOptions (un blocco, omesso per non includerlo)no—
scriptScriptOptions (un blocco, omesso per non includerlo)no—
dicomDICOMOptions (un blocco, omesso per non includerlo)no—
sourceSorgentesì—
filtertestono—
transformationselenco di transform.Stepno—
scriptsScripts (un blocco, omesso per non includerlo)no—
shadowShadow (un blocco, omesso per non includerlo)no—
destinationselenco di Destinationsì—

21.1.1 nome

Il nome identifica il canale nei log e nelle metriche.

Obbligatorio e univoco.

21.1.2 gruppo

Il gruppo è a cosa appartiene questo canale, per organizzare un elenco che è cresciuto troppo lungo per essere letto.

Cosmetico a cinque canali e strutturale a duecento: i canali di un sito si dividono per il sistema a cui si connettono, o per il team che li possiede, e un elenco piatto di duecento nomi è inutilizzabile per quanto buona sia l'interfaccia.

Una stringa semplice piuttosto che un oggetto gruppo con il proprio file, perché un gruppo non ha comportamento. Il momento in cui ha un file acquisisce impostazioni, e le impostazioni su un gruppo significano che il comportamento di un canale dipende da qualcosa che non è scritto nel canale - che è la proprietà che rende la configurazione di Mirth difficile da comprendere. I gruppi qui sono un'etichetta e nulla più.

21.1.3 allegati

Gli allegati spostano i payload grandi fuori dal messaggio e li ripristinano prima della consegna.

Opzionale per canale: un feed di messaggi ADT semplici non ha nulla da estrarre e non dovrebbe pagare per la macchina.

21.1.4 delimitato

Delimitato configura un canale delimitato.

Significativo solo quando il tipo di dati è delimitato.

21.1.5 tabelle

I nomi dei file delle tabelle di mappatura condivise che una trasformazione può fare riferimento per nome.

Condivise perché la tassonomia del dominio è in gran parte una rielaborazione di una mappatura che qualcun altro ha già derivato: i codici di sesso e le classi di pazienti di un sito vengono tradotti allo stesso modo in ogni canale che li tocca, e una tabella all'interno di un canale è una tabella che solo quel canale può utilizzare.

21.1.6 abilitato

Abilitato predefinito su true.

Un canale disabilitato viene caricato e convalidato ma non avviato, quindi un file che è temporaneamente spento è ancora controllato da CI.

21.1.7 tipo di dati

Il tipo di dati è il formato dei messaggi che questo canale riceve.

Di default è hl7, quindi ogni canale scritto prima dell'esistenza di questo continua a funzionare.

21.1.8 x12

X12 contiene le impostazioni che hanno senso solo su un canale X12.

Impostarlo su qualsiasi altro tipo viene rifiutato invece di essere ignorato.

21.1.9 script

Script configura un canale NCPDP SCRIPT.

I suoi passaggi si trovano qui invece che nelle trasformazioni di livello superiore per lo stesso motivo per cui ogni altro formato non v2 fa: i tipi di passaggi differiscono per formato, quindi una chiave avrebbe significati diversi a seconda del tipo di dati.

21.1.10 dicom

Imaging configura i passaggi di trasformazione denominati di un canale DICOM.

Imaging denominato invece di DICOM perché Sorgente e Destinazione hanno già un campo DICOM e tre campi con lo stesso nome a livelli diversi è il modo in cui qualcuno imposta il campo sbagliato. La chiave yaml è dicom, che è ciò che una persona che scrive il file si aspetta, e il nome Go è quello che evita un errore nel sito di chiamata.

21.1.11 filtro

Filtro è un'espressione che deve essere vera affinché un messaggio venga inoltrato.

Un messaggio che non corrisponde viene comunque confermato: il mittente non ha fatto nulla di sbagliato, semplicemente non siamo interessati.

21.1.12 trasformazioni

Le trasformazioni sono modifiche dichiarative applicate ai messaggi accettati, in ordine, prima di eseguire qualsiasi script.

Questo è il livello destinato a svolgere il lavoro ordinario: ogni passaggio viene convalidato quando il file viene caricato, appare in una diff e può essere esaminato da qualcuno che non legge JavaScript.

21.1.13 script

Script contiene JavaScript per i casi in cui i passaggi dichiarativi non possono esprimere, ed è ciò in cui gli script propri di un canale Mirth vengono inseriti invariati.

Un canale con uno script è contrassegnato come tale nell'interfaccia, perché il suo comportamento non può essere stabilito leggendo la configurazione.

21.1.14 ombra

Ombra esegue una versione candidata di questo canale accanto ad esso e segnala dove differiscono.

Niente di ciò che fa può raggiungere un ricevitore.

22 Riferimento sorgente

Ogni modo in cui un canale può ricevere messaggi e ogni chiave che ogni uno accetta. Un canale ha esattamente una sorgente.

22.1 Sorgente AMQP

AMQPSource riceve da una coda o sottoscrizione.

Un messaggio è accettato solo dopo che il canale lo ha gestito. Uno che non poteva essere gestito viene rilasciato come consegna non riuscita, quindi il broker lo ridelivera e - su Service Bus, oltre il numero massimo di consegne della coda - lo sposta nella coda dei messaggi morti.

Definito come AMQPSource in internal/config.

ChiaveTipoObbligatorioPredefinito
prefetchnumero interono10
reconnectdurata, ad esempio 30s o 5mno5s

22.1.1 prefetch

Prefetch è il numero di messaggi che il broker può inviare in anticipo.

Il valore predefinito è 10. Vengono comunque gestiti uno alla volta, in ordine.

22.1.2 reconnect

Reconnect è l'attesa dopo una connessione persa.

Defaults to 5s.

22.2 Sorgente AS2

AS2Source riceve AS2 (RFC 4130): EDI inviato tramite HTTP, firmato e crittografato con S/MIME, risposto con una ricevuta (un MDN) che contiene un digest di ciò che è arrivato.

Il payload è ciò che il canale gestisce; X12 e EDIFACT sono quelli più comuni.

Definito come AS2Source in internal/config.

ChiaveTipoObbligatorioPredefinito
listentestosì—
pathtestono—
tlstlsconf.Settings (un blocco, omesso per non utilizzarlo)no—
idtestosì—
cert_filetestosì—
key_filetestosì—
partnerselenco di AS2Partnersì—
max_message_sizenumero interono—
duplicate_windowdurata, ad esempio 30s o 5mno—

22.2.1 path

Path è il percorso URL a cui i partner inviano.

Default /as2.

22.2.2 tls

TLS serve HTTPS.

La maggior parte dei partner richiede TLS nel loro accordo, oltre al S/MIME.

22.2.3 id

ID è il nostro identificatore AS2, che i partner inviano in AS2-To.

Un messaggio inviato a qualsiasi altro identificatore viene rifiutato.

22.2.4 partners

I partner sono coloro che possono inviare messaggi qui.

Un messaggio da chiunque altro viene rifiutato.

22.2.5 duplicate_window

DuplicateWindow è il periodo di tempo durante il quale l'ID del messaggio di un partner viene ricordato, in modo che un messaggio inviato nuovamente (il partner non ha ricevuto la nostra ricevuta e ha ritentato) venga risposto con una ricevuta e non venga inoltrato due volte (RFC 4130 sezione 7.5).

Default 30 days.

22.3 Azure Blob Source

AzureBlobSource raccoglie i blob da un prefisso del contenitore.

Definito come AzureBlobSource in internal/config.

ChiaveTipoObbligatorioPredefinito
prefixtestosì—
suffixtestono—
after_readtestono—
move_totestonoprocessed/
error_prefixtestonoerror/
poll_intervaldurata, ad esempio 30s o 5mno30s
max_object_sizenumero interono16 MiB
framedtrue o falseno—

22.3.1 move_to

MoveTo è dove si sposta un blob gestito.

Predefinito su processed/.

22.3.2 error_prefix

ErrorPrefix è dove si sposta un blob che non può essere gestito, in modo che non blocchi il resto.

Predefinito su error/.

22.3.3 poll_interval

PollInterval tra le liste.

Defaults to 30s.

22.3.4 max_object_size

MaxObjectSize rifiuta un blob più grande, che rimane dove si trova.

Predefinito su 16 MiB.

22.4 Broker Source

BrokerSource legge i messaggi da un message broker.

JMS Reader di Mirth, raggiunto tramite STOMP perché JMS è un'API Java e non un protocollo. Vedi internal/stomp per sapere perché STOMP e non OpenWire.

Definito come BrokerSource in internal/config.

ChiaveTipoObbligatorioPredefinito
addrtestosì—
destinationtestosì—
logintestono—
passcodetestono—
hosttestonol'host dell'indirizzo
selectortestono—
subscription_idtestonoil nome del canale
heartbeatdurata, ad esempio 30s o 5mnotrenta secondi
reconnectdurata, ad esempio 30s o 5mnocinque secondi
timeoutdurata, ad esempio 30s o 5mnotrenta secondi
tlstlsconf.Settings (un blocco, omesso per lasciare fuori)no—

22.4.1 addr

Addr è l'host e la porta del broker.

Obbligatorio. 61613 è la porta STOMP usuale.

22.4.2 destinazione

La destinazione è la coda o l'argomento da cui leggere.

Required.

I broker scrivono questi in modo diverso - /queue/name su ActiveMQ, un nome semplice su RabbitMQ - quindi viene passato invariato anziché essere assemblato qui. Indovinare significherebbe lavorare contro un broker e leggere silenziosamente nulla su un altro.

22.4.3 accesso

Accesso e codice di accesso autenticano.

La maggior parte dei broker rifiuta una connessione anonima.

22.4.4 codice di accesso

Accesso e codice di accesso autenticano.

La maggior parte dei broker rifiuta una connessione anonima.

22.4.5 host

L'host è l'host virtuale.

Di default è l'host dell'indirizzo.

22.4.6 selettore

Il selettore filtra i messaggi nel broker.

Un selettore JMS, passato invariato anziché interpretato. La filtratura nel broker anziché qui significa che i messaggi che questo canale non vuole non attraversano mai la rete - il che, in una coda condivisa, è la differenza tra la lettura di cento messaggi al giorno e centomila.

22.4.7 id_abbonamento

L'ID di abbonamento nomina l'abbonamento.

Di default è il nome del canale.

Nominali anziché generati, perché un abbonamento durevole è identificato da esso: uno generato creerebbe un nuovo abbonamento ad ogni riavvio e lascerebbe gli abbonamenti vecchi accumulare messaggi che nessuno legge.

22.4.8 batticuore

Il batticuore mantiene la connessione attiva.

Di default è trenta secondi.

Attivato di default qui, a differenza del default del client, perché una sorgente mantiene una connessione aperta per settimane. Senza batticuori, una connessione attraverso un firewall che ha silenziosamente rilasciato il percorso sembra perfettamente sana da questo capo e i messaggi semplicemente smettono di arrivare, senza nulla registrato.

22.4.9 reconnect

La riconnessione è il tempo di attesa prima di riconnettersi dopo un errore.

Di default è cinque secondi.

22.4.10 timeout

Limiti di timeout durante la connessione.

Di default è trenta secondi.

22.5 Sorgente di query DICOM

DICOMQuerySource interroga un archivio con C-FIND ed emette un messaggio per ogni nuovo studio.

Mirth non ha un connettore equivalente. Il suo supporto DICOM è un listener e un inviante - può ricevere immagini inviate e inoltrarle, e questo è tutto. Chiedere a un archivio cosa contiene è stato richiesto nei loro forum dal 2015.

Ciò che lo rende utile non è la query, ma l'automazione: un prefetch che si esegue alle tre del mattino, una riconciliazione che nota che all'archivio manca uno studio che il RIS dice esiste, un elenco di lavoro costruito da ciò che è stato effettivamente scansionato piuttosto che da ciò che è stato ordinato. Sono lavori che i siti attualmente eseguono con uno script pianificato all'esterno del motore, il che significa che sono invisibili ad esso - nessun ritento, nessun allarme, nessuna storia dei messaggi.

Definito come DICOMQuerySource in internal/config.

ChiaveTipoObbligatorioPredefinito
addresstestosì—
called_aetestosì—
calling_aetestono—
leveltestonoSTUDY
patient_rootvero o falsono—
matchmappatura di testo su testono—
returnelenco di testono—
intervaldurata, ad esempio 30s o 5msì—
windowdurata, ad esempio 30s o 5mno—
overlapdurata, ad esempio 30s o 5mnoun'ora
limitnumero interono500
timeoutdurata, ad esempio 30s o 5mnodue minuti
tlstlsconf.Settings (un blocco, omesso per lasciare fuori)no—
emit_on_first_pollvero o falsonofalso

22.5.1 indirizzo

L'indirizzo è l'host e la porta dell'archivio.

Required.

Denominato per corrispondere alla destinazione DICOM piuttosto che abbreviato. I due erano "indirizzo" e "addr" per un pomeriggio, il che è il tipo di inconsistenza che qualcuno che scrive a mano un file di canale si sbaglia una volta e poi non si fida più del formato.

22.5.2 called_ae

CalledAE è il titolo AE dell'archivio.

Obbligatorio nella pratica: la maggior parte degli archivi rifiuta un'associazione indirizzata ad altro, e quel rifiuto si legge come un'interruzione piuttosto che come un errore di configurazione.

22.5.3 calling_ae

CallingAE è il titolo AE presentato da Perfuse.

Gli archivi lo utilizzano comunemente per il controllo di accesso.

22.5.4 livello

Il livello è il livello di query: PATIENT, STUDY, SERIES o IMAGE.

Predefinito su STUDY.

STUDY è il predefinito perché è ciò che quasi ogni query utile vuole e perché le alternative sorprendono le persone: il livello IMAGE contro un grande CT restituisce una risposta per ogni fetta, che è di centinaia per studio.

22.5.5 corrispondenza

Le corrispondenze sono le chiavi di query.

Un valore filtra; un valore vuoto chiede di restituire il campo.

Le chiavi sono nominate piuttosto che numerate - "PatientID" anziché "0010,0020" - perché un file di canale è letto dalle persone, e un numero di tag in un file di configurazione è una ricerca che ogni lettore deve eseguire.

22.5.6 ritorna

I campi di ritorno sono campi da restituire senza applicare filtri su di essi.

Separati da Match con un valore vuoto, anche se vengono codificati in modo identico, perché l'intento differisce e un lettore può vedere quali chiavi stanno restringendo la ricerca e quali stanno venendo raccolte.

22.5.7 intervallo

L'intervallo è la frequenza con cui eseguire il polling.

Required.

22.5.8 finestra

La finestra è quanto indietro ogni polling guarda, come un intervallo di data di studio.

Zero disabilita completamente il filtro di data.

Una finestra è ciò che mantiene questo limite. Senza di essa, ogni polling chiede all'archivio tutto ciò che ha mai contenuto e poi scarta ciò che ha visto prima - il che funziona su un archivio di test e è antisociale contro un archivio reale che contiene milioni di studi.

22.5.9 sovrapposizione

La sovrapposizione richiede nuovamente questo periodo già pollato.

Il valore predefinito è di un'ora.

Necessario piuttosto che cauto. Uno studio può essere registrato con la data di ieri, il nostro orologio e quello dell'archivio non devono essere d'accordo, e un limite di polling che si allinea esattamente con un arrivo lo perde. La sovrapposizione richiede nuovamente e il controllo già visto ferma il duplicato - quindi il costo della sovrapposizione è una query leggermente più grande e il costo della mancanza di sovrapposizione è uno studio silenziosamente perso.

22.5.10 limite

Il limite limita le corrispondenze accettate da un singolo polling.

Defaults to 500.

Un limite piuttosto che nessun limite perché una chiave di corrispondenza errata trasforma questo in "dammi tutto", e il primo sintomo di ciò contro un archivio reale è l'amministratore dell'archivio che chiede chi sta martellando.

22.5.11 timeout

Il timeout delimita un singolo polling.

Il valore predefinito è di due minuti.

22.5.12 emetti_al_primo_polling

EmitOnFirstPoll invia messaggi per tutto ciò che il primo polling trova.

Il valore predefinito è false.

False è importante. Puntare questo su un archivio che già contiene un milione di studi e farlo emettere un messaggio per ognuno non è un primo esecuzione utile, ed è il tipo di errore che viene notato a valle piuttosto che qui. Il primo polling registra ciò che esiste e non emette nulla; il secondo polling in poi segnala ciò che è nuovo.

22.6 Sorgente DICOM

DICOMSource riceve oggetti di imaging come un fornitore di servizio di classe C-STORE.

Ciò a cui un ospedale punta una modalità o un PACS. Mirth chiama questo il listener DICOM e fa solo C-STORE, quindi questo è parità piuttosto che un subset.

Definito come DICOMSource in internal/config.

ChiaveTipoObbligatorioPredefinito
listentestosì—
ae_titletestono—
allowed_calling_aeelenco di testono—
sop_classeselenco di testono—
transfer_syntaxeselenco di testono—
max_object_bytesnumero interono—
idle_timeoutdurata, ad esempio 30s o 5mno—
tlstlsconf.Settings (un blocco, omesso per non utilizzarlo)no—

22.6.1 listen

Listen è l'indirizzo su cui servire.

Obbligatorio. 104 è la porta DICOM registrata; 11112 è l'alternativa comune dove non è possibile eseguire il binding di una porta privilegiata.

22.6.2 ae_title

AETitle è il nome con cui questo endpoint si identifica.

Fortemente raccomandato piuttosto che obbligatorio e avvertito quando assente. L'accesso a un endpoint DICOM è spesso controllato solo dal titolo AE, quindi un endpoint che accetta qualsiasi titolo accetta tutto ciò che può raggiungerlo.

22.6.3 allowed_calling_ae

AllowedCallingAE elenca i titoli AE consentiti per la connessione.

Vuoto accetta qualsiasi chiamante.

Questo è il controllo di accesso che il DICOM ha effettivamente. Un PACS è solitamente configurato per accettare un titolo di chiamata denominato e rifiutare tutto il resto, e questo endpoint non aveva un equivalente: il titolo chiamato è stato controllato - che è il nome che il chiamante compone, quindi chiunque può inviarlo correttamente - mentre chi stava chiamando è stato registrato nel log e ignorato altrimenti.

Vuoto accetta ancora qualsiasi cosa, perché una modalità che nessuno ha elencato è lo stato normale di una prima installazione e rifiutare per impostazione predefinita romperebbe ogni distribuzione nel giorno uno. Avverte invece, e l'avvertimento nomina i titoli che si sono connessi in modo che qualcuno possa riempire questo elenco con ciò che è effettivamente arrivato.

22.6.4 sop_classes

SOPClasses limita i tipi di oggetto da accettare.

Vuoto accetta qualsiasi oggetto.

Vuoto è un valore predefinito ragionevole qui perché questo motore inoltra oggetti invece di interpretarli, quindi rifiutare una classe sconosciuta rifiuterebbe immagini valide senza alcun beneficio.

22.6.5 transfer_syntaxes

TransferSyntaxes limita le codifiche da accettare, nell'ordine di preferenza.

Vuoto accetta i tre non compressi.

22.6.6 max_object_bytes

MaxObjectBytes delimita un oggetto ricevuto.

Zero applica un valore predefinito.

22.6.7 idle_timeout

IdleTimeout chiude un'associazione che è diventata silenziosa.

Zero significa mai, che è solitamente corretto - una modalità mantiene un'associazione aperta tra gli studi.

22.6.8 tls

TLS crittografa le associazioni in entrata e può richiedere un certificato client.

Vale la pena affermarlo chiaramente: Mirth necessita della sua estensione SSL Manager a pagamento per questo, e le fork della community non possono spedirla affatto. DICOM trasporta i nomi dei pazienti nei suoi metadati, quindi questo è uno dei luoghi in cui essere una riscrittura piuttosto che una fork è un vero vantaggio piuttosto che uno stilistico.

22.7 Sorgente Mweb DICO

DICOMwebSource accetta richieste STOW-RS.

Definito come DICOMwebSource in internal/config.

ChiaveTipoObbligatorioPredefinito
listentestosì—
pathtestono/dicom-web
tokentestono—
usernametestono—
passwordtestono—
max_object_bytesnumero interono—
tlstlsconf.Impostazioni (un blocco, omesso per lasciare fuori)no—

22.7.1 listen

Listen è l'indirizzo su cui servire.

Required.

22.7.2 path

Percorso è la radice del servizio.

Gli oggetti sono accettati in Path/studies e Path/studies/{uid}. Di default è /dicom-web, che è ciò che utilizzano Orthanc e dcm4chee, quindi un mittente configurato per uno di essi ha bisogno solo di cambiare l'host.

22.7.3 token

Token, quando impostato, è richiesto come token bearer.

Username e Password richiedono autenticazione HTTP di base.

22.7.4 username

Token, quando impostato, è richiesto come token bearer.

Username e Password richiedono autenticazione HTTP di base.

22.7.5 password

Token, quando impostato, è richiesto come token bearer.

Username e Password richiedono autenticazione HTTP di base.

22.8 Sorgente del database

DatabaseSource legge le righe da un database e le trasforma in messaggi.

Questo è il modo in cui inizia la maggior parte delle interfacce ospedaliere. Un sistema di reparto non ha la capacità HL7, quindi qualcuno scrive righe in una tabella di staging e il motore di interfaccia la interpella. È poco glamour e si trova ovunque.

È anche il modo più comune in cui un canale Mirth si blocca, e il motivo è quasi sempre della stessa forma: una riga che non può essere elaborata viene letta, fallisce e viene letta di nuovo, all'infinito, perché nulla l'ha segnalata. Il canale sembra vivo. La coda sembra vuota. Nulla si muove e ogni messaggio dietro la riga cattiva aspetta una riga che non avrà mai successo.

La maggior parte della progettazione qui è su questo.

Definito come DatabaseSource in internal/config.

ChiaveTipoObbligatorioPredefinito
drivertestosì—
dsntestosì—
querytestosì—
after_querytestono—
key_columntestono—
templatetestono—
columntestono—
poll_intervaldurata, come 30s o 5mno—
batch_sizenumero interono100
max_attemptsnumero interono3
query_timeoutdurata, come 30s o 5mno30s

22.8.1 driver

Driver nomina il database.

See SupportedDrivers.

22.8.2 dsn

DSN è la stringa di connessione.

Preferisci un riferimento a una variabile d'ambiente rispetto a un valore letterale, poiché questo contiene normalmente una password e i canali sono destinati a vivere in git.

22.8.3 query

La query seleziona le righe in attesa di essere inviate.

Required.

Deve essere un SELECT. Un'interrogazione che esegue silenziosamente scritture sarebbe in esecuzione su una pianificazione senza alcun record di cosa è stato modificato.

22.8.4 after_query

AfterQuery contrassegna una riga come elaborata ed esegue con la chiave della riga associata ad esso.

Strongly recommended.

Senza di esso, ogni interrogazione ri-legge ogni riga che la query ancora corrisponde, quindi la query stessa deve escludere le righe elaborate in qualche altro modo. Se nessuna delle due condizioni è vera, il canale rinviare le stesse righe all'infinito, il che è una tempesta di duplicati piuttosto che un blocco e potrebbe essere considerato peggiore.

22.8.5 key_column

KeyColumn identifica una riga per AfterQuery, quarantena e de-duplicazione.

Obbligatorio quando AfterQuery è impostato.

22.8.6 template

Il modello costruisce un messaggio da una riga.

È richiesto o questo o Colonna.

I riferimenti alle colonne utilizzano ${nome_colonna}. Le colonne mancanti sono un errore durante il caricamento piuttosto che una stringa vuota in un messaggio clinico.

22.8.7 batch_size

BatchSize limita le righe prese per ogni interrogazione.

Defaults to 100.

È limitato perché un'interrogazione iniziale non limitata contro un tableau che qualcuno ha riempito per un anno leggerebbe tutto in memoria e poi lo invierebbe tutto, il che è il modo in cui una migrazione allaga un ricevitore live.

22.8.8 max_attempts

MaxAttempts indica quante volte una singola riga può fallire prima di essere messa in quarantena e l'interrogazione passa oltre.

Defaults to 3.

Questo è l'impostazione che impedisce il blocco. Il ritentare all'infinito non è resilienza; è una riga cattiva che ferma un flusso di dati ospedaliero.

22.8.9 query_timeout

QueryTimeout limita una singola interrogazione.

Defaults to 30s.

22.9 Sorgente diretta

DirectSource riceve la posta Direct che il HISP consegna: un listener SMTP per l'indirizzo di posta di questo.

Ogni messaggio viene decrittografato, la sua firma viene verificata contro gli anchor e il suo firmatario contro From, e il suo contenuto viene passato: un pacchetto XDM dei documenti, altrimenti ogni allegato, altrimenti il testo.

Definito come DirectSource in internal/config.

ChiaveTipoObbligatorioPredefinito
listentestono—
tls_certtestono—
tls_keytestono—
max_bytesnumero interono—
smtp_hosttestono—
usernametestono—
passwordtestono—
imapDirectIMAP (un blocco, omesso per non utilizzarlo)no—
xdrDirectXDR (un blocco, omesso per non utilizzarlo)no—

22.9.1 smtp_host

SMTPHost, Username e Password sono il server di invio HISP, utilizzato per inviare una notifica di consegna "elaborata" (MDN) al mittente una volta che un messaggio è stato preso in carico.

Senza di esso, non viene inviata alcuna notifica.

22.9.2 username

SMTPHost, Username e Password sono il server di invio HISP, utilizzato per inviare una notifica di consegna "elaborata" (MDN) al mittente una volta che un messaggio è stato preso in carico.

Senza di esso, non viene inviata alcuna notifica.

22.9.3 password

SMTPHost, Username e Password sono il server di invio HISP, utilizzato per inviare una notifica di consegna "elaborata" (MDN) al mittente una volta che un messaggio è stato preso in carico.

Senza di esso, non viene inviata alcuna notifica.

22.10 Sorgente email

EmailSource legge la posta da una casella di posta e trasforma gli allegati, i corpi o interi messaggi in messaggi.

Definito come EmailSource in internal/config.

ChiaveTipoObbligatorioPredefinito
protocoltestono—
hosttestosì—
portnumero interono—
securitytestono—
tlstlsconf.Settings (un blocco, omesso per lasciare fuori)no—
usernametestosì—
passwordtestono—
oauthEmailOAuth (un blocco, omesso per lasciare fuori)no—
mailboxtestono—
taketestono—
attachment_nameselenco di testono—
allowed_senderselenco di testono—
after_readtestono—
move_totestono—
error_foldertestono—
poll_intervaldurata, ad esempio 30s o 5mno—
max_message_sizenumero interono—

22.10.1 password

La password può essere ${ENV}; per Gmail è necessaria una password dell'app.

Ignorato con oauth.

22.10.2 attachment_names

AttachmentNames limita quali allegati vengono presi, in base al pattern del nome file (*.hl7).

Vuoto prende tutti gli allegati.

22.10.3 allowed_senders

AllowedSenders limita la posta di chi viene letta: indirizzi e domini.

L'intestazione From può essere contraffatta, quindi questo tiene fuori gli incidenti e la posta casuale, non un attaccante.

22.10.4 move_to

MoveTo è la cartella in cui vengono spostati i messaggi gestiti; di default è "Processed".

Viene creata quando manca.

22.11 Sorgente FTP

FTPSource raccoglie file da un server FTP o FTPS.

Perché FTP è ancora qui

Sono passati trent'anni dalla sua sostituzione raccomandata e molti sistemi ospedalieri ancora esportano su di esso: apparecchiature il cui firmware non verrà mai aggiornato, sistemi di fatturazione il cui fornitore addebita per le modifiche. Rifiutare di parlare non fa scomparire quei sistemi, significa che il motore di integrazione non può essere utilizzato.

FTPS è il valore predefinito. È lo stesso protocollo con TLS, la maggior parte dei server sopravvissuti lo supporta e rappresenta una conversazione molto più semplice con un team di sicurezza rispetto al semplice FTP.

Definito come FTPSource in internal/config.

ChiaveTipoObbligatorioPredefinito
hosttestosì—
usertestono—
passwordtestono—
securityftpconn.Securitynoesplicito
insecure_skip_verifytrue o falseno—
roottestono—
timeoutdurata, ad esempio 30s o 5mnotrenta secondi

22.11.1 host

L'host è il server, con una porta opzionale.

Si presume la porta 21.

22.11.2 utente

Utente e Password autenticano.

Entrambi possono essere omessi per un server anonimo.

Il FTP anonimo è ancora il modo in cui vengono pubblicati alcuni feed di riferimento pubblici, quindi un utente vuoto è una configurazione legittima piuttosto che un errore e non viene rifiutato. Su un server che si aspetta le credenziali, ometterle produce un errore di accesso al momento della connessione, che viene segnalato contro il canale piuttosto che ritentato silenziosamente.

22.11.3 password

Utente e Password autenticano.

Entrambi possono essere omessi per un server anonimo.

Il FTP anonimo è ancora il modo in cui vengono pubblicati alcuni feed di riferimento pubblici, quindi un utente vuoto è una configurazione legittima piuttosto che un errore e non viene rifiutato. Su un server che si aspetta le credenziali, ometterle produce un errore di accesso al momento della connessione, che viene segnalato contro il canale piuttosto che ritentato silenziosamente.

22.11.4 sicurezza

La sicurezza è esplicita, implicita o nulla.

Predefinita su esplicita, che è FTPS negoziato con AUTH TLS sulla porta ordinaria. "nessuna" è il FTP piano e deve essere richiesto per nome.

22.11.5 radice

La radice è la directory a cui ogni percorso è relativo e contro cui viene applicata la containment.

Il server non ha nozione di essa: un server FTP accetterà volentieri ../.. come percorso. Quindi questo è ciò che impedisce a un move_to di scrivere ovunque l'account possa raggiungere.

22.11.6 timeout

Il timeout delimita un'operazione, non l'intero poll.

Di default è trenta secondi.

Per operazione perché un poll che elenca una directory e recupera venti file esegue ventuno operazioni, e un solo budget per tutte loro interromperebbe un trasferimento perfettamente sano di un file di grandi dimensioni.

22.12 Sorgente file

FileSource legge i file da una directory che questo server può vedere.

Il connettore che un sito prova per primo

Un analizzatore scrive i risultati in una cartella. Un sistema di fatturazione rilascia un batch durante la notte. La radiologia esporta i rapporti in una directory che qualcuno ha montato anni fa. Nessuno di loro coinvolge un protocollo, e un motore di integrazione che non può leggere una cartella fallisce la sua valutazione nel primo pomeriggio.

Definito come FileSource in internal/config.

ChiaveTipoObbligatorioPredefinito
roottestosì—
follow_symlinkstrue o falseno—

22.12.1 radice

La radice delimita ogni percorso che questa sorgente tocca.

Required.

Separata da Dir in modo che move_to ed error_dir possano essere relativi e comunque essere contenuti. Dato solo Dir, un error_dir di "../failed" sarebbe al di fuori di tutto ciò che la sorgente aveva ricevuto, e rifiutarlo sarebbe arbitrario perché non ci sarebbe nulla contro cui rifiutarlo.

22.13 Sorgente GCS

GCSSource raccoglie gli oggetti da un prefisso del bucket, come le sorgenti s3 e azure_blob.

Definito come GCSSource in internal/config.

ChiaveTipoObbligatorioPredefinito
prefixtestosì—
suffixtestono—
after_readtestono—
move_totestonoprocessed/
error_prefixtestonoerror/
poll_intervaldurata, ad esempio 30s o 5mno30s
max_object_sizenumero interono16 MiB
framedtrue o falseno—

22.13.1 move_to

MoveTo è dove va un oggetto gestito quando after_read è spostato.

Predefinito su processed/.

22.13.2 error_prefix

ErrorPrefix è dove va un oggetto che non poteva essere gestito.

Predefinito su error/.

22.13.3 poll_interval

PollInterval è la frequenza con cui il prefisso viene elencato.

Defaults to 30s.

22.13.4 max_object_size

MaxObjectSize lascia gli oggetti più grandi dove sono.

Predefinito su 16 MiB.

22.14 Sorgente HTTP

HTTPSource accetta messaggi tramite HTTP.

Un listener piuttosto che un poller: qualcosa pubblica un messaggio e riceve un ack di risposta, che è il modo in cui la metà moderna dell'ospedale si integra quando MLLP non è disponibile.

Definito come HTTPSource in internal/config.

ChiaveTipoObbligatorioPredefinito
listentestosì—
pathtestono"/"
tlstlsconf.Settings (un blocco, omesso per lasciare fuori)no—
tokentestono—
max_message_sizenumero interono—
read_timeoutdurata, ad esempio 30s o 5mno—
ackAckno—

22.14.1 listen

Listen è l'indirizzo su cui servire.

Required.

22.14.2 path

Path è il percorso URL per accettare messaggi.

Defaults to "/".

22.14.3 token

Token, quando impostato, è richiesto in un'intestazione Authorization: Bearer.

Non c'è un valore predefinito e non c'è un toggle per la modalità anonima: un endpoint HTTP su una rete ospedaliera senza alcuna autenticazione è una decisione che deve essere visibile nel file, quindi lasciare questo campo vuoto viene segnalato come un avviso durante il caricamento.

22.14.4 max_message_size

MaxMessageSize delimita il corpo in entrata.

Zero applica un valore predefinito.

22.15 Sorgente IBMMQ

IBMMQSource legge una coda.

Definito come IBMMQSource in internal/config.

ChiaveTipoObbligatorioPredefinito
poll_intervaldurata, ad esempio 30s o 5mno2s

22.15.1 poll_interval

PollInterval è l'attesa quando la coda è vuota o dopo un messaggio che non poteva essere gestito.

Defaults to 2s.

22.16 Sorgente JavaScript

JavaScriptSource configura una sorgente che esegue uno script su un timer e alimenta i messaggi restituiti nel canale.

Questo è l'equivalente del lettore JavaScript di Mirth.

Lo script viene eseguito in una macchina virtuale goja con lo stesso sandbox degli script di trasformazione: msg non è disponibile (non c'è ancora un messaggio in entrata), ma globalMap, configurationMap, logger e DateUtil sono presenti. Lo script deve restituire una stringa (un messaggio) o un array di stringhe (molti). Restituire nulla o un array vuoto significa che il poll non ha prodotto messaggi, il che è normale.

Definito come JavaScriptSource in internal/config.

ChiaveTipoObbligatorioPredefinito
scripttestosì—
poll_intervaldurata, ad esempio 30s o 5mno—
timeoutdurata, ad esempio 30s o 5mno—

22.16.1 poll_interval

PollInterval indica la frequenza di esecuzione dello script.

Zero significa 5 secondi.

22.16.2 timeout

Timeout delimita l'esecuzione di uno script singolo.

Zero significa 30 secondi.

22.17 Sorgente Kafka

KafkaSource legge i messaggi da un argomento Kafka.

Definito come KafkaSource in internal/config.

ChiaveTipoObbligatorioPredefinito
brokerselenco di testosì—
topicselenco di testosì—
grouptestosì—
from_beginningtrue o falseno—
commit_after_deliverytrue o false (un blocco, omesso per lasciare fuori)no—
max_message_sizenumero interonoil limite del canale
session_timeoutdurata, ad esempio 30s o 5mnoquarantacinque secondi
timeoutdurata, ad esempio 30s o 5mnotrenta secondi
saslKafkaSASL (un blocco, omesso per lasciare fuori)no—
tlstlsconf.Settings (un blocco, omesso per lasciare fuori)no—

22.17.1 broker

I broker sono l'elenco dei server di avvio.

Required.

Un elenco piuttosto che un singolo indirizzo, perché un singolo broker di avvio è un punto di guasto singolo per l'avvio: il cluster sopravvive alla perdita e questo canale non lo farebbe.

22.17.2 argomenti

Gli argomenti sono gli argomenti da leggere.

Almeno uno è richiesto.

22.17.3 gruppo

Il gruppo è il gruppo di consumatori.

Required.

Denominato piuttosto che generato, e richiesto piuttosto che predefinito, perché è ciò che ricorda quanto lontano questo canale ha letto. Un gruppo generato inizierebbe dall'inizio - o dalla fine, perdendo tutto - ad ogni riavvio, e lascerebbe il vecchio gruppo indietro mantenendo gli offset committed che nessuno legge. Richiederlo fa sì che la persona nomini la cosa che deve rimanere la stessa attraverso i riavvii.

22.17.4 from_beginning

FromBeginning legge l'argomento dal suo inizio quando il gruppo non ha un offset committed.

Disattivato per impostazione predefinita, quindi un nuovo canale puntato su un argomento con due anni di storia non riproduce due anni di eventi del paziente in un sistema live il giorno in cui viene attivato. La prima persona a colpirlo lo farebbe in produzione, perché è lì che si trova l'argomento con la storia.

22.17.5 commit_after_delivery

CommitAfterDelivery imposta l'offset solo una volta che il messaggio è stato gestito.

Attivato per impostazione predefinita, e il motivo è tutta la differenza tra la perdita di un messaggio e la visualizzazione di due volte. L'impostazione dell'offset su lettura significa che un crash tra l'impostazione e la consegna perde il messaggio in silenzio, e nulla da nessuna parte registra che è esistito. L'impostazione dopo significa che un crash nella stessa finestra ridelivera, il che è visibile e che i ricevitori HL7 sono costruiti per tollerare - una copia duplicata A08 è un fastidio e un risultato di laboratorio mancante è un evento di sicurezza del paziente.

22.17.6 max_message_size

MaxMessageSize delimita un record singolo.

Predefinito per il limite del canale.

22.17.7 session_timeout

SessionTimeout rappresenta il tempo di attesa del coordinatore del gruppo prima di ritenere che questo consumatore sia stato rimosso e di riassegnare le sue partizioni.

Il valore predefinito è di quarantacinque secondi.

22.17.8 timeout

Limiti di timeout per le richieste di connessione e di metadata.

Di default è trenta secondi.

22.18 Sorgente MQTT

MQTTSource si iscrive a un filtro di argomento.

Definito come MQTTSource in internal/config.

ChiaveTipoObbligatorioPredefinito
topictestosì—
reconnectdurata, ad esempio 30s o 5mno5s

22.18.1 reconnect

Riconnessione è l'attesa dopo una connessione persa o dopo un messaggio che non poteva essere gestito.

Defaults to 5s.

22.19 Sorgente Pub Sub

PubSubSource recupera da una sottoscrizione Pub/Sub.

Definito come PubSubSource in internal/config.

ChiaveTipoObbligatorioPredefinito
subscriptiontestosì—
max_messagesnumero interono10
reconnectdurata, ad esempio 30s o 5mno5s

22.19.1 max_messaggi

MaxMessages rappresenta il numero di messaggi recuperati contemporaneamente.

Tuttavia, vengono gestiti uno alla volta, in ordine. Il valore predefinito è 10.

22.19.2 reconnect

Riconnessione è l'attesa dopo un errore.

Defaults to 5s.

22.20 Sorgente S3

S3Source recupera oggetti da un bucket.

Definito come S3Source in internal/config.

ChiaveTipoObbligatorioPredefinito
buckettestosì—
path_stylevero o falsono—
prefixtestono—
suffixtestono—
after_readtestono—
move_totestonoprocessed/
error_prefixtestonoerror/
poll_intervaldurata, ad esempio 30s o 5mno30s
max_object_sizenumero interono16 MiB
framedvero o falsono—

22.20.1 prefisso

Il prefisso limita gli oggetti letti, ad esempio inbound/.

La lettura vuota legge l'intero bucket, che viene rifiutata a meno che dopo_lettura: sposta a meno che sposta_in non sia all'esterno di esso - altrimenti gli oggetti spostati verrebbero letti nuovamente.

22.20.2 dopo_lettura

AfterRead si sposta (il valore predefinito) o elimina.

Non c'è lasciare: un bucket non ha un file che un poller possa ricordare di aver visto attraverso un riavvio, quindi lasciare gli oggetti significa rileggerli tutti di nuovo ogni volta che Perfuse si avvia.

22.20.3 move_to

MoveTo è il prefisso a cui si sposta un oggetto gestito.

Predefinito su processed/.

22.20.4 error_prefix

ErrorPrefix è dove si sposta un oggetto che non poteva essere gestito, in modo che un singolo file dannoso non blocchi gli altri.

Predefinito su error/.

22.20.5 poll_interval

PollInterval tra le liste.

Defaults to 30s.

22.20.6 max_object_size

MaxObjectSize rifiuta qualsiasi oggetto più grande.

Predefinito su 16 MiB.

22.20.7 inquadrate

Framed legge più messaggi inquadrate MLLP da un singolo oggetto.

Altrimenti, un oggetto è un messaggio.

22.21 Sorgente SFTP

SFTPSource raccoglie messaggi da una directory su un server SFTP.

Estremamente comune e raramente discusso. Un laboratorio o un sistema di radiologia scrive un file ogni pochi minuti, un server SFTP lo tiene e qualcosa deve venire a prenderlo. La metà dei feed descritti come "ti inviamo HL7" sono questo.

La parte che merita attenzione non è il trasferimento. È che un file che viene scritto e un file che è stato scritto appaiono identici tramite SFTP, quindi un poll che è anche solo leggermente troppo ansioso raccoglie metà di un messaggio. Ciò produce un messaggio HL7 troncato ma spesso parsabile, che è il peggiore risultato disponibile: viene accettato, confermato, archiviato e consegnato e la metà mancante non viene più menzionata.

Definito come SFTPSource in internal/config.

ChiaveTipoObbligatorioPredefinito
hosttestosì22
usertestosì—
passwordtestono—
key_filetestono—
key_passphrasetestono—
known_hosts_filetestono—
insecure_skip_host_key_checkvero o falsono—
dirtestosì—
patterntestonotutto
poll_intervaldurata, ad esempio 30s o 5mno—
after_readtestono—
move_totestono—
error_dirtestono—
stable_fordurata, ad esempio 30s o 5mno5s
framedvero o falsono—
max_file_sizenumero interono64MB
timeoutdurata, ad esempio 30s o 5mno60s

22.21.1 host

L'host è il server, con una porta opzionale.

Defaults to 22.

22.21.2 password

Password autentica con una password.

Prefer KeyFile.

22.21.3 key_file

KeyFile è una chiave privata.

La scelta migliore, e quella che le squadre di sicurezza degli ospedali chiedono.

22.21.4 known_hosts_file

KnownHostsFile verifica l'identità del server.

Obbligatorio a meno che InsecureSkipHostKeyCheck non sia impostato. Senza di esso non c'è nulla per distinguere il server reale da qualsiasi cosa che risponda a quell'indirizzo e le credenziali vengono consegnate prima che qualcuno se ne accorga.

22.21.5 insecure_skip_host_key_check

InsecureSkipHostKeyCheck accetta qualsiasi chiave host.

Esiste perché rifiutare tout court invia le persone a uno script shell con StrictHostKeyChecking=no, che è peggiore in ogni modo, compresa l'auditabilità. Avverte ad alta voce e non è mai il valore predefinito.

22.21.6 pattern

Il pattern seleziona i file in base a glob.

Di default seleziona tutti.

22.21.7 move_to

MoveTo è la directory remota in cui vengono spostati i file dopo la lettura.

Richiesto quando AfterRead è "move".

22.21.8 stabile_per

StabilePer è il tempo durante il quale le dimensioni e l'ora di modifica di un file devono rimanere invariate prima di essere lette.

Defaults to 5s.

Questo è l'impostazione che impedisce di raccogliere metà di un messaggio. Zero significa leggere tutto ciò che è presente, il che funziona fino a quando un file non è abbastanza grande o una rete non è abbastanza lenta da far durare la scrittura più a lungo di un poll.

22.21.9 inquadrate

Framed indica che il file contiene messaggi in formato MLLP.

Quando è false, il file viene suddiviso sui confini MSH.

22.21.10 dimensione_massima_file

DimensioneMassimaFile rifiuta un file più grande di questo numero di byte.

Di default è 64MB.

22.21.11 timeout

Il timeout delimita una singola connessione.

Defaults to 60s.

22.22 Sorgente SMB

SMBSource raccoglie file da una condivisione di file Windows.

Definito come SMBSource in internal/config.

ChiaveTipoObbligatorioPredefinito
hosttestosì—
sharetestosì—
usertestono—
passwordtestono—
domaintestono—
roottestono—
timeoutdurata, ad esempio 30s o 5mnotrenta secondi

22.22.1 host

L'host è il server, con una porta opzionale.

Si presume la porta 445.

22.22.2 condivisione

La condivisione è il nome della condivisione solo: il "dati" in \\\server\dati.

Un percorso qui è rifiutato piuttosto che troncato.

22.22.3 utente

Utente e Password sono l'account Windows.

Richiesto nella pratica.

Una condivisione raggiungibile senza credenziali è rara a sufficienza in un dominio che un utente vuoto qui è molto più probabile essere un errore che una condivisione guest - ma è accettato, perché rifiutarlo bloccerebbe l'unico accordo in cui è corretto. Se l'account appartiene a un dominio, impostare anche il Dominio: l'autenticazione di un account di dominio senza di esso fallisce in un modo che sembra una password errata.

22.22.4 password

Utente e Password sono l'account Windows.

Richiesto nella pratica.

Una condivisione raggiungibile senza credenziali è rara a sufficienza in un dominio che un utente vuoto qui è molto più probabile essere un errore che una condivisione guest - ma è accettato, perché rifiutarlo bloccerebbe l'unico accordo in cui è corretto. Se l'account appartiene a un dominio, impostare anche il Dominio: l'autenticazione di un account di dominio senza di esso fallisce in un modo che sembra una password errata.

22.22.5 dominio

Il dominio è il dominio o il gruppo di lavoro Windows.

Vuoto è di solito corretto per un account locale.

22.22.6 timeout

Il timeout limita un'operazione.

Di default è trenta secondi.

Vale la pena aumentarlo se si raggiunge una condivisione attraverso un collegamento di sito. Un'operazione SMB contro un server remoto è più lenta della stessa operazione in locale di quanto basti per far sembrare che una regolazione predefinita ottimizzata per una LAN produca timeout che sembrano una condivisione non disponibile.

22.23 Origine SOAP

SOAPSource accetta messaggi avvolti in un envelope SOAP.

Il corrispettivo della destinazione SOAP, e la direzione più rara: la maggior parte dell'integrazione ospedaliera ha Perfuse che chiama un servizio invece di esserne uno. Esiste perché Mirth's Web Service Listener esiste, e un sito il cui sistema di invio parla solo SOAP non può migrare senza di esso.

Non è deliberatamente un framework generico per servizi web. Accetta un envelope, estrae il messaggio da esso e risponde con un envelope. Non ci sono WS-Security, MTOM, WS-Addressing e binding generati - le stesse omissioni della destinazione, per lo stesso motivo: un'implementazione parziale di WS-Security è peggiore di nessuna.

Definito come SOAPSource in internal/config.

ChiaveTipoObbligatorioPredefinito
listentestosì—
profiletestono—
pathtestono"/"
versiontestono1
elementtestono—
base64vero o falsono—
response_elementtestono"AckResponse"
response_namespacetestono—
wsdltestono—
tlstlsconf.Settings (un blocco, omesso per lasciare fuori)no—
tokentestono—
usernametestono—
passwordtestono—
max_message_sizenumero interono—
read_timeoutdurata, ad esempio 30s o 5mno—
ackAckno—
fault_on_nakvero o falsono—

22.23.1 listen

Listen è l'indirizzo su cui servire.

Required.

22.23.2 profilo

Il nome del profilo indica un servizio standard che questo endpoint implementa.

Vuoto accetta qualsiasi envelope come configurato di seguito.

"cdc-iis" risponde come un registro di immunizzazione fa, sull'interfaccia CDC (urn:cdc:iisb:2011): connectivityTest viene ripetuto, submitSingleMessage's hl7Message è il messaggio e l'acknowledgement del canale torna indietro in risposta, il WSDL viene servito alla ?wsdl e username e password, quando impostati, vengono verificati contro quelli nel corpo (dove il WSDL li mette) invece di contro l'autenticazione HTTP. Per un test double di un registro o per un sito che riceve invii nel modo in cui i registri fanno.

22.23.3 path

Il percorso è il percorso URL per accettare gli envelope.

Defaults to "/".

22.23.4 versione

La versione è la versione SOAP da utilizzare per rispondere, "1.1" o "1.2".

Defaults to 1.1.

Le richieste vengono accettate in entrambe le versioni indipendentemente, perché un mittente che si sbaglia è comune e rifiutarlo non insegna nulla a nessuno. L'impostazione controlla la risposta, dove sbagliare significa che il mittente non può leggere la risposta.

22.23.5 elemento

L'elemento nomina l'elemento all'interno del corpo SOAP che contiene il messaggio.

Vuoto significa l'intero testo del corpo.

Nominato invece di indovinato perché un corpo può trasportare più elementi - un messaggio accanto a un identificatore del mittente e a un timestamp - e prendere l'intero corpo significherebbe consegnare al motore un frammento XML dove ci si aspettava HL7.

22.23.6 base64

La codifica base64 decodifica il contenuto dell'elemento prima di trattarlo come un messaggio.

Comune nei servizi reali, perché HL7 trasporta ritorni a capo e i chiamanti che non hanno pensato a quello finiscono con XML che li mutila. Se il contenuto decodifica come base64 ma non era destinato a essere, il risultato non è un messaggio e il motore lo dice - il che è il motivo per cui questo è esplicito invece di sniffato.

22.23.7 elemento_di_risposta

ResponseElement nomina l'elemento che avvolge l'acknowledgement nella risposta.

Di default è "AckResponse".

22.23.8 wsdl

WSDL è un file servito nel percorso di ascolto con ?wsdl.

Vuoto significa che non viene servito.

Un file piuttosto che qualcosa generato. Un WSDL generato descriverebbe ciò che questo endpoint accetta, il che è quasi mai ciò contro cui il sistema di invio è stato costruito - e un WSDL che è quasi giusto costa più tempo di nessun WSDL, perché sembra autoritativo.

22.23.9 username

Nome utente e Password, quando impostati, richiedono l'autenticazione HTTP di base.

Offerto insieme a un token perché i chiamanti SOAP si aspettano in modo schiacciante l'autenticazione di base, e un sito il cui sistema di invio non può essere modificato ha bisogno dell'opzione che già ha.

22.23.10 password

Nome utente e Password, quando impostati, richiedono l'autenticazione HTTP di base.

Offerto insieme a un token perché i chiamanti SOAP si aspettano in modo schiacciante l'autenticazione di base, e un sito il cui sistema di invio non può essere modificato ha bisogno dell'opzione che già ha.

22.23.11 max_message_size

MaxMessageSize delimita il corpo in entrata.

Zero applica un valore predefinito.

22.23.12 fault_on_nak

FaultOnNak risponde a un acknowledgement negativo con una fault SOAP invece di una risposta normale che trasporta il NAK.

Disattivato di default, che è il default giusto e vale la pena spiegarlo. HL7 già ha un modo per dire "Ho ricevuto questo e l'ho rifiutato", e che è un NAK - uno scambio di successo che segnala un messaggio rifiutato. Trasformare la stessa cosa in una fault di trasporto dice al mittente che la sua richiesta era malformata, il che non è, e molti client si ritirano per sempre.

Esiste perché alcuni chiamanti guardano solo lo stato HTTP e altrimenti trattano un rifiuto come un successo.

22.24 Sorgente SQS

SQSSource legge da una coda SQS.

Un messaggio viene eliminato solo dopo che il canale lo ha gestito - consegnato, o filtrato, o fallito in un modo che il canale registra. Fino ad allora rimane nella coda, invisibile per visibility_timeout, e torna se Perfuse si ferma. Quindi un messaggio non viene mai perso; il prezzo è che uno può arrivare due volte, il che SQS stesso già consente.

Definito come SQSSource in internal/config.

ChiaveTipoRichiestoDefault
queue_urltestosì—
wait_secondsnumero interono20: una coda vuota costa una richiesta ogni venti secondi
max_messagesnumero interono10
visibility_timeoutdurata, come 30s o 5mnol'impostazione della coda stessa

22.24.1 visibility_timeout

VisibilityTimeout è il tempo per cui un messaggio ricevuto rimane nascosto mentre viene gestito.

Di default è l'impostazione della coda stessa.

22.25 Sorgente Seriale

SerialSource legge i messaggi da una porta seriale.

Perché un connettore seriale nel 2026

Perché l'attrezzatura è ancora lì. Un analizzatore del gas sanguigno acquistato nel 2009 con un sensore funzionante e una presa a 25 pin, un monitor del letto, una bilancia in un'unità di dialisi, una macchina anestetica più vecchia. Nessuno di loro avrà mai un porta Ethernet, diversi di loro costano sei cifre, e l'alternativa alla lettura è che qualcuno digiti i risultati in un modulo.

Mirth ha un connettore seriale. Perfuse non aveva nulla e un sito con uno di questi non aveva alcuna route di ingresso.

Il framing è condiviso con il connettore TCP

I framing sono gli stessi indipendentemente da dove provengono i byte: un analizzatore che parla STX/ETX su una socket parla STX/ETX su un cavo. Quindi si riutilizza il blocco di framing TCP invece di definirne uno proprio, il che significa anche che un dispositivo spostato da un cavo seriale a un adattatore seriale-Ethernet mantiene la sua configurazione di framing.

Cosa è diverso in una linea seriale

Non c'è connessione. Una socket ti dice quando il peer se n'è andato; un cavo no. Un cavo scollegato, un dispositivo spento e un dispositivo con nulla da dire sono indistinguibili - tutti e tre sono silenzio. È per questo che esiste quiet_after: senza qualcosa che dica "questa linea è stata silenziosa per più tempo di quanto dovrebbe", un feed morto sembra esattamente come una notte tranquilla.

Definito come SerialSource in internal/config.

ChiaveTipoObbligatorioPredefinito
porttestosì—
baudnumero interosì—
data_bitsnumero interono8
paritytestononone
stop_bitstestono1
flow_controltestononone
max_message_sizenumero interono—
quiet_afterdurata, ad esempio 30s o 5mno—
replytestono—
reply_texttestono—
reopen_afterdurata, ad esempio 30s o 5mno—

22.25.1 baud

Baud è la velocità.

Obbligatorio, perché indovinare produce byte invece di un errore.

Un tasso di baud errato non fallisce. Produce spazzatura plausibile: i byte di framing appaiono casualmente, occasionali sequenze si decodificano come caratteri stampabili e un parser indulgente accetta alcune di esse. Non c'è predefinito di proposito.

22.25.2 parity

La parità è none, odd, even, mark o space.

Predefinita su none.

22.25.3 stop_bits

StopBits è 1, 1.5 o 2, scritto come "1", "1.5" o "2".

Defaults to 1.

22.25.4 flow_control

FlowControl è none, hardware o software.

Predefinita su none.

Vale la pena impostarlo correttamente invece di lasciarlo. Con il controllo di flusso hardware atteso e non configurato, un dispositivo si ferma durante l'invio di un messaggio lungo e il risultato è un messaggio troncato invece di un errore.

22.25.5 quiet_after

QuietAfter registra un avviso quando nulla è stato ricevuto per questo tempo.

L'unico modo per notare un feed seriale morto. Un cavo scollegato e una notte tranquilla sono lo stesso silenzio, quindi qualcuno deve dire quanto tempo è troppo lungo per questo dispositivo specifico.

22.25.6 reopen_after

ReopenAfter è quanto tempo aspettare prima di riaprire una porta che non ha funzionato.

Un adattatore seriale USB scollegato e riattaccato torna come lo stesso percorso del dispositivo ma con un handle del kernel diverso, quindi il vecchio restituisce errori per sempre. Riaprire è l'unico recupero e farlo in un ciclo stretto riempie il log.

22.26 Sorgente

La sorgente è dove un canale riceve messaggi.

Definito come Source in internal/config.

ChiaveTipoObbligatorioPredefinito
typeSourceTypesì—
listentestosì—
max_message_sizenumero interono—
idle_timeoutdurata, ad esempio 30s o 5mno—
max_connectionsnumero interono—
tlstlsconf.Settings (un blocco, omesso per non utilizzarlo)no—
httpHTTPSource (un blocco, omesso per non utilizzarlo)no—
soapSOAPSource (un blocco, omesso per non utilizzarlo)no—
dicomwebDICOMwebSource (un blocco, omesso per non utilizzarlo)no—
directDirectSource (un blocco, omesso per non utilizzarlo)no—
dicomDICOMSource (un blocco, omesso per non utilizzarlo)no—
fileFileSource (un blocco, omesso per non utilizzarlo)no—
tcpTCPSource (un blocco, omesso per non utilizzarlo)no—
ftpFTPSource (un blocco, omesso per non utilizzarlo)no—
smbSMBSource (un blocco, omesso per non utilizzarlo)no—
webdavWebDAVSource (un blocco, omesso per non utilizzarlo)no—
serialSerialSource (un blocco, omesso per non utilizzarlo)no—
dicom_queryDICOMQuerySource (un blocco, omesso per non utilizzarlo)no—
brokerBrokerSource (un blocco, omesso per non utilizzarlo)no—
kafkaKafkaSource (un blocco, omesso per non utilizzarlo)no—
sqsSQSSource (un blocco, omesso per non utilizzarlo)no—
s3S3Source (un blocco, omesso per non utilizzarlo)no—
amqpAMQPSource (un blocco, omesso per non utilizzarlo)no—
azure_blobAzureBlobSource (un blocco, omesso per non utilizzarlo)no—
emailEmailSource (un blocco, omesso per non utilizzarlo)no—
as2AS2Source (un blocco, omesso per non utilizzarlo)no—
pgpPGPReceive (un blocco, omesso per non utilizzarlo)no—
mqttMQTTSource (un blocco, omesso per non utilizzarlo)no—
ibm_mqIBMMQSource (un blocco, omesso per non utilizzarlo)no—
pubsubPubSubSource (un blocco, omesso per non utilizzarlo)no—
gcsGCSSource (un blocco, omesso per non utilizzarlo)no—
databaseDatabaseSource (un blocco, omesso per non utilizzarlo)no—
sftpSFTPSource (un blocco, omesso per non utilizzarlo)no—
javascriptJavaScriptSource (un blocco, omesso per non utilizzarlo)no—
ackAckno—

22.26.1 tipo

Il tipo è il trasporto.

Solo mllp è implementato.

22.26.2 max_message_size

MaxMessageSize limita un messaggio in entrata.

Zero utilizza il valore predefinito del trasporto.

22.26.3 idle_timeout

IdleTimeout chiude una connessione che è stata silenziosa per questo tempo.

Zero significa mai, il che è solitamente corretto: un flusso di dati di un ospedale mantiene una connessione aperta per mesi e si ferma durante la notte.

22.26.4 max_connections

MaxConnections limita le connessioni concorrenti.

Zero significa illimitato.

22.27 Sorgente TCP

TCPSource ascolta una socket per messaggi che non sono necessariamente HL7.

Perché questo è separato da una sorgente mllp

MLLP è un framing e Perfuse lo ha sempre parlato. Un gran numero di apparecchiature non lo fa: un analizzatore di laboratorio, una bilancia, un monitor del letto, un sistema di fatturazione più vecchio. Ognuno tende ad avere la propria convenzione e il connettore TCP di Mirth copre tutti loro, quindi un sito con un flusso di dati della socket che non era HL7 non poteva utilizzare Perfuse affatto.

Definito come TCPSource in internal/config.

ChiaveTipoObbligatorioPredefinito
listentestosì—
max_message_sizenumero interono—
idle_timeoutdurata, ad esempio 30s o 5mno—
max_connectionsnumero interono—
replytestono—
reply_texttestono—
tlstlsconf.Settings (un blocco, omesso per non utilizzarlo)no—

22.27.1 idle_timeout

IdleTimeout chiude una connessione che è stata silenziosa per questo tempo.

Zero significa mai, il che è solitamente corretto: un flusso di dati di un dispositivo mantiene una connessione aperta per mesi e si ferma durante la notte.

22.27.2 max_connections

MaxConnections limita le connessioni concorrenti.

Zero significa illimitato.

22.27.3 risposta

La risposta è cosa inviare indietro dopo ogni messaggio: nulla, ack o una stringa fissa.

La maggior parte dei flussi di dati grezzi si aspetta nulla. Alcuni si aspettano un singolo byte ACK. Un dispositivo che si aspetta una risposta e non la riceve solitamente ritenta lo stesso messaggio all'infinito, quindi è utile essere espliciti al riguardo.

22.28 Sorgente Web DAV

WebDAVSource raccoglie file da una raccolta WebDAV.

Dove si presenta: sistemi di gestione dei documenti, SharePoint, Nextcloud e portali di venditori che espongono una cartella di drop tramite HTTPS perché è l'unico porta in uscita consentita dai firewall dei loro clienti.

Definito come WebDAVSource in internal/config.

ChiaveTipoObbligatorioPredefinito
urltestosì—
usertestono—
passwordtestono—
insecure_skip_verifyvero o falsono—
timeoutdurata, ad esempio 30s o 5mnosessanta secondi

22.28.1 utente

Utente e Password autenticano con autenticazione di base HTTP.

L'autenticazione di base invia la password in un'intestazione protetta solo da TLS, quindi queste appartengono a un URL https. Su http sono leggibili da qualsiasi cosa sul percorso e nessun avviso dal server ti informerà.

22.28.2 password

Utente e Password autenticano con autenticazione di base HTTP.

L'autenticazione di base invia la password in un'intestazione protetta solo da TLS, quindi queste appartengono a un URL https. Su http sono leggibili da qualsiasi cosa sul percorso e nessun avviso dal server ti informerà.

22.28.3 timeout

Timeout delimita una richiesta.

Predefinito a sessanta secondi.

Più lungo dei valori predefiniti FTP e SMB di proposito. Un elenco di raccolta WebDAV è un singolo PROPFIND che il server potrebbe impiegare molto tempo ad assemblare per una directory grande, e non c'è un risultato parziale a cui fare riferimento.

23 Riferimento di destinazione

Ogni modo in cui un canale può inviare messaggi, e ogni chiave che ogni uno accetta. Un canale può avere qualsiasi numero di destinazioni, e sono indipendenti: una che non riesce non ferma le altre.

23.1 Destinazione AMQP

AMQPDestination invia a una coda o a un argomento e segnala il successo solo una volta che il broker ha accettato il messaggio.

Definito come AMQPDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
content_typetestonoil tipo di dati del canale

23.1.1 content_type

ContentType viene inviato con ogni messaggio.

Predefinito al tipo di dati del canale.

23.2 Destinazione AS2

AS2Destination invia ogni messaggio come AS2: firmato con la nostra chiave, crittografato con il certificato del partner, pubblicato sull'URL del partner e, per impostazione predefinita, consegnato solo una volta che la ricevuta firmata del partner nomina lo stesso digest.

Definito come AS2Destination in internal/config.

ChiaveTipoObbligatorioPredefinito
urltestosì—
fromtestosì—
totestosì—
cert_filetestono—
key_filetestono—
partner_cert_filetestono—
unsignedvero o falsono—
unencryptedvero o falsono—
compressvero o falsono—
receipttestono—
unsigned_receiptvero o falsono—
receipt_urltestono—
content_typetestono—
file_nametestono—
subjecttestono—
usernametestono—
passwordtestono—
tlstlsconf.Settings (un blocco, omesso per lasciare fuori)no—

23.2.1 compress

Compress compressa il payload (zlib, RFC 5402) prima della firma e della crittografia.

Ogni ricevitore AS2 che annuncia la versione 1.1 o successiva la legge; chiedi al partner prima di attivarla.

23.2.2 ricevuta_non_firmata

UnsignedReceipt richiede una ricevuta non firmata.

Off: viene richiesta una firmata e rifiutata una non firmata.

23.2.3 content_type

ContentType è il tipo MIME del payload.

Predefinito in base al tipo di dati del canale: application/edi-x12, application/edifact, application/hl7-v2, altrimenti application/octet-stream.

23.3 Destinazione Azure Blob

AzureBlobDestination scrive ogni messaggio come blob a blocchi.

Definito come AzureBlobDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
blobtestono${data}/${canale}/${id_controllo}
tiertestono—
content_typetestono—

23.3.1 blob

I nomi dei blob, con i segnaposto della destinazione S3.

Predefinito su ${data}/${canale}/${id_controllo}.hl7.

23.3.2 tier

Il livello è Hot, Cool, Cold o Archive.

Archive è offline: la lettura di un blob significa reidratazione, che richiede ore.

23.4 Destinazione Broker

BrokerDestination pubblica i messaggi su un broker di messaggi.

Scrittore JMS di Mirth.

Definito come BrokerDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
addrtestosì—
destinationtestosì—
logintestono—
passcodetestono—
hosttestonol'host dell'indirizzo
content_typetestonotext/plain per HL7
headersmappatura di testo su testono—
persistentvero o falso (un blocco, omesso per lasciare fuori)novero
timeoutdurata, ad esempio 30s o 5mno—
tlstlsconf.Settings (un blocco, omesso per lasciare fuori)no—

23.4.1 addr

Addr è l'host e la porta del broker.

Required.

23.4.2 destinazione

La destinazione è la coda o l'argomento da pubblicare.

Required.

23.4.3 accesso

Accesso e codice di accesso autenticano.

La maggior parte dei broker rifiuta una connessione anonima.

23.4.4 codice di accesso

Accesso e codice di accesso autenticano.

La maggior parte dei broker rifiuta una connessione anonima.

23.4.5 host

L'host è l'host virtuale.

Di default è l'host dell'indirizzo.

Vale la pena impostarlo esplicitamente su un broker che ospita più host virtuali, dove il predefinito atterra la pubblicazione su quello che risponde al nome del server - una coda che esiste, accetta il messaggio e viene letta da nessuno.

23.4.6 content_type

ContentType viene inviato con ogni messaggio.

Predefinito su text/plain per HL7.

23.4.7 header

Gli header vengono inviati con ogni messaggio.

La configurazione solo, mai il contenuto del messaggio. Un header preso da un campo inserirebbe un identificatore di paziente nei metadati del broker che vengono registrati, indicizzati e resi visibili a ogni altra applicazione nella coda.

23.4.8 persistente

Persistente chiede al broker di sopravvivere a un riavvio.

Il valore predefinito è true.

True perché un messaggio non persistente viene perso quando il broker si riavvia, e ciò non è un valore predefinito ragionevole per i dati clinici. False esiste per un feed veramente transitorio - un heartbeat di monitoraggio - e deve essere scelto.

23.5 Destinazione CDA

CDADestination configura una destinazione cda: prende il documento clinico all'interno di un messaggio HL7 v2, lo converte e scrive o pubblica il risultato.

Ciò esiste perché un documento arriva quasi mai da solo. Arriva codificato in base64 all'interno di un MDM^T02, e ogni motore che tratta quel messaggio come un blob opaco lascia il documento non letto. Possedere entrambe le estremità di ciò è l'obiettivo.

Definito come CDADestination in internal/config.

ChiaveTipoRichiestoPredefinito
urltestono—
dirtestono—
writetestono—
versiontestonoR5
identifier_systemsmappatura di testo su testono—
require_agreementtrue o falseno—
on_no_documenttestono—
headersmappatura di testo su testono—
bearer_tokentestono—

23.5.1 url

L'URL è un server FHIR a cui pubblicare il bundle convertito.

Lascialo vuoto per scrivere su Dir invece. Uno dei due è richiesto.

23.5.2 dir

Dir scrive l'output su file invece di pubblicarlo.

Utile per una zona di atterraggio che un altro processo raccoglie, e per vedere cosa produce la conversione prima di puntarlo a un server live.

23.5.3 write

Write seleziona cosa viene scritto o pubblicato:

fhir il bundle di transazione convertito (predefinito) documenta il documento originale bytes, invariato entrambi, con il documento accanto al bundle trasferisce un riassunto di transizione di cura PACIO: un documento FHIR R4 Bundle per il luogo in cui il paziente va dopo (una casa di cura, una unità di riabilitazione, assistenza sanitaria a domicilio), inviato a url/Bundle o scritto in dir

"documento" vale la pena di averlo da solo: un sito che vuole i suoi CDAs su disco per un team di registi non ha bisogno della conversione FHIR.

23.5.4 identifier_systems

IdentifierSystems mappa una radice OID dal documento a un URI, in modo che un MRN diventi namespaced.

Un CDA identifica le persone tramite OID e FHIR tramite URI, e nulla può derivare uno dall'altro.

23.5.5 require_agreement

RequireAgreement rifiuta un documento la cui narrazione e le voci codificate si contraddicono a vicenda.

Disabilitato per impostazione predefinita, e intenzionalmente. Il controllo è utile, ma rappresenta un giudizio su un documento creato da qualcun altro, e un canale che scarta silenziosamente documenti clinici reali a causa di un generatore C-CDA non affidabile del mittente è peggiore di uno che li passa con un avviso. Un sito che ha esaminato i propri risultati e deciso di volerlo attivare può abilitarlo.

23.5.6 on_no_document

OnNoDocument decide cosa succede quando il messaggio non contiene un documento clinico:

salta non consegnare nulla e segnalare il successo (predefinito) fallisce trattarlo come un errore di consegna

Il valore predefinito è salta, poiché un canale che trasporta un flusso misto ADT e MDM fallirebbe altrimenti ogni ammissione. Un canale dedicato ai documenti dovrebbe impostare fallisce, poiché un messaggio di documento senza documento al suo interno è un problema reale nel mittente.

23.5.7 bearer_token

BearerToken viene inviato come intestazione di autorizzazione.

Preferire un riferimento a una variabile d'ambiente rispetto a un valore letterale in un file che viene inserito in git.

23.6 Destinazione del canale

ChannelDestination instrada a un altro canale sullo stesso server.

Definito come ChannelDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
nametestosì—

23.7 Destinazione DICOM

DICOMDestination invia oggetti di imaging come utente della classe di servizio C-STORE.

Mirth chiama questo il mittente DICOM.

Definito come DICOMDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
addresstestosì—
called_aetestono—
calling_aetestono—
transfer_syntaxeselenco di testono—
timeoutdurata, ad esempio 30s o 5mno—
tlstlsconf.Settings (un blocco, omesso per lasciare fuori)no—

23.7.1 indirizzo

L'indirizzo è l'host e la porta remota.

Required.

23.7.2 called_ae

CalledAE è come il remoto si chiama, e CallingAE è come questo estremo si chiama.

Entrambi sono importanti. I siti configurano un PACS per accettare un solo titolo di chiamata specifico e rifiutare tutto il resto, quindi una mancata corrispondenza è il motivo più comune per cui una prima connessione fallisce - e il fallimento sembra un problema di rete.

23.7.3 calling_ae

CalledAE è come il remoto si chiama, e CallingAE è come questo estremo si chiama.

Entrambi sono importanti. I siti configurano un PACS per accettare un solo titolo di chiamata specifico e rifiutare tutto il resto, quindi una mancata corrispondenza è il motivo più comune per cui una prima connessione fallisce - e il fallimento sembra un problema di rete.

23.7.4 transfer_syntaxes

TransferSyntaxes limita ciò che viene offerto, nell'ordine di preferenza.

Vuoto offre la codifica dell'oggetto stesso e poi implicita VR little endian come fallback.

23.7.5 timeout

Il timeout limita un'operazione di archiviazione.

Zero applica un valore predefinito.

23.8 Destinazione Mweb DICOM

DICOMwebDestination archivia ogni oggetto con STOW-RS.

Definito come DICOMwebDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
urltestosì—
tokentestono—
usernametestono—
passwordtestono—
headersmappa di testo su testono—
tlstlsconf.Settings (un blocco, omesso per non utilizzarlo)no—
timeoutdurata, ad esempio 30s o 5mno—

23.9 Destinazione del database

DatabaseDestination scrive ogni messaggio su un database.

Definito come DatabaseDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
drivertestosì—
dsntestosì—
statementtestosì—
paramselenco di testono—
timeoutdurata, ad esempio 30s o 5mno30s
max_open_connsnumero interono4

23.9.1 driver

Driver nomina il database.

See SupportedDrivers.

23.9.2 istruzione

L'istruzione viene eseguita una volta per messaggio, con i parametri Params legati ad esso in ordine.

I segnaposto sono propri del driver: $1 per postgres, ? per mysql e sqlite, @p1 per sqlserver. Perfuse non li riscrive, perché un livello di traduzione che sbaglia un segnaposto lega il nome di un paziente alla colonna sbagliata e il risultato sembra dati validi.

23.9.3 parametri

I parametri sono percorsi HL7 o espressioni ${...}, legati all'istruzione in ordine.

I valori sono sempre legati come parametri e non interpolati nel SQL. Ciò non riguarda solo l'iniezione: O'Brien è un nome comune e una query concatenata si rompe sull'apostrofo.

23.9.4 timeout

Il timeout delimita un'unica istruzione.

Defaults to 30s.

23.9.5 max_open_conns

MaxOpenConns limita la dimensione del pool.

Defaults to 4.

23.10 Destinazione

La destinazione è un luogo in cui un canale invia i messaggi.

Definito come Destination in internal/config.

ChiaveTipoObbligatorioPredefinito
nametestosì—
typeDestinationTypesì—
enabledtrue o false (un blocco, omesso per lasciare fuori)no—
filtertestono—
addresstestono—
dirtestono—
file_nametestono—
temp_suffixtestono"
appendtrue o falseno—
retain_hoursnumero interono—
tlstlsconf.Settings (un blocco, omesso per lasciare fuori)no—
fhirFHIRDestination (un blocco, omesso per lasciare fuori)no—
cdaCDADestination (un blocco, omesso per lasciare fuori)no—
httpHTTPDestination (un blocco, omesso per lasciare fuori)no—
databaseDatabaseDestination (un blocco, omesso per lasciare fuori)no—
sftpSFTPDestination (un blocco, omesso per lasciare fuori)no—
tcpTCPDest (un blocco, omesso per lasciare fuori)no—
smtpSMTPDestination (un blocco, omesso per lasciare fuori)no—
channelChannelDestination (un blocco, omesso per lasciare fuori)no—
s3S3Destination (un blocco, omesso per lasciare fuori)no—
ftpFTPDestination (un blocco, omesso per lasciare fuori)no—
documentDocumentDestination (un blocco, omesso per lasciare fuori)no—
soapSOAPDestination (un blocco, omesso per lasciare fuori)no—
dicomwebDICOMwebDestination (un blocco, omesso per lasciare fuori)no—
xdsXDSDestination (un blocco, omesso per lasciare fuori)no—
directDirectDestination (un blocco, omesso per lasciare fuori)no—
as2AS2Destination (un blocco, omesso per lasciare fuori)no—
mpiMPIDestination (un blocco, omesso per lasciare fuori)no—
tefcaTEFCADestination (un blocco, omesso per lasciare fuori)no—
pasPASDestination (un blocco, omesso per lasciare fuori)no—
x12_astestono—
dicomDICOMDestination (un blocco, omesso per lasciare fuori)no—
javascriptJavaScriptDestination (un blocco, omesso per lasciare fuori)no—
brokerBrokerDestination (un blocco, omesso per lasciare fuori)no—
kafkaKafkaDestination (un blocco, omesso per lasciare fuori)no—
sqsSQSDestination (un blocco, omesso per lasciare fuori)no—
snsSNSDestination (un blocco, omesso per lasciare fuori)no—
amqpAMQPDestination (un blocco, omesso per lasciare fuori)no—
azure_blobAzureBlobDestination (un blocco, omesso per lasciare fuori)no—
mqttMQTTDestination (un blocco, omesso per lasciare fuori)no—
ibm_mqIBMMQDestination (un blocco, omesso per lasciare fuori)no—
pubsubPubSubDestination (un blocco, omesso per lasciare fuori)no—
gcsGCSDestination (un blocco, omesso per lasciare fuori)no—
elrELRDestination (un blocco, omesso per lasciare fuori)no—
pgpPGPSend (un blocco, omesso per lasciare fuori)no—
response_transformertestono—
timeoutdurata, ad esempio 30s o 5mno—
retryRetryno—
queueQueueConfig (un blocco, omesso per lasciare fuori)no—

23.10.1 nome

Il nome identifica la destinazione nei log e nelle metriche.

Obbligatorio all'interno di un canale.

23.10.2 file_name

FileName, per una destinazione file, crea un file per ogni messaggio (${timestamp}, ${date}, ${control_id}, ${message_type}, ${destination}).

Vuoto mantiene il valore predefinito: un file per giorno e tipo di messaggio, aggiunto a.

23.10.3 temp_suffix

TempSuffix è il nome che un file per messaggio porta mentre viene scritto, rimosso da un rename una volta completato, in modo che qualunque cosa raccolga i file non legga mai metà di uno.

Predefinito su ".part".

23.10.4 retain_hours

RetainHours elimina i file in Dir più vecchi di questo.

Zero li mantiene per sempre.

23.10.5 x12_as

X12As è un xml per una destinazione su un canale X12 che riceve l'intercambio come l'XML Mirth Connect e Open Integration Engine scrivono per X12, per un ricevitore costruito contro ciò che Mirth gli ha inviato.

Vuoto o x12 invia X12.

23.10.6 elr

ELR rende questa destinazione un rapporto di laboratorio di salute pubblica: ogni risultato di laboratorio (ORU^R01) viene riorganizzato in un messaggio ELR 2.5.1 che contiene solo gli ordini con un risultato segnalabile e che è ciò che viene consegnato; un messaggio con nulla di segnalabile non viene inviato affatto.

Si applica alle destinazioni che consegnano un messaggio HL7 v2 come è (mllp, http, file, sftp e il resto), su un canale hl7.

23.10.7 response_transformer

ResponseTransformer ispeziona cosa ha detto il ricevitore e può contrassegnare la consegna come fallita.

Esiste perché "è arrivato questo" è spesso una domanda che il trasporto non può rispondere: un ricevitore MLLP restituisce un riconoscimento dell'applicazione il cui significato è nel testo e un ricevitore HTTP restituisce 200 con un documento di errore. In entrambi i casi il trasporto ha avuto successo e il messaggio non è arrivato.

Ha senso solo su una destinazione che riceve una risposta. Su una che non può, viene rifiutata al caricamento anziché lasciata mai in esecuzione.

23.10.8 queue

La coda rende la consegna durevole: un messaggio che non può essere consegnato ora viene mantenuto su disco e ritentato fino a quando non può essere consegnato.

Disabilitato per default.

23.11 Destinazione diretta

DirectDestination invia ogni messaggio come Direct: firmato con questo indirizzo, crittografato con il certificato di ogni destinatario e inviato al HISP tramite SMTP.

Definito come DirectDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
toelenco di testosì—
subjecttestono—
texttestono—
attach_nametestono—
xdmvero o falsono—
xdm_source_idtestono—
recipient_certs_dirtestono—
dnstestono—
ldaptestono—
smtp_hosttestosì—
usernametestono—
passwordtestono—
request_mdnvero o falsono—
timeoutdurata, ad esempio 30s o 5mno—

23.11.1 a

I destinatari sono gli indirizzi Direct.

Le referenze ai campi vengono sostituite, quindi un destinatario può provenire dal messaggio.

23.11.2 recipient_certs_dir

RecipientCertsDir contiene i certificati dei destinatari (PEM, un file per indirizzo o dominio, address.pem o domain.pem) trovati in anticipo; vuoto legge l'elenco degli indirizzi Direct del server (la schermata Direct).

I destinatari non presenti vengono cercati nel DNS (record CERT). Direct non invia a un destinatario il cui certificato non può essere trovato.

23.11.3 ldap

LDAP è il directory in cui viene cercato il certificato di un destinatario quando DNS non ne ha uno (host:porta, porta 389): il secondo modo in cui consente la guida alla scoperta diretta del certificato.

Vuoto trova il directory del dominio del destinatario tramite il suo record SRV DNS (_ldap._tcp), come dice la guida; "off" non chiede mai a un directory.

23.12 Destinazione del documento

DocumentDestination rende ogni messaggio in un documento.

Definito come DocumentDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
dirtestosì—
formatDocumentFormatnopdf
templatetestosì—
titletestono—
file_nametestono—
font_sizenumerono10
landscapevero o falsono—
temp_suffixtestono"
timeoutdurata, ad esempio 30s o 5mno30s

23.12.1 formato

Il formato è pdf o testo.

Predefinito su pdf.

23.12.2 template

Il modello è il corpo del documento, con riferimenti allo stile ${PID-5.1} ai percorsi del messaggio.

Obbligatorio. Non esiste un valore predefinito sensato: un documento senza modello sarebbe il messaggio grezzo, che nessuno vuole stampare, o vuoto.

23.12.3 dimensione del font

Dimensione del font in punti.

Predefinito su 10, che si adatta a 80 caratteri su A4.

23.12.4 temp_suffix

TempSuffix viene aggiunto durante la scrittura e rimosso da un rename.

Predefinito su ".part".

Stessa cortesia di ogni altra destinazione file, e qui conta di più: un watcher di stampa che raccoglie un PDF scritto a metà produce una pagina vuota, e nessuno indaga su una pagina vuota.

23.12.5 timeout

I limiti di timeout vincolano una scrittura.

Defaults to 30s.

23.13 Destinazione ECR

ECRDestination configura la segnalazione di casi elettronica.

Definito come ECRDestination in internal/config.

ChiaveTipoRichiestoPredefinito
rctctestono—
sourcetestosì—
facilityECRFacilitysì—

23.13.1 rctc

RCTC è un FHIR ValueSet, o un Bundle di essi come l'eRSD, che contiene i codici di attivazione.

Senza di esso, Perfuse utilizza il suo breve esempio integrato, che è per test: le agenzie si aspettano RCTC.

23.14 Destinazione ELR

ELRDestination configura la segnalazione di laboratorio elettronica.

Definito come ELRDestination in internal/config.

ChiaveTipoRichiestoPredefinito
configtestosì—
rctctestono—

23.14.1 config

La configurazione è il file ELR perfuse elr -config che legge: le applicazioni e le strutture di invio e ricezione per OID, la modalità di elaborazione e cosa riempie le lacune che un feed di laboratorio lascia (struttura di ordinazione, laboratorio eseguente, autorità di assegnazione).

Un percorso relativo viene letto dalla directory del file del canale.

23.14.2 rctc

RCTC è un FHIR ValueSet, o un Bundle di essi come l'eRSD, che contiene i codici di attivazione.

Senza di esso, Perfuse utilizza il suo breve esempio integrato, che è per test: le agenzie si aspettano RCTC. Relativo al file del canale, come Config.

23.15 Destinazione FHIR

FHIRDestination configura la conversione in FHIR e la consegna a un server FHIR.

Definito come FHIRDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
urltestosì—
versiontestonoR5
timezonetestono—
default_identifier_systemtestono—
identifier_systemsmappatura di testo su testono—
claim_us_corevero o falsono—
validate_before_sendvero o falso (un blocco, omesso per lasciare fuori)novero: l'invio di una risorsa a un server che la rifiuterà spreca un budget di ritentativi e nasconde il problema reale dietro un errore di trasporto
reject_on_warningvero o falsono—
headersmappatura di testo su testono—
bearer_tokentestono—
authFHIRAuth (un blocco, omesso per lasciare fuori)no—
ecrECRDestination (un blocco, omesso per lasciare fuori)no—
bundle_scripttestono—

23.15.1 url

L'URL è l'URL di base del server FHIR, ad esempio "https://fhir.example.org/fhir".

Il bundle viene inviato direttamente ad esso.

23.15.2 versione

La versione è la versione FHIR da produrre: R4, R4B o R5. Predefinita su R5, l'ultima versione pubblicata.

Un deployment che comunica con un EHR vuole quasi sempre R4 e dovrebbe dirlo, perché il declassamento silenzioso nasconderebbe una decisione di interoperabilità reale.

23.15.3 fuso orario

Il fuso orario viene applicato ai timestamp HL7 v2 che non hanno un offset. La versione 2 consente un tempo locale senza offset, mentre FHIR no, quindi qualcosa deve fornirlo.

Quando non è impostato, viene utilizzato l'offset inserito dal mittente su MSH-7, poiché la versione 2 presume che un tempo senza offset sia l'orario locale del mittente; un messaggio il cui MSH-7 non ha offset ricorre all'UTC.

23.15.4 sistema_di_identificazione_predefinito

DefaultIdentifierSystem fornisce namespace per gli identificatori il cui autorità di assegnazione non ha un URI configurato.

Senza un sistema, un MRN è ambiguo tra le strutture.

23.15.5 richiesta_us_core

ClaimUSCore aggiunge il profilo US Core 9.0.0 a ogni risorsa prodotta che è stata verificata e rispetta il profilo.

Una risorsa che non soddisfa i requisiti viene inviata senza la richiesta, con una nota che spiega il motivo.

23.15.6 convalida_prima_dell_invio

ValidateBeforeSend rifiuta di inviare un bundle che non supera la convalida.

Il valore predefinito è true: l'invio di una risorsa che un server rifiuterà spreca il budget di ritentativi e nasconde il problema reale dietro un errore di trasporto.

23.15.7 rifiuta_in_caso_di_avvertimento

RejectOnWarning rifiuta anche in caso di avvertimenti, come ad esempio un identificatore US Core mancante.

Disabilitato per default, poiché un avvertimento è un giudizio sulla conformità del profilo piuttosto che sulla validità.

23.15.8 bearer_token

BearerToken viene inviato come intestazione di autorizzazione.

Preferire un riferimento a una variabile d'ambiente, ${NAME}, rispetto a un valore letterale in un file che viene inserito in git.

23.15.9 ecr

ECR rende questo un destinatario di segnalazione dei casi di salute pubblica.

Ogni messaggio viene verificato per i codici di attivazione; un messaggio che ne ha alcuni viene inviato come un eCR 2.1 eICR, avvolto in un messaggio eCR, all'URL $process-message, e un messaggio senza codici di attivazione non viene inviato.

23.15.10 script del bundle

Lo script del bundle è JavaScript eseguito su ogni Bundle convertito prima della sua convalida e invio: bundle è il Bundle come oggetto, modificato sul posto.

È il modo in cui un sito aggiunge ciò che i propri sistemi conoscono e il messaggio v2 non dice - il codice IKNR o ODS dell'organizzazione, un livello di profilo nazionale - senza che il convertitore lo indovini. Uno script che genera un'eccezione fallisce il messaggio, come qualsiasi altro trasformatore. Non viene eseguito per i report di casi (ecr).

23.16 Destinazione FTP

FTPDestination carica un file per ogni messaggio.

Definito come FTPDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
hosttestosì21
usertestono—
passwordtestono—
securityFTPSecuritynoimplicito anziché none
insecure_skip_verifytrue o falseno—
allow_clear_passwordtrue o falseno—
dirtestosì—
file_nametestono—
temp_suffixtestono"
framedtrue o falseno—
timeoutdurata, ad esempio 30s o 5mno60s

23.16.1 host

L'host è il server, con una porta opzionale.

Il valore predefinito è 21, o 990 per il TLS implicito.

23.16.2 utente

Utente e Password autenticano.

Un utente vuoto significa anonimo.

23.16.3 password

Utente e Password autenticano.

Un utente vuoto significa anonimo.

23.16.4 sicurezza

La sicurezza seleziona TLS: esplicito, implicito o nessuno.

Di default è impostato su esplicito anziché nessuno, perché impostare la default su FTP piano renderebbe la scelta insicura la più silenziosa, e un sito che genuinamente non ha TLS dovrebbe essere costretto a scrivere che non utilizza la crittografia.

23.16.5 insecure_skip_verify

InsecureSkipVerify accetta qualsiasi certificato.

Necessario più spesso di quanto si vorrebbe: questi server hanno spesso un certificato auto-firmato generato anni fa che nessuno può rilasciare nuovamente. È stato nominato separatamente in modo che la scelta di utilizzarlo sia deliberata e visibile nel file piuttosto che nascosta all'interno di una modalità di "sicurezza: rilassata".

23.16.6 allow_clear_password

AllowClearPassword consente di utilizzare una password su FTP piano.

Rifiutato di default, perché invia una credenziale attraverso la rete in testo chiaro ad ogni singola consegna. Alcuni analizzatori non hanno genuinamente TLS, quindi deve essere possibile - ma deve essere scritto, in modo che sia una decisione presa da qualcuno piuttosto che una default ereditata. Il nome è stato scelto deliberatamente per essere scomodo da digitare.

23.16.7 temp_suffix

TempSuffix viene aggiunto mentre il file viene scritto e rimosso tramite un rename una volta completato.

Predefinito su ".part".

Chiunque raccolga questi file è solitamente un lavoro pianificato che prende tutto ciò che trova, e senza il rename alla fine prende metà di un messaggio.

23.16.8 timeout

Il timeout limita una trasferimento.

Defaults to 60s.

23.17 Destinazione GCS

GCSDestination scrive ogni messaggio come un oggetto.

Definito come GCSDestination in internal/config.

ChiaveTipoRichiestoDefault
objecttestono${data}/${canale}/${control_id}
storage_classtestono—
content_typetestono—

23.17.1 object

L'oggetto è il nome dell'oggetto, con gli stessi placeholder di una chiave S3.

Predefinito su ${data}/${canale}/${id_controllo}.hl7.

23.18 Destinazione HTTP

HTTPDestination invia messaggi a un endpoint HTTP.

La cosa più comune che un canale Mirth fa che Perfuse non poteva fare, e il più comune blocco che il traduttore segnala. La maggior parte degli utilizzi sono poco glamour: inviare il messaggio a un'API interna, inviarlo a un servizio web che avvolge un sistema legacy, inviarlo a qualcosa che qualcuno ha scritto in un pomeriggio.

Definito come HTTPDestination in internal/config.

ChiaveTipoRichiestoDefault
urltestosì—
methodtestono—
content_typetestono—
headersmappatura di testo su testono—
bearer_tokentestono—
usernametestono—
passwordtestono—
tlstlsconf.Settings (un blocco, omesso per lasciare fuori)no—
success_statuselenco di numero interonoqualsiasi 2xx
fail_on_bodyelenco di testono—
follow_redirectsvero o falsono—

23.18.1 url

L'URL è dove inviare.

Required.

23.18.2 method

Il metodo di default è POST.

PUT è consentito per un endpoint che lo richiede.

GET e DELETE sono rifiutati: questo invia un corpo del messaggio e un trasporto che silenziosamente scarta il messaggio a causa di una scelta di metodo sarebbe un modo molto silenzioso per perdere dati.

23.18.3 content_type

ContentType predefinito è application/hl7-v2+er7, che è il tipo registrato per un messaggio HL7 v2 delimitato da pipe.

Molti endpoint preferiscono text/plain.

23.18.4 bearer_token

BearerToken viene inviato come intestazione di autorizzazione.

Preferire un riferimento a una variabile d'ambiente rispetto a un valore letterale in un file che viene inserito in git.

23.18.5 stato_di_successo

SuccessStatus elenca i codici di stato che contano come consegnati.

Predefinito su qualsiasi codice 2xx.

Configurabile perché gli endpoint non concordano su cosa significhi successo: alcuni rispondono 200 con un errore nel corpo e alcuni rispondono 202 per una coda che hanno accettato il messaggio.

23.18.6 fallire_su_corpo

FailOnBody tratta una risposta contenente alcuna di queste stringhe come un fallimento, indipendentemente dal codice di stato.

Ciò esiste perché un endpoint che risponde 200 con "ERROR: paziente non trovato" nel corpo è comune e trattarlo come consegnato significa che il messaggio è perso e nessuno lo sa.

23.18.7 seguire_reindirizzamenti

FollowRedirects consente alla richiesta di essere reindirizzata.

Disattivato per impostazione predefinita: un reindirizzamento su una scrittura ripubblicherebbe i dati clinici in un luogo che la configurazione non ha mai nominato.

23.19 Destinazione IBMMQ

IBMMQDestination mette ogni messaggio in una coda.

Definito come IBMMQDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
non_persistenttrue o falseno—

23.19.1 non_persistente

NonPersistent invia messaggi che non sopravvivono a un riavvio del gestore della coda.

Disabilitato per default.

23.20 Destinazione Java Script

JavaScriptDestination esegue uno script invece di inviare da qualche parte.

Mirth's JavaScript Writer, e viene utilizzato molto più di quanto suggerisca la sua posizione in un elenco di funzionalità. È il modo per uscire: quando un sito deve comunicare con qualcosa che non è coperto da un connettore o applicare una logica che non esprime una trasformazione, scrivono uno script JavaScript Writer. Una migrazione che non può eseguire questi script non può spostare i canali che li utilizzano, il che in un'installazione Mirth maturo è una grande frazione.

Volontariamente non un host di scripting generico. Lo script ottiene il messaggio e gli stessi aiutanti che ottiene un trasformatore; ciò che non ottiene è un modo per raggiungere il file system o la rete, perché questo è ciò per cui sono previsti gli altri destinatari e uno script che apre la sua propia socket è invisibile a ogni retry, coda e metrica nel motore.

Definito come JavaScriptDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
scripttestosì—
timeoutdurata, ad esempio 30s o 5mno—
success_on_undefinedtrue o false (un blocco, omesso per lasciare fuori)notrue

23.20.1 script

Lo script è il codice da eseguire.

Required.

23.20.2 timeout

Il timeout delimita un'esecuzione.

Zero applica un valore predefinito.

È delimitato perché uno script di destinazione è sul percorso di consegna: un ciclo infinito in uno non fa solo fallire un messaggio, ma tiene anche la coda dietro di esso.

23.20.3 success_on_undefined

SuccessOnUndefined tratta uno script che non restituisce nulla come un successo.

Il valore predefinito è true.

True è il valore predefinito giusto e vale la pena spiegarlo. Gli script JavaScript di Mirth fanno prevalentemente il loro lavoro e non restituiscono nulla, quindi richiedere un ritorno esplicito li romperebbe tutti all'importazione. Impostare false è per un sito che desidera che uno script sia esplicito su se ha funzionato.

23.21 Destinazione Kafka

KafkaDestination pubblica messaggi su un argomento Kafka.

Definito come KafkaDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
brokerselenco di testosì—
topictestosì—
keytestono—
ackstestonoall
compressiontestonosnappy
headersmappatura di testo su testono—
timeoutdurata, ad esempio 30s o 5mnotrenta secondi
saslKafkaSASL (un blocco, omesso per lasciare fuori)no—
tlstlsconf.Settings (un blocco, omesso per lasciare fuori)no—

23.21.1 broker

I broker sono l'elenco dei server di avvio.

Required.

23.21.2 argomento

L'argomento è dove pubblicare.

Required.

23.21.3 chiave

La chiave è un modello per la chiave del record, che decide la partizione.

Questo è il campo che rende Kafka sicuro per un flusso clinico, e vale la pena essere precisi sul perché. Kafka garantisce l'ordine all'interno di una partizione e da nessun'altra parte. I record con la stessa chiave finiscono sempre nella stessa partizione, quindi la chiave sul l'identificatore del paziente mantiene gli eventi di quel paziente in ordine mentre lascia che i pazienti diversi vadano in parallelo.

Senza una chiave non c'è alcuna garanzia. Misurato contro un broker reale, trenta record non chiave sono andati a una partizione invece di diffondersi: il client mantiene un batch insieme e sceglie una nuova partizione tra i batch. Quindi l'ordinamento si mantiene per caso e si rompe in un confine che nessuno può vedere, il che è peggio che rompersi costantemente - un A03 di dimissioni letto prima del suo A01 di ammissione, intermittente, sotto carico.

Un percorso HL7, valutato contro il messaggio in uscita: PID-3.1 chiave per paziente.

23.21.4 acks

Acks è il numero di broker che devono confermare una scrittura: "all", "leader" o "none".

Predefinito su all, che è l'unico parametro che sopravvive a un broker che fallisce tra la scrittura e la replica. "none" è fire-and-forget e perderà messaggi; esiste perché qualcuno che sposta telemetria non clinica potrebbe legittimamente volerlo, e rifiutarlo direttamente significherebbe che hanno scritto il loro produttore invece.

23.21.5 compressione

La compressione è "nessuna", "gzip", "snappy", "lz4" o "zstd".

Predefinito su snappy.

Attivato per impostazione predefinita perché HL7 è testo altamente compressibile e il filo è di solito il vincolo. Snappy invece di zstd come predefinito: è il più economico in CPU, e un connettore sul percorso di consegna non dovrebbe essere la cosa che satura un nucleo.

23.21.6 header

Le intestazioni sono intestazioni di record da impostare.

I valori sono modelli valutati per ogni messaggio.

23.21.7 timeout

Il timeout limita una pubblicazione.

Di default è trenta secondi.

23.22 Destinazione MPI

MPIDestination registra ogni messaggio del paziente in questo indice dei pazienti del server: un PID HL7 v2 (un merge A40 unisce), o un paziente FHIR su un canale grezzo.

L'indice decide quali record sono la stessa persona; vedere lo schermo dell'indice dei pazienti.

Definito come MPIDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
authoritiesmappatura di testo su testono—
id_typetestono—
ssn_systemtestono—
no_mergevero o falsono—

23.22.1 autorità

Le autorità mappano uno spazio dei nomi dell'autorità di assegnazione (PID-3.4.1) al suo sistema di identificatori, per i mittenti che non forniscono un identificatore universale.

Quelli non mappati diventano urn:perfuse:aa:<namespace>.

23.22.2 id_type

IDType è il tipo di identificatore (PID-3.5) del numero del record.

Default MR.

23.22.3 ssn_system

SSNSystem nomina PID-19 come identificatore.

Default http://hl7.org/fhir/sid/us-ssn.

23.23 Destinazione MQTT

MQTTDestination pubblica su un argomento.

Definito come MQTTDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
topictestosì—
retainvero o falsono—

23.23.1 argomento

Argomento pubblicato.

Non può contenere wildcard.

23.24 Destinazione PAS

PASDestination invia ogni messaggio, un bundle di richiesta Da Vinci PAS, al Claim/$submit di un pagatore, per un fornitore il cui sistema costruisce la richiesta (un EHR, DTR) e ha bisogno che venga inviata, la decisione registrata e la risposta passata.

Definito come PASDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
payertestosì—
bearer_tokentestono—
authFHIRAuth (un blocco, omesso per lasciare fuori)no—
results_totestono—

23.24.1 bearer_token

BearerToken è un token statico, ${ENV} consentito.

Auth è OAuth client credentials invece, o Azure, come una destinazione FHIR.

23.24.2 auth

BearerToken è un token statico, ${ENV} consentito.

Auth è OAuth client credentials invece, o Azure, come una destinazione FHIR.

23.25 Destinazione Pub Sub

PubSubDestination pubblica su un argomento Pub/Sub.

Definito come PubSubDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
topictestosì—
order_bytestono—

23.26 Destinazione S3

S3Destination scrive ogni messaggio come un oggetto.

Definito come S3Destination in internal/config.

ChiaveTipoObbligatorioPredefinito
buckettestosì—
regiontestosì—
keytestonoun percorso partizionato per data più l'ID di controllo
access_key_idtestono—
secret_access_keytestono—
session_tokentestono—
endpointtestono—
path_stylevero o falsono—
server_side_encryptiontestono—
content_typetestonoapplication/hl7-v2 per HL7 e testo/piano otherwise
framedvero o falsono—
timeoutdurata, ad esempio 30s o 5mno60s
storage_classtestono—
formattestono—

23.26.1 chiave

La chiave modella la chiave dell'oggetto, utilizzando gli stessi segnaposto ${date}, ${timestamp}, ${control_id}, ${message_type} e ${channel} delle destinazioni file e SFTP.

Predefinito su un percorso partizionato per data più l'ID di controllo.

La partizione per data per impostazione predefinita perché l'alternativa - ogni oggetto in un unico prefisso piatto - rende il bucket lento da elencare e impossibile da gestire per età, e nessuno scopre questo fino a quando non ci sono quattro milioni di oggetti al suo interno.

23.26.2 access_key_id

AccessKeyID e SecretAccessKey autenticano.

Uno di essi può anche essere il nome di una variabile di ambiente invece di contenere il valore, utilizzando la forma ${NAME}.

23.26.3 secret_access_key

AccessKeyID e SecretAccessKey autenticano.

Uno di essi può anche essere il nome di una variabile di ambiente invece di contenere il valore, utilizzando la forma ${NAME}.

23.26.4 path_style

PathStyle indirizza il bucket come un percorso anziché come un sottodominio.

La maggior parte degli archivi compatibili con S3 necessita di questo.

23.26.5 content_type

ContentType etichetta l'oggetto.

Predefinito su application/hl7-v2 per HL7 e testo/piano altrimenti.

23.26.6 timeout

Timeout delimita un upload.

Defaults to 60s.

23.26.7 storage_class

StorageClass è la classe di archiviazione S3 con cui ogni oggetto viene scritto: STANDARD_IA, INTELLIGENT_TIERING, GLACIER_IR, GLACIER, DEEP_ARCHIVE e così via.

Questo è il modo in cui un archivio va direttamente su Glacier - S3 non ha un'API separata per Glacier da chiamare.

23.26.8 formato

Il formato è hl7 (predefinito: ogni oggetto è il messaggio) o ndjson: ogni oggetto è una riga JSON con il messaggio e i campi degni di query, sotto chiavi partizionate per data, in modo che Amazon Athena possa interrogare l'archivio.

Vedere perfuse athena.

23.27 Destinazione SFTP

SFTPDestination scrive ogni messaggio in un file su un server SFTP.

Definito come SFTPDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
hosttestosì22
usertestosì—
passwordtestono—
key_filetestono—
key_passphrasetestono—
known_hosts_filetestono—
insecure_skip_host_key_checkvero o falsono—
dirtestosì—
file_nametestonoun timestamp più l'ID di controllo
temp_suffixtestono"
framedvero o falsono—
appendvero o falsono—
timeoutdurata, ad esempio 30s o 5mno60s

23.27.1 host

L'host è il server, con una porta opzionale.

Defaults to 22.

23.27.2 password

Password autentica con una password.

Prefer KeyFile.

23.27.3 file_name

FileName formatta il nome.

Predefinito per un timestamp più l'ID di controllo.

23.27.4 temp_suffix

TempSuffix viene aggiunto mentre un file viene scritto e rimosso tramite un rename una volta completato.

Predefinito su ".part".

La stessa cortesia di cui questo connettore ha bisogno lungo la strada. Chiunque raccoglie questi file ha lo stesso problema e un rename all'interno di una directory è atomico su ogni server degno di essere utilizzato.

23.27.5 timeout

Il timeout delimita una singola connessione.

Defaults to 60s.

23.28 Destinazione SMTP

SMTPDestination configura la consegna tramite posta elettronica.

Definito come SMTPDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
hosttestosì—
fromtestosì—
toelenco di testosì—
ccelenco di testono—
bccelenco di testono—
subjecttestono—
bodytestono—
attachvero o falsono—
attach_nametestonol'ID di controllo con un
usernametestono—
passwordtestono—
starttlsvero o falso (un blocco, omesso per lasciare fuori)no—
insecure_skip_verifyvero o falsono—
timeoutdurata, ad esempio 30s o 5mno—

23.28.1 host

Host è il server di posta, con una porta opzionale.

Si presume la porta 587, che è la porta di invio con STARTTLS - la porta che un server moderno si aspetta da un client. La porta 25 è server-to-server e di solito è bloccata o non autenticata.

23.28.2 da

Da è il mittente dell'intestazione.

Obbligatorio, perché un messaggio senza mittente viene scartato silenziosamente da una grande quantità di infrastrutture di posta, il che lo rende il più difficile possibile da diagnosticare.

23.28.3 a

A, CC e BCC sono i destinatari.

Almeno un A è obbligatorio.

23.28.4 cc

A, CC e BCC sono i destinatari.

Almeno un A è obbligatorio.

23.28.5 bcc

A, CC e BCC sono i destinatari.

Almeno un A è obbligatorio.

23.28.6 corpo

Corpo è il testo del messaggio.

I riferimenti ai campi vengono sostituiti, come in Oggetto. Quando è vuoto, il messaggio stesso è il corpo.

23.28.7 nome_allegato

AttachName nomina l'allegato.

Predefinito per l'ID di controllo con un suffisso .hl7.

23.28.8 username

Nome utente e Password autenticano il server.

Entrambi o nessuno.

23.28.9 password

Nome utente e Password autenticano il server.

Entrambi o nessuno.

23.28.10 starttls

StartTLS migliora la connessione prima dell'autenticazione.

È abilitato per default e disabilitarlo con un nome utente impostato viene rifiutato anziché consentito: inviare una password su una connessione non crittografata non è un compromesso accettabile.

23.28.11 insecure_skip_verify

InsecureSkipVerify accetta qualsiasi certificato.

Denominato in modo univoco perché è ciò che fa.

23.29 Destinazione SNS

SNSDestination pubblica ogni messaggio su un argomento SNS.

Definito come SNSDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
topic_arntestosì—
subjecttestono—
group_bytestono—

23.29.1 oggetto

L'oggetto viene inviato con le iscrizioni via e-mail.

Opzionale; ${message_type} e ${control_id} vengono compilati.

23.30 Destinazione SOAP

SOAPDestination invia una richiesta SOAP per ogni messaggio.

Definito come SOAPDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
urltestosì—
profiletestono—
facility_idtestono—
warnings_are_errorstrue o falseno—
actiontestono—
versiontestono1
bodytestosì—
headertestono—
headersmappatura di testo su testono—
usernametestono—
passwordtestono—
tlstlsconf.Settings (un blocco, omesso per non utilizzarlo)no—
fault_is_successelenco di testono—
timeoutdurata, ad esempio 30s o 5mno30s

23.30.1 profilo

Il nome del profilo indica un servizio standard la cui busta Perfuse costruisce da sé.

Vuoto è una semplice chiamata SOAP con il corpo scritto in questo file.

"cdc-iis" è l'interfaccia del registro di immunizzazione dei CDC (urn:cdc:iisb:2011), utilizzato da ogni registro statale degli Stati Uniti: il messaggio va in submitSingleMessage, il nome utente e la password vanno nel corpo come dice il WSDL (non come autenticazione HTTP), SOAP 1.2 per default e l'acknowledgement HL7 del registro decide se il messaggio è stato consegnato. Un registro risponde a un rifiuto con HTTP 200 e un AR all'interno, quindi senza questo un rifiuto viene letto come un successo.

23.30.2 facility_id

FacilityID è l'ID della struttura cdc-iis, l'identificatore del registro per l'organizzazione che invia.

Opzionale nel WSDL; alcuni registri lo richiedono.

23.30.3 warnings_are_errors

WarningsAreErrors, per cdc-iis, tratta un acknowledgement AE che contiene solo avvisi come un errore.

Disabilitato per default: i registri inviano AE per "accettato con avvisi" e la gravità ERR indica se qualcosa è stato perso.

23.30.4 azione

L'azione è il SOAPAction.

Richiesto dalla maggior parte dei servizi 1.1.

23.30.5 corpo

Il corpo è l'XML che va all'interno dell'involucro, con riferimenti allo stile ${PID-5.1} ai percorsi dei messaggi.

Obbligatorio, a meno che un profilo non lo costruisca. Non c'è un valore predefinito utile: i nomi degli elementi provengono dallo schema del servizio stesso e nessun motore può indovinarli.

23.30.6 intestazione

L'intestazione è l'XML per l'elemento Intestazione dell'involucro.

Omesso interamente quando è vuoto, perché alcuni servizi rifiutano un'intestazione vuota.

23.30.7 fault_is_success

FaultIsSuccess elenca i codici di errore che vengono considerati consegnati.

Necessario più spesso di quanto dovrebbe essere. Un servizio che risponde a una richiesta di rinviare con "già inviato" sta dicendo che il messaggio è arrivato e senza questo un sito deve scrivere un trasformatore di risposta per dirlo - o peggio, guarda una coda che si ripete all'infinito contro un destinatario che ha già il messaggio.

23.30.8 timeout

Il timeout delimita una chiamata.

Defaults to 30s.

23.31 Destinazione SQS

La destinazione SQS invia ogni messaggio a una coda SQS.

Definito come SQSDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
queue_urltestosì—
group_bytestono—

23.31.1 queue_url

QueueURL nomina la coda.

Una coda che termina con .fifo è una coda FIFO e viene raggruppata e deduplicata.

23.32 Destinazione TCP

TCPDest invia i messaggi a un socket con framing configurabile.

Definito come TCPDest in internal/config.

ChiaveTipoObbligatorioPredefinito
addresstestosì—
max_message_sizenumero interono—
timeoutdurata, ad esempio 30s o 5mno—
expect_replyvero o falsono—
keep_alivevero o falsono—
tlstlsconf.Settings (un blocco, omesso per lasciarlo fuori)no—

23.32.1 expect_reply

ExpectReply attende byte di ritorno prima di segnalare il successo.

Disabilitato per impostazione predefinita e vale la pena considerarlo. Con esso disabilitato, "consegnato" significa che i byte hanno raggiunto il buffer di invio del sistema operativo, che un peer che si è verificato un attimo dopo non ha mai letto. Con esso abilitato, un peer che non risponde fa scadere ogni messaggio.

23.32.2 keep_alive

KeepAlive mantiene una connessione aperta tra i messaggi invece di stabilire una connessione per ogni messaggio.

La maggior parte degli endpoint dei dispositivi si aspetta questo; alcuni rifiutano un secondo messaggio sulla stessa connessione. Disabilitato per impostazione predefinita perché una connessione per messaggio è il comportamento che funziona ovunque, al costo di una stretta di mano ogni volta.

23.33 Destinazione TEFCA

TEFCADestination chiede al partner FHIR facilitato da TEFCA i record di ogni paziente del messaggio.

Chi è questo server nella rete, il suo certificato e il partner sono impostazioni del server (Impostazioni, TEFCA), poiché appartengono all'organizzazione e al suo accordo con un QHIN. Ciò che un canale decide è quando chiedere e perché: lo scopo di utilizzo fa parte del canale, non di chi è connesso, quindi ogni query che un feed esegue dichiara lo stesso motivo e la traccia di audit può essere letta contro di essa.

Definito come TEFCADestination in internal/config.

ChiaveTipoObbligatorioPredefinito
purposetestosì—
results_totestono—

23.33.1 scopo

Lo scopo è lo scopo di utilizzo: trattamento, pagamento, operazioni, salute_pubblica o accesso_individuale.

Deve essere uno di quelli dichiarati dal partecipante.

23.33.2 results_to

ResultsTo nomina un canale in questo server che riceve ogni Bundle che il partner restituisce, come un messaggio proprio.

Vuoto mantiene il Bundle come risposta di questa destinazione solo, per un trasformatore di risposta da leggere.

23.34 Destinazione XDS

XDSDestination pubblica ogni documento clinico in un repository di documenti XDS.b IHE con ITI-41 Fornire e registrare.

I metadati vengono letti dal documento CDA (paziente, titolo, tipo, tempo, autore, riservatezza, lingua) e completati da queste impostazioni, che dicono cosa il documento non può: chi lo sta inviando, che tipo di struttura e pratica è provenuto e quale degli identificatori del paziente è il dominio di affinità.

Definito come XDSDestination in internal/config.

ChiaveTipoObbligatorioPredefinito
urltestosì—
source_idtestosì—
patient_domaintestono—
facility_typeXDSCodesì—
practice_settingXDSCodesì—
classXDSCode (un blocco, omesso per non utilizzarlo)no—
content_typeXDSCode (un blocco, omesso per non utilizzarlo)no—
tokentestono—
usernametestono—
passwordtestono—
headersmappatura di testo su testono—
tlstlsconf.Settings (un blocco, omesso per non utilizzarlo)no—
timeoutdurata, ad esempio 30s o 5mno—
direct_fromtestono—
direct_toelenco di testono—

23.34.1 patient_domain

PatientDomain è l'autorità OID assegnata dal dominio di affinità: l'identificatore del paziente con questa radice è quello registrato.

Senza di esso un documento il cui paziente ha un identificatore invia quell'identificatore e uno con più identificatori viene rifiutato.

23.34.2 token

Token o Username/Password autenticano; Headers vengono aggiunti a ogni richiesta.

La maggior parte dei domini di affinità utilizza il TLS reciproco (tls) invece.

23.34.3 username

Token o Username/Password autenticano; Headers vengono aggiunti a ogni richiesta.

La maggior parte dei domini di affinità utilizza il TLS reciproco (tls) invece.

23.34.4 password

Token o Username/Password autenticano; Headers vengono aggiunti a ogni richiesta.

La maggior parte dei domini di affinità utilizza il TLS reciproco (tls) invece.

23.34.5 header

Token o Username/Password autenticano; Headers vengono aggiunti a ogni richiesta.

La maggior parte dei domini di affinità utilizza il TLS reciproco (tls) invece.

23.34.6 tls

Token o Username/Password autenticano; Headers vengono aggiunti a ogni richiesta.

La maggior parte dei domini di affinità utilizza il TLS reciproco (tls) invece.

23.34.7 direct_from

DirectFrom e DirectTo rendono la presentazione XDR come trasporto Direct: un blocco di indirizzamento Direct che nomina l'indirizzo Direct di questo mittente e quello dei destinatari, e i destinatari nel campo intendedRecipient della presentazione.

Un HISP che prende XDR lo consegna come posta Direct, o all'endpoint XDR del destinatario.

23.34.8 direct_to

DirectFrom e DirectTo rendono la presentazione XDR come trasporto Direct: un blocco di indirizzamento Direct che nomina l'indirizzo Direct di questo mittente e quello dei destinatari, e i destinatari nel campo intendedRecipient della presentazione.

Un HISP che prende XDR lo consegna come posta Direct, o all'endpoint XDR del destinatario.

24 Riferimento al formato

Opzioni che governano come vengono analizzati e scritti i messaggi, per i formati che richiedono più di un nome.

24.1 Allegati

Allegati configura lo spostamento di grandi payload fuori da un messaggio.

Un messaggio che trasporta un report scansionato o un PDF è ordinario nei flussi di lavoro dei documenti e il payload è routine centinaia di volte più grande del messaggio che lo circonda. Lasciato in linea significa che l'archiviazione cresce al ritmo dei documenti invece del traffico, un messaggio in coda per cinque destinazioni viene copiato cinque volte e l'interfaccia trasmette megabyte per mostrare a qualcuno il nome di un paziente.

Mirth chiama questi gestori di allegati. Questo è l'equivalente e si tratta di un'opzione facoltativa per canale perché un feed di messaggi ADT semplici non ha nulla da estrarre e non dovrebbe pagare per la macchina.

Definito come Attachments in internal/config.

ChiaveTipoObbligatorioPredefinito
extractelenco di attach.Rulesì—
reassemblevero o falso (un blocco, omesso per lasciare fuori)novero

24.1.1 reassemble

Reassemble riporta i payload prima della consegna.

Il valore predefinito è true.

Il valore predefinito è attivato perché un ricevitore che si aspetta un documento deve ricevere un documento; un messaggio che contiene un token letterale verrebbe archiviato come un report e nessuno lo scoprirebbe fino a quando qualcuno non aprisse il record.

Disattivarlo è utile nel caso in cui lo scopo del canale sia quello di rimuovere i documenti - inoltrare i metadati a un sistema che non ha bisogno dell'immagine, dove inviarla sarebbe una questione di privacy piuttosto che di larghezza di banda.

24.2 Delimitato

Delimitato configura un canale delimitato.

Il tipo di dati Delimited di Mirth: CSV, separati da tab, e la lunga coda di formati emessi da un analizzatore di laboratorio o da un servizio di bureau.

Definito come Delimited in internal/config.

ChiaveTipoObbligatorioPredefinito
delimitertestono—
quotetestonovirgolette doppie
commenttestono—
has_headervero o falsono—
columnselenco di testono—
trim_spacevero o falsono—
relaxedvero o falsono—
splitvero o falso (un blocco, omesso per lasciare fuori)novero
keep_blank_linesvero o falsono—
filtertestono—
transformationselenco di passaggi.Stepno—

24.2.1 delimitatore

Il delimitatore separa le colonne, come un carattere o un nome.

Un nome è accettato perché un tab non può essere scritto in un file YAML in modo univoco e un file di configurazione che contiene un carattere invisibile è illeggibile per chi lo apre successivamente.

24.2.2 virgolette

La virgolette racchiude i valori che contengono il delimitatore.

Predefinito su virgolette doppie; "nessuno" lo disabilita.

24.2.3 dividi

La divisione rende ogni riga un messaggio a sé stante.

Il valore predefinito è true.

Questa è la decisione che dà forma a un canale delimitato e merita di essere detta ad alta voce. Un file di cinquemila risultati è o un messaggio o cinquemila. Un messaggio significa un'unica conferma, un'unica voce nel browser e un'unica fallita che coinvolge l'intero file. Cinquemila significa che ogni riga è filtrata, trasformata, consegnata e ritentata singolarmente e una singola riga cattiva non blocca le altre.

La divisione è predefinita perché l'elaborazione riga per riga è ciò che quasi ogni sito desidera e perché l'alternativa è scoperta tardi: un canale che sembrava funzionare correttamente durante i test con un file di tre righe fallisce l'intera notte di trasferimento a causa di una sola riga malformata.

24.2.4 conserva_righeVuote

ConservaRigheVuote impedisce che le righe vuote vengano saltate.

Il salto è predefinito, perché ogni file termina con un newline e un record di campi vuoti non è un record. Questo esiste per il raro formato in cui una riga vuota è significativa.

24.2.5 filtro

Il filtro decide quali messaggi continuano, scritto contro i nomi delle colonne.

Qui piuttosto che sul canale perché il filtro a livello di canale compila i percorsi HL7. Due impostazioni denominate filtro sarebbero confuse, ma un'impostazione che significa cose diverse a seconda del tipo di dati è peggiore: un canale delimitato che compila silenziosamente il filtro come HL7 non corrisponderebbe a nulla e scarterebbe tutto, che è il fallimento che il rifiuto a livello superiore esiste per prevenire.

24.2.6 trasformazioni

Le trasformazioni sono i passaggi dichiarativi, che si rivolgono alle colonne piuttosto che ai campi HL7.

Separate dalle trasformazioni del canale per lo stesso motivo del filtro, ed è l'organizzazione che X12 e NCPDP già utilizzano.

24.3 Opzioni HL7v3

Le opzioni HL7v3 sono le impostazioni che si applicano solo a un canale HL7 v3.

Definito come HL7v3Options in internal/config.

ChiaveTipoObbligatorioPredefinito
filtertestono—
acknowledgevero o falso (un blocco, omesso per lasciare fuori)no—
sender_devicetestono—
sender_oidtestono—
transformationselenco di passaggi hl7v3.Stepno—

24.3.1 filtro

Il filtro esclude i messaggi utilizzando percorsi v3.

Utilizza un campo proprio anziché il filtro ordinario del canale, poiché si tratta di due linguaggi diversi contro modelli di messaggio diversi. Condividere il campo significherebbe che un filtro v2 non corrisponderebbe mai silenziosamente su un canale v3, o che un filtro v3 non riuscirebbe a essere analizzato come v2 - e la seconda opzione è migliore solo perché fallisce in modo rumoroso.

Un canale che imposta entrambi viene rifiutato durante il caricamento, poiché uno di essi dovrebbe essere ignorato e non c'è un modo onesto per scegliere.

24.3.2 conferma

La conferma invia un acknowledgement MCCI_IN000002UV01.

Attivata per default, a differenza di X12. Un'interazione v3 su un trasporto sincrono si aspetta una conferma - l'applicazione di invio sta generalmente aspettando una conferma - e un mittente che non riceve nulla ritenterà solitamente, il che è il modo in cui un paziente viene registrato tre volte.

Un puntatore in modo che 'non impostato' e 'impostato su false' siano diversi: il valore predefinito è attivato e qualcuno che lo disattiva dovrebbe averlo detto.

24.3.3 dispositivo_mittente

SenderDevice è l'identificatore del dispositivo che inseriamo in una conferma.

Richiesto quando si conferma. Una conferma v3 nomina il dispositivo da cui proviene e un ricevente che non riconosce il nostro potrebbe scartarla - il che sembra esattamente come non inviarla.

24.3.4 trasformazioni

Le trasformazioni modificano il contenuto di un documento v3.

Utilizza un campo proprio anziché le trasformazioni ordinarie del canale, per lo stesso motivo del filtro: si tratta di vocabolari diversi contro modelli di messaggio diversi. I passaggi v2 si rivolgono a segmenti e campi, che un documento v3 non ha, quindi condividere il campo significherebbe che un passaggio faccia silenziosamente nulla.

I nomi dei passaggi corrispondono a quelli v2 ovunque il significato corrisponda, in modo che qualcuno che abbia scritto un canale possa scrivere l'altro. Ciò che è diverso è ciò che v3 richiede e v2 non può esprimere - principalmente che rimuovere un valore ha tre significati distinti, quindi clear, nullflavor e remove sono tre passaggi anziché uno.

24.4 strutturazione TCP

La strutturazione TCP è il modo in cui vengono trovati i limiti dei messaggi su un socket grezzo.

Condivisa dalla sorgente TCP e dalla destinazione TCP, e dalla sorgente seriale, poiché le strutturazioni sono le stesse ovunque provengano i byte. Un analizzatore di laboratorio che parla STX/ETX su un socket parla STX/ETX anche su un cavo seriale.

Definito come TCPFraming in internal/config.

ChiaveTipoObbligatorioPredefinito
framingtestosì—
delimitertestono—
start_blocktestono—
keep_delimitertrue o falseno—
record_lengthnumero interono—
trim_paddingtrue o false (un blocco, omesso per non utilizzarlo)no—
length_bytesnumero interono—
big_endiantrue o falseno—
length_includes_headertrue o falseno—

24.4.1 strutturazione

La strutturazione è mllp, delimitata, fissa, lunghezza o intera.

Richiesto, senza valore predefinito. La lettura di un flusso con la strutturazione errata produce messaggi che sembrano plausibili piuttosto che un errore, quindi indovinare è peggio che chiedere.

24.4.2 blocco_iniziale

StartBlock inizia facoltativamente un messaggio.

I byte prima di esso vengono scartati come rumore da una connessione parziale.

24.4.3 mantieni_delimitatore

KeepDelimiter include il delimitatore nel messaggio.

Disabilitato di default: si tratta di framing, non di contenuto.

24.4.4 trim_padding

TrimPadding rimuove gli spazi e i NUL di fine da un record fisso.

Abilitato di default.

24.5 Opzioni X12

X12Options sono le impostazioni che si applicano solo a un canale X12.

Definito come X12Options in internal/config.

ChiaveTipoObbligatorioPredefinito
envelopeEnvelopePolicynorequire
splitvero o falsono—
acknowledgetestono—
ack_sender_idtestono—
ack_sender_qualifiertestono—
arrives_astestono—
transformationselenco di x12.Stepno—

24.5.1 envelope

Envelope specifica cosa fare quando i conteggi auto-dichiarati non corrispondono a quanto presente.

Predefinito su richiedi.

24.5.2 dividi

Split invia un messaggio per ogni set di transazioni invece di uno per file.

Disabilitato di default. Un singolo 837 può trasportare centinaia di richieste, quindi attivarlo moltiplica tutto a valle - conteggi dei messaggi, conferme, righe, soglie di allarme - e ciò dovrebbe essere una decisione presa da qualcuno piuttosto che un default ereditato.

24.5.3 conferma

Acknowledge specifica quale conferma inviare indietro: 999, 997, ta1 o nessuna.

Quale sia una proprietà della relazione di partner commerciale piuttosto che del messaggio, quindi deve essere configurata. Un 999 sostituisce un 997 per le transazioni HIPAA, ma molti partner - in particolare le connessioni dei pagatori più vecchi - sono configurati per aspettarsi un 997 e tratteranno un 999 come un file non riconosciuto. Inviare la conferma sbagliata è peggiore che non inviarne alcuna, perché risponde a una domanda che nessuno ha posto e lascia aperta la vera domanda.

Vuoto significa nessuna, che è il default sicuro: un partner che non si aspetta una conferma e la riceve può trattarla come un interscambio non sollecitato.

24.5.4 ack_sender_id

AckSenderID e AckSenderQualifier sono il nostro identificatore di interscambio, che diventa ISA06 e ISA05 di qualsiasi conferma.

Richiesto ogni volta che Acknowledge è impostato e rifiutato al caricamento in caso contrario. Questi devono essere i valori che il partner commerciale ha configurato per noi e non c'è modo di indovinarli: un interscambio il cui ISA06 il partner non riconosce viene scartato prima che qualcuno lo legga, quindi un valore errato produce silenzio che sembra esattamente come non inviare nulla - e qualcuno spende una settimana a cercare nel posto sbagliato.

24.5.5 ack_sender_qualifier

AckSenderID e AckSenderQualifier sono il nostro identificatore di interscambio, che diventa ISA06 e ISA05 di qualsiasi conferma.

Richiesto ogni volta che Acknowledge è impostato e rifiutato al caricamento in caso contrario. Questi devono essere i valori che il partner commerciale ha configurato per noi e non c'è modo di indovinarli: un interscambio il cui ISA06 il partner non riconosce viene scartato prima che qualcuno lo legga, quindi un valore errato produce silenzio che sembra esattamente come non inviare nulla - e qualcuno spende una settimana a cercare nel posto sbagliato.

24.5.6 arrives_as

ArrivesAs è xml quando la sorgente consegna l'intercambio come l'XML di Mirth Connect e Open Integration Engine scrivono per X12 (una radice X12Transaction, elementi denominati CLM.05.1), come un motore migrato da uno di essi o un sistema costruito contro di esso lo invia.

Viene riportato nuovamente in X12 prima che accada qualsiasi altra cosa. Vuoto o x12 è X12.

24.5.7 trasformazioni

Le trasformazioni sono modifiche dichiarative applicate agli interscambi accettati.

Separate dalle trasformazioni a livello di canale per lo stesso motivo per cui quelle v3 sono: queste ultime si rivolgono ai campi HL7 attraverso un parser che legge segmento-campo-componente-sottocomponente, e X12 non ha sottocomponenti, tratta i segmenti ripetuti come ordinari piuttosto che eccezionali e viene scritto CLM01 dalle persone che lo configurano. Un parser condiviso dovrebbe accettare entrambe le notazioni e sarebbe quindi ambiguo in entrambe.

I nomi dei passaggi sono gli stessi che utilizzano i passaggi HL7 e v3, quindi ciò che un autore ha già appreso si applica.

25 Riferimento al comportamento

Conferma, messa in coda, ritentativo, polling, impostazioni di scripting e ombreggiatura. Queste si applicano indipendentemente dal trasporto utilizzato da un canale.

25.1 Connessione AMQP

AMQPConnection è dove e come connettersi.

Definito come AMQPConnection in internal/config.

ChiaveTipoObbligatorioPredefinito
addrtestosì—
addresstestosì—
usernametestono—
passwordtestono—
hostnametestonol'host di addr
tlstlsconf.Settings (un blocco, omesso per non utilizzarlo)no—
timeoutdurata, ad esempio 30s o 5mno30s

25.1.1 username

Nome utente e password autenticano con SASL PLAIN; entrambi vuoti significano ANONYMOUS.

Per Service Bus, il nome del criterio e la chiave.

25.1.2 password

Nome utente e password autenticano con SASL PLAIN; entrambi vuoti significano ANONYMOUS.

Per Service Bus, il nome del criterio e la chiave.

25.1.3 nome host

Il nome host viene inviato al broker, che Service Bus instrada.

Predefinito per l'host di addr.

25.1.4 tls

TLS crittografa la connessione.

Obbligatorio per Service Bus e Event Hubs.

25.1.5 timeout

Timeout delimita la connessione e ogni attesa per il broker.

Defaults to 30s.

25.2 Partner AS2

AS2Partner è un partner commerciale che un'origine AS2 accetta messaggi da.

Definito come AS2Partner in internal/config.

ChiaveTipoObbligatorioPredefinito
idtestosì—
cert_filetestosì—
allow_unsignedvero o falsono—
allow_unencryptedvero o falsono—

25.2.1 cert_file

CertFile è il certificato del partner (PEM), per le sue firme.

Spesso auto-firmato: i partner AS2 scambiano certificati direttamente piuttosto che attraverso un'autorità.

25.2.2 allow_unsigned

AllowUnsigned e AllowUnencrypted accettano un messaggio da questo partner che non è firmato o non crittografato.

Disattivato: un tale messaggio viene rifiutato con una ricevuta che indica il motivo.

25.2.3 allow_unencrypted

AllowUnsigned e AllowUnencrypted accettano un messaggio da questo partner che non è firmato o non crittografato.

Disattivato: un tale messaggio viene rifiutato con una ricevuta che indica il motivo.

25.3 Accesso AWS

L'accesso AWS è il modo in cui un connettore raggiunge AWS: la regione per cui si firma, le chiavi e un endpoint facoltativo.

Le credenziali possono essere letterali o riferimenti ${ENV_VAR}, che è il modo in cui dovrebbero essere fornite. Non esiste una catena di credenziali instance-metadata, intenzionalmente: vedere internal/awsv4.

Definito come AWSAccess in internal/config.

ChiaveTipoObbligatorioPredefinito
regiontestosì—
access_key_idtestono—
secret_access_keytestono—
session_tokentestono—
endpointtestono—

25.3.1 secret_access_key

SecretAccessKey è il segreto, letterale o ${AWS_SECRET_ACCESS_KEY}.

Preferire il riferimento: questo file va nel controllo versione.

25.3.2 session_token

SessionToken è utilizzato solo per le credenziali temporanee.

Queste scadono e il connettore smette di funzionare quando lo fanno.

25.4 Ack

Ack configura la generazione di conferme.

Definito come Ack in internal/config.

ChiaveTipoObbligatorioPredefinito
whenAckWhenno—
applicationtestono—
facilitytestono—
include_trigger_eventvero o falsono—

25.4.1 include_trigger_event

IncludeTriggerEvent invia ACK^A01 invece di ACK.

Alcuni ricevitori lo richiedono e altri lo rifiutano, quindi è esplicito.

25.5 Accesso Azure Blob

AzureBlobAccess è l'account, il contenitore e le credenziali.

Definito come AzureBlobAccess in internal/config.

ChiaveTipoObbligatorioPredefinito
accounttestosì—
containertestosì—
keytestono—
sastestono—
endpointtestono—

25.5.1 chiave

La chiave è la chiave dell'account o ${AZURE_STORAGE_KEY}.

Impostarla o sas.

25.5.2 sas

SAS è una stringa di query di firma di accesso condiviso o un riferimento ${...}.

Preferito: può essere limitato a questo contenitore.

25.6 Riferimento contrattuale

ContractRef punta un canale al suo contratto.

Definito come ContractRef in internal/config.

ChiaveTipoObbligatorioPredefinito
filetestosì—
check_everytestono15 minuti
overnumero interono500

25.6.1 check_every

CheckEvery indica la frequenza di ri-controllo, come durata.

Predefinito a 15 minuti.

Effettivamente limitato all'intervallo di valutazione dell'avviso, che è di 30 secondi per default, poiché il controllo viene eseguito da quel ciclo e non da un timer proprio - quindi un contratto che richiede 3 secondi ottiene 30 secondi. Ciò è deliberato: un timer è più facile da gestire di due, e mantiene il risultato del contratto in sincronia con la lettura a cui è collegato. Vale la pena saperlo prima che qualcuno imposti un intervallo breve e concluda che è rotto.

Non per messaggio. La creazione di un profilo significa leggere il traffico recente, e farlo per ogni messaggio renderebbe la velocità di un canale dipendente dalla quantità di storia che ha - che è il tipo di caratteristica delle prestazioni che si verifica solo in produzione, dopo sei mesi.

25.6.2 over

Over indica quanti messaggi recenti profiliare.

Defaults to 500.

Un conteggio piuttosto che una finestra temporale, poiché un feed tranquillo e uno occupato necessitano della stessa quantità di prove per giustificare una velocità, e una finestra temporale fornisce loro quantità molto diverse.

25.7 Opzioni DICOM

DICOMOptions configura un canale di imaging.

Perché i passaggi sono denominati e non percorsi

Ogni altro formato ottiene uno scrittore di percorso. DICOM non lo fa deliberatamente, e il motivo è i dati dei pixel: un oggetto è binario, uno scrittore di tag generico può impostare qualsiasi tag su qualsiasi byte, e un errore lì non produce un messaggio rifiutato - produce un'immagine che si apre e che è errata. Un radiologo che legge uno studio non ha modo di capirlo.

Quindi le quattro cose di cui i siti hanno effettivamente bisogno sono azioni denominate con effetti limitati: de-identificare, riscrivere un titolo AE, rimuovere tag privati, impostare l'istituzione. Ognuna sa quali tag tocca, e nessuna può raggiungere i dati dei pixel.

Perché questo blocco esiste ora

internal/dicom ha trasportato steps.go e transform.go per un po' - le quattro azioni, dicom.Apply e test. Nulla li ha referenziati. Cinquecento righe senza chiamante, che la sezione 7 della coda stessa nomina: un'implementazione senza chiamante è indistinguibile da una funzionalità che non esiste. Questo blocco e la chiamata del motore sono il cablaggio, non la funzionalità.

Definito come DICOMOptions in internal/config.

ChiaveTipoObbligatorioPredefinito
transformationselenco di dicom.Stepno—

25.8 Indirizzo diretto

DirectAddress è un indirizzo Direct che questo server possiede: il suo certificato e chiave, e gli anchor che si fidano.

Lo stesso blocco viene utilizzato per inviare (firmare come questo indirizzo) e ricevere (decrittare per esso).

Definito come DirectAddress in internal/config.

ChiaveTipoObbligatorioPredefinito
addresstestosì—
cert_filetestosì—
key_filetestosì—
anchors_filetestosì—

25.8.1 cert_file

CertFile e KeyFile sono il certificato dell'indirizzo (PEM, con la sua catena dopo di esso) e la chiave privata (PEM).

Il HISP o la sua autorità di registrazione li rilascia; sono l'identità dell'indirizzo.

25.8.2 key_file

CertFile e KeyFile sono il certificato dell'indirizzo (PEM, con la sua catena dopo di esso) e la chiave privata (PEM).

Il HISP o la sua autorità di registrazione li rilascia; sono l'identità dell'indirizzo.

25.8.3 anchors_file

AnchorsFile sono gli anchor di trust (PEM): le autorità di certificazione che questo indirizzo si fida, come il bundle DirectTrust.

Un messaggio firmato con qualsiasi altra cosa viene rifiutato.

25.9 Direct IMAP

DirectIMAP è la casella di posta del HISP che una sorgente Direct legge.

Definito come DirectIMAP in internal/config.

ChiaveTipoObbligatorioPredefinito
hosttestosì—
portnumero interono—
securitytestono—
usernametestosì—
passwordtestono—
mailboxtestono—
after_readtestono—
move_totestono—
error_foldertestono—
poll_intervaldurata, ad esempio 30s o 5mno—
tlstlsconf.Settings (un blocco, omesso per non utilizzarlo)no—

25.9.1 move_to

MoveTo è la cartella in cui vengono spostati i messaggi elaborati; predefinito su Processed.

Viene creata quando manca.

25.9.2 tls

TLS si affida a un file CA (o al certificato proprio del HISP) e nomina il server previsto in esso, per un HISP il cui certificato IMAP non proviene da un'autorità pubblica.

Il certificato viene sempre verificato.

25.10 Direct XDR

DirectXDR è l'endpoint a cui una sorgente Direct prende XDR.

Definito come DirectXDR in internal/config.

ChiaveTipoObbligatorioPredefinito
listentestosì—
tls_certtestono—
tls_keytestono—
client_ca_filetestono—

25.11 Struttura ECR

ECRFacility è l'organizzazione che invia rapporti di casi.

Definito come ECRFacility in internal/config.

ChiaveTipoObbligatorioPredefinito
nametestosì—
npitestono—
phonetestosì—
linetestono—
citytestosì—
statetestosì—
postal_codetestono—

25.12 Opzioni EDIFACT

EDIFACTOptions sono le impostazioni che si applicano solo a un canale EDIFACT.

Definito come EDIFACTOptions in internal/config.

ChiaveTipoObbligatorioPredefinito
envelopetestono—
splitvero o falsono—
acknowledgetestono—

25.12.1 conferma

Acknowledge risponde a un mittente che invia tramite HTTP con un CONTRL nella risposta: accettato (azione 7) quando l'intercambio è stato letto e consegnato, rifiutato (4) altrimenti.

Default none.

25.13 OAuth di posta elettronica

EmailOAuth si autentica con OAuth 2.0 (SASL XOAUTH2), che Microsoft 365 e Gmail richiedono al posto di una password.

Definito come EmailOAuth in internal/config.

ChiaveTipoObbligatorioPredefinito
providertestosì—
tenanttestono—
token_urltestono—
client_idtestosì—
client_secrettestono—
refresh_tokentestono—
scopetestono—

25.13.1 client_secret

ClientSecret può essere ${ENV}.

Senza refresh_token, seleziona il grant di credenziali client-only di Microsoft.

25.13.2 refresh_token

RefreshToken può essere ${ENV}: una casella di posta a cui una persona ha acconsentito.

Richiesto per Gmail.

25.14 Autenticazione FHIR

FHIRAuth è il modo in cui una destinazione FHIR si autentica a un servizio FHIR ospitato.

Tre preset, poiché i servizi ospitati sono dove un token bearer incollato in un file smette di funzionare entro un'ora:

I token vengono recuperati quando necessario e riutilizzati fino a un minuto prima della scadenza.

Definito come FHIRAuth in internal/config.

ChiaveTipoObbligatorioPredefinito
typetestosì—
regiontestono—
access_key_idtestono—
secret_access_keytestono—
session_tokentestono—
tenant_idtestono—
token_urltestono—
client_idtestono—
client_secrettestono—
scopetestono—

25.14.1 regione

La regione è la regione AWS.

Letta da un URL HealthLake quando non è fornita.

25.14.2 token_url

TokenURL è l'endpoint del token OAuth, per client_credentials.

Per azure è derivato dal tenant.

25.14.3 client_id

ClientID e ClientSecret identificano l'applicazione.

Il segreto può essere un riferimento ${ENV}, che è il modo in cui dovrebbe essere fornito.

25.14.4 client_secret

ClientID e ClientSecret identificano l'applicazione.

Il segreto può essere un riferimento ${ENV}, che è il modo in cui dovrebbe essere fornito.

25.14.5 scope

L'ambito è richiesto con il token.

Per azure, di default è l'URL del servizio FHIR seguito da /.default, che è il suo pubblico.

25.15 Poll dei file

FilePoll è la parte di una sorgente di raccolta dei file che non ha nulla a che fare con il trasporto.

Condiviso dalle sorgenti locali, FTP, SMB e WebDAV, e da SFTP. Ogni una di queste impostazioni esiste a causa di un modo in cui i file vanno male piuttosto che un modo in cui i trasporti differiscono, quindi appartengono insieme: un sito che ha lavorato per ottenere il giusto stable_for per il suo analizzatore non dovrebbe doverlo lavorare di nuovo quando l'analizzatore si sposta in una condivisione.

Definito come FilePoll in internal/config.

ChiaveTipoObbligatorioPredefinito
dirtestosì—
patterntestono—
poll_intervaldurata, come 30s o 5mno—
after_readtestono—
move_totestono—
error_dirtestono—
stable_fordurata, come 30s o 5mno—
max_file_sizenumero interono—
framedvero o falsono—
rawvero o falsono—
batch_sizenumero interono—
sort_bytestononome

25.15.1 pattern

Il pattern seleziona i file in base a glob.

Vuoto significa ogni file.

25.15.2 directory_errori

ErrorDir è dove viene spostato un file che non può essere elaborato.

Separato da MoveTo di proposito. Un directory che contiene solo errori è qualcosa che qualcuno può monitorare, e mescolare gli errori nell'archivio significa che l'unico modo per trovarli è leggere ogni file.

25.15.3 grezzo

Raw tratta l'intero file come un unico messaggio indipendentemente dal contenuto.

L'impostazione che rende questo connettore utile per qualcosa di diverso da HL7. Senza di essa, un batch CSV, un file di richiesta X12 o un PDF viene diviso in righe che iniziano con MSH e produce nulla, e l'errore dice che il file non è HL7 - vero, ma non è il punto, poiché il file non era mai destinato a essere.

25.15.4 batch_size

La dimensione del batch limita il numero di file che una sola richiesta di poll può leggere.

Zero significa nessun limite.

Esiste per la prima richiesta di poll dopo un'interruzione. Un directory che contiene quarantamila file accumulati durante la notte verrà altrimenti letto in un'unica passata, il che tiene bloccato il ciclo di poll per tutto il tempo necessario e fa sembrare il canale bloccato. La lettura di un numero limitato di file per poll mantiene il canale rispondente e la coda di messaggi visibilmente in scarico.

25.15.5 ordinare_per

SortBy ordina i file all'interno di una richiesta di poll: nome, modificato o nessuno.

Predefinito su nome. L'ordinamento è più importante di quanto sembri: un flusso ADT in cui gli aggiornamenti A08 arrivano prima dell'ammissione A01 produce pazienti che non esistono ancora. L'ordine di elencazione della directory è arbitrario nella maggior parte dei file system, quindi lasciarlo non ordinato significa che l'ordine cambia tra le richieste di poll senza un motivo visibile.

25.16 Accesso GCP

GCPAccess è il modo in cui autenticarsi a Google Cloud.

Definito come GCPAccess in internal/config.

ChiaveTipoObbligatorioPredefinito
projecttestono—
credentials_filetestono—
endpointtestono—

25.16.1 credentials_file

CredentialsFile è una chiave JSON di un account di servizio.

Vuoto utilizza l'account di servizio attaccato alla VM, al pod GKE o al servizio Cloud Run su cui Perfuse è in esecuzione (il server di metadati), a meno che Endpoint non nomini un emulatore.

25.17 Accesso GCS

GCSAccess è un bucket di Cloud Storage.

Definito come GCSAccess in internal/config.

ChiaveTipoObbligatorioPredefinito
buckettestosì—

25.18 Connessione IBMMQ

IBMMQConnection è una coda raggiunta attraverso l'API REST di messaggistica del gestore di code.

Definito come IBMMQConnection in internal/config.

ChiaveTipoObbligatorioPredefinito
urltestosì—
queue_managertestosì—
queuetestosì—
usernametestono—
passwordtestono—
tlstlsconf.Settings (un blocco, omesso per non utilizzarlo)no—
api_versiontestono—
timeoutdurata, ad esempio 30s o 5mno30s

25.18.1 username

Username e Password sono un utente mqweb con il ruolo MQWebUser; la password può essere ${ENV}.

Lasciare entrambi vuoti quando un certificato client (tls.cert_file) autentica.

25.18.2 password

Username e Password sono un utente mqweb con il ruolo MQWebUser; la password può essere ${ENV}.

Lasciare entrambi vuoti quando un certificato client (tls.cert_file) autentica.

25.18.3 timeout

Timeout delimita ogni richiesta.

Defaults to 30s.

25.19 Kafka SASL

KafkaSASL autentica a un cluster Kafka.

Definito come KafkaSASL in internal/config.

ChiaveTipoObbligatorioPredefinito
mechanismtestosì—
usernametestosì—
passwordtestosì—

25.19.1 meccanismo

Il meccanismo è "plain", "scram-sha-256" o "scram-sha-512".

PLAIN invia la password leggibile sul filo, quindi appartiene al TLS. SCRAM non lo fa, ed è per questo che vale la pena nominare la differenza qui piuttosto che trattare i tre come intercambiabili.

25.19.2 password

La password è la password SASL.

Supporta riferimenti ${ENV} come ogni altro segreto qui, quindi una credenziale di cluster non deve essere scritta nel file del canale.

25.20 Connessione MQTT

MQTTConnection è il modo per raggiungere un broker MQTT 3.1.1: Mosquitto, EMQX, HiveMQ, AWS IoT Core, Azure Event Grid.

Definito come MQTTConnection in internal/config.

ChiaveTipoObbligatorioPredefinito
addrtestosì—
client_idtestono—
usernametestono—
passwordtestono—
tlstlsconf.Settings (un blocco, omesso per non utilizzarlo)no—
qosnumero intero (un blocco, omesso per non utilizzarlo)no—
timeoutdurata, ad esempio 30s o 5mno30s

25.20.1 client_id

ClientID nomina la sessione.

Un'origine mantiene i suoi messaggi attraverso le riconnessioni solo con un ID client fisso; di default è perfuse-<canale>.

25.20.2 username

Username e Password autenticano; uno di essi può essere vuoto.

La password può essere ${ENV}.

25.20.3 password

Username e Password autenticano; uno di essi può essere vuoto.

La password può essere ${ENV}.

25.20.4 timeout

Timeout delimita la connessione e ogni attesa per il broker.

Defaults to 30s.

25.21 Opzioni NCPDP

NCPDPOptions sono le impostazioni che si applicano solo a un canale di richiesta di farmacia.

Definito come NCPDPOptions in internal/config.

ChiaveTipoObbligatorioPredefinito
transformationselenco di ncpdp.Stepno—

25.21.1 trasformazioni

Le trasformazioni sono modifiche dichiarative applicate a ogni trasmissione prima della consegna.

Lo stesso vocabolario di ogni altro formato - impostare, copiare, cancellare, mappare, sostituire, tagliare, caso, ognuno con una condizione opzionale - perché il motore di passaggi in internal/steps è generico. Ciò che differisce è la notazione: un percorso è scritto D1 o 07-D7, utilizzando gli identificatori di campo a due caratteri standard.

25.22 Ricezione PGP

PGPReceive apre ciò che una sorgente riceve con OpenPGP: decrittografato con la nostra chiave segreta e la sua firma verificata contro le chiavi pubbliche dei mittenti.

Definito come PGPReceive in internal/config.

ChiaveTipoObbligatorioPredefinito
decrypt_withtestono—
passphrasetestono—
verify_withelenco di testono—
require_signaturetrue o falseno—
allow_unencryptedtrue o falseno—
pass_plaintrue o falseno—

25.22.1 decrittografare_con

DecryptWith è il nostro file di chiave segreta.

Obbligatorio a meno che allow_unencrypted non sia attivato e i messaggi siano solo firmati.

25.22.2 frase_segreta

La frase segreta sblocca DecryptWith quando è protetta.

Preferire un riferimento a una variabile di ambiente, ${NAME}.

25.22.3 verificare_con

VerifyWith sono i file di chiave pubblica dei mittenti.

Una firma di qualsiasi di essi viene verificata e registrata.

25.22.4 passaggio_piano

PassPlain consente a un messaggio che non è PGP di passare invariato, per una cartella che riceve entrambi.

Disattivato: un tale messaggio viene rifiutato, quindi un mittente che ha dimenticato di crittografare viene informato.

25.23 Invio PGP

PGPSend protegge ciò che una destinazione consegna con OpenPGP: crittografato con la chiave pubblica del ricevente, firmato con la nostra, o entrambi.

I pagatori, le casse di compensazione e le agenzie statali spesso ricevono file tramite SFTP solo in questo modo.

Definito come PGPSend in internal/config.

ChiaveTipoObbligatorioPredefinito
encrypt_toelenco di testono—
sign_withtestono—
passphrasetestono—
armortrue o falseno—
no_compresstrue o falseno—
file_nametestono—

25.23.1 crittografare_per

EncryptTo sono i file delle chiavi pubbliche dei destinatari (armored o binari).

Il messaggio è leggibile da ciascuno di essi. Vuoto: il messaggio è firmato solo.

25.23.2 sign_with

SignWith è il nostro file di chiave segreta, per firmare ogni messaggio.

Vuoto: crittografato solo.

25.23.3 frase_segreta

La passphrase sblocca SignWith quando è protetto.

Preferire un riferimento a una variabile di ambiente, ${NAME}.

25.24 Configurazione della coda

QueueConfig attiva la memorizzazione della coda per un destinatario.

Senza di essa, un destinatario che è stato spento per due minuti perde tutto ciò che gli è stato inviato durante quei due minuti: i tentativi di ritrasmissione avvengono in memoria e quando si esauriscono il messaggio viene registrato come non riuscito e perso. Con essa, il messaggio è sul disco e mantiene la sua posizione fino a quando il destinatario non torna online.

È disattivata per impostazione predefinita, il che è una scelta deliberata piuttosto che una precauzione. Una coda modifica ciò che significa un'accettazione e modifica il comportamento di ordinamento durante un'interruzione, e entrambe queste cose un operatore dovrebbe optare consapevolmente piuttosto che scoprirle.

Definito come QueueConfig in internal/config.

ChiaveTipoObbligatorioPredefinito
enabledvero o falsono—
max_attemptsnumero interono—
backoffdurata, ad esempio 30s o 5mno—
max_backoffdurata, ad esempio 30s o 5mno—
max_depthnumero interono—
retain_hoursnumero interono—

25.24.1 max_attempts

MaxAttempts è il numero di volte che la coda tenta prima di contrassegnare un messaggio come non riuscito e passare al successivo.

Zero significa continuare a provare indefinitamente, il che è legittimo per un flusso di dati che non deve perdere nulla, ma dovrebbe essere scelto piuttosto che ereditato.

25.24.2 max_backoff

MaxBackoff limita l'aumento della durata.

Il valore predefinito è di un minuto piuttosto che qualcosa di più grande perché un destinatario che torna online dopo un'interruzione breve dovrebbe essere trovato rapidamente: un tetto di un'ora trasforma un'interruzione di due minuti in un ritardo di un'ora.

25.24.3 max_depth

MaxDepth rifiuta nuovi messaggi una volta che ce ne sono così tanti in attesa, quindi un destinatario che è stato spento per una settimana non può riempire il disco.

Zero significa nessun limite.

Quando si raggiunge il limite, il messaggio viene contrassegnato come non riuscito piuttosto che messo in coda, e il mittente viene informato - il che è la risposta onesta, perché non stiamo più promettendo di consegnarlo.

25.24.4 retain_hours

RetainHours è il tempo per cui vengono conservati gli elementi consegnati e abbandonati prima di essere eliminati.

Vengono conservati affinché qualcuno che guarda un backlog che si sta svuotando possa vederlo accadere, e affinché un messaggio abbandonato possa essere trovato in seguito.

25.25 Ritentativo

Ritentativo controlla la ridistribuzione dopo un errore.

Definito come Retry in internal/config.

ChiaveTipoObbligatorioPredefinito
attemptsnumero interono—
backoffdurata, ad esempio 30s o 5mno—
max_backoffdurata, ad esempio 30s o 5mno—

25.25.1 tentativi

I tentativi sono il numero totale di tentativi, compreso il primo.

Zero significa il valore predefinito.

25.25.2 backoff

Il backoff è l'attesa prima del secondo tentativo.

Raddoppia ogni volta, fino a MaxBackoff.

25.26 Opzioni di script

ScriptOptions configura un canale NCPDP SCRIPT.

Perché SCRIPT ottiene un blocco quando il suo filtro è di livello superiore

Il filtro del canale per ogni tipo di dati è la chiave del filtro di livello superiore, perché internal/expr è generico sul tipo di messaggio: una chiave, compilata contro qualsiasi albero o richiesta che il canale trasporta. I passaggi non possono essere organizzati in questo modo. Un passaggio v2 si riferisce a un segmento e a un campo, un passaggio X12 si riferisce a un elemento a larghezza fissa, e i tipi sono diversi, quindi una chiave yaml dovrebbe contenere qualsiasi cosa implicata dal tipo di dati - che è un campo che significa cose diverse a seconda di un altro campo, e la modalità di errore è un passaggio che silenziosamente non fa nulla.

Quindi questo segue hl7v3, x12, ncpdp e delimited: i passaggi vivono nel blocco del formato stesso, e la chiave delle trasformazioni di livello superiore viene rifiutata su un canale SCRIPT invece di essere accettata e ignorata.

Definito come ScriptOptions in internal/config.

ChiaveTipoObbligatorioPredefinito
transformationselenco di hl7v3.Stepno—

25.26.1 trasformazioni

Le trasformazioni sono i passaggi dichiarativi, che si riferiscono alla prescrizione come un albero XML.

hl7v3.Step piuttosto che un tipo proprio, e non è pigrizia. Una prescrizione e un documento v3 sono entrambi XML, la grammatica del percorso è la stessa, e internal/eprescribe già utilizza hl7v3.Path per il suo filtro con un commento che lo dice - v3 e CDA già lo utilizzano, e una terza copia sarebbe un terzo set di risposte a cosa significa //a/b[2]@c.

I passaggi che trasportano un significato esclusivo di v3 vengono rifiutati durante il caricamento invece di essere disponibili silenziosamente. nullflavor è quello: scrive l'attributo v3 che afferma il motivo per cui un valore è assente, che una prescrizione non ha un equivalente, e un passaggio che lo scrive produrrebbe un documento che il ricevente non comprende.

25.27 Script

Scripts contiene il codice JavaScript associato a un canale.

Definito come Scripts in internal/config.

ChiaveTipoObbligatorioPredefinito
filtertestono—
transformertestono—
preprocessortestono—
deploytestono—
undeploytestono—
postprocessortestono—
languagetestono—
timeoutdurata, ad esempio 30s o 5mno—
includeelenco di testono—
file_rootselenco di testono—
allowelenco di testono—

25.27.1 filtro

Il filtro viene eseguito dopo il filtro dell'espressione, se presente, e deve restituire un valore booleano.

Uno script di filtro Mirth si inserisce qui invariato.

25.27.2 transformer

Il transformer viene eseguito dopo i passaggi dichiarativi e può modificare il messaggio.

Uno script di transformer Mirth si inserisce qui invariato.

25.27.3 preelaboratore

Il preelaboratore esegue prima che il messaggio venga analizzato, legge il testo come "messaggio" e restituisce il testo da analizzare.

Un preelaboratore Mirth si inserisce qui senza modifiche.

Questo è l'unico posto in cui un messaggio che non viene analizzato può essere riparato. I siti lo utilizzano per un carattere vagante da un gateway seriale, un terminatore di segmento che è arrivato come un carattere di avanzamento riga, o un fornitore che riempie un campo con qualcosa di illegale per la sua posizione. Senza di esso, Perfuse rifiuta il traffico che Mirth accetta oggi.

25.27.4 distribuire

La distribuzione si esegue una volta all'avvio del canale, prima che accetti qualcosa.

Questo è il posto in cui i siti caricano una cache di ricerca o verificano che qualcosa su cui dipendono sia raggiungibile. Esegue prima che la sorgente si connetta, quindi uno script di distribuzione che fallisce impedisce al canale di avviarsi piuttosto che lasciarlo accettare messaggi che non può gestire.

25.27.5 rimuovere la distribuzione

La rimozione della distribuzione si esegue una volta quando il canale si ferma.

Dopo che la sorgente ha smesso di accettare e dopo che i messaggi in volo sono stati completati, quindi vede un canale che è effettivamente inattivo. Il suo fallimento non può impedire di fermare: un canale che non potesse essere chiuso perché uno script di pulizia ha generato un'eccezione sarebbe peggiore di uno che ha registrato e chiuso.

25.27.6 postelaboratore

Il postelaboratore esegue dopo che il messaggio è stato gestito e non può modificarlo.

Il messaggio e ciò che gli è accaduto sono visibili, quindi può notificare, contare o registrare. Non può alterare ciò che è stato inviato: al momento dell'esecuzione, l'invio è già avvenuto e uno script che sembra modificare un messaggio consegnato starebbe mentendo al riguardo.

25.27.7 linguaggio

Il linguaggio è il linguaggio di scripting in cui questi script sono scritti: javascript o lua.

Perché un'impostazione per l'intero blocco invece di una per script

Gli script di un canale condividono la mappa del canale e la mappa del connettore e vengono letti insieme da chi li mantiene. Un filtro in Lua accanto a un trasformatore in JavaScript significherebbe due linguaggi in una revisione, condividendo lo stato attraverso una mappa i cui valori dovrebbero avere lo stesso significato in entrambi. I siti che desiderano questo possono dividere il canale.

Perché l'impostazione predefinita è javascript

Ogni script scritto prima dell'esistenza di questa impostazione è JavaScript e non dice nulla sul proprio linguaggio. Rendere lua l'impostazione predefinita li reinterpretarebbe silenziosamente; richiedere il campo li rifiuterebbe. Nessuna delle due opzioni è accettabile per un'impostazione aggiunta in seguito.

25.27.8 timeout

Il timeout delimita ogni script.

Zero significa cinque secondi.

Non esiste un modo deliberato per disabilitarlo. Mirth consente a un trasformatore di eseguire un ciclo infinito, il che blocca il canale, e un'interfaccia che smette di accettare ammissioni a causa di un errore di battitura non è qualcosa che si vuole offrire come opzione.

25.27.9 includere

Includere nomina file di codice sorgente condiviso reso disponibile per ogni script in questo canale, nel linguaggio che script.linguaggio nomina.

Si tratta dei modelli di codice Mirth. Un sito con quaranta canali di solito ha una libreria che ogni canale chiama, e senza di essa una migrazione significa copiare quella libreria in quaranta file - quaranta posti in cui correggere la prossima volta che cambia.

I percorsi sono relativi al file del canale, quindi una libreria accanto ai canali li accompagna. È un elenco perché l'alternativa è un unico file enorme e le librerie tendono a dividersi per argomento.

I file devono essere nel linguaggio del canale. Ciò era possibile solo con JavaScript per un po' di tempo, e non per rifiuto: un canale Lua leggeva i file, rifiutava uno mancante e poi il runtime non installava nulla, quindi ogni chiamata alla libreria falliva al primo messaggio con un globale nil - l'errore esatto che il rifiuto sopra esiste per evitare. Entrambi i linguaggi lo installano ora e una libreria che non viene analizzata viene rifiutata al caricamento con il nome del file.

25.27.10 file_roots

FileRoots sono le directory che FileUtil può leggere e scrivere.

Richiesto ogni volta che è consentito "file". Concedere l'accesso al file senza specificare le directory utilizzate significava in precedenza l'intero file system: uno script poteva leggere il database di Perfuse, che contiene hash di password, la password dell'account di servizio LDAP e il segreto del client OIDC. La creazione di un canale richiede solo il ruolo dell'editor, quindi l'escalation si è completata nel momento in cui un amministratore lo ha avviato.

25.27.11 allow

Allow concede capacità che uno script altrimenti verrebbe rifiutato: "file", "database", "route".

Mirth concede tutti questi a ogni script; richiedere che vengano nominati significa che un trasformatore non può iniziare a leggere silenziosamente il file system dopo un copia-incolla.

25.28 Ombra

Shadow esegue una versione candidata di un canale accanto a quello live e segnala dove differiscono.

Questa è la risposta alla domanda che rende il lavoro di interfaccia spaventoso: come si fa a sapere che una modifica è sicura? Non leggendola. Una trasformazione è un programma che opera su messaggi la cui varietà nessuno ha catalogato e il caso che si rompe è sempre quello che nessuno ha pensato - il paziente con due identificatori, il risultato con un campo unità vuoto, l'A08 che arriva prima del suo A01.

Un test del canale prova i casi che qualcuno ha pensato. La modalità shadow prova i casi che arrivano effettivamente, contro traffico reale, prima che la modifica trasporti alcuno di essi.

Due proprietà la rendono sicura, entrambe strutturali piuttosto che configurabili:

Definito come Shadow in internal/config.

ChiaveTipoObbligatorioPredefinito
channeltestosì—
samplenumerono1
compareelenco di testono—
ignoreelenco di testono—
max_differencesnumero interono100
timeoutdurata, ad esempio 30s o 5mno5s

25.28.1 canale

Canale è il percorso del file del canale candidato.

Un file separato piuttosto che un blocco inline, di proposito: il candidato è destinato a diventare il canale live, quindi dovrebbe essere l'artefatto che viene esaminato, impegnato e promosso, non un frammento che deve essere estratto.

25.28.2 sample

Sample è la frazione di messaggi da shadow, da 0 a 1. Predefinito su 1.

Vale la pena abbassarlo solo su un feed occupato e vale la pena capirlo prima di farlo: il campionamento riduce i costi e riduce la fiducia nella stessa proporzione e il messaggio che avrebbe mostrato la differenza è quello insolito.

25.28.3 compare

Compare limita il confronto a questi percorsi di campo.

Un confronto vuoto confronta tutto.

25.28.4 ignore

Ignora i percorsi esclusi dal confronto.

Necessario nella pratica, poiché un canale che appone un timestamp o un numero di sequenza differisce in ogni singolo messaggio e riporterebbe un tasso di differenza del 100% senza fornire alcuna informazione.

25.28.5 max_differences

MaxDifferences limita il numero di messaggi diversi mantenuti per l'ispezione.

Defaults to 100.

25.28.6 timeout

Il timeout limita una singola esecuzione shadow.

Defaults to 5s.

Separato dal timeout del canale stesso e più breve. Un candidato con uno script fuori controllo non deve accumulare goroutine dietro il traffico live.

25.29 Codice XDS

XDSCode è un valore codificato nelle impostazioni di destinazione: codice, schema di codifica (un OID) e visualizzazione.

Definito come XDSCode in internal/config.

ChiaveTipoRichiestoPredefinito
codetestosì—
schemetestosì—
displaytestono—

26 Come funziona ogni componente

Perfuse è costruito da piccoli pacchetti, ognuno con un solo lavoro. Questo capitolo è il resoconto di ogni pacchetto su cosa fa e perché è costruito in quel modo, preso dalla fonte. Dove una decisione ha una ragione che non è ovvia, la ragione è qui piuttosto che in un messaggio di commit che nessuno troverà.

26.1 fhir

Il pacchetto fhir implementa le risorse FHIR, la serializzazione e la convalida.

La gestione delle versioni è la prima decisione di progettazione, poiché "FHIR" da solo non identifica un formato di rete. R5 è l'ultima versione pubblicata e è la predefinita qui. R4 è ciò che la base installata e la regolamentazione statunitense consumano effettivamente, quindi è supportata integralmente piuttosto che trattata come legacy. R6 è in votazione al momento della scrittura e non è implementata di proposito: spedire un'ipotesi su una specifica non pubblicata sarebbe peggiore che non supportarla.

Il modello di risorse è R5-shaped. Dove R4 differisce, la differenza è applicata durante la serializzazione piuttosto che mantenendo due set di strutture parallele, che è il modo in cui un codice base finisce con due definizioni leggermente divergenti di Patient.

Source: github.com/biodream-llc/perfuse/fhir

26.2 principale

Il comando xmlordergen scrive l'ordine degli elementi FHIR XML necessari, a partire dalle StructureDefinitions di un pacchetto principale.

go run ./fhir/xmlordergen hl7.fhir.r4.core-4.0.1.tgz | gzip -9 -n > fhir/xmlorder_r4.txt.gz

Gli oggetti JSON possono contenere i loro membri in qualsiasi ordine; XML no: ogni elemento deve essere nell'ordine elencato nella sua definizione. Ogni riga di output è un percorso e i suoi figli in quell'ordine, ogni figlio con informazioni su come trovare i propri figli: "@Path" (un elemento definito inline, una struttura portante), "#Path" (lo stesso di un altro elemento), o i suoi tipi.

Source: github.com/biodream-llc/perfuse/fhir/xmlordergen

26.3 hl7

Il pacchetto hl7 legge i messaggi HL7 versione 2.

Non ha dipendenze al di fuori della libreria standard e un test impone che. Non esegue operazioni di rete I/O, non scrive file e non avvia goroutine, quindi è sicuro da utilizzare da qualsiasi luogo.

Reading a message

msg, err := hl7.Parse(raw) if err != nil { return err } mrn := msg.MustGet("PID-3.1") name := msg.MustGet("PID-5.1") msgType, event, _ := msg.Type() // "ADT", "A01"

I percorsi sono la notazione che le persone già utilizzano quando parlano di HL7: segmento, campo, quindi componente e sottocomponente opzionali, come in PID-5.1 o OBX-5.2.3. Le ripetizioni sono indirizzate con parentesi quadre, come in PID-3[2].1.

Get restituisce un errore per un percorso che non può essere analizzato; MustGet restituisce la stringa vuota al suo posto. Entrambi sono sicuri su segmenti e campi assenti, poiché un feed reale è pieno di entrambi e un parser che si blocca sui dati mancanti è inutile per il lavoro. L'assenza non è un errore — un messaggio che semplicemente non trasporta PID-8 produce "" piuttosto che un fallimento.

Assente e vuoto

HL7 distingue un campo che non è stato inviato da uno inviato deliberatamente vuoto, e clinicamente possono significare cose diverse - "nessuna allergia registrata" non è "nessuna allergia nota". Value.Exists segnala la differenza dove i chiamanti ne hanno bisogno, mentre String appiattisce entrambi su "" per il caso comune.

Copia e il modo per sbagliare

Parse copia l'input, quindi il Message restituito rimane valido indipendentemente da come il chiamante riutilizza il buffer. Ciò costa circa il 3% e un'allocation per messaggio.

WithZeroCopy salta la copia e mantiene un riferimento alla slice del chiamante invece. È più veloce e rende il Message insicuro da utilizzare dopo che la slice è stata scritta di nuovo. Leggere in un buffer riutilizzato è il modo normale ed efficiente per leggere da una rete in Go, quindi la trappola cattura il codice attento e il sintomo è un valore di campo silenziosamente errato piuttosto che un errore - i dati di un paziente sotto il nome di un altro paziente. Utilizzarlo per input che è immutabile o sopravvive al Message, e non altrimenti.

Acknowledgements

AckFor costruisce un ACK o NAK per un messaggio, inclusi per quelli che non sono riusciti a parsare, che è il caso che conta di più: un mittente ha bisogno di una risposta anche quando ciò che ha inviato non era un messaggio. Vedere AckOptions.

Cosa questo pacchetto non fa

Non scrive o modifica messaggi. Non ha nozione di struttura del messaggio oltre i segmenti, quindi non ti dirà che un PV1 appartiene a un particolare gruppo di visite. Non valida contro le tabelle di una versione. Queste sono omissioni deliberate piuttosto che errori: questo è un indexer per traffico reale, che è frequentemente non conforme agli standard e comunque deve essere instradato.

Source: github.com/biodream-llc/perfuse/hl7

26.4 ammettere

Il pacchetto ammettere limita la quantità di lavoro in volo alla volta.

Il motore crea una goroutine per ogni destinazione per ogni messaggio. Le goroutine sono economiche; ciò che tengono non lo è. Ogni consegna in uscita tiene una socket all'estremità remota e un file descriptor qui, e li tiene per l'intero budget di ritentativi - con i valori predefiniti, cinque tentativi con un timeout di trenta secondi più quindici secondi di backoff, quindi quasi tre minuti. Alcuni centinaia di mittenti contro un ricevitore che è diventato silenzioso è quindi alcuni centinaia di descriptor tenuti per minuti, e il processo esce.

Uscire è il fallimento che vale la pena prevenire, perché non si presenta dove è avvenuto. Si presenta come "troppi file aperti" da qualche parte non correlato: il database non può aprire il suo giornale, l'interfaccia smette di accettare, un log non può essere scritto. Il motore sembra rotto in tre posti alla volta e la causa è un sistema partner che ha smesso di rispondere.

Due limiti, e il secondo conta più del primo:

Un totale, in modo che il processo rimanga all'interno del suo budget di descriptor.

Un limite per destinazione, in modo che un ricevitore non possa consumare il totale. Senza di esso, un unico partner bloccato fa cadere tutti gli altri canali, il che è peggio che non avere un limite affatto: il raggio di azione cresce da un'interfaccia a tutte.

Source: github.com/biodream-llc/perfuse/internal/admit

26.5 avvisi

Il pacchetto avvisi controlla le metriche e dice quando qualcosa va storto.

Il punto è che nessuno dovrebbe dover guardare il cruscotto. "Le transazioni fallite rimangono in coda senza un'indagine tempestiva" è un fallimento operativo documentato in questa classe di software, e il motivo è sempre lo stesso: le informazioni erano su uno schermo che nessuno stava guardando alle quattro del mattino.

Tre decisioni lo plasmano.

Un avviso deve cancellarsi da solo. Una notifica che si attiva e non si risolve addestra le persone a ignorare le notifiche. Ogni regola qui è valutata contro lo stato attuale, quindi un ricevitore che torna chiude l'avviso che ha aperto.

Gli avvisi sono debounced per durata, non per conteggio. "Tasso di errore sopra il 5% proprio adesso" si attiva con un unico messaggio sfortunato durante un'ora tranquilla. "Sopra il 5% per due minuti" no. Ogni regola porta una durata For e nulla si attiva fino a quando la condizione non è stata mantenuta per così tanto tempo.

Ciò che viene inviato non contiene dati del paziente. Un avviso porta un nome di canale, un nome di destinazione, un numero e una soglia. Questi provengono dalla configurazione e dal conteggio. Un webhook va in una chat room, una chat room ha uno scrollback, e uno scrollback non è un posto dove un identificatore di paziente dovrebbe finire.

Source: github.com/biodream-llc/perfuse/internal/alerts

26.6 amqp

Il pacchetto amqp è un client AMQP 1.0: una connessione, una sessione, collegamenti di invio e ricezione, sistemati dopo che il ricevitore lo dice.

AMQP 1.0 è ciò che Azure Service Bus e Event Hubs parlano, ciò che RabbitMQ 4 parla nativamente, e ciò che ActiveMQ e Artemis parlano accanto a STOMP. Scritto qui per il motivo per cui il client STOMP e il firmatario AWS sono: una libreria client completa sarebbe la maggior parte dell'elenco di dipendenze del binary per quattro performativi che contano.

Ciò che fa: SASL PLAIN o ANONYMOUS (Service Bus prende un nome di chiave di accesso condiviso e chiave come PLAIN), TLS, apri/inizia/attacca, flusso basato su credito, un trasferimento diviso in frame quando supera la dimensione massima del frame del peer, e disposizioni - accettate, rilasciate, rifiutate. Il mittente aspetta la disposizione del broker prima di segnalare il successo, quindi "inviato" significa che il broker ha preso in custodia. I frame vuoti mantengono la connessione attiva all'interno del timeout idle del peer, che Service Bus applica.

Ciò che non fa: transazioni, più sessioni, recupero di collegamento e annotazioni di messaggio oltre la lettura.

Source: github.com/biodream-llc/perfuse/internal/amqp

26.7 analizzare

Il pacchetto analyze trasforma un canale Mirth analizzato in qualcosa su cui un essere umano può agire: una descrizione semplice di cosa fa il canale e un elenco onesto di cosa non sopravvivrà a una migrazione.

La regola di progettazione qui è che una scoperta deve essere abbastanza specifica da poter essere utilizzata. "Questo canale utilizza JavaScript" non è una scoperta. "La destinazione 1 chiama java.util.Date, che non ha un equivalente al di fuori della JVM" è.

Source: github.com/biodream-llc/perfuse/internal/analyze

26.8 api

Il pacchetto api serve l'interfaccia HTTP utilizzata dal front-end web.

La importante vincolo di progettazione: i canali vengono letti e scritti su file su disco. L'API è un editor per quei file, non un sistema di archiviazione diverso che esporta YAML. Un canale creato nel browser e uno scritto a mano sono lo stesso artefatto, che è ciò che rende "esportare per condividere" banale e mantiene git come la storia di record.

Source: github.com/biodream-llc/perfuse/internal/api

26.9 as2

Il pacchetto as2 è Applicability Statement 2 (RFC 4130): EDI su HTTP, firmato e crittografato con S/MIME, con una ricevuta firmata (un MDN) che nomina un digest di ciò che è arrivato.

I pagatori e i partner commerciali lo utilizzano per X12 e EDIFACT.

Il S/MIME è internal/cms, lo stesso codice utilizzato dalla messaggistica Direct. Ciò che è qui è specifico di AS2: le intestazioni, il controllo di integrità del messaggio (MIC) e la ricevuta.

Source: github.com/biodream-llc/perfuse/internal/as2

26.10 attach

Il pacchetto attach sposta grandi payload fuori da un messaggio e li ripristina.

Un messaggio HL7 che trasporta un report scansionato o un PDF è ordinario nei flussi di lavoro dei documenti, e il payload è routine centinaia di volte più grande del messaggio che lo circonda. Archiviare ciò in linea significa che il negozio di messaggi cresce al ritmo dei documenti piuttosto che del traffico, un messaggio in coda per cinque destinazioni viene copiato cinque volte, e l'interfaccia deve trasmettere megabyte per mostrare a qualcuno un nome di paziente.

Quindi il payload viene estratto, archiviato una volta per contenuto e sostituito nel messaggio con un token. Mirth chiama questi gestori di allegati ed è una funzione di migrazione documentata, che è il motivo per cui il formato del token è progettato per essere riconoscibile piuttosto che intelligente.

Cosa questo pacchetto non decide

Non esegue alcun archiviazione e alcun I/O. L'estrazione produce il messaggio riscritto e i payload; un archivio da qualche altra parte decide dove vanno quelli. Quella separazione è ciò che rende l'estrazione testabile senza un database, ed è anche ciò che consente alla stessa logica di essere eseguita nel playground WASM dove non c'è database.

Source: github.com/biodream-llc/perfuse/internal/attach

26.11 authlimit

Il pacchetto authlimit limita i tentativi di autenticazione falliti per indirizzo di origine.

Esiste perché due listener avevano bisogno della stessa cosa e uno di loro non aveva nulla. Il server FHIR ha ottenuto un limitatore quando ha ottenuto l'autenticazione; il login della console non aveva nulla e una misurazione ha mostrato venti tentativi di password al secondo sostenuti contro l'account amministratore senza ritardo e senza blocco. A quel ritmo una password debole è persa in una notte e l'unico indizio è un registro pieno di avvertimenti identici.

Non è un limitatore di velocità generico. Limita i fallimenti, non le richieste: un client legittimo impegnato non è mai influenzato, e l'unica cosa che si accumula è l'essere errato.

Source: github.com/biodream-llc/perfuse/internal/authlimit

26.12 awsmsg

Il pacchetto awsmsg comunica con Amazon SQS e SNS con la libreria standard e il firmatario condiviso Signature Version 4.

Lo stesso argomento di s3put: l'SDK di AWS raddoppierebbe le dimensioni del elenco dei materiali per quattro chiamate API. SQS utilizza il suo protocollo JSON (AWS JSON 1.0, X-Amz-Target AmazonSQS.<Action>), che AWS documenta come l'attuale; SNS utilizza il suo protocollo di query, che è l'unico che ha. Entrambi funzionano contro LocalStack e endpoint VPC tramite un override dell'endpoint.

Source: github.com/biodream-llc/perfuse/internal/awsmsg

26.13 awsv4

Il pacchetto awsv4 firma le richieste a AWS con Signature Version 4, utilizzando solo la libreria standard.

È iniziato all'interno di s3put. SQS, SNS e la lettura da S3 necessitano della stessa firma con un nome di servizio diverso e con una stringa di query, e una seconda copia del codice di firma sarebbe un secondo posto per l'unico bug che conta - una mancata corrispondenza della firma legge esattamente come credenziali errate. Quindi vive qui, controllato contro i vettori di test pubblicati da AWS, e ogni connettore AWS lo utilizza.

Le credenziali sono chiavi statiche o le variabili d'ambiente standard. Non esiste una catena di credenziali dell'istanza dei metadati: significa chiamate IMDS, caching e refresh, che è dove un'implementazione piccola smette di essere piccola, e Perfuse rifiuta gli indirizzi dei metadati come destinazioni per impostazione predefinita.

Source: github.com/biodream-llc/perfuse/internal/awsv4

26.14 azblob

Il pacchetto azblob legge e scrive Azure Blob Storage con la libreria standard: autorizzazione con chiave condivisa o SAS tramite chiamate HTTP semplici.

La stessa logica di s3put: l'SDK di Azure è grande e le operazioni di cui ha bisogno un motore di integrazione sono cinque - put, get, list, delete e impostazione del livello di accesso. La firma della chiave condivisa è specificata esattamente ("Autorizza con chiave condivisa", Azure Storage REST), e Azurite, l'emulatore di Microsoft, la controlla nel modo in cui lo fa il servizio.

Source: github.com/biodream-llc/perfuse/internal/azblob

26.15 branding

Il pacchetto branding memorizza il logo e il nome del prodotto di un cliente in modo che un'installazione possa presentarsi come proprio prodotto anziché come Perfuse.

Perché il logo non è un'impostazione

Tutto il resto che un operatore può modificare è uno scalare nel file di impostazioni. Un logo è alcuni centinaia di kilobyte di dati binari, e metterlo lì significherebbe avere una base64 in un file YAML che una persona dovrebbe essere in grado di leggere e modificare manualmente. Esso si trova accanto a quel file invece, e solo la sua presenza è visibile tramite la superficie delle impostazioni.

La parte che conta: un'immagine caricata è un input non attendibile

Un logo viene caricato da un amministratore e poi servito a ogni browser che carica la console, compresa la pagina di accesso prima che qualcuno si sia autenticato. Ciò lo rende il contenuto più ampiamente distribuito fornito dall'attaccante nel prodotto, quindi viene trattato di conseguenza:

Source: github.com/biodream-llc/perfuse/internal/branding

26.16 cda

Il pacchetto cda legge documenti clinici.

La progettazione inizia da come questi documenti viaggiano effettivamente, che non è come file. Un riassunto di dimissione lascia un EHR all'interno di un messaggio HL7 v2 MDM^T02, con l'intero documento codificato in base64 in OBX-5 e descritto da un segmento TXA. Ciò significa migliaia di messaggi al giorno in un ospedale di medie dimensioni, ed è il motivo per cui questo pacchetto si trova accanto a un parser HL7 v2 anziché in un toolkit di documenti: la metà v2 è già qui, quindi la pipeline da "un messaggio è arrivato" a "esiste un riferimento a un documento FHIR" è breve.

Tre cose sono deliberateamente in ambito e una non lo è.

In ambito: leggere un documento e dire cosa contiene in termini semplici; controllare che la narrazione leggibile dall'uomo e le voci codificate concordino; e convertire in FHIR. Il controllo della narrazione è quello insolito. Ogni sezione C-CDA trasporta le stesse informazioni due volte, una volta come testo per un clinico e una volta come codici per una macchina, e dovrebbero corrispondere. In pratica spesso non lo fanno, e nulla lo controlla - non gli strumenti di certificazione, non i motori. Quando il testo dice che un paziente è allergico alla penicillina e la voce codificata dice qualcos'altro, uno dei due lettori agisce sulle informazioni errate. È un difetto di sicurezza del paziente che è meccanicamente rilevabile, quindi viene rilevato qui.

Non in ambito: generare C-CDA conformi. Scrivere uno significa soddisfare diverse centinaia di regole di modello e uno Schematron, e produrre documenti che sono al 95% corretti fallirebbero la certificazione in modi che sono miserabili da debuggare. Leggere, controllare e convertire è la maggior parte del valore per una frazione del rischio.

Source: github.com/biodream-llc/perfuse/internal/cda

26.17 channeltest

Il pacchetto channeltest esegue test su una definizione di canale.

Un canale è un programma. Filtra, riscrive e instrada messaggi clinici, e viene modificato sotto pressione da persone che non possono provarlo contro la produzione. L'assenza di un modo per testarlo è il singolo motivo più grande per cui il lavoro di interfaccia è spaventoso, e "ho modificato il trasformatore e nulla sembra diverso nel browser dei messaggi" non è un test.

La decisione centrale è che un test esegue il messaggio attraverso il percorso di trasformazione reale — lo stesso filtro, gli stessi passaggi dichiarativi, lo stesso motore di script, nello stesso ordine — con solo il trasporto sostituito. Un test che esercita una riimplementazione passerebbe mentre il canale fallirebbe, il che è peggio di non avere un test affatto perché attivamente inganna.

Source: github.com/biodream-llc/perfuse/internal/channeltest

26.18 chanscope

Il pacchetto chanscope restringe le letture e le scritture su un contesto a alcuni canali.

Viaggia sul contesto piuttosto che essere un parametro di ogni query perché ci sono decine di query attraverso il message store e la coda di consegna, e il limite è una proprietà di chi chiede, non della domanda. L'API lo imposta una volta per richiesta per una persona limitata a alcuni gruppi di canali; ogni conteggio, elenco, grafico, ricerca e azione di coda concorda con gli altri, quindi a nessuno viene detto un totale di quaranta errori e mostrato quattro.

Source: github.com/biodream-llc/perfuse/internal/chanscope

26.19 cluster

Il pacchetto cluster consente a più server Perfuse di condividere un archivio PostgreSQL e decidere, tra loro, quale esegue cosa.

Il problema che risolve

Un server è un punto di guasto: quando si ferma, ogni interfaccia si ferma. Due server su un database risolvono questo problema solo se non eseguono mai lo stesso canale, perché due listener MLLP su un flusso si alternano con il mittente, due lavoratori di coda consegnano lo stesso messaggio due volte e due poller DICOM segnalano ogni studio.

How

Un lease è una riga che nomina chi detiene qualcosa, con un contatore che il detentore sposta ad ogni rinnovo, ogni pochi secondi. Nessun orologio viene confrontato con un altro: un detentore che non può rinnovare (crash, disconnesso dal database) ferma ciò che il lease copre una volta che il suo orologio dice che il lease è quasi finito, e un altro server lo prende solo dopo che il suo orologio ha osservato il contatore rimanere fermo per l'intero lease. Ogni server misura un intervallo sul proprio orologio, quindi gli orologi dei server e del database non devono essere concordi; devono solo funzionare alla stessa velocità. Un orologio che salta (una macchina virtuale che si risincronizza, un amministratore che imposta l'ora) non cambia nulla: la prima versione utilizzava l'orologio del database per la scadenza e un test ha trovato un database il cui orologio saltava di tredici secondi e consegnava ogni lease a un nuovo server mentre i vecchi server li eseguivano ancora.

Tra la fine del detentore e l'inizio del successivo c'è una breve pausa con nessuno in esecuzione, che costa al mittente alcuni secondi di connessioni rifiutate e mai un momento con due.

Two modes:

Ogni lease porta un'epoca, conteggiata ogni volta che il detentore cambia, che nomina un possesso nella storia.

Source: github.com/biodream-llc/perfuse/internal/cluster

26.20 cms

Il pacchetto cms è la Cryptographic Message Syntax (RFC 5652) come utilizzata da S/MIME e Direct secure messaging: SignedData (firma un messaggio, verifica uno e dice chi l'ha firmato) e EnvelopedData (crittografa un messaggio per i certificati dei destinatari, decrittografa uno con la nostra chiave).

Solo ciò che lo Standard Applicability Statement e la sua Guida all'implementazione richiedono: RSA con SHA-256 (SHA-1 accettato solo per la lettura, poiché gli HISPs più vecchi lo inviano ancora), RSA key transport con PKCS#1 v1.5 o OAEP e AES-128 o AES-256 in modalità CBC. La crittografia è quella della libreria standard; questo pacchetto è l'ASN.1 intorno ad essa.

Source: github.com/biodream-llc/perfuse/internal/cms

26.21 cms0057

Il pacchetto cms0057 contiene le parti relative al pagatore della regola finale di interoperabilità e autorizzazione preventiva del CMS (CMS-0057-F) che riguardano i dati piuttosto che il trasporto: rivendicazioni liquidate come risorse CARIN Blue Button ExplanationOfBenefit, autorizzazioni preventive come risorse Da Vinci PDex ExplanationOfBenefit, abbinamento dei membri HRex per l'API Payer-to-Payer, l'elenco dei membri dietro l'API Provider Access e le metriche di autorizzazione preventiva che un pagatore deve pubblicare ogni anno.

I punti finali FHIR che servono questi vivono in fhirserver; questo pacchetto decide cosa va inserito in essi.

I farmaci sono fuori dall'ambito in tutto, come lo sono nelle disposizioni di autorizzazione preventiva della regola: nessuna spiegazione di beneficio farmaceutico, nessun formulari, nessun NCPDP.

Source: github.com/biodream-llc/perfuse/internal/cms0057

26.22 codeset

Il pacchetto codeset contiene tabelle di mapping che sopravvivono al canale che le ha create per la prima volta.

La tassa di dominio consiste principalmente nel ricalcolare un mapping che qualcuno ha già derivato. I codici di sesso di un sito, le classi di pazienti, gli stati degli ordini e gli identificatori di strutture vengono tradotti allo stesso modo in ogni canale che li tocca e oggi ogni traduzione è una tabella separata all'interno di un canale separato. Quaranta canali significano quaranta copie e quaranta posti in cui correggere la prossima volta che il sistema di ricezione cambia.

Quindi una tabella diventa un oggetto denominato a cui si fa riferimento per nome. Questo è ovvio e rappresenta la metà più piccola del valore.

La metà che nessuno costruisce

La metà più grande è la provenienza. La maggior parte di ciò che rende un'interfaccia difficile da mantenere non è il mapping - è il fatto che nessuno sa *perché*. "Eliminiamo gli zeri iniziali perché la colonna MRN del laboratorio è numerica" è una conoscenza che esiste nella testa di una persona e lascia l'edificio quando si ritira, e il mapping che rimane diventa qualcosa che nessuno osa cambiare e nessuno osa eliminare.

Quindi ogni tabella registra chi ha deciso e quando, ogni voce può registrare la propria ragione e entrambe sopravvivono nel file che va nel controllo di versione. Un mapping con una ragione può essere discusso. Un mapping senza una ragione diventa superstizione.

Perché il file è separato dal canale

Perché è condiviso. Una tabella all'interno di un canale è una tabella che solo quel canale può utilizzare, ed è questo il problema. E una tabella condivisa necessita della sua propia storia: "chi ha modificato il mapping del sesso e quando" è una domanda sulla tabella, non sul canale che è stato modificato quel giorno.

Source: github.com/biodream-llc/perfuse/internal/codeset

26.23 conformità

Il pacchetto conformità implementa il flusso di notifica degli eventi ADT del CMS richiesto dal 42 CFR 482.24(d) a partire da maggio 2021.

Gli ospedali devono notificare elettronicamente i fornitori stabiliti di un paziente — cure primarie, specialisti, strutture di assistenza post-acuta — quando il paziente viene ammesso, dimesso o trasferito. La regolamentazione esiste perché i pazienti possono cadere nel vuoto durante le transizioni: un medico di base che non sa di una dimissione non può pianificare il follow-up che prevenisce una riammissione.

Questo pacchetto fornisce la macchina per: - Tenere traccia dei fornitori stabiliti per ogni paziente. - Inviare eventi ADT ai fornitori corretti con la priorità corretta. - Registrare ogni notifica inviata, con lo stato di consegna, per gli audit dei surveyor del CMS. - Generare report di conformità che mostrano i tassi di notifica e gli insuccessi.

La sicurezza del thread è richiesta in tutta la pipeline perché i messaggi ADT arrivano contemporaneamente da più canali e la pipeline di notifica viene eseguita in parallelo.

Source: github.com/biodream-llc/perfuse/internal/compliance

26.24 config

Il pacchetto config carica le definizioni dei canali da file.

La configurazione risiede in file piuttosto che in un database, che è la cosa principale che Perfuse fa diversamente da Mirth. Mirth mantiene i canali nel suo proprio database, per cui il controllo delle versioni è un prodotto separato, per cui la promozione di un canale da test a produzione è difficile, e per cui nessuno può rispondere a "cosa è cambiato l'ultima settimana" senza una chiamata di supporto. I file forniscono git, diff, revisione, CI e promozione dell'ambiente senza alcuna macchina aggiuntiva.

La convalida è deliberatamente rigorosa e avviene al caricamento: i campi sconosciuti sono un errore, le espressioni dei filtri vengono compilate, gli indirizzi vengono controllati. Un canale che non può essere compreso deve rifiutare di avviarsi piuttosto che eseguirsi in un modo che nessuno ha inteso.

Source: github.com/biodream-llc/perfuse/internal/config

26.25 contratto

Il pacchetto contratto trasforma ciò che un feed sembra in ciò che un feed deve sembrare.

Un profilo risponde a "cosa sto ricevendo". Ciò è utile una volta. Il problema costoso è il giorno in cui cambia: un aggiornamento del fornitore elimina un campo, un nuovo codice appare, un segmento inizia a ripetersi. Nessuno di questi è un errore - i messaggi sono ancora validi HL7 e ogni motore nel mondo li accetta - quindi nulla si accorge fino a quando un ricevitore non cade, di solito settimane dopo, e l'indagine inizia dalla fine sbagliata.

Un contratto è il profilo scritto come un'aspettativa e quindi verificato. Si tratta di testing del contratto, che è un'idea risolta nel software in generale e quasi completamente assente dall'integrazione sanitaria.

Perché l'unità è un tasso e non un messaggio

La progettazione ovvia è quella di controllare ogni messaggio e lamentarsi quando uno fallisce. Ciò produce un sistema che nessuno può utilizzare. I feed reali contengono una proporzione di messaggi genuinamente strani - un messaggio di test del fornitore, un paziente senza sesso registrato, un inserimento manuale - e l'avviso su ciascuno di essi addestra le persone a ignorare gli avvisi, al punto in cui la funzione è peggiore di nulla perché ha consumato l'attenzione di cui aveva bisogno.

Quindi un'aspettativa è su una proporzione su una finestra: "PID-3 è popolato in almeno il 99% dei messaggi". Un messaggio strano non si attiva mai. Il 5% dei messaggi che perdono il numero del record medico si attiva.

Un contratto descrive cosa arriva, non cosa esce

Questa è la distinzione che le persone ottengono per primo, compreso me mentre testavo l'integrazione. Perfuse memorizza il messaggio come è arrivato - ciò è deliberato, perché il messaggio memorizzato è la prova di cosa un mittente ha inviato - quindi un contratto viene verificato contro il feed in entrata e non contro l'output delle trasformazioni del canale.

Ciò è il default giusto di gran lunga: la cosa che cambia senza preavviso è il sistema di invio, e lo scopo di un contratto è notare. Ma significa che un'aspettativa scritta su un valore mappato ("dopo la mappatura, solo i codici del laboratorio dovrebbero rimanere") fallirà immediatamente e in modo confuso, perché i codici che nomina non appaiono mai nel traffico che viene profilato. Qualsiasi cosa su ciò che esce appartiene a un test del canale, che esegue le trasformazioni reali.

Perché una violazione nomina la tolleranza che ha violato

"PID-3 fallito" non dice nulla a qualcuno. "PID-3 è stato popolato nel 94,2% degli ultimi 500 messaggi; il contratto richiede il 99%" dice loro quanto è grave, quanto possono essere sicuri, e se vale la pena svegliare qualcuno. I numeri sono il messaggio.

Source: github.com/biodream-llc/perfuse/internal/contract

26.26 crd

Il pacchetto crd è un servizio Da Vinci Coverage Requirements Discovery (CRD 2.2.1): il lato del pagatore della conversazione CDS Hooks che dice a un clinico, mentre l'ordine è ancora uno schema, se è coperto, se necessita di autorizzazione preventiva e quale documentazione il pagatore vorrà.

L'API di autorizzazione preventiva CMS-0057 è in pratica tre guide Da Vinci insieme: CRD per dire cosa è richiesto, DTR per raccoglierlo, PAS per inviarlo. Perfuse aveva PAS. Questo è il primo dei due; il pacchetto $questionnaire di DTR è sull'endpoint FHIR.

Le decisioni di copertura provengono da un file di regole, poiché sono la politica del pagatore e cambiano senza rilasci software: un codice (o un elenco di codici) e ciò che si applica ad esso - coperto o no, autorizzazione preventiva necessaria o no, documentazione e il questionario DTR che la raccoglie. Un ordine che non corrisponde a nessuna regola viene risposto come "condizionale" e "indeterminato", che è ciò che CRD dice di restituire quando il servizio non può decidere - mai un'ipotesi che sia coperto.

Le risposte seguono la guida: un'azione di sistema che aggiorna ogni ordine con l'estensione delle informazioni di copertura, che il sistema di gestione delle cartelle cliniche memorizza sull'ordine e invia successivamente con l'autorizzazione preventiva; e una carta per ogni ordine, in modo che un clinico possa vederla.

Source: github.com/biodream-llc/perfuse/internal/crd

26.27 dashboard

I dashboard del pacchetto definiscono i dashboard che Perfuse fornisce per ogni tipo di persona che li osserva e come una persona li ottiene: in base al proprio ruolo, a un gruppo di directory che il file dei dashboard mappa o alla visualizzazione salvata.

I dashboard sono composti da tile e i tile mostrano solo aggregati - conteggi, tassi, tempi, stati. Nessuno mostra un messaggio, un paziente o un identificatore, quindi un dashboard può essere assegnato a un responsabile del reparto o visualizzato su uno schermo a muro senza allargare chi vede i dati dei pazienti. Un tile che necessita di dati che Perfuse non registra ancora non viene contraffatto: il dashboard lo elenca sotto Pianificato.

La piena flessibilità è il lavoro di Grafana, non di questo pacchetto. Ogni tile che ha una metrica dietro di esso esporta come pannello Grafana su /metrics di Perfuse, quindi un sito che desidera più della configurazione leggera prende il dashboard lì.

Source: github.com/biodream-llc/perfuse/internal/dashboards

26.28 davinci

Il pacchetto davinci indica quale versione delle linee guida di autorizzazione preventiva Da Vinci (CRD, DTR, PAS) un client supporta.

Perfuse risponde in due modi: 2.2 (CRD 2.2.1, DTR 2.2.0, PAS 2.2.1), la versione più recente, e 2.1 (CRD, DTR e PAS 2.1.0), la versione raccomandata dall'elenco di CMS-0057-F una volta scaduta la base US Core 3.1.1 delle versioni 2.0.1. Le due versioni differiscono nelle forme che un client legge per nome - i parametri del pacchetto di DTR ($questionnaire-package) (PackageBundle in 2.1, packagebundle in 2.2), la risposta di $inquire di PAS (un Bundle in 2.1, un Parameters in 2.2), le estensioni che esistono in una sola di esse - quindi una risposta non può servire entrambe, e il server deve conoscere con quale versione sta comunicando.

Viene indicato, più specifico per primo: dalla richiesta stessa (davinci-crd.requestedVersion; la versione su un profilo che l'input afferma, profilo|2.1.0), poi dalla registrazione del client (davinci_version su un client SMART o CDS), poi dall'impostazione del server stesso (serve -davinci-version), che di default è la versione più recente.

Source: github.com/biodream-llc/perfuse/internal/davinci

26.29 dbtime

Il pacchetto dbtime formatta i timestamp in modo che l'ordinamento come testo li ordini come tempo.

Ogni archivio in Perfuse memorizza i timestamp come TESTO in SQLite e si affida al confronto tra stringhe per l'ordinamento e per le query di intervallo: ORDER BY received_at DESC, WHERE expires_at < ?, WHERE at >= ?. Questo è un progetto ragionevole - mantiene un database che qualcuno può leggere con il shell sqlite3 - ma funziona solo se la forma del testo è a larghezza fissa.

time.RFC3339Nano non lo è. La sua documentazione afferma che rimuove gli zeri finali dal campo dei secondi, quindi lo stesso orologio produce stringhe di lunghezze diverse:

20:56:33.12345Z <- 123450 microsecondi, zero finale rimosso 20:56:33.123456Z <- 123456 microsecondi

Confrontati come testo, il primo è *maggiore*, perché dopo il prefisso condiviso "12345" ha 'Z' dove il secondo ha '6', e 'Z' si ordina sopra ogni cifra. Quindi l'istante precedente si ordina dopo. Circa una coppia adiacente su dieci è interessata, ed è il motivo per cui si è presentato come un fallimento intermittente del test piuttosto che come una funzionalità ovviamente rotta.

Ciò che ha effettivamente rotto: il registro di controllo e il browser dei messaggi si ordinano entrambi per un timestamp e possono quindi elencare le voci dello stesso secondo nell'ordine sbagliato. Un registro di controllo è un artefatto di conformità e un browser dei messaggi è il modo in cui qualcuno ricostruisce cosa è successo, quindi in entrambi i casi l'ordine è il punto.

La disposizione qui sotto utilizza .000000000 anziché .999999999. Entrambi stampano nanosecondi; la differenza è che gli zeri sono significativi nel primo e rilasciati nel secondo.

Source: github.com/biodream-llc/perfuse/internal/dbtime

26.30 delimitato

Il pacchetto delimited analizza i record separati e divisi da caratteri configurati.

Questo è il tipo di dati Delimited di Mirth: CSV, file separati da tab, file separati da pipe, file a colonne fisse e la lunga coda di formati che un laboratorio di analisi o un servizio di bureau emette perché qualcuno lo ha scritto nel 1994 e funziona.

Volontariamente non è una libreria CSV generale. Ciò che conta qui è cosa fa un flusso di assistenza sanitaria che un CSV ben formato non fa: una riga di intestazione che può essere presente o no, una riga vuota finale che non deve diventare un record vuoto, colonne a cui si fa riferimento per nome in modo che una trasformazione non si rompa quando un fornitore ne inserisce uno, e la capacità di trattare l'intero file come un unico messaggio o ogni riga come un messaggio proprio.

L'ultimo di questi è la decisione che plasma tutto il resto. Un file di cinquemila risultati è un messaggio o cinquemila, e i due non sono interscambiabili: un messaggio significa un'unica conferma e un'unica fail per l'intero file, e cinquemila significa che ogni riga può essere filtrata, trasformata e ritentata singolarmente.

Source: github.com/biodream-llc/perfuse/internal/delimited

26.31 dicom

Il pacchetto dicom legge i set di dati DICOM.

DICOM è dove vive la radiologia, e un motore di integrazione sanitaria che non può parlare DICOM è escluso completamente dall'imaging. Mirth ha un listener e un inviante DICOM, quindi questo è un blocco di migrazione per qualsiasi sito che esegue lavori di modalità.

Ambito, dichiarato apertamente

Questo pacchetto analizza i set di dati: le informazioni di metafile, gli elementi, la sintassi di trasferimento e i valori che contano per il routing e l'identificazione. Non decodifica i dati dei pixel e non lo farà mai per quanto riguarda questo pacchetto - un motore di integrazione si sposta, non visualizza le immagini, e un decodificatore è un grande corpo di lavoro specifico del formato il cui unico scopo qui sarebbe quello di rendere il binario più grande.

La lettura dei metadati senza toccare i pixel è anche ciò che lo rende veloce sul traffico che conta: una TAC al torace è di centinaia di megabyte di pixel dietro due kilobyte di informazioni su cui chiunque si basa per il routing.

Perché le rappresentazioni dei valori vengono gestite esplicitamente

Un elemento DICOM trasporta un valore di rappresentazione a due lettere che indica come leggere il suo valore e le regole differiscono per VR in modi che non possono essere indovinati: alcuni hanno una lunghezza di due byte e alcuni quattro, alcuni sono riempiti con uno spazio e alcuni con un carattere nullo, e le stringhe numeriche possono contenere più valori separati da barre rovesce. Ottenere uno sbagliato non produce un errore, produce un valore errato plausibile - un nome del paziente letto dal centro di una data o un identificatore di studio spostato di un byte.

Source: github.com/biodream-llc/perfuse/internal/dicom

26.32 dicomweb

Il pacchetto dicomweb parla DICOMweb (DICOM PS3.18): QIDO-RS per la ricerca, WADO-RS e WADO-URI per il recupero, STOW-RS per l'archiviazione, tramite HTTP.

È il modo in cui i visualizzatori, i servizi di intelligenza artificiale e gli archivi cloud raggiungono le immagini ora: OHIF, Google Cloud Healthcare, Azure Health Data Services, AWS HealthImaging, interfacce DICOMweb di Orthanc e dcm4chee. Un motore di integrazione che parla solo il protocollo di rete del 1993 (DIMSE: C-STORE, C-FIND) può alimentare un PACS ma non un browser.

Il pacchetto è composto da quattro parti: un lettore di set di dati che attraversa l'intero oggetto, incluse le sequenze, e conosce la posizione dei dati dei pixel senza caricarli; il modello JSON DICOM (PS3.18 F.2); multipart/related, che è il modo in cui DICOMweb sposta più oggetti in una richiesta; e un archivio con un indice, che è ciò che QIDO e WADO rispondono da.

Source: github.com/biodream-llc/perfuse/internal/dicomweb

26.33 direct

Il pacchetto direct è un sistema di messaggistica sicura Direct: un messaggio a un indirizzo Direct è firmato con il certificato di questo indirizzo e crittografato per il destinatario, come S/MIME, e inviato a un HISP tramite SMTP; un messaggio ricevuto dal HISP (tramite SMTP o raccolto tramite IMAP) è decrittografato e la sua firma è verificata contro gli anchor di trust prima che qualcosa lo legga.

Segue la Dichiarazione di applicabilità del progetto Direct per il trasporto sanitario sicuro 1.2 e la specifica XDM (IHE ITI TF-1 Allegato 15) per i documenti con metadati. Non è un HISP: l'accreditamento del HISP, la sua politica di certificato e la sua directory rimangono con il HISP.

Source: github.com/biodream-llc/perfuse/internal/direct

26.34 farmaco

Il pacchetto farmaco gestisce i codici e le quantità che identificano un medicinale.

Diviso dalle norme farmaceutiche che li trasportano, perché lo stesso codice farmaco appare in una richiesta NCPDP, una prescrizione SCRIPT, un segmento HL7 RXE e una richiesta di medicinale FHIR, e una conversione che vive in uno di questi posti è una conversione che gli altri tre fanno a meno.

Source: github.com/biodream-llc/perfuse/internal/drug

26.35 dsdr

Il pacchetto dsdr firma e verifica i documenti CDA come descritto nella Guida di implementazione HL7 per CDA Release 2: firme digitali e delega di diritti, Rilascio 1 (ottobre 2014) - lo standard di firma elettronica adottato da HIPAA per gli allegati alle richieste di rimborso in CMS-0053-F, 45 CFR 162.2002(e), con conformità dal 26 maggio 2028.

Ciò che la guida richiede e dove viene fatto qui:

Dove la guida è silenziosa, le scelte fatte sono nominate: non fornisce uno spazio dei nomi per i suoi elementi (digitalSignature, authorizedSigner, SignaturePurpose), quindi vengono inseriti in urn:hl7-org:sdtc; e lo scopo è anche espresso come un indicatore di tipo di impegno XAdES con l'OID ASTM, che gli strumenti XAdES leggono e l'elemento della guida stessa non lo fanno.

La delega dei diritti (un firmatario delegato con un assert SAML) non viene prodotta; una firma che ne trasporta uno viene segnalata come tale.

Source: github.com/biodream-llc/perfuse/internal/dsdr

26.36 e4x

Il pacchetto e4x fa eseguire lo script JavaScript di Mirth Connect senza modifiche.

Gli script Mirth sono scritti per Rhino, che implementa E4X: XML è un tipo nativo con una propria sintassi. Il motore qui è goja, che non lo fa, e il divario non è solo a runtime.

tre pezzi di E4X sono *sintassi*, quindi il parser di goja rifiuta il file tout court prima che qualsiasi modello di oggetto possa aiutare: per ogni (var seg in msg..OBX) { } // per-each, e l'operatore discendente var z = <ZZZ><ZZZ.1>valore</ZZZ.1></ZZZ>; // un letterale XML var id = node.@root; // un riferimento all'attributo

Questo file riscrive quelli in ECMAScript ordinario che goja analizza, lasciando la semantica al modello di oggetto runtime in xml.go. Tutto il resto di E4X - accesso alle proprietà per nome di elemento, indicizzazione delle ripetizioni, assegnazione, toString - è già una sintassi JavaScript valida e non richiede riscrittura.

La riscrittura viene eseguita con un lexer reale anziché con espressioni regolari, perché l'alternativa corrompe gli script funzionanti. Un modello per l'operatore discendente ne trova uno all'interno di "http://example.org", un modello per i letterali XML ne trova uno in "a < b && c > d", e uno script che cambia silenziosamente il significato è molto peggio di uno che rifiuta di caricarsi.

Source: github.com/biodream-llc/perfuse/internal/e4x

26.37 edifact

Il pacchetto edifact legge e scrive gli scambi UN/EDIFACT (ISO 9735): la stringa di servizio UNA, l'involucro di scambio UNB/UNZ, i gruppi funzionali UNG/UNE opzionali e i messaggi UNH/UNT, con il carattere di rilascio e, per la versione della sintassi 4, il separatore di ripetizione.

Verifica i conteggi e i riferimenti dell'intestazione, indirizza gli elementi di dati per i filtri, divide uno scambio in uno per messaggio e costruisce un ack di CONTRL.

Legge qualsiasi tipo di messaggio (ORDERS, INVOIC, IFTSTA, MEDRPT ...); non contiene i directory che specificano quali segmenti un tipo di messaggio può contenere, quindi controlla la struttura, non il contenuto.

Source: github.com/biodream-llc/perfuse/internal/edifact

26.38 uscita

Il pacchetto di uscita decide se questo motore può connettersi all'esterno a un indirizzo.

Esiste perché una destinazione può essere puntata ovunque e una combinazione la trasforma in un modo per leggere la rete interna: una destinazione SOAP con un trasformatore di risposta restituisce la risposta del ricevitore a uno script, quindi un editor può creare un canale che recupera un URL interno e scrive il corpo in un log o in un messaggio.

Dimostrato piuttosto che teorizzato: una destinazione SOAP rivolta a un server HTTP locale ha inserito il corpo della risposta del server in una riga di log del canale.

La risposta proporzionata non è quella di vietare le connessioni in uscita - consegnare messaggi agli endpoint configurati è l'intero scopo del software, e un editor è destinato a configurarli. È quella di rifiutare gli indirizzi specifici che non sono mai una destinazione di messaggio e sono sempre un archivio di credenziali.

Source: github.com/biodream-llc/perfuse/internal/egress

26.39 motore

Il pacchetto motore esegue canali configurati.

Un canale è una sorgente, un filtro e un set di destinazioni. Il lavoro del runtime è quello di essere onesto su cosa è successo a ogni messaggio: un ack di risposta dovrebbe significare ciò che la configurazione dice che significa, un messaggio che è stato filtrato dovrebbe essere distinguibile da uno che è stato consegnato, e un messaggio che non poteva essere consegnato dovunque non deve essere segnalato come accettato.

Source: github.com/biodream-llc/perfuse/internal/engine

26.40 epa

Il pacchetto epa è l'autorizzazione elettronica precedente alla prescrizione NCPDP SCRIPT, dal lato del pagatore: PAInitiationRequest, PARequest, PAAppealRequest e PACancelRequest in entrata, e le loro risposte in uscita.

La proposta CMS-0062-P prevede che i pagatori interessati supportino questo standard a partire dal 1 ottobre 2027, e Medicare Part D già lo richiede. Una richiesta viene decisa nel modo in cui ogni autorizzazione precedente alla prescrizione su questo server viene decisa: diventa una richiesta Da Vinci PAS (una richiesta di rimborso, la richiesta di medicazione e le risposte del prescrittore come una risposta al questionario) e va allo stesso file di regole, servizio di decisione e coda di revisione. La formularia dice quali farmaci richiedono una di queste e quali domande porre, dalla stessa domanda FHIR Da Vinci DTR.

Gli schemi NCPDP sono protetti da licenza. I nomi degli elementi e l'ordine seguiti qui seguono la guida companion pubblica Surescripts e i suoi esempi; due elementi che il materiale pubblico non mostra mai (il motivo all'interno di Closed e all'interno di Denied) seguono il modello SCRIPT utilizzato altrove e sono nominati nel manuale in modo che un pagatore possa controllarli contro la propria copia dello schema.

Source: github.com/biodream-llc/perfuse/internal/epa

26.41 eprescrizione

Il pacchetto eprescrizione legge e scrive NCPDP SCRIPT, lo standard in cui viaggiano le prescrizioni.

Denominato per ciò che fa piuttosto che per lo standard, perché internal/script è già il motore JavaScript e due pacchetti chiamati script in un albero è un errore che aspetta di essere fatto in una riga di importazione.

SCRIPT è XML, a differenza dello standard di telecomunicazione che trasporta la richiesta di rimborso risultante. Un prescrittore invia un NEWRX a una farmacia; la farmacia invia indietro RXFILL per dire cosa è successo, REFREQ per chiedere un rinnovo, o RXCHG per chiedere una modifica. Ognuno di questi è un messaggio qui.

Dove è il pericolo

Due campi in una prescrizione sono pericolosi quando letti in modo errato piuttosto che quando mancanti.

Le sostituzioni sono il primo. Uno zero significa che la sostituzione è consentita e un uno significa dispensare come scritto. Legge al contrario per chiunque si aspetti un flag dove uno significa sì, e sbagliare dispensa un generico dove il prescrittore ha richiesto il marchio - o rifiuta una sostituzione che era consentita, che è lo stesso errore che costa al paziente denaro invece. Quindi questo pacchetto rifiuta di indovinare: un elemento Substitutions assente è un errore piuttosto che un valore predefinito, perché entrambi i valori predefiniti sono errati.

Il numero di rinnovi è il secondo. Una prescrizione di classe II non può essere rinnovata affatto, e un sistema che trasporta un numero di rinnovi da un modello non controllato produce una prescrizione che sembra valida che una farmacia deve rifiutare.

Cosa non è stato verificato

La struttura del messaggio segue i nomi degli elementi SCRIPT pubblicati. Nessun messaggio da questo pacchetto è stato inviato attraverso una rete di routing reale come Surescripts, e la certificazione da parte di uno di questi è un processo commerciale piuttosto che tecnico. Questo analizza e costruisce il formato; non afferma di essere certificato.

Source: github.com/biodream-llc/perfuse/internal/eprescribe

26.42 equivalente

Package equiv dimostra che due motori concordano, o indica esattamente dove non concordano.

Questa è la risposta all'unica domanda che blocca effettivamente una migrazione. Un team di interfaccia non rifiuta un nuovo motore perché manca di funzionalità; lo rifiuta perché non può essere sicuro che farà la stessa cosa al traffico che già hanno, e sbagliare significa che i risultati dei test non raggiungono i medici. Nessun confronto delle funzionalità risponde a questa domanda. Le prove sì.

L'uso previsto è un'esecuzione parallela. Entrambi i motori ricevono gli stessi messaggi di produzione; il motore esistente continua a consegnare e Perfuse consegna a nessuno, che è ciò che già fanno i canali shadow. Dopo due settimane, i risultati vengono confrontati qui, e la conversazione cambia da "fidati di questo" a "ecco i tre messaggi su quattrocentomila dove abbiamo differito, e perché".

Il raggruppamento è l'intera funzionalità

Un confronto ingenuo di 400.000 messaggi produce 400.000 risultati e viene chiuso senza essere letto. Quasi ogni differenza reale ha una causa: un formato di data, un codice di struttura, un passaggio di trasformazione che nessuno ha portato oltre. Quindi le differenze vengono raggruppate per causa - il percorso nel messaggio e il tipo di differenza - e segnalate una volta con un conteggio. Tremila differenze da una causa sono un risultato, non tremila. Quella singola decisione è ciò che rende il rapporto leggibile, e un rapporto leggibile è la differenza tra una migrazione che procede e una che si blocca.

I valori vengono trattenuti per impostazione predefinita

Il traffico reale è il dato del paziente, quindi un rapporto di confronto è un posto in cui il PHI potrebbe essere esposto in un biglietto, un'e-mail o una diapositiva. Per impostazione predefinita, questo rapporto segnala percorsi, tipi e conteggi - mai valori. Ciò è sufficiente per trovare la causa: "MSH-7 differisce in 3.000 di 3.000 messaggi" dice a un analista che si tratta del formato di data senza mostrare una data.

I valori possono essere abilitati intenzionalmente, perché alla fine qualcuno deve vederne uno, e fingere il contrario significherebbe solo spingerli a uno strumento peggiore. È un opt-in esplicito e il rapporto dice chiaramente che contiene il contenuto del messaggio.

Source: github.com/biodream-llc/perfuse/internal/equiv

26.43 expr

Il binding HL7 v2.

Questa è la logica che un tempo viveva in linea in eval.go. Il comportamento non è cambiato - intenzionalmente, perché il filtro v2 è ciò che ogni canale HL7 esegue e lo scopo della grammatica generica era aggiungere formati, non alterare questo.

Source: github.com/biodream-llc/perfuse/internal/expr

26.44 fdlimit

Il pacchetto fdlimit scopre quanti descrittori di file questo processo può aprire e aumenta il limite se possibile.

Ciò esiste a causa della forma del fallimento che previene. Ogni connessione in entrata è un descrittore, e anche ogni consegna in uscita in volo. Un ricevitore che ha smesso di rispondere tiene un descrittore per l'intero budget di ritentativi - con i valori predefiniti, cinque tentativi con un timeout di trenta secondi più quindici secondi di backoff, quindi quasi tre minuti. Un paio di centinaia di connessioni contro un ricevitore bloccato sono quindi un paio di centinaia di descrittori trattenuti per minuti.

Eseguire il limite non produce un errore ordinato nel posto che è eseguito. Produce "troppi file aperti" da qualche altra parte: il database non può aprire il suo giornale, l'interfaccia web smette di accettare, un file di log non può essere scritto. Il motore sembra essere rotto in tre posti non correlati allo stesso tempo, e la vera causa è un sistema di partner che è diventato silenzioso. Questa è la richiesta di supporto che questo pacchetto esiste per evitare.

Due cose accadono all'avvio. Il limite morbido viene aumentato al limite rigido, che di solito rimuove il problema tout court - il limite morbido predefinito è spesso alcune centinaia mentre il limite rigido è decine di migliaia. Quindi, qualunque cosa sia disponibile viene segnalata, in modo che il motore possa limitare la propria concorrenza all'interno piuttosto che scoprirlo colpendolo.

Source: github.com/biodream-llc/perfuse/internal/fdlimit

26.45 fhirpath

Il pacchetto fhirpath valuta FHIRPath (HL7 FHIRPath N1, 2.0.0) su risorse FHIR tenute come JSON decodificato.

Non ha un modello FHIR: il tipo di un elemento è noto quando il JSON FHIR lo dice (un suffisso di un elemento di scelta, come valueQuantity, un resourceType di una risorsa) o dedotto dal valore JSON altrimenti. Ciò copre ciò che SQL su viste FHIR e misure di qualità CQL-free necessitano; la navigazione che dipende dal modello (il tipo di un primitivo quando non è una scelta) viene risposta dalla forma del valore.

Source: github.com/biodream-llc/perfuse/internal/fhirpath

26.46 fhirserver

Il pacchetto fhirserver implementa un server FHIR REST.

Ciò esiste perché l'estremità utile di un mapper v2-to-FHIR è da qualche parte per mettere il risultato. Essere in grado di convertire un messaggio è una demo; essere in grado di convertirlo, memorizzarlo e poi trovare nuovamente il paziente in base all'identificatore è un prodotto.

È un vero server FHIR nelle parti che contano per questo: una dichiarazione di capacità, creare, leggere, aggiornare, eliminare, cercare sui parametri che le persone utilizzano effettivamente e bundle di transazioni applicate atomicamente. Non è un server FHIR completo - nessuna storia, nessuna ricerca concatenata, nessun _include - e lo dice nella sua stessa dichiarazione di capacità piuttosto che lasciare che un client scopra le lacune.

Source: github.com/biodream-llc/perfuse/internal/fhirserver

26.47 formulary

Il pacchetto formulary è un formulary di farmaci di un pagatore: quali farmaci ogni piano copre, su quale livello e con quali limiti (autorizzazione preventiva, terapia a gradini, limiti di quantità) e cosa paga il membro.

Un file è l'unica fonte per tutto ciò che risponde a una domanda su un farmaco: l'API Da Vinci US Drug Formulary (pubblicata come FHIR), le risposte NCPDP Real-Time Prescription Benefit e l'autorizzazione elettronica NCPDP SCRIPT (se un farmaco ne necessita e quali domande porre). Un formulario che vive in tre luoghi risponderebbe alla stessa domanda in tre modi diversi.

Source: github.com/biodream-llc/perfuse/internal/formulary

26.48 strutturazione

Il framing del pacchetto legge e scrive messaggi su un flusso di byte che non è MLLP.

Perché esiste separatamente da mllp

MLLP è un framing: 0x0B prima, 0x1C 0x0D dopo. È ciò che HL7 v2 utilizza su TCP e Perfuse lo ha sempre parlato.

Molta attrezzatura non lo fa. Un analizzatore di laboratorio, una bilancia, un monitor da letto, un sistema di fatturazione più vecchio - ognuno tende ad avere la propria convenzione e le convenzioni sono tutte semplici variazioni sulle stesse tre idee: un delimitatore da qualche parte, una lunghezza di record fissa o una lunghezza scritta davanti al payload.

Il connettore TCP di Mirth copre questo e Perfuse non aveva nulla, quindi un sito con un flusso di socket che non era HL7 non poteva utilizzarlo affatto.

L'errore che questo pacchetto è scritto per evitare

La lettura da un flusso e l'indovinare dove finisce un messaggio è l'intero problema. Indovinare troppo breve e un messaggio viene tagliato a metà; indovinare troppo lungo e due messaggi arrivano come uno. Entrambi producono output che spesso sembra plausibile, il che è peggio di un errore, quindi ogni modalità qui è esplicita su cosa termina un messaggio e nessuna di esse ricorre a un'altra.

Un messaggio senza framing è una configurazione legittima - alcuni dispositivi aprono una connessione, inviano un messaggio e chiudono - ma non può essere combinato con nulla altro e non può essere utilizzato su una connessione che rimane aperta, quindi è nominato e convalidato piuttosto che trattato come predefinito.

Source: github.com/biodream-llc/perfuse/internal/framing

26.49 ftpconn

Il pacchetto ftpconn carica file tramite FTP e FTPS utilizzando solo la libreria standard.

FTP è vecchio, chiacchierato e non è un buon protocollo. È anche ancora il modo in cui molti sistemi ospedalieri accettano file, di solito perché l'estremità remota è un analizzatore di laboratorio o un servizio di bureau il cui software non è stato toccato dal momento in cui funzionava. Rifiutare di supportarlo non rende quei sistemi moderni; rende Perfuse inutilizzabile in quei siti.

Implementato qui piuttosto che preso come dipendenza per lo stesso motivo di S3: la lista di materiali di otto dipendenze è un argomento reale con chiunque esamini il software prima che un ospedale lo installi. Il canale di controllo FTP è testo orientato a riga su TCP, quindi questo è un paio di centinaia di righe di net e crypto/tls.

Cosa è supportato e cosa è rifiutato

Modalità passiva solo. La modalità attiva richiede al server di aprire una connessione di ritorno al client, che ogni firewall ospedaliero costruito questo secolo blocca, e offrirla significherebbe che le persone la configurano e poi eseguono il debug del firewall.

FTPS esplicito (AUTH TLS) è supportato ed è il valore predefinito quando si richiede TLS. FTPS implicito sulla porta 990 è anche supportato perché alcuni analizzatori parlano solo quello.

FTP semplice è supportato e avverte. Invia la password in chiaro e un sito che deve utilizzarlo dovrebbe essere informato una volta piuttosto che lasciato a scoprire da una cattura del pacchetto.

Source: github.com/biodream-llc/perfuse/internal/ftpconn

26.50 gcp

Il pacchetto gcp comunica con Google Cloud Pub/Sub e Cloud Storage tramite le loro API REST, con OAuth 2.0 di Google eseguito qui: una chiave di account di servizio firma un JWT (RS256, crypto/rsa) che viene scambiato per un token di accesso, o, su Google Cloud stesso, il server di metadati ne consegna uno.

Nessun SDK Google.

Gli emulatori (l'emulatore Pub/Sub, fake-gcs-server) non richiedono credenziali: impostare Endpoint e lasciare le credenziali vuote.

Source: github.com/biodream-llc/perfuse/internal/gcp

26.51 generate

Il pacchetto generate crea messaggi HL7 v2 sintetici.

Due utilizzi. Qualcuno che prova Perfuse ha bisogno di traffico a cui guardare e un test del canale ha bisogno di un fixture che sia abbastanza realistico da esercitare la cosa che viene testata. Un generatore è un'estensione a pagamento in Mirth, il che ti dice che le persone lo vogliono.

Tutto qui è inventato. I nomi provengono da un elenco fisso di nomi evidentemente fittizi, gli identificatori sono sequenziali all'interno di un'esecuzione e gli indirizzi sono inventati. Ciò non è una disclamazione, è la progettazione: un generatore che produceva nomi realistici alla fine li avrebbe inseriti in un fixture di test, in un rapporto di bug e poi in un repository.

Il realismo viene speso dove conta per i test e da nessun'altra parte. I timestamp hanno offset, i campi ripetuti si ripetono effettivamente, un nome a volte ha un'iniziale del secondo nome e a volte no, e circa un messaggio su dodici è deliberatamente scomodo: un campo opzionale mancante, un separatore insolito ma legale, un componente vuoto. Alimentare un canale solo con messaggi perfettamente formati ti dice molto poco.

Source: github.com/biodream-llc/perfuse/internal/generate

26.52 hl7dict

Il pacchetto hl7dict nomina i campi dei segmenti HL7 v2.

Esiste per uno schermo: un visualizzatore di messaggi che può dirti che PID-5.1 è il cognome del paziente invece di lasciarti contare i caret. Chiunque abbia debuggato un'interfaccia ha fatto quel conteggio a mano, ed è la fonte più comune degli errori di offset che mettono un valore nel campo sbagliato.

Non è l'intero standard. HL7 v2 ha centinaia di segmenti e migliaia di campi, e quelli qui sono quelli che appaiono nel traffico ADT, ORU, ORM e SIU. Un campo sconosciuto viene segnalato come sconosciuto invece di essere indovinato.

Source: github.com/biodream-llc/perfuse/internal/hl7dict

26.53 hl7v3

Il pacchetto hl7v3 legge i messaggi HL7 versione 3.

La versione 3 è una cosa diversa dalla versione 2 con lo stesso nome. La versione 2 è un flusso di segmenti delimitati da pipe il cui significato è posizionale; la versione 3 è XML generato da un modello di informazioni di riferimento, dove il significato è trasportato dai nomi degli elementi e da un piccolo set di tipi di dati che si ripetono ovunque. Quasi nulla si trasferisce tra i due al di là del vocabolario clinico.

Nella pratica, la versione 3 arriva in una delle due forme. O è un documento CDA, che è derivato dalla versione 3 e gestito dal pacchetto cda, o è una transazione IHE - in particolare PIX e PDQ v3, che è il modo in cui molti ospedali risolvono gli identificatori dei pazienti tra i sistemi. Questo pacchetto si concentra sul secondo.

Perché i tipi di dati vengono per primi

La cosa più conseguente sulla versione 3 è che un elemento può essere presente e esplicitamente nullo, con un motivo dichiarato. Una data di nascita che trasporta nullFlavor="ASKU" significa che il paziente è stato chiesto e ha rifiutato di rispondere. Una che trasporta nullFlavor="NAV" significa che il valore esiste ma non è disponibile al momento, quindi chiedere di nuovo potrebbe funzionare. Una che è semplicemente assente significa che nessuno ha registrato nulla.

Collassare questi in una stringa vuota è l'errore che questo pacchetto è progettato per prevenire. Non è una perdita cosmetica: un sistema a valle che riceve una data di nascita vuota dove la sorgente ha detto "paziente ha rifiutato" la tratterà probabilmente come dati mancanti da inseguire, e una corrispondenza demografica che avrebbe dovuto essere lasciata irrisolta viene risolta da un essere umano che indovina. Quindi ogni tipo di dati qui distingue assente, nullo-con-motivo e presente.

Source: github.com/biodream-llc/perfuse/internal/hl7v3

26.54 hl7xml

Il pacchetto hl7xml converte i messaggi HL7 v2 nel formato XML che Mirth Connect utilizza, e torna all'encoding ER7.

La forma non è una scelta di progettazione. Gli script di Mirth sono scritti contro l'output del suo serializzatore ER7-XML, quindi contengono espressioni come

msg['PID']['PID.5']['PID.5.1'].toString()

e la promessa che uno script esistente funziona invariato è mantenuta solo se l'albero che attraversa ha esattamente gli stessi nomi di elemento, annidamento e comportamento di ripetizione. Ogni decisione qui sotto è quindi "cosa fa Mirth", non "cosa sarebbe più ordinato".

I due che contano di più:

Ogni campo è avvolto in elementi di componente numerati anche quando il campo ha solo un componente, quindi PID-5 con il valore "Doe" produce ancora <PID.5><PID.5.1>Doe</PID.5.1></PID.5>. Gli script indicizzano direttamente a .1 costantemente e un albero che mette il testo sull'elemento del campo romperebbe quasi tutti.

MSH mantiene i numeri di campo HL7 standard, dove MSH-1 è il separatore di campo e MSH-9 è il tipo di messaggio. Il parser in internal/hl7 indice MSH con un offset perché il separatore occupa una posizione che nessun delimitatore divide, e quell'offset si ferma qui: uno script che dice MSH.9 significa il tipo di messaggio.

Source: github.com/biodream-llc/perfuse/internal/hl7xml

26.55 ibmmq

Il pacchetto ibmmq invia a e legge da code IBM MQ attraverso l'API REST di gestione della coda (mqweb), che IBM MQ 9.1.5 e successivi consegnano su ogni piattaforma, z/OS inclusa.

Non ha bisogno di una libreria client MQ: il protocollo MQI nativo è di IBM e non documentato, e l'API REST è il modo supportato per raggiungere MQ senza uno. (IBM MQ parla anche AMQP 1.0 su un canale AMQP; il connettore amqp di Perfuse copre quella rotta.)

La lettura è almeno una volta: il primo messaggio viene sfogliato, consegnato al chiamante e rimosso dal suo ID di messaggio solo una volta che il chiamante lo ha gestito. Un messaggio che non poteva essere gestito rimane nella coda, primo in linea.

Source: github.com/biodream-llc/perfuse/internal/ibmmq

26.56 identità

Trovare un messaggio per quello che si sa di esso, qualunque sia il formato in cui è arrivato.

La ricerca di contenuti esistenti corrisponde ai metadati, offre una corrispondenza di substring contro il payload e può valutare un'espressione di filtro - ma l'espressione è valutata solo contro HL7 v2, e ogni espressione richiede la conoscenza del percorso. Quindi trovare il traffico di un paziente significava conoscere che l'identità si trova in PID-3 in un messaggio di ammissione HL7 v2, in Patient.identifier in una risorsa FHIR, in (0010,0020) in un'istanza DICOM e in NM109 di un ciclo NM1*IL in una richiesta di rimborso 837. Quattro formati, quattro vocabolari, e durante un incidente il messaggio che si sta cercando potrebbe essere in uno qualsiasi di essi.

Questo pacchetto mappa un piccolo set di concetti - chi è il messaggio, quale visita, quale studio, quale richiesta di rimborso - nel posto in cui ogni formato li conserva, in modo che una ricerca possa essere effettuata per "MRN 12345" anziché per un percorso. I concetti sono deliberatamente pochi: sono le cose che le persone hanno effettivamente a portata di mano quando devono trovare un messaggio, che è un numero di una telefonata o un nome di una lamentela.

Perché l'estrazione avviene una volta, al momento della registrazione

L'alternativa è l'analisi dei payload al momento della query, che è ciò che fa la ricerca dell'espressione. Funziona e è onesto riguardo alla scansione limitata, ma non può rispondere a "ogni messaggio su questo paziente attraverso quattro feed e due mesi" senza leggere ogni riga. L'estrazione una volta in una tabella indicizzata lo trasforma in una ricerca di indice.

Questo è un aumento della privacy, ed è opzionale

I nomi e gli identificatori dei pazienti attualmente si trovano all'interno di una colonna di payload opaca. L'indicizzazione li rende interrogabili, che è lo scopo, e li rende anche elencabili, il che rappresenta un reale cambiamento di esposizione: un database che poteva essere solo cercato può ora essere interrogato con "elencare ogni paziente". Questa è una decisione per il sito, non per questo pacchetto, quindi l'estrazione è commutabile e ogni ricerca attraverso di essa viene registrata nel registro di audit dei dati sanitari.

Source: github.com/biodream-llc/perfuse/internal/identity

26.57 iis

Il pacchetto iis parla il trasporto condiviso da ogni registro di immunizzazione degli Stati Uniti: il servizio web SOAP dell'IIS del CDC.

Nel 2011, un gruppo di esperti convocato dal CDC e dall'American Immunization Registry Association ha scelto un'interfaccia SOAP per l'invio di messaggi HL7 v2 ai sistemi di informazione sull'immunizzazione, e i registri l'hanno adottata. Il WSDL è piccolo - due operazioni, connectivityTest e submitSingleMessage - e il messaggio HL7 (un VXU per segnalare un vaccino, un QBP^Q11 per chiedere la storia di un paziente) viaggia come testo escapato all'interno del corpo SOAP. La risposta torna indietro allo stesso modo: un ACK, o un RSP^K11 che trasporta la storia e la previsione.

La destinazione SOAP generica potrebbe essere configurata per farlo, ma ogni sito dovrebbe digitare la stessa busta, impostare correttamente lo spazio dei nomi, inserire le credenziali nel corpo anziché nell'autenticazione HTTP e quindi leggere l'acknowledgement HL7 dalla risposta per apprendere se il registro ha mantenuto il record. Un registro risponde a un vaccino rifiutato con HTTP 200 e un AR all'interno; trattare il 200 come un successo è il modo in cui le immunizzazioni falliscono silenziosamente nell'essere segnalate. Quindi questo pacchetto esegue la busta del CDC e valuta l'acknowledgement, una volta.

Cosa non fa: le credenziali dell'utente e della password del WSDL sono le credenziali dell'applicazione del registro e vengono inviate come dice il WSDL, nel corpo. Il TLS reciproco, dove un registro lo richiede, è l'impostazione TLS della destinazione come per qualsiasi chiamata HTTPS. Nulla di qui è specifico per uno stato; dove gli stati differiscono (ID della struttura richiesto o no, SOAP 1.1 accettato o no, avvertimenti inviati come AE) l'impostazione della destinazione lo dice.

Source: github.com/biodream-llc/perfuse/internal/iis

26.58 kafka

Kafka, come client piuttosto che come qualcosa da sostituire.

Un sistema sanitario che ha una colonna vertebrale di eventi ha una colonna vertebrale Kafka, e i sistemi costruiti nell'ultimo decennio pubblicano su di essa anziché su un broker JMS. Quindi questo connettore esiste per rendere Perfuse il bordo consapevole della sanità di qualcun altro piattaforma di eventi: legge i messaggi clinici dai topic e li pubblica sui topic, e deliberatamente non tenta di essere una piattaforma di streaming. La finestra, le join, l'elaborazione del flusso e i registri degli schemi sono l'ecosistema di Kafka e rimangono lì.

Perché una dipendenza, quando STOMP e MLLP sono stati scritti a mano

La regola dichiarata in questo repository è che una dipendenza deve comprare la capacità piuttosto che la convenienza, e deve essere puro Go in modo che un binario statico possa ancora essere compilato incrociato per ogni target. franz-go è puro Go e non porta alcun cgo, il che è stato verificato contro tutti e sei i target.

Il protocollo di Kafka non è STOMP. STOMP è un protocollo di testo che si adatta in poche centinaia di righe. Kafka è un protocollo binario versionato su circa settanta tipi di richiesta, e la parte che conta di più qui - i gruppi di consumatori - è un protocollo di coordinamento distribuito con fasi di join, sync, heartbeat e offset-commit e una danza di riavvio tra loro. Ottenere questo sottilmente sbagliato non produce un fallimento ovvio: produce una partizione che nessuno sta leggendo, o due consumatori che leggono la stessa partizione. In un flusso clinico, queste sono un risultato di laboratorio mancante e un ordine duplicato. Questa è la capacità, e non vale la pena scriverla a mano per risparmiare una dipendenza.

Source: github.com/biodream-llc/perfuse/internal/kafka

26.59 ldap

Il pacchetto ldap parla abbastanza LDAP per autenticare una persona e leggere i suoi gruppi.

Gli ospedali eseguono Active Directory quasi universalmente, e AD parla LDAP. OpenID Connect è la risposta migliore dove è raggiungibile - vedere internal/oidc, e la nota lì su Mirth che non ha single sign-on a nessun prezzo - ma un motore di integrazione spesso si trova su una VLAN isolata dove un browser non può raggiungere un provider di identità. È questo il motivo per cui esiste.

BER personalizzato invece di una dipendenza, per lo stesso motivo di DICOM e STOMP: la codifica è piccola e ciò che arriva su questo socket decide se qualcuno entra in un sistema che sposta dati dei pazienti.

encoding/asn1 nella libreria standard non è utilizzabile qui. Si concentra su DER e rifiuta i tag specifici del contesto e l'etichettatura implicita che LDAP utilizza in tutto, quindi le parti che contano dovrebbero comunque essere personalizzate.

Source: github.com/biodream-llc/perfuse/internal/ldap

26.60 casella postale

Il pacchetto casella postale legge la posta dai server IMAP4rev1 (RFC 3501) e POP3 (RFC 1939), accedendo con una password o con OAuth 2.0 (SASL XOAUTH2, come richiesto da Microsoft 365 e Gmail), e divide i messaggi (RFC 5322 e MIME) in modo che un allegato o il corpo del testo possa diventare un messaggio su un canale.

Solo ciò di cui un flusso in entrata ha bisogno: selezionare una casella postale, trovare la posta non letta, recuperarla interamente, quindi spostarla, contrassegnarla o eliminarla. Solo libreria standard; TLS è crypto/tls.

Source: github.com/biodream-llc/perfuse/internal/mailbox

26.61 mappatore

Il pacchetto mappatore suggerisce mapping dei campi tra sistemi con punteggi di confidenza.

Questo è un motore di mapping intelligente basato su regole. Nessun LLM, nessuna chiamata di rete, nessuna dipendenza esterna. Esegue offline nello stesso binario e non invia mai dati dei pazienti da nessuna parte.

Il motore combina più segnali - corrispondenza di stringhe fuzzy sui nomi dei campi, riconoscimento di modelli di identificatori sanitari, ricerche di sistemi di codici e dati storici di accettazione - in un singolo punteggio di confidenza per ogni suggerimento. Quando la confidenza è al di sotto di una soglia configurabile, il mappatore si astiene dal suggerire piuttosto che indovinare male, perché un mapping errato in sanità può instradare i dati nel campo sbagliato e ciò è un difetto di sicurezza per i pazienti.

L'astensione è la decisione di progettazione fondamentale. Un sistema che produce sempre una risposta addestra gli utenti a smettere di controllare, e la volta in cui è sbagliato nessuno se ne accorge fino a quando un risultato di laboratorio non finisce in un campo di nota. Un sistema che dice "Non so" costringe a una decisione umana esattamente quando è necessario l'intervento umano.

Source: github.com/biodream-llc/perfuse/internal/mapper

26.62 misura

Il pacchetto misura valuta le Misure FHIR (misure di qualità digitali) le cui criteri di popolazione sono FHIRPath, e scrive il risultato come un rapporto di misura FHIR: riassunto, individuale o elenco di soggetti, con stratificatori e un punteggio di proporzioni.

Ogni criterio viene valutato una volta per paziente, con l'attenzione su un Bundle del record del paziente (la sua compartimentazione) e queste variabili: %soggetto (il Paziente), %periodoInizio e %periodoFine (il periodo di misurazione, come DateTimes) e %"Periodo di misurazione" (lo stesso di un Periodo). I criteri in CQL vengono rifiutati con il motivo: Perfuse non ha un motore CQL.

Source: github.com/biodream-llc/perfuse/internal/measure

26.63 metriche

Il pacchetto metriche raccoglie ciò che il motore sta facendo e mantiene abbastanza storia per disegnarla.

Un motore di interfaccia viene monitorato, non solo eseguito. Quando un reparto dice che i risultati hanno smesso di arrivare venti minuti fa, la domanda è cosa è cambiato venti minuti fa, e ciò non può essere risposto dai contatori attuali da soli. Quindi questo mantiene serie invece di totali, in memoria, a risoluzione fissa.

Tre decisioni lo plasmano.

La latenza viene mantenuta come un istogramma piuttosto che come una media. Un tempo di consegna medio è quasi inutile in questo dominio: il numero che conta è se i pochi percentuali più lenti di messaggi sono abbastanza lenti da violare un impegno di consegna, e una media nasconde esattamente ciò. I bucket sono esponenziali e fissi al momento della costruzione, quindi la registrazione di una durata è un confronto e un incremento senza allocazione.

Le serie sono buffer anelli limitati, dimensionati quando il collector viene creato. Nulla qui cresce senza limiti, perché un motore di interfaccia esegue per mesi alla volta e un sistema di metriche che richiede un riavvio è peggiore di nessuno.

La cardinalità è limitata. Un valore di etichetta preso dai dati dei messaggi - un'applicazione di invio, ad esempio - può assumere migliaia di valori se qualcuno configura male un flusso, e le etichette illimitate sono il modo standard in cui il monitoraggio abbassa la cosa che monitora. Oltre il limite, i valori collassano in un bucket "altro" e il limite stesso viene segnalato.

Source: github.com/biodream-llc/perfuse/internal/metrics

26.64 mirth

Analisi Java per canali Mirth importati.

Perché esiste

Mirth esegue Rhino sulla JVM, quindi uno script Mirth può chiamare qualsiasi Java sul classpath, inclusi le classi del server Mirth. Perfuse esegue goja e non ha un runtime Java. Rifiuta quelle chiamate con un errore che nomina la classe - ma quel rifiuto si verifica quando lo script viene eseguito, il che per un connettore di origine significa quando arriva il primo messaggio reale.

Quindi una migrazione usata andare: l'importazione ha esito positivo in silenzio, il canale viene distribuito e il primo messaggio dalla rete fallisce. Una migrazione che sembra pulita e si rompe al primo traffico è peggiore di una che rifiuta alla porta, perché la persona che l'ha fatto ha già detto ai suoi colleghi che ha funzionato.

Trova quelle chiamate al momento dell'importazione e dice cosa fare per ognuna di esse.

Perché quattro verdetti e non due

"Utilizza Java" è un pezzo di informazione e quello sbagliato, perché il Java utilizzato da un canale Mirth reale rientra in gruppi con quantità di lavoro completamente diverse. All'incirca la metà di ciò che i siti scrivono effettivamente è SimpleDateFormat e HashMap, che JavaScript esegue in modo nativo. Una parte di esso è l'API di script documentata da Mirth, che Perfuse implementa già con gli stessi nomi. Un po' di esso vuole avviare e interrompere i canali, che Perfuse può fare tramite la sua API REST ma non espone agli script. E una parte di esso è un jar di vendor che non verrà mai eseguito qui.

Segnalare questi come un numero unico non dice nulla a un migratore su se il suo pomeriggio o il suo trimestre è in gioco.

Source: github.com/biodream-llc/perfuse/internal/mirth

26.65 mirthlive

Il pacchetto mirthlive trova i motori Mirth-family in esecuzione che i test di interoperabilità si connettono.

Mirth Connect ha smesso di essere open source alla versione 4.6 (marzo 2025). I siti che lo lasciano vanno in uno di tre posti: Mirth 4.5.2, l'ultima versione open, che continuano a eseguire; il motore di integrazione open, il fork ospitato da Eclipse; o BridgeLink, il fork di Innovar, che numera le sue versioni per anno (26.9.0). Un canale che Perfuse esporta deve essere caricato in tutti loro, e un canale che uno di loro esporta deve essere importato qui, quindi ogni test live viene eseguito una volta per motore che risponde.

I motori vengono trovati chiedendo, non configurati: ./scripts/interop-up.sh li avvia su porte fisse e un motore che non è in esecuzione viene segnalato come saltato invece di passare silenziosamente. PERFUSE_MIRTH_ENGINES sostituisce l'elenco, come coppie nome=url separate da virgole.

Solo i test importano questo. Vive al di fuori di un file _test.go perché due pacchetti lo condividono.

Source: github.com/biodream-llc/perfuse/internal/mirth/mirthlive

26.66 mpi

Il pacchetto mpi è un indice dei pazienti: prende i record dei pazienti da ogni sistema di origine (ognuno identificato dalla sua autorità di assegnazione e numero), decide quali appartengono alla stessa persona e assegna a ogni persona un identificatore aziendale (EUID).

Alcune corrispondenze si collegano da sole; quelle incerte attendono in una coda di revisione per una persona che prenda una decisione; ogni collegamento, scollegamento, fusione e decisione viene registrata con chi l'ha effettuata.

L'abbinamento è deterministico per primo (un identificatore da un sistema che il sito si fida di essere unico per persona, come un identificatore nazionale o un numero aziendale) e probabilistico altrimenti: pesi di Fellegi-Sunter su nome, data di nascita, sesso, codice postale, telefono e indirizzo, con Jaro-Winkler per i nomi. Non decide nulla di clinico: dice quali record sono la stessa persona, con le sue ragioni, per una persona che conferma quando non è sicuro.

Source: github.com/biodream-llc/perfuse/internal/mpi

26.67 mqtt

Il pacchetto mqtt è un client MQTT 3.1.1: connette (con TLS, un nome utente e una password, o un certificato client), pubblica a QoS 0 o 1, si iscrive e conferma ogni messaggio QoS 1 ricevuto solo una volta che il chiamante dice che è stato gestito.

Scritto contro lo standard OASIS MQTT 3.1.1 piuttosto che importato, come i protocolli di rete di Perfuse. La versione 3.1.1 è quella che ogni broker parla: Mosquitto, EMQX, HiveMQ, VerneMQ, il plugin MQTT di RabbitMQ, il canale di telemetria di IBM MQ, AWS IoT Core e Azure Event Grid.

Consegna: un messaggio ricevuto a QoS 1 viene confermato (PUBACK) solo quando Ack viene chiamato. Un chiamante che non può gestire un messaggio chiude la connessione invece; con una sessione persistente (CleanSession false) il broker invia nuovamente il messaggio, contrassegnato come duplicato, quando il client si riconnette. MQTT 3.1.1 non ha un rifiuto negativo, quindi questo è l'unico modo per chiedere nuovamente un messaggio.

Source: github.com/biodream-llc/perfuse/internal/mqtt

26.68 msgstore

Trovare un messaggio archiviato in base a ciò che qualcuno sa su di esso.

La ricerca che una persona effettivamente necessita è "eccomi un numero da una chiamata telefonica, mostrami ogni messaggio su di esso". Prima di questo, significava o una corrispondenza di substring sui payload, che è grep e lento, o un'espressione di filtro, che richiede di sapere che l'identità vive a PID-3 in HL7 v2 e da qualche altra parte nel formato delle altre tre sullo stesso server.

L'identità viene estratta una volta quando il messaggio viene registrato e indicizzato, quindi questo è un lookup piuttosto che uno scan. Il costo viene pagato sul percorso di registrazione, una volta per messaggio, invece di su ogni ricerca.

Source: github.com/biodream-llc/perfuse/internal/msgstore

26.69 natid

Il pacchetto natid conosce gli identificatori nazionali dei pazienti e delle persone del Regno Unito e dell'Europa: i loro formati, i loro cifrari di controllo, il sistema di identificatori che le guide FHIR di ogni paese li chiamano e quanto di uno può essere mostrato.

Esiste per l'indice dei pazienti. Un numero nazionale è la prova più forte che due record sono una persona, e anche il più facile da sbagliare: un cifra digitata due volte dà un numero che appartiene a qualcun altro, e una fonte invia il numero NHS sotto un OID mentre un'altra lo invia sotto il suo URL FHIR. Quindi ogni identificatore che l'indice archivia passa attraverso di esso: il suo cifra di controllo viene testato (un cifra di controllo errato non viene mai utilizzato per collegare), lo spazio viene rimosso e il sistema viene scritto in un modo unico.

Ciò che viene verificato e ciò che non lo è viene detto per schema. Gli algoritmi sono pubblici; gli URI del sistema di identificatori sono quelli del paese stesso quando una guida FHIR nazionale ne nomina uno (SystemVerified), e un valore predefinito documentato altrimenti, che un sito può modificare nel proprio valore nazionale in Impostazioni → Indice dei pazienti. Nulla qui decide nulla di clinico.

Source: github.com/biodream-llc/perfuse/internal/natid

26.70 ncpdp

Scrivere un campo in una trasmissione NCPDP.

Perché una scrittura rifiuta un percorso ambiguo

La lettura restituisce ogni valore che un percorso indirizza, perché un filtro che chiede se esiste un conflitto DUR dovrebbe vedere tutti. Una scrittura non può funzionare in questo modo. Se D7 indirizza i codici prodotto di due richieste in una trasmissione, impostare D7 non ha un significato univoco: scrivere entrambi cambierebbe un farmaco che nessuno ha chiesto, e scrivere il primo silenziosamente lascerebbe il secondo.

Quindi una scrittura rifiuta un percorso che indirizza più di un campo, e l'errore nomina la forma qualificata che sarebbe inequivocabile. Questo è lo stesso ragionamento che dà i passaggi di trasformazione senza azione di rimozione: dove la risposta onesta è che la configurazione è ambigua, dire così è meglio che scegliere uno.

Source: github.com/biodream-llc/perfuse/internal/ncpdp

26.71 oidc

Il pacchetto oidc verifica le identità OpenID Connect.

Scritto contro la libreria standard piuttosto che una dipendenza JWT. L'autenticazione è il posto in cui una dipendenza non verificata è meno accettabile, la verifica della firma per gli algoritmi che contano è di circa cento righe di crypto/rsa e crypto/ecdsa, e Perfuse già trasporta abbastanza per aggiungere altro senza un motivo valido.

L'ambito è deliberatamente limitato: verificare che un fornitore di identità abbia garantito per una persona e riportare cosa ha detto su di loro. Tutto il resto - cosa possono fare, quanto dura la sessione - rimane con Perfuse, perché un fornitore di identità sa chi è qualcuno e non cosa è consentito fare in un motore di integrazione.

Source: github.com/biodream-llc/perfuse/internal/oidc

26.72 parity

Il pacchetto parity confronta ciò che Perfuse produce con ciò che il motore sostituito produce.

Perché esiste

Perfuse può importare un canale Mirth e può tracciare cosa farebbe con un messaggio. Nessuna di queste due cose risponde alla domanda che qualcuno ha realmente prima di spostare un flusso live, che è: produrrà lo stesso output della cosa che è stata in esecuzione per sei anni?

Nessuna quantità di qualità del design risponde a questa domanda. La sola risposta onesta è l'evidenza, e l'evidenza deve provenire dal proprio output del motore vecchio sul traffico del sito.

Perché le coppie devono essere fornite

Questo non può raggiungere Mirth, e fingere il contrario sarebbe il peggior tipo di funzionalità. Ciò che richiede sono coppie: un messaggio come è arrivato e il messaggio che il motore vecchio ha prodotto da esso. Entrambi si trovano nel negozio di messaggi di Mirth e possono essere esportati dal browser dei messaggi di Mirth, che è una cosa che un amministratore già sa come fare.

Questo vincolo è dichiarato piuttosto che nascosto. Uno strumento che afferma di verificare una migrazione senza mai vedere l'output del motore vecchio starebbe verificando nulla.

Perché le differenze sono raggruppate e non elencate

Un'esecuzione su cinquantamila messaggi che segnala quattromila differenze non ha detto nulla che si possa utilizzare. La stessa esecuzione che segnala che PID-8 differisce in ogni messaggio perché il motore vecchio ha mappato M su Maschio ha detto esattamente una cosa da decidere.

Quindi i risultati sono raggruppati per campo, con un conteggio, un esempio e le coppie di valori distinti visualizzate. Una decisione per risultato è l'unità che qualcuno può lavorare.

Source: github.com/biodream-llc/perfuse/internal/parity

26.73 pas278

Il pacchetto pas278 mappa tra l'autorizzazione preventiva Da Vinci e la transazione X12 278.

Perché esiste

CMS-0057-F richiede ai pagatori di esporre un'API di autorizzazione preventiva FHIR entro il 1° gennaio 2027. Non sostituisce la transazione X12 278 e non lo farà: il sistema di gestione dell'utilizzo di un pagatore decide le autorizzazioni e parla 278. Quindi un pagatore che incontra la regola sta traducendo FHIR in 278 e viceversa, e un fornitore che invia 278 oggi invierà FHIR domani ai pagatori che accettano ancora entrambi.

Quella traduzione è la cosa più importante da possedere. Un motore che tiene entrambi i modelli e non può convertire tra loro lascia la parte più difficile del lavoro - e la parte in cui gli errori sono costosi - a chi sta integrando.

Le regole che questo pacchetto segue, dichiarate piuttosto che implicite

Scritte per lo stesso motivo per cui v2fhir scrive le proprie: la mappatura è dove i progetti di interoperabilità falliscono, e i fallimenti sono silenziosi.

Source: github.com/biodream-llc/perfuse/internal/pas278

26.74 pdf

Il pacchetto pdf scrive documenti di testo semplici, utilizzando solo la libreria standard.

Il writer di documenti di Mirth rende HTML in PDF, che necessita di un motore di layout. Questo non è ciò che questo pacchetto fa. Questo produce un documento di testo semplice e paginato con un font a larghezza fissa, ed esiste perché il requisito effettivo in quasi tutti i siti che utilizzano quel connettore è "metti questo report su una condivisione in modo che qualcuno possa stamparlo" - una sintesi di dimissione, un report di risultati, una riconciliazione giornaliera. Quelli sono testi.

Rifiutare completamente la funzionalità lascerebbe un blocco di migrazione di livello 2 in place. Includere un motore di rendering HTML costerebbe più di tutto il resto del binario e porterebbe con sé un flusso di CVE, che annullerebbe l'argomento della lista dei materiali. Quindi: testo, descritto onestamente come testo, e un sito che ha realmente bisogno di output composti è meglio servito da una destinazione di file e da uno strumento costruito per esso.

Perché scrivere un PDF invece di un file di testo

Perché l'estremità ricevente è di solito una persona con una stampante e una condivisione Windows, e un file .txt stampato da una condivisione perde la paginazione, i margini e spesso le terminazioni di riga. Un PDF si stampa allo stesso modo ovunque, che è il motivo per cui qualcuno ha chiesto uno.

Source: github.com/biodream-llc/perfuse/internal/pdf

26.75 pgp

Il pacchetto pgp crittografa, firma, decrittografa e verifica i messaggi OpenPGP (RFC 9580, e RFC 4880 per i peer più vecchi), per i pagatori, le agenzie di compensazione e le agenzie statali che scambiano file tramite SFTP o email sotto PGP.

La crittografia è github.com/ProtonMail/go-crypto, il fork mantenuto di golang.org/x/crypto/openpgp; nulla qui implementa un primitivo. Questo pacchetto carica solo le chiavi e decide cosa un messaggio deve trasportare.

Source: github.com/biodream-llc/perfuse/internal/pgp

26.76 pixv3

Il pacchetto pixv3 è il volto HL7 versione 3 dell'indice dei pazienti: i profili IHE Patient Identifier Cross-referencing e Patient Demographics Query, poiché la maggior parte degli ospedali al di fuori del mondo FHIR li parla ancora.

Le risposte provengono dallo stesso indice dei pazienti di PIXm, PDQm, Patient/$match e lo schermo dell'indice, quindi un record alimentato in v3 viene trovato su FHIR e viceversa. I messaggi sono scritti a mano, nell'ordine dello schema, per il motivo hl7v3.Ack.

Source: github.com/biodream-llc/perfuse/internal/pixv3

26.77 priorauth

Il pacchetto priorauth implementa il flusso di lavoro di autorizzazione preventiva richiesto dal provider CMS-0057. Invia richieste di autorizzazione preventiva alle API FHIR dei pagatori, tiene traccia delle risposte e converte tra tipi interni e risorse FHIR.

Source: github.com/biodream-llc/perfuse/internal/priorauth

26.78 privacy

Il pacchetto privacy risponde alle richieste di un soggetto dei dati ai sensi del GDPR e del GDPR del Regno Unito: trovare tutto ciò che questo server tiene su una persona, darlo loro (Articoli 15 e 20), cancellarlo (Articolo 17) e mantenere ciò che una presa legale copre.

Raggiunge ogni luogo in cui Perfuse mantiene i dati dei pazienti: l'archivio dei messaggi (attraverso il suo indice di identità), la coda di consegna, l'archivio FHIR (le risorse Patient della persona e tutto ciò che si riferisce a loro, con la loro storia), le richieste di autorizzazione preventiva archiviate, e l'indice del paziente, i cui collegamenti allargano un identificatore in tutti i numeri della persona. Ciò che non può raggiungere lo nomina: tracce inviate a un collector, il registro di controllo (mantenuto, come il record di chi ha fatto cosa), e i backup, che mantengono ciò che è stato cancellato fino a quando non scadono - quindi ogni cancellazione viene scritta su un registro, come hash salati degli identificatori piuttosto che degli identificatori, e può essere applicata nuovamente a una copia ripristinata.

Non decide nulla per conto di nessuno. Se una richiesta deve essere concessa, e se si applica un'esenzione, è la decisione del controller; la cancellazione richiede l'approvazione di un secondo amministratore, e una presa legale rifiuta di concederla.

Source: github.com/biodream-llc/perfuse/internal/privacy

26.79 publichealth

Il pacchetto publichealth implementa la segnalazione sanitaria pubblica bidirezionale: segnalazione di casi elettronica (eCR), segnalazione di laboratorio elettronica (ELR) e query del registro di immunizzazione.

Ogni ospedale è obbligato per legge a segnalare determinate condizioni - tubercolosi, morbillo, epatite, COVID-19, infezioni sessualmente trasmissibili, malattie trasmesse da alimenti - alle agenzie di sanità pubblica statali e locali. La segnalazione avviene attraverso tre interfacce distinte:

Il pacchetto è bidirezionale: segnala all'esterno (ELR, eCR, VXU) e interroga all'indietro (VXQ/VXR). Tutte le operazioni sono in tempo reale piuttosto che in batch notturno.

Sicurezza del thread: SubmissionLog è sicuro per l'uso concorrente. Le funzioni del costruttore sono pure e sicure da chiamare da qualsiasi goroutine.

Source: github.com/biodream-llc/perfuse/internal/publichealth

26.80 published

Il pacchetto published contiene le guardie per i pacchetti importabili di Perfuse, in un unico posto.

hl7 è stato il primo pacchetto pubblicato e trasporta la sua copia di questi controlli. fhir e pas sono stati pubblicati in modo che un servizio di decisione come Vaglio legga le richieste FHIR e PAS con esattamente il codice che Perfuse utilizza, piuttosto che una copia che deriva: quattro lettori dei codici di azione X12 in questo repository una volta discordavano, e uno leggeva un rifiuto come un'approvazione. Le guardie sono mantenute qui piuttosto che copiate in ogni pacchetto, per lo stesso motivo.

Source: github.com/biodream-llc/perfuse/internal/published

26.81 queue

Il pacchetto queue è una coda di consegna durevole, per destinazione.

Senza di esso, una destinazione che è down per due minuti perde tutto ciò che le viene inviato durante quei due minuti: le ritentive avvengono in memoria e quando si esauriscono il messaggio viene registrato come non riuscito e perso. Con esso, il messaggio è su disco e mantiene la sua posizione fino a quando la destinazione non torna online.

Due decisioni di progettazione influenzano tutto il resto.

L'ordine è preservato per destinazione, e ciò significa che una destinazione in coda smette di utilizzare il percorso veloce. HL7 è un flusso di eventi relativi agli stessi pazienti: un A01 ammette, un A03 dimette. Se un A01 non riuscito va in coda mentre il successivo A03 viene consegnato direttamente, il sistema di ricezione vede una dimissione per un paziente che non è mai stato ammesso. Quindi, una volta che qualcosa è in coda per una destinazione, tutto per quella destinazione si mette in coda dietro di esso fino a quando la coda non si svuota. Ciò costa throughput durante un'interruzione e non è opzionale, perché l'alternativa è un nonsenso clinico silenzioso. È anche la cosa specifica che va storta in altri motori quando qualcuno attiva i thread di coda concorrenti per far svuotare più velocemente un backlog.

Un messaggio in coda è un messaggio accettato. Il mittente viene informato con AA, perché i byte sono su disco e fsynced prima che la conferma venga inviata. Dire AE renderebbe una coda store-and-forward funzionante correttamente come un guasto e inviterebbe il mittente a rinviare ciò che già possediamo.

Source: github.com/biodream-llc/perfuse/internal/queue

26.82 residenza

La residenza del pacchetto dice dove possono andare i dati di questo server: le regioni cloud che un sito consente (l'EEA, il Regno Unito, la Svizzera o regioni nominate una per una) e se la regione di un connettore è una di esse.

Perfuse controlla ciò che può sapere. Un connettore AWS nomina la sua regione (S3, SQS, SNS) e un hostname AWS porta una regione (sqs.eu-west-2.amazonaws.com); queste vengono controllate quando un canale viene salvato e caricato, quindi un canale non può inviare dati di pazienti a un bucket in Virginia da un server il cui dati devono rimanere a Francoforte. Un hostname semplice (il sistema di un ospedale, il listener MLLP di un partner) non dice nulla su dove si trova e non viene giudicato qui: il record di elaborazione elenca ogni host a cui un canale invia, per il controller che controlla.

Source: github.com/biodream-llc/perfuse/internal/residency

26.83 rtpb

Il pacchetto rtpb risponde alle richieste di beneficio per prescrizione in tempo reale di NCPDP da un formulary: quanto costa un farmaco a questo membro in questa farmacia, se necessita di un'autorizzazione preventiva o di un passo prima e quali alternative costano meno.

La proposta CMS-0062-P prevede RTPB per i pagatori interessati dal 1 ottobre 2027. L'XML è NCPDP RTPB v13 (PBv13). Lo schema NCPDP è concesso in licenza, quindi i nomi degli elementi e l'ordine seguono gli esempi pubblici di Surescripts RTPB e le Raccomandazioni di implementazione pubbliche di NCPDP (codici di restrizione di copertura e lo stato di copertura a cui ciascuno si riferisce); una risposta non viene controllata contro lo XSD qui e una certificazione di rete è dove ciò avviene.

Source: github.com/biodream-llc/perfuse/internal/rtpb

26.84 s3put

Il pacchetto s3put scrive oggetti su S3 utilizzando solo la libreria standard.

Il modo ovvio per comunicare con S3 è l'SDK di AWS e l'SDK è enorme. Questo progetto vende un binario statico con otto dipendenze dirette e un elenco dei materiali che si adatta a uno schermo - ciò è un argomento reale con la persona che esamina il software prima che un ospedale lo installi e scambiarlo per un connettore sarebbe un cattivo affare.

Ciò di cui S3 ha effettivamente bisogno è un HTTP PUT e una firma. La versione 4 della firma è completamente specificata, è deterministica e AWS pubblica vettori di test per essa. Quindi è implementata qui: circa duecento righe contro crypto/hmac e net/http, senza nuove dipendenze e nulla da patchare quando l'SDK ha un advisory.

Ciò che questo fa deliberatamente non

Nessun upload multiparte, nessuna ritentiva propria, nessuna catena di credenziali oltre le chiavi statiche e le variabili di ambiente standard. Un messaggio HL7 è di kilobyte, quindi l'upload multiparte risolve un problema che non esiste; il motore già ritenta; e una catena di credenziali di istanza-ruolo significherebbe chiamate IMDS, caching e logica di aggiornamento, che è dove un'implementazione piccola smette di essere piccola. Se qualcuno ne ha bisogno, la risposta onesta è una destinazione file e uno strumento di sincronizzazione, non un SDK a metà costruito.

Funziona con qualsiasi cosa che parli l'API S3 - MinIO, Ceph, Wasabi, Backblaze - perché è solo HTTP firmato. Ciò è un effetto collaterale che vale la pena avere, poiché un archivio di oggetti di un ospedale spesso non è AWS.

Source: github.com/biodream-llc/perfuse/internal/s3put

26.85 saml

Canonicalizzazione XML esclusiva (exc-c14n) in base a https://www.w3.org/TR/xml-exc-c14n/

Questa è la forma canonica esatta dei byte che una firma XML firma. Sbagliare significa che le firme valide appaiono non valide e - peggio - un'implementazione che la ottiene per lo più giusta passerà nel test contro le proprie firme mentre rifiuterà le risposte reali di IdP.

Le regole che contano per SAML: - Le dichiarazioni di namespace vengono rese solo se visibilmente utilizzate dall'elemento o dai suoi attributi. - I namespace ereditati che un elemento utilizza ma non dichiara vengono resi come se dichiarati su quell'elemento. - Gli attributi vengono ordinati: dichiarazioni di namespace prima (ordinate per prefisso), poi altri attributi (ordinati per nome esteso: URI di namespace quindi nome locale). - Gli elementi vuoti utilizzano start-tag/end-tag, mai self-closing. - I nodi di testo vengono output verbatim; CDATA viene sostituito dal suo contenuto con escaping di entità. - Le istruzioni di elaborazione e i commenti all'esterno dell'elemento del documento vengono esclusi.

Source: github.com/biodream-llc/perfuse/internal/saml

26.86 scim

Il pacchetto scim implementa SCIM 2.0, il protocollo che i provider di identità utilizzano per provisionare account.

Okta, Entra ID, Google Workspace e OneLogin lo supportano tutti. Un amministratore aggiunge qualcuno a un gruppo nel provider di identità e, entro un minuto, appare un account qui con il ruolo giusto. Lo rimuovono e l'account scompare.

La disattivazione è il punto

La provisione è una comodità. La disattivazione è il motivo per cui vale la pena costruire questo e è la metà che va storta.

Quando qualcuno lascia un'organizzazione, il provider di identità è il sistema che lo sa per primo - di solito perché il reparto risorse umane lo termina e il provider è gestito dal record del reparto risorse umane. Quindi informa ogni applicazione connessa di disabilitare l'account. Se la chiamata fallisce o ha successo senza effettivamente rimuovere l'accesso, un ex dipendente mantiene l'accesso a un motore di integrazione clinica e nessuno lo scopre, perché nulla sta monitorando una cosa che non è successa.

Quindi le parti di questo pacchetto che contano di più sono quelle che rendono la disattivazione reale:

Perché è un pacchetto separato

Le forme di SCIM non sono quelle di Perfuse. Ha il proprio formato di errore, la propria busta di elenco, il proprio linguaggio di patch e le proprie opinioni sulla casistica degli attributi. Mantenere la traduzione in un solo posto significa che i gestori possono occuparsi di ciò che accade a un account piuttosto che del JSON.

Source: github.com/biodream-llc/perfuse/internal/scim

26.87 script

Lo script del pacchetto esegue JavaScript di Mirth Connect.

L'obiettivo è che gli script di un canale si spostino senza essere toccati. È un esercizio di compatibilità, non di progettazione, quindi la forma di tutto ciò è dettata da ciò che Mirth espone: msg e tmp come alberi E4X, sei mappe con metodi Map di Java, la famiglia di funzioni di lookup $, logger e un certo numero di oggetti di utilità il cui nome del metodo e stringa di formato data sono di Java.

Tre decisioni sono nostre piuttosto che di Mirth e ognuna è una deviazione deliberata:

Uno script viene eseguito con una scadenza e viene interrotto quando la supera. Mirth lascerà che uno script si blocchi all'infinito, il che porta via il canale con esso; un'interfaccia che smette di accettare ammissioni a causa di un errore di battitura in un trasformatore non è accettabile, quindi c'è sempre un timeout.

L'interoperabilità Java viene rifiutata con un errore che nomina la classe, piuttosto che restituire undefined. Uno script che si estende a Packages.java.sql non può essere fatto funzionare qui e il risultato utile è un messaggio che dice esattamente ciò alla riga in cui si verifica, non un NullPointerException tre righe dopo.

L'accesso ai file e al database è disattivato a meno che un canale non lo attivi. Mirth concede entrambi a ogni script per impostazione predefinita. Un trasformatore che può leggere qualsiasi file che il processo possa leggere è una cosa ragionevole da volere e una scelta predefinita irragionevole.

Source: github.com/biodream-llc/perfuse/internal/script

26.88 impostazioni

Le impostazioni del pacchetto sono la descrizione unica di tutto ciò che riguarda un server Perfuse che un operatore può modificare.

Perché esiste

Prima di questo pacchetto, circa trenta cose erano flag della riga di comando e nulla più. Modificare la durata di conservazione dei messaggi significava modificare una definizione di servizio e riavviare, il che in un ospedale significa un ticket di modifica - quindi, nella pratica, nessuno li modificava e un valore predefinito scelto nel primo pomeriggio diventava l'impostazione per sempre.

Perché un registro piuttosto che un modulo

Il modo ovvio per costruire una pagina di impostazioni è scrivere il modulo. Ciò produce due descrizioni di ogni impostazione - una nel server che la convalida e una nell'interfaccia che la rende - e queste descrizioni divergono. La divergenza è silenziosa: un campo che il server ha smesso di accettare ha ancora un controllo, quindi qualcuno lo imposta, lo vede salvato e non fa nulla.

Quindi un'impostazione viene dichiarata una volta, qui, con tutto il necessario per controllarla e disegnarla: che tipo di valore è, quale controllo gli si adatta, a quale gruppo appartiene, cosa significa e se la modifica ha effetto ora. L'interfaccia chiede quella descrizione e rende qualsiasi cosa le venga detto. Aggiungere un'impostazione è una voce in questo pacchetto e nessun lavoro sull'interfaccia.

TestEverySettingIsFullyDescribed impone le parti che un essere umano deve fornire, perché un'impostazione senza testo di aiuto è un'impostazione a cui qualcuno deve indovinare.

Perché un file piuttosto che il database

Le impostazioni vivono in un file YAML che l'interfaccia modifica in-place, corrispondente a come i canali e le regole di allarme già funzionano. Tre motivi, in ordine di peso: il controllo dei cambiamenti di un ospedale vuole una configurazione che possa essere diffusa e inserita nel controllo di versione; un operatore con la macchina ma non l'applicazione può leggere un file e non può leggere un database; e il ripristino delle impostazioni di ieri non dovrebbe richiedere che l'applicazione funzioni.

Perché i flag solo lo inizializzano

Il file vince una volta che esiste e le flag forniscono i contenuti iniziali. L'alternativa - le flag vincenti sempre - renderebbe l'interfaccia un bugiardo, poiché qualsiasi cosa passata sulla riga di comando potrebbe essere modificata e salvata e ignorata silenziosamente.

Una flag che non è d'accordo con il file viene segnalata all'avvio, nominando entrambi i valori, perché altrimenti la flag rimane nella definizione del servizio per anni e la prossima persona che la legge crede che sia vera.

Source: github.com/biodream-llc/perfuse/internal/settings

26.89 sftpconn

Il pacchetto sftpconn apre connessioni SFTP.

Diviso dai connettori perché la parte interessante è l'autenticazione e la verifica della chiave host, e entrambe sono identiche sia che un canale stia raccogliendo file che scrivendoli. Due copie si discosterebbero e la metà che si discosterebbe sarebbe la metà che ha smesso di verificare.

Source: github.com/biodream-llc/perfuse/internal/sftpconn

26.90 ombra

Il pacchetto shadow confronta un canale candidato con quello live.

Il confronto stesso è la parte facile. Il valore completo è in due garanzie, e entrambe sono enforce dalla costruzione piuttosto che dalla configurazione:

Qualsiasi cosa meno di questo e la modalità ombra diventa un modo per rompere la produzione mentre si tenta di evitare di rompere la produzione.

Source: github.com/biodream-llc/perfuse/internal/shadow

26.91 shl

Il pacchetto shl implementa SMART Health Links e SMART Health Cards: i codici QR di CMS "Kill the Clipboard" che chiedono ai fornitori di accettare al check-in e di restituire con il record della visita.

Un link di salute SMART (SMART Health Links STU 1) è shlink:/ seguito da JSON in base64url: un URL di manifesto, una chiave a 256 bit e opzionalmente una scadenza, un'etichetta e flag (P passcode, L a lungo termine, U un singolo file tramite GET). Il ricevitore invia una richiesta al URL del manifesto e ottiene file, ognuno crittografato con quella chiave - alg dir, enc A256GCM, opzionalmente compresso con DEFLATE - che contiene JSON FHIR, carte di salute SMART o un token di accesso SMART. Il server che ospita i file non vede mai la chiave: viaggia solo nel link, che è del paziente.

Una carta di salute SMART (SMART Health Cards Framework 1.4) è un bundle FHIR firmato: un JWS compatto, ES256, con un payload compresso con DEFLATE che nomina l'emittente, la cui chiave pubblica è in <iss>/.well-known/jwks.json. Viaggia come un codice QR numerico shc:/ o un file .smart-health-card.

Solo la libreria standard: crypto/aes, crypto/cipher, crypto/ecdsa e compress/flate coprono tutto, e una libreria JOSE porterebbe una superficie molto più grande per due algoritmi.

Source: github.com/biodream-llc/perfuse/internal/shl

26.92 smartauth

Il pacchetto smartauth è un server di autorizzazione per l'avvio dell'app SMART: emette i token di accesso che il endpoint FHIR di Perfuse accetta.

Scritto contro la libreria standard, come internal/oidc, che verifica ciò che questo firma. I token sono JWT firmati RS256, l'unico algoritmo su cui ogni client SMART e le regole del token ID della specifica possono fare affidamento.

Source: github.com/biodream-llc/perfuse/internal/smartauth

26.93 snmp

Il pacchetto snmp è un agente SNMPv2c di sola lettura: GET, GETNEXT e GETBULK su UDP contro una tabella di valori che il chiamante riempie, e trappole SNMPv2.

I messaggi sono codificati BER (X.690) qui; nulla in esso è crittografia (la stringa di comunità v2c è una password in testo normale, che è il motivo per cui l'agente risponde solo alle reti a cui è stato detto di farlo).

Source: github.com/biodream-llc/perfuse/internal/snmp

26.94 soap

Il pacchetto soap invia richieste SOAP e legge errori SOAP, utilizzando solo la libreria standard.

SOAP è una quantità di cerimonia intorno a un POST HTTP, e ancora è il modo in cui una grande quantità di middleware ospedaliero accetta i dati - sistemi di amministrazione dei pazienti, repository di documenti, servizi di registrazione regionale, qualsiasi cosa specificata nel decennio in cui questo era la risposta. Mirth ha un connettore di servizio Web, quindi questo è un blocco di migrazione di livello 2 piuttosto che un optional.

Perché non un client generato

L'approccio usuale è prendere un WSDL e generare tipi Go da esso. Questo è la risposta giusta per un'applicazione che parla con un servizio noto, e la risposta sbagliata qui: la destinazione di un motore di integrazione è configurata da qualcuno che modifica un canale, non ricompilato, quindi l'involucro deve essere assemblato al momento dell'esecuzione da un modello che può vedere e modificare. Ciò significa anche che non c'è un passaggio di generazione del codice e nulla da rigenerare quando l'estremità remota pubblica un nuovo WSDL.

Ciò che questo fa deliberatamente non

Nessun parsing WSDL, nessun WS-Security, nessun MTOM, nessun WS-Addressing. Ognuno di questi è una specifica a sé stante e fingere di supportarne uno mentre si commette un errore è peggio che non offrirlo affatto - una firma che quasi verifica è indistinguibile da un attacco all'estremità opposta. Il WS-Security in particolare è dove un'implementazione parziale potrebbe causare danni reali.

Ciò che è presente: buste SOAP 1.1 e 1.2, un corpo template, l'intestazione SOAPAction e la rilevazione degli errori che legge la stringa di errore anziché segnalare "500".

Source: github.com/biodream-llc/perfuse/internal/soap

26.95 sof

Il pacchetto sof esegue SQL su FHIR v2 ViewDefinitions: una vista trasforma ogni risorsa FHIR di un tipo in righe di colonne nominate, tramite FHIRPath, in modo che i dati FHIR possano essere letti come tabelle da motori SQL, fogli di calcolo e misure di qualità.

Segue l'algoritmo di elaborazione della ViewDefinition (colonna, selezione, forEach, forEachOrNull, ripetizione, unione di tutte, dove, costanti, %rowIndex, getResourceKey e getReferenceKey) e viene verificato contro i fixture di test ufficiali sql-on-fhir.

Source: github.com/biodream-llc/perfuse/internal/sof

26.96 sqldb

Il pacchetto sqldb apre le connessioni al database per la sorgente e la destinazione del database.

I driver sono registrati qui e da nessun'altra parte, quindi c'è esattamente un posto che decide a cosa Perfuse può connettersi.

Source: github.com/biodream-llc/perfuse/internal/sqldb

26.97 sqlitedb

Il pacchetto sqlitedb apre SQLite nel modo in cui un server lo richiede: una connessione per le scritture e più connessioni per le letture.

Il motivo è un modo di guasto che appare solo una volta che una distribuzione è stata in esecuzione per un po' di tempo. SQLite in modalità WAL consente ai lettori di eseguire operazioni accanto a uno scrittore, ma il pool di connessioni di Go si trova al di sopra di SQLite, quindi un pool di una sola connessione serializza tutto, indipendentemente da ciò che il database consentirebbe. Una ricerca del browser dei messaggi che scansiona la colonna del payload tiene quindi la sola connessione e ogni messaggio in arrivo attende dietro di essa.

Misurato su questa macchina, una scrittura richiede 104µs con l'archiviazione inattiva e 2,6 ms mentre una ricerca scansiona quattromila messaggi: venti volte più lento. Ciò si scala con la tabella, quindi a poche centinaia di migliaia di messaggi archiviati un report si trasforma in secondi di latenza di consegna e una scrittura si trova sul percorso di ack. Il mittente vede un timeout, ritrasmette e qualcuno trascorre una mattinata alla ricerca di un problema nella rete.

Dividere le connessioni non costa nulla e rimuove l'interazione: i report ottengono le proprie connessioni e lo scrittore mantiene una connessione per sé perché SQLite consente comunque solo uno scrittore.

Source: github.com/biodream-llc/perfuse/internal/sqlitedb

26.98 steps

Passaggi di trasformazione dichiarativi per qualsiasi formato di messaggio.

Perché questo è condiviso

Il vocabolario dei passaggi - impostazione, copia, cancellazione, mappatura, sostituzione, ritaglio, caso, ognuno con una descrizione e una condizione opzionale - non ha nulla a che fare con un formato particolare. Solo tre cose differiscono tra i formati: come viene scritto un percorso, come viene letto un valore e come viene scritto nuovamente.

Questa è la stessa conclusione raggiunta dalla grammatica dei filtri in internal/expr e per lo stesso motivo. X12 aveva un motore di passaggi e NCPDP ne aveva bisogno; copiarlo avrebbe prodotto un secondo motore di 400 righe da mantenere a mano e poi un terzo per i delimitati. Il comportamento che vale la pena avere è abbastanza sottile che una copia non lo manterrebbe - il motivo per cui il risultato viene riletto dopo ogni scrittura, ad esempio, ha richiesto un difetto reale per essere scoperto.

Cosa fornisce un formato

Un Accessor: un compilatore di percorsi, un compilatore di condizioni e un veto opzionale sui passaggi che non può onorare. Nulla altro.

Source: github.com/biodream-llc/perfuse/internal/steps

26.99 stomp

Il pacchetto stomp parla STOMP 1.2 a un broker di messaggi.

Questo è ciò che "supporto JMS" deve significare in un programma che non è Java. JMS è un'API piuttosto che un protocollo, quindi non c'è nulla da implementare: ciò di cui un sito ha effettivamente bisogno è che Perfuse parli con il broker che si trova dietro le sue applicazioni JMS.

STOMP piuttosto che OpenWire, e il ragionamento vale la pena registrarlo perché la risposta ovvia è sbagliata. OpenWire è il protocollo nativo di ActiveMQ e una serializzazione binaria dei comandi JMS - settimane di lavoro, specifiche per una famiglia di broker, e non documentate se non dalla loro implementazione. ActiveMQ rileva automaticamente STOMP, AMQP e MQTT sulla stessa porta su cui serve OpenWire, quindi un protocollo di testo raggiunge gli stessi broker. STOMP copre ActiveMQ Classic, Artemis e RabbitMQ; AMQP 1.0 aggiungerebbe Azure Service Bus e IBM MQ ed è il prossimo sensato piuttosto che OpenWire.

Scritto contro la libreria standard. Un client del broker non è il posto per una dipendenza i cui modi di guasto sono da spiegare da qualcun altro, e l'incorniciatura qui è abbastanza piccola che possederla costa meno che leggere il loro issue tracker.

Source: github.com/biodream-llc/perfuse/internal/stomp

26.100 archiviazione

L'archiviazione dei pacchetti contiene i dati che sono effettivamente stati salvati: utenti, sessioni e un registro di controllo.

I canali sono deliberatamente esclusi. Essi vivono in file, perché è ciò che consente di utilizzare git, diff, revisione del codice e promozione dell'ambiente gratuitamente. Inserire i canali in un database è la decisione che costringe a comprare separatamente ognuno di essi, ed è il motivo per cui esiste un prodotto di terze parti che esiste solo per spostare i canali di Mirth tra il suo database e un repository git.

Quindi la divisione è: configurazione nei file, identità e storia in SQLite.

Source: github.com/biodream-llc/perfuse/internal/store

26.101 tefca

Il pacchetto tefca implementa le parti della partecipazione a TEFCA che non richiedono una connessione QHIN.

Cosa è reale

Convalida dell'uso, convalida della configurazione e registro di controllo - compresa la sua persistenza, la sua interfaccia di query e il suo obbligo di registrare i tentativi falliti oltre che quelli riusciti. Quest'ultima parte non è una questione tecnica: una serie di consegne fallite a un destinatario è il modo in cui si presenta un partner non configurato correttamente, e una serie di query fallite per diversi pazienti è il modo in cui si presenta un tentativo di sondaggio.

Cosa non è

La rete. Non c'è trasporto QHIN in questa build, quindi non si verifica alcuno scambio, e ogni funzione di scambio rifiuta con ErrExchangeNotImplemented invece di restituire il successo.

Questa distinzione non è sempre stata tracciata, e il modo in cui è andata storta vale la pena di essere mantenuta. Tutte e quattro le funzioni di scambio utilizzavano per convalidare i loro input, non effettuavano alcuna chiamata di rete e restituivano il successo; Deliver restituiva una risposta Accettata con un identificatore di tracciamento costruito dall'orologio. Il livello di registro registrava poi ognuno come uno scambio completato - nel registro che esiste per provare cosa è stato scambiato quando qualcuno chiede mesi dopo. Quattro test affermavano che comportamento e passavano.

Cosa richiede il completamento

Onboarding con una rete di informazioni sanitarie qualificate, autenticazione TLS mutualmente autenticata utilizzando certificati rilasciati attraverso quel processo, e o i profili IHE iniziati con l'Accordo comune o Facilitated FHIR come definito dalla procedura operativa standard di Sequoia Project, in vigore dal 8 marzo 2026. Nessuno di essi può essere scritto in modo speculativo: viene testato contro un QHIN reale o non viene testato, e un'implementazione di scambio non testata è lo stesso difetto di un'implementazione senza maschera.

Source: github.com/biodream-llc/perfuse/internal/tefca

26.102 tenant

Il pacchetto tenant fornisce le regole di identità e isolamento per l'operazione multi-tenant.

Un HIE, un clearinghouse o un fornitore di servizi gestiti esegue un motore su behalf di molte organizzazioni. Mirth non può farlo - un'istanza serve un'organizzazione, e un MSP finisce per eseguire cinquanta JVM e cinquanta database.

Cosa possiede un tenant

I suoi canali, come una directory di file. I suoi utenti. I suoi messaggi, coda, registro di controllo e risorse FHIR. Le sue etichette dei metric. Nulla è condiviso tranne il processo, le porte di ascolto assegnate e gli amministratori della piattaforma.

L'isolamento è strutturale, non ricordato

Il fallimento pericoloso qui non è un crash. È il tenant A che vede i messaggi del tenant B, che è una violazione segnalabile piuttosto che un bug. Un design in cui ogni query richiede un parametro tenant_id fallisce la prima volta che qualcuno scrive una query e dimentica uno, e quella query sembra perfettamente corretta nella revisione.

Quindi il tenant non è un parametro. L'accesso ai dati passa attraverso un handle che già lo trasporta, e non c'è modo di raggiungere le tabelle senza uno. Dimenticare non è disponibile.

Source: github.com/biodream-llc/perfuse/internal/tenant

26.103 terminologia

Il pacchetto terminologia mantiene i sistemi di codici pubblicati (LOINC, SNOMED CT, RxNorm, ICD-10-CM, CPT e locali) per la ricerca dei codici, e le tabelle di mapping dei valori che non avevano, per qualcuno da mappare.

I sistemi di codici sono importati dai file che i loro editori distribuiscono. Diversi sono licenziati (LOINC richiede un account gratuito, SNOMED CT una licenza affiliata, RxNorm una licenza UMLS, CPT una licenza AMA), quindi nessuno viene fornito con Perfuse: un amministratore che detiene la licenza carica il file, e Perfuse registra chi l'ha importato e quando.

Source: github.com/biodream-llc/perfuse/internal/terminology

26.104 tlsconf

Il pacchetto tlsconf costruisce la configurazione TLS da file e descrive i certificati.

Questo è l'equivalente gratuito di un'estensione di Mirth per cui adesso si paga. La maggior parte del valore non è la crittografia, che è costituita da poche righe, ma la parte che impedisce a qualcuno di distribuire qualcosa che pensa essere sicuro e non lo è: rifiutare di saltare la verifica in silenzio, insistere che un certificato client venga effettivamente controllato quando ne viene richiesto uno, e dichiarare chiaramente quando un certificato sta per scadere.

Un certificato scaduto su un flusso di interfaccia è un vero e proprio blocco dell'ospedale, e accade perché nessuno ne è stato informato. La parte descrittiva di questo pacchetto esiste per questo motivo.

Source: github.com/biodream-llc/perfuse/internal/tlsconf

26.105 tomirth

Il pacchetto tomirth scrive un canale Perfuse come canale Mirth XML.

Perché questo esiste. L'obiezione all'adozione di un nuovo motore di integrazione raramente è "è valido?". È "e se abbiamo torto e rimaniamo bloccati?", e la risposta più economica a questo è essere in grado di tornare indietro. Perfuse legge i canali di Mirth fin dall'inizio; fino ad ora non poteva scriverne uno, il che rendeva la rassicurazione unidirezionale e quindi non molto rassicurante.

Come evita la trappola che ha reso inutile il primo tentativo. L'XML di Mirth è l'output di XStream, e XStream legge gli attributi di classe e versione come istruzioni: un elemento che non riconosce viene eliminato senza una parola, e un canale che non può essere assemblato viene memorizzato con la sua descrizione sostituita da "Questo canale non è valido. Verificare che tutte le estensioni richieste siano caricate correttamente" e le sue destinazioni eliminate. Nulla in quella risposta nomina l'elemento in errore. Un esportatore che compone blocchi di proprietà da una lettura del formato quindi fallisce nel modo più costoso da diagnosticare, che è ciò che è accaduto: questo repository conteneva un esportatore con nove test superati il cui output Mirth ha gettato via, perché ogni test lo confrontava con il nostro parser invece di un server.

Quindi nessuno dei blocchi di proprietà viene composto qui. scripts/mirth-dump-connector-templates.sh ha l'ObjectXMLSerializer di Mirth serializzare i valori predefiniti di ogni classe di proprietà del connettore, e quei documenti vengono committed sotto templates/. Questo pacchetto sostituisce i valori in essi, e mirth.SetRawProperty rifiuta qualsiasi percorso che il modello non contenga già - quindi un errore è un errore di denominazione del percorso, nel momento dell'esportazione, piuttosto che un canale che scompare all'importazione.

Cosa non farà. Un trasporto senza equivalente Mirth viene rifiutato per nome anziché approssimato. Un'esportazione che trasforma silenziosamente una destinazione S3 in uno scrittore di file sarebbe peggiore di nessuna esportazione, perché il canale verrebbe importato pulito e consegnato nel posto sbagliato.

Source: github.com/biodream-llc/perfuse/internal/tomirth

26.106 trace

Il pacchetto trace produce tracce distribuite per i messaggi in movimento attraverso un canale, e le esporta su OTLP/HTTP con la codifica JSON.

Perché questo esiste invece del SDK OpenTelemetry: il SDK più un esportatore OTLP richiama circa sessanta moduli e aggiunge circa quanto l'intero resto di questo programma alla dimensione del binario. Quello che è effettivamente necessario qui è limitato - la propagazione del contesto di traccia W3C, un modello di span, il campionamento della testa e un POST HTTP batch - e OTLP/JSON è una codifica stabile documentata che può essere prodotta con la libreria standard da sola. Stesso scambio di scegliere lib/pq su pgx: prendere la cosa piccola quando si vuole solo una parte della cosa grande.

La conseguenza degna di nota: non c'è auto-strumentazione e non c'è esportatore specifico del fornitore. Le span sono quelle che questo programma crea deliberatamente, e vanno a qualsiasi endpoint OTLP - un collector, Jaeger, Grafana Tempo, Honeycomb, Datadog's OTLP ingest.

La proprietà che conta più delle span

Un messaggio arriva frequentemente trasportando un'intestazione traceparent dal sistema che lo ha inviato, e parte verso un sistema che registrerà una propria. Continuare quella traccia invece di iniziare una nuova è ciò che rende possibile una visione unica di "il registro EHR ha inviato questo, il motore lo ha trasformato, il registro lo ha rifiutato"

La tracciabilità non deve mai influenzare la consegna

Ogni operazione qui è best-effort. Le span vengono eliminate quando il buffer è pieno, i fallimenti dell'esportazione vengono conteggiati e mai ritentati nel percorso del messaggio, e nessuna chiamata blocca la rete. Una span eliminata è un fastidio. Un messaggio ritardato o perso perché il backend di tracciamento era lento è un incidente clinico, quindi lo scambio non è mai in discussione.

Source: github.com/biodream-llc/perfuse/internal/trace

26.107 transform

Il pacchetto transform applica modifiche dichiarative a un messaggio.

Questo è il livello destinato a svolgere il lavoro ordinario, con la scripting mantenuta come una via di fuga marcata. La distinzione non è stilistica. Un passaggio dichiarato in YAML può essere convalidato prima di essere eseguito, mostrato in una diff, esaminato da qualcuno che non legge JavaScript, e segnalato; uno script può essere eseguito e sperare; la maggior parte di ciò che i trasformatori Mirth fanno effettivamente è noioso - copiare un campo, riempire un identificatore, mappare un codice attraverso una tabella, cancellare qualcosa che non dovrebbe lasciare l'edificio - e tutto ciò appartiene qui.

Ogni passaggio nomina il suo bersaglio esplicitamente e ogni passaggio è reversibile nel senso che dice cosa ha fatto, perché il fallimento più costoso in un'interfaccia è una trasformazione che nessuno sapeva stava accadendo.

Source: github.com/biodream-llc/perfuse/internal/transform

26.108 translate

Il pacchetto translate converte un canale Mirth in una definizione di canale Perfuse.

perfuse explain segnala cosa blocca una migrazione. Questo esegue la maggior parte della migrazione, che è un'affermazione diversa e molto più ampia, quindi è deliberatamente conservativo su ciò che affermerà.

Tre regole definiscono l'intero processo.

Nessun dato viene eliminato silenziosamente. Ogni parte del canale di origine viene tradotta, copiata integralmente come script o segnalata come necessitante di un intervento umano. Un traduttore che omettesse silenziosamente un passaggio produrrebbe un canale che inizia, esegue e perde dati — il peggiore esito possibile e il motivo per cui le persone diffidano degli strumenti di migrazione.

Declarativo quando è certo, script quando non lo è. Un passaggio Mapper che copia un campo diventa un passaggio declarativo, perché è leggibile e verificabile. Un passaggio JavaScript diventa uno script, perché Perfuse esegue JavaScript di Mirth senza modifiche e riscriverlo in qualcosa che sembra equivalente è esattamente dove un traduttore introdurrebbe una differenza che nessuno nota.

L'output è destinato a essere letto. Contiene commenti che spiegano da dove proviene ogni parte e cosa è stato lasciato per un intervento umano. Una migrazione viene esaminata da qualcuno che deve approvarla, e un muro non annotato di YAML non può essere esaminato.

Source: github.com/biodream-llc/perfuse/internal/translate

26.109 udap

Il pacchetto udap implementa la metà client della sicurezza HL7 per la registrazione, l'autenticazione e l'autorizzazione su larga scala — la specifica su cui si basa lo scambio FHIR facilitato da TEFCA.

UDAP è un'infrastruttura a chiave pubblica fissata su OAuth 2.0. Una comunità di trust rilascia certificati X.509 ai suoi membri; un membro dimostra la propria identità firmando JWT con la chiave privata e allegando la catena di certificati nell'intestazione JWT. Ciò sostituisce il segreto condiviso del client di OAuth normale, che non si scala a migliaia di organizzazioni che non si sono mai incontrate.

Perché questo pacchetto esiste. Lo scambio TEFCA non può essere completamente verificato senza un vero QHIN: unirsi richiede l'onboarding e i certificati rilasciati, e non può essere contraffatto. Ma il profilo di sicurezza sottostante è una guida di implementazione HL7 pubblicata con server di riferimento pubblici, e uno di essi risponde su Internet aperto. Quindi, la parte che può essere verificata viene verificata qui, e la parte che non può essere verificata viene rifiutata al confine anziché ipotizzata.

La distinzione è importante a causa di ciò che è successo con SAML in questo repository: mille righe di test sono state superate, cinque di esse specificamente sulla canonizzazione della firma, mentre nessun provider di identità reale poteva autenticare qualcuno. Entrambe le metà erano state scritte qui e concordavano tra loro. La lezione tratta da ciò è che un'implementazione di sicurezza non vale nulla fino a quando qualcosa scritto da qualcun altro non l'ha accettata o rifiutata.

Riferimenti alla specifica: - HL7 UDAP Security STU 1: http://hl7.org/fhir/us/udap-security/STU1/ - TEFCA SOP Facilitated FHIR Implementation v2.0, in vigore dal 8 marzo 2026

Source: github.com/biodream-llc/perfuse/internal/udap

Il pacchetto umlink trasporta X12 278 a un sistema di gestione dell'utilizzo di un pagatore e le relative risposte, illustrando i modi in cui questi sistemi vengono raggiunti nella pratica: X12 nel corpo di un POST HTTPS; busta SOAP di CAQH CORE (Regola di connettività vC2.2.0, quella utilizzata dalla maggior parte dei pagatori e dei sistemi CMS esMD, e vC4.0.0); busta MIME multipart di CAQH CORE su HTTP (vC2.2.0); e file batch tramite SFTP.

Scritto in base alle Regole di connettività pubblicate da CAQH (vC2.2.0 e vC4.0.0), al loro schema XML e WSDL, nonché alla Guida companion X12N 278 di esMD di CMS. Non è certificato CORE: la certificazione è eseguita dai vendor di test autorizzati da CAQH.

I collegamenti in tempo reale restituiscono la risposta fornita dal sistema UM, che può essere una risposta 278 o, quando non è possibile leggere la richiesta, un 999 o TA1: il chiamante legge quale. Il collegamento batch restituisce ErrAnswerLater una volta consegnato il file e Poll raccoglie ciò che torna indietro.

Source: github.com/biodream-llc/perfuse/internal/umlink

26.111 v2fhir

Il pacchetto v2fhir mappa i messaggi HL7 v2 alle risorse FHIR.

La mappatura è dove i progetti di interoperabilità falliscono effettivamente, quindi le regole che questo pacchetto segue sono dichiarate anziché implicite:

Source: github.com/biodream-llc/perfuse/internal/v2fhir

26.112 vcs

Il pacchetto vcs legge la cronologia dei file del canale da git.

La cronologia del canale è un'estensione a pagamento altrove, ed è un'estensione a pagamento perché quei motori mantengono i canali in un database, quindi il monitoraggio delle modifiche significa costruire un sistema di monitoraggio delle modifiche. Perfuse mantiene i canali in file, quindi la cronologia esiste già e esiste fin dal primo commit. Questo pacchetto deve solo leggerla.

Esegue git esternamente anziché incorporare una libreria git. La libreria aggiungerebbe una grande dipendenza a un binario il cui punto di forza è avere quattro, e non comprerebbe nulla: una distribuzione che mantiene i suoi canali sotto controllo versione ha git installato, e una che non lo fa ottiene un chiaro "non è un repository git" anziché un'implementazione leggermente diversa della stessa cosa.

Source: github.com/biodream-llc/perfuse/internal/vcs

26.113 vfs

Il pacchetto vfs è il piccolo set di operazioni su file di cui un connettore di polling ha bisogno.

Perché un'interfaccia anziché quattro connettori

Perfuse raccoglie file da un disco locale, un server SFTP, un server FTP, una condivisione Windows e un server WebDAV. Il trasferimento differisce in ogni caso. Tutto ciò che decide effettivamente se i messaggi sopravvivono non differisce:

Scritto una volta per trasporto, queste regole sarebbero leggermente diverse cinque volte, e le differenze apparirebbero solo come messaggi che sono scomparsi in un sito. Quindi sono scritte una volta, qui, sull'interfaccia più piccola che le supporta.

Cosa non è deliberatamente qui

Nessuna scrittura, oltre a ciò che la gestione dei rifiuti richiede. L'invio di file è un problema diverso con modalità di errore diverse - un file parzialmente scritto all'estremità remota, che gli inviati esistenti gestiscono scrivendo su un nome temporaneo e rinominandolo. Unire entrambe le direzioni in un'interfaccia renderebbe ogni direzione più difficile da ragionare.

Nessuna ricorsione. Un sondatore che scende nelle sottodirectory raccoglie la directory di archiviazione che ha appena spostato un file.

Source: github.com/biodream-llc/perfuse/internal/vfs

26.114 vpn

Il pacchetto vpn segnala lo stato dei tunnel VPN da sito a sito che il traffico dei partner esegue - AWS Site-to-Site VPN, connessioni Azure VPN Gateway e strongSwan - e mantiene il foglio di connessione di ogni partner: le impostazioni del tunnel di entrambi i lati e se sono d'accordo.

Un tunnel che è down appare, da un motore di interfaccia, esattamente come un partner la cui interfaccia è ferma: le connessioni scadono. Dire 'il tunnel è down' invece è la differenza tra chiamare il team di rete e chiamare il partner.

Sola lettura. Nulla qui modifica un tunnel e nessuna chiave condivisa viene mai letta, mantenuta o visualizzata.

Source: github.com/biodream-llc/perfuse/internal/vpn

26.115 web

Il pacchetto web serve la parte front-end costruita all'interno del binario.

Le risorse sono incorporate invece di essere spedite accanto, quindi il deployment rimane un file. Questo è lo stesso motivo per cui il motore evita cgo: un operatore dovrebbe essere in grado di copiare un binario su un server e eseguirlo, senza JVM, senza installer e senza directory di risorse da mettere fuori fase con l'eseguibile.

L'output costruito è confermato in modo che go build funzioni su un checkout senza Node installato. Ricostruirlo con make web.

Source: github.com/biodream-llc/perfuse/internal/web

26.116 webauthn

Il pacchetto webauthn verifica le passkey.

Una passkey è una coppia di chiavi che l'autenticatore mantiene - Touch ID, Windows Hello, una YubiKey, un telefono - dove la metà privata non lascia mai il dispositivo. L'accesso significa che il server invia una sfida casuale, l'autenticatore la firma dopo aver verificato che l'utente è presente e il server verifica la firma contro la chiave pubblica memorizzata durante la registrazione.

La proprietà che conta non è che sia conveniente. È che non c'è nulla da pescare. Una password può essere digitata in una copia convincente di una pagina di accesso; una firma passkey è legata all'origine per cui è stata creata, quindi la copia ottiene una firma che il suo server non può utilizzare. Per un motore di integrazione che tiene le interfacce di un ospedale, questa è la differenza che vale la pena avere.

Cosa questo implementazione rifiuta di fare

La specifica è permissiva in luoghi in cui essere permissivo è come gli implementazioni vengono rotte. Questa non lo è:

Source: github.com/biodream-llc/perfuse/internal/webauthn

26.117 winservice

Il pacchetto winservice esegue Perfuse come servizio Windows.

Questo file è la metà di ogni altra parte. Esiste in modo che cmd/perfuse possa chiamare questo pacchetto senza avvolgere ogni sito di chiamata in un tag di build: il sottocomando è sempre compilato e su Linux o macOS spiega che i servizi sono un'idea di Windows invece di fallire nell'esistenza.

Rifiutare con una frase chiara è meglio che nascondere il sottocomando. Qualcuno che segue le istruzioni di Windows sulla macchina sbagliata viene detto cosa sta realmente accadendo e l'equivalente per la sua piattaforma.

Source: github.com/biodream-llc/perfuse/internal/winservice

26.118 x12

Lettura e scrittura di valori in un percorso.

Perché questo è separato da Path

path.go decide cosa significa un'espressione di percorso. Questo file risolve uno contro un interchange effettivo. Tenuto separato perché le regole di parsing sono degne di essere lette senza la gestione dei byte, e perché il parser è utilizzato dal validator di configurazione, che non ha un messaggio da risolvere.

Perché una scrittura riparsinga invece di modificare i byte in posto

Gli elementi di Segment sono subslice di Segment.raw, e Message.segs indice in Message.raw. La modifica di un valore in posto cambia la lunghezza di tutto ciò che lo segue, quindi ogni uno di quei slice dovrebbe essere aggiustato, e qualsiasi cosa che fosse persa leggerebbe correttamente fino al messaggio in cui non lo fa.

Quindi una scrittura ricostruisce il segmento, ricostruisce l'interchange e lo riparsinga. Ciò costa un parsing per ogni messaggio modificato e acquista la garanzia che un Message restituito da qui è esattamente ciò che il parsing dei propri byte produce. Non c'è stato in cui gli indici e i byte non sono d'accordo, perché quello stato è non rappresentabile.

Source: github.com/biodream-llc/perfuse/internal/x12

26.119 x12xml

Il pacchetto x12xml converte X12 (e altri EDI delimitati) nel XML che Mirth Connect e Open Integration Engine scrivono per esso e viceversa.

Perché quel XML e non uno dei nostri

Lo scopo di una forma XML di X12 è costituito dai sistemi che già la utilizzano. Un sito che si sposta da Mirth ha ricevitori costruiti contro ciò che il tipo di dati EDI/X12 di Mirth emette, script che eseguono msg['CLM']['CLM.05']['CLM.05.1'] e motori upstream che inviano X12 come quel XML. Una forma più ordinata di nostra proprietà non servirebbe a nessuno di essi. Quindi questo scrive esattamente ciò che Open Integration Engine 4.6 scrive e legge esattamente ciò che legge, e i test li confrontano byte per byte con il serializer di OIE.

Una versione precedente di questo pacchetto ha inventato la sua forma (una radice X12Interchange, elementi denominati CLM05) e ha affermato che corrispondeva a Mirth. Non corrispondeva; non era mai stato confrontato con Mirth e nulla in Perfuse lo utilizzava.

The format

La radice è X12Transaction quando il messaggio inizia con un segmento ISA e EDIMessage altrimenti, trasportando i tre delimitatori come attributi (segmentDelimiter, elementDelimiter, subelementDelimiter). Ogni segmento è un elemento denominato dal suo identificatore. Ogni elemento di dati è SEG.NN, numerato da 01 (ISA.01, CLM.05), e contiene i suoi componenti come SEG.NN.1, SEG.NN.2 e così via: sempre almeno SEG.NN.1 per un elemento con un valore, nessuno per un elemento vuoto.

I delimitatori vengono letti dall'ISA quando c'è uno: il separatore di elementi dalla posizione 3, il separatore di componenti dalla posizione 104 e il terminatore di segmento dalla posizione 105, con un avanzamento di riga dopo di esso conteggiato come parte di esso. Altrimenti sono ~ * e:. Il separatore di ripetizione (ISA11) non viene interpretato, che è anche il comportamento di OIE: un elemento ripetuto mantiene il suo ^ all'interno di un valore.

Questo è un riimplementazione del comportamento, scritto osservando l'output di OIE e dal suo formato documentato; nessun codice di Mirth è in esso.

Source: github.com/biodream-llc/perfuse/internal/x12xml

26.120 xds

Il pacchetto xds è la condivisione di documenti cross-enterprise IHE: un registro e un repository di documenti XDS.b (ITI-41 Fornire e registrare, ITI-18 Query di archiviazione del registro, ITI-43 Recupero del set di documenti), un gateway di risposta XCA sullo stesso archivio (ITI-38, ITI-39) e il lato client di ognuno, quindi un canale può pubblicare un documento nel repository di un'altra organizzazione e la console può interrogare un registro o una comunità.

I metadati sono ebXML Registry 3.0 (ebRIM), come XDS.b li definisce in IHE ITI TF-3 capitolo 4. Sono modellati qui come struct Go le cui etichette XML portano i namespace, quindi un messaggio viene letto nello stesso modo indipendentemente dai prefissi scelti dal mittente e scritto correttamente nel namespace.

Source: github.com/biodream-llc/perfuse/internal/xds

26.121 xmldsig

Il pacchetto xmldsig implementa le firme digitali XML e il profilo XAdES di esse.

Perché questo è scritto invece di essere preso in prestito

Un documento clinico firmato è un artefatto legale. Afferma che una persona denominata, in un momento denominato, ha assunto la responsabilità di un set di byte specifico. Ottenere ciò sbagliato in entrambe le direzioni è grave: una firma che non può essere verificata fa apparire un documento valido come contraffatto, e un verificatore che è troppo generoso accetta un documento che qualcuno ha alterato.

La canonicalizzazione è l'intero problema

L'XML ha molte sequenze di byte che significano la stessa cosa. L'ordine degli attributi non è significativo, i prefissi dei namespace possono essere rinominati, gli elementi vuoti possono essere scritti in due modi e gli spazi all'interno di un tag sono liberi. Una firma è su byte, quindi prima di hashare qualsiasi cosa entrambe le estremità devono concordare esattamente su una sequenza di byte per un documento dato. Quell'accordo è la canonicalizzazione e là dove le implementazioni vanno male, perché ogni errore produce una firma che verifica contro la propria uscita e fallisce contro quella di tutti gli altri.

Quindi questo file è la canonicalizzazione, da solo, con i propri test. Non c'è nulla sulla firma che appaia qui.

Esclusivo piuttosto che inclusivo, per impostazione predefinita

La canonicalizzazione inclusiva trascina dentro ogni dichiarazione di namespace che è in ambito, comprese quelle che l'elemento firmato non utilizza mai. Ciò fa in modo che una firma si rompa quando il documento viene successivamente incorporato all'interno di qualcosa che dichiara un namespace non correlato su un antenato, che è esattamente ciò che accade quando un CDA viene inserito in un envelope SOAP o in un wrapper di metadati IHE. La canonicalizzazione esclusiva include solo le dichiarazioni che l'elemento effettivamente utilizza ed è ciò che i profili di scambio di documenti specificano per quel motivo.

Source: github.com/biodream-llc/perfuse/internal/xmldsig

26.122 xtree

Il pacchetto xtree è un albero XML mutabile.

Tre caratteristiche molto diverse devono modificare XML: le trasformazioni HL7, che Mirth modella come XML perché è ciò su cui operano i suoi script; i documenti clinici, che sono nativamente XML; e i passaggi di trasformazione dichiarativi. Condividono questo unico albero invece di farne crescere ognuno il proprio, perché l'alternativa sono tre modelli che non concordano sul significato di un elemento vuoto.

L'obiettivo di progettazione è la fedeltà alle semantiche E4X, poiché gli script Mirth sono E4X e l'intero punto dell'esecuzione senza modifiche è che si comportano allo stesso modo. Ciò determina due decisioni che altrimenti sembrerebbero strane: un nodo mantiene un puntatore al suo genitore, perché E4X espone parent(), e i figli sono ordinati con duplicati consentiti, perché una ripetizione di campo HL7 è letteralmente un elemento ripetuto e gli script si indicizzano in base alla posizione.

Source: github.com/biodream-llc/perfuse/internal/xtree

26.123 pacchetto pas

Il pacchetto pas legge le richieste di supporto per l'autorizzazione preventiva Da Vinci (PAS) Bundle.

È il lettore utilizzato dal server PAS di Perfuse, pubblicato in modo che qualsiasi cosa decida un'autorizzazione preventiva - le regole di un pagatore, un sistema di gestione dell'utilizzo, un servizio di decisione come Vaglio - legga una richiesta con lo stesso codice e quindi le stesse risposte su cosa contiene una richiesta. Due lettori di un formato di messaggio sono due opinioni su di esso.

Non ha dipendenze al di fuori della libreria standard. Una richiesta viene mantenuta come JSON decodificato (map[string]any) anziché come risorse tipizzate, perché un Bundle PAS trasporta qualsiasi risorsa di supporto scelta dal fornitore e un lettore che scarta ciò che non modella nasconderebbe prove alla decisione.

req, problemi := pas.Leggi(bundle, false) se len(problemi) > 0 { // rifiuta: la richiesta non può essere risposta correttamente } per _, svc := range req.Servizi() { // svc.Codici, svc.Voce, e req.Risolve per qualsiasi elemento a cui si fa riferimento }

Source: github.com/biodream-llc/perfuse/pas

27 Indice delle chiavi di configurazione

Ogni chiave in ordine alfabetico, con i blocchi in cui può apparire. Una chiave che appare in più blocchi significa la stessa cosa in ognuno; dove non è così, i blocchi sono documentati separatamente e la differenza è indicata lì.

27.1 Tutte le chiavi

ChiaveAppare in
access_key_idAccesso AWS, Autenticazione FHIR, Destinazione S3
accountAccesso Azure Blob
ackOrigine HTTP, Origine SOAP, Origine
ack_sender_idOpzioni X12
ack_sender_qualifierOpzioni X12
acknowledgeOpzioni EDIFACT, Opzioni HL7v3, Opzioni X12
acksDestinazione Kafka
actionDestinazione SOAP
addrConnessione AMQP, Destinazione Broker, Origine Broker, Connessione MQTT
addressConnessione AMQP, Destinazione DICOM, Origine query DICOM, Destinazione, Indirizzo diretto, Destinazione TCP
ae_titleOrigine DICOM
after_queryOrigine del database
after_readOrigine Azure Blob, IMAP diretto, Origine e-mail, Poll del file, Origine GCS, Origine S3, Origine SFTP
allowScript
allow_clear_passwordDestinazione FTP
allow_unencryptedPartner AS2, Ricezione PGP
allow_unsignedPartner AS2
allowed_calling_aeOrigine DICOM
allowed_sendersOrigine e-mail
amqpDestinazione, Origine
anchors_fileIndirizzo diretto
api_versionConnessione IBMMQ
appendDestinazione, Destinazione SFTP
applicationAck
armorInvio PGP
arrives_asOpzioni X12
as2Destinazione, Origine
attachDestinazione SMTP
attach_nameDestinazione diretta, Destinazione SMTP
attachment_namesOrigine e-mail
attachmentsCanale
attemptsRetry
authDestinazione FHIR, Destinazione PAS
authoritiesDestinazione MPI
azure_blobDestinazione, Origine
backoffConfigurazione della coda, Retry
base64Origine SOAP
batch_sizeOrigine del database, Poll del file
baudOrigine seriale
bccDestinazione SMTP
bearer_tokenDestinazione CDA, Destinazione FHIR, Destinazione HTTP, Destinazione PAS
big_endianImpostazione del framing TCP
blobDestinazione Azure Blob
bodyDestinazione SMTP, Destinazione SOAP
brokerDestinazione, Origine
brokersDestinazione Kafka, Origine Kafka
bucketAccesso GCS, Destinazione S3, Origine S3
bundle_scriptDestinazione FHIR
called_aeDestinazione DICOM, Origine query DICOM
calling_aeDestinazione DICOM, Origine query DICOM
ccDestinazione SMTP
cdaDestinazione
cert_fileDestinazione AS2, Partner AS2, Origine AS2, Indirizzo diretto
channelDestinazione, Ombra
check_everyRiferimento contratto
cityStruttura ECR
claim_us_coreDestinazione FHIR
classDestinazione XDS
client_ca_fileXDR diretto
client_idAutenticazione e-mail, Autenticazione FHIR, Connessione MQTT
client_secretAutenticazione e-mail, Autenticazione FHIR
codeCodice XDS
columnOrigine del database
columnsDelimitato
commentDelimitato
commit_after_deliveryOrigine Kafka
compareOmbra
compressDestinazione AS2
compressionDestinazione Kafka
configDestinazione ELR
containerAccesso Azure Blob
content_typeDestinazione AMQP, Destinazione AS2, Destinazione Azure Blob, Destinazione Broker, Destinazione GCS, Destinazione HTTP, Destinazione S3, Destinazione XDS
contractCanale
credentials_fileAccesso GCP
dataTypeCanale
data_bitsOrigine seriale
databaseDestinazione, Origine
decrypt_withRicezione PGP
default_identifier_systemDestinazione FHIR
delimitedCanale
delimiterDelimitato, Impostazione del framing TCP
deployScript
descriptionCanale
destinationDestinazione Broker, Origine Broker
destinationsCanale
dicomCanale, Destinazione, Origine
dicom_queryOrigine
dicomwebDestinazione, Origine
dirDestinazione CDA, Destinazione, Destinazione del documento, Destinazione FTP, Poll del file, Destinazione SFTP, Origine SFTP
directDestinazione, Origine
direct_fromDestinazione XDS
direct_toDestinazione XDS
displayCodice XDS
dnsDestinazione diretta
documentDestinazione
domainOrigine SMB
driverDestinazione del database, Origine del database
dsnDestinazione del database, Origine del database
duplicate_windowOrigine AS2
ecrDestinazione FHIR
edifactCanale
elementOrigine SOAP
elrDestinazione
emailOrigine
emit_on_first_pollOrigine query DICOM
enabledCanale, Destinazione, Configurazione della coda
encrypt_toInvio PGP
endpointAccesso AWS, Accesso Azure Blob, Accesso GCP, Destinazione S3
envelopeOpzioni EDIFACT, Opzioni X12
error_dirPoll del file, Origine SFTP
error_folderIMAP diretto, Origine e-mail
error_prefixOrigine Azure Blob, Origine GCS, Origine S3
expect_replyDestinazione TCP
extractAllegati
facilityAck, Destinazione ECR
facility_idDestinazione SOAP
facility_typeDestinazione XDS
fail_on_bodyDestinazione HTTP
fault_is_successDestinazione SOAP
fault_on_nakOrigine SOAP
fhirDestinazione
fileRiferimento contratto, Origine
file_nameDestinazione AS2, Destinazione, Destinazione del documento, Destinazione FTP, Invio PGP, Destinazione SFTP
file_rootsScript
filterCanale, Delimitato, Destinazione, Opzioni HL7v3, Script
flow_controlOrigine seriale
follow_redirectsDestinazione HTTP
follow_symlinksOrigine del file
font_sizeDestinazione del documento
formatDestinazione del documento, Destinazione S3
framedOrigine Azure Blob, Destinazione FTP, Poll del file, Origine GCS, Destinazione S3, Origine S3, Destinazione SFTP, Origine SFTP
framingImpostazione del framing TCP
fromDestinazione AS2, Destinazione SMTP
from_beginningOrigine Kafka
ftpDestinazione, Origine
gcsDestinazione, Origine
groupCanale, Origine Kafka
group_byDestinazione SNS, Destinazione SQS
has_headerDelimitato
headerDestinazione SOAP
headersDestinazione Broker, Destinazione CDA, Destinazione DICO Mweb, Destinazione FHIR, Destinazione HTTP, Destinazione Kafka, Destinazione SOAP, Destinazione XDS
heartbeatOrigine Broker
hl7v3Canale
hostDestinazione Broker, Origine Broker, IMAP diretto, Origine e-mail, Destinazione FTP, Origine FTP, Destinazione SFTP, Origine SFTP, Origine SMB, Destinazione SMTP
hostnameConnessione AMQP
httpDestinazione, Origine
ibm_mqDestinazione, Origine
idPartner AS2, Origine AS2
id_typeDestinazione MPI
identifier_systemsDestinazione CDA, Destinazione FHIR
idle_timeoutOrigine DICOM, Origine, Origine TCP
ignoreOmbra
imapOrigine diretta
includeScript
include_trigger_eventAck
insecure_skip_host_key_checkDestinazione SFTP, Origine SFTP
insecure_skip_verifyDestinazione FTP, Origine FTP, Destinazione SMTP, Origine Web DAV
intervalOrigine query DICOM
javascriptDestinazione, Origine
kafkaDestinazione, Origine
keep_aliveDestinazione TCP
keep_blank_linesDelimitato
keep_delimiterImpostazione del framing TCP
keyAccesso Azure Blob, Destinazione Kafka, Destinazione S3
key_columnOrigine del database
key_fileDestinazione AS2, Origine AS2, Indirizzo diretto, Destinazione SFTP, Origine SFTP
key_passphraseDestinazione SFTP, Origine SFTP
known_hosts_fileDestinazione SFTP, Origine SFTP
landscapeDestinazione del documento
languageScript
ldapDestinazione diretta
length_bytesImpostazione del framing TCP
length_includes_headerImpostazione del framing TCP
levelOrigine query DICOM
limitOrigine query DICOM
lineStruttura ECR
listenOrigine AS2, Origine DICO Mweb, Origine DICOM, Origine diretta, XDR diretto, Origine HTTP, Origine SOAP, Origine, Origine TCP
loginDestinazione Broker, Origine Broker
mailboxIMAP diretto, Origine e-mail
matchOrigine query DICOM
max_attemptsOrigine del database, Configurazione della coda
max_backoffConfigurazione della coda, Retry
max_bytesOrigine diretta
max_connectionsOrigine, Origine TCP
max_depthConfigurazione della coda
max_differencesOmbra
max_file_sizePoll del file, Origine SFTP
max_message_sizeOrigine AS2, Origine e-mail, Origine HTTP, Origine Kafka, Origine SOAP, Origine seriale, Origine, Destinazione TCP, Origine TCP
max_messagesOrigine Pub Sub, Origine SQS
max_object_bytesOrigine DICO Mweb, Origine DICOM
max_object_sizeOrigine Azure Blob, Origine GCS, Origine S3
max_open_connsDestinazione del database
mechanismAutenticazione SASL Kafka
methodDestinazione HTTP
move_toOrigine Azure Blob, IMAP diretto, Origine e-mail, Poll del file, Origine GCS, Origine S3, Origine SFTP
mpiDestinazione
mqttDestinazione, Origine
nameCanale, Destinazione del canale, Destinazione, Struttura ECR
ncpdpCanale
no_compressInvio PGP
no_mergeDestinazione MPI
non_persistentDestinazione IBMMQ
npiStruttura ECR
oauthOrigine e-mail
objectDestinazione GCS
on_no_documentDestinazione CDA
order_byDestinazione Pub Sub
overRiferimento contratto
overlapOrigine query DICOM
paramsDestinazione del database
parityOrigine seriale
partner_cert_fileDestinazione AS2
partnersOrigine AS2
pasDestinazione
pass_plainRicezione PGP
passcodeDestinazione Broker, Origine Broker
passphraseRicezione PGP, Invio PGP
passwordConnessione AMQP, Destinazione AS2, Destinazione DICO Mweb, Origine DICO Mweb, Destinazione diretta, IMAP diretto, Origine diretta, Origine e-mail, Destinazione FTP, Origine FTP, Destinazione HTTP, Connessione IBMMQ, Autenticazione SASL Kafka, Connessione MQTT, Destinazione SFTP, Origine SFTP, Origine SMB, Destinazione SMTP, Destinazione SOAP, Origine SOAP, Origine Web DAV, Destinazione XDS
pathOrigine AS2, Origine DICO Mweb, Origine HTTP, Origine SOAP
path_styleDestinazione S3, Origine S3
patient_domainDestinazione XDS
patient_rootOrigine query DICOM
patternPoll del file, Origine SFTP
payerDestinazione PAS
persistentDestinazione Broker
pgpDestinazione, Origine
phoneStruttura ECR
poll_intervalOrigine Azure Blob, Origine del database, IMAP diretto, Origine e-mail, Poll del file, Origine GCS, Origine IBMMQ, Origine Java Script, Origine S3, Origine SFTP
portIMAP diretto, Origine e-mail, Origine seriale
postal_codeStruttura ECR
postprocessorScript
practice_settingDestinazione XDS
prefetchOrigine AMQP
prefixOrigine Azure Blob, Origine GCS, Origine S3
preprocessorScript
profileDestinazione SOAP, Origine SOAP
projectAccesso GCP
protocolOrigine e-mail
providerAutenticazione e-mail
pubsubDestinazione, Origine
purposeDestinazione TEFCA
qosConnessione MQTT
queryOrigine del database
query_timeoutOrigine del database
queueDestinazione, Connessione IBMMQ
queue_managerConnessione IBMMQ
queue_urlDestinazione SQS, Origine SQS
quiet_afterOrigine seriale
quoteDelimitato
rawPoll del file
rctcDestinazione ECR, Destinazione ELR
read_timeoutOrigine HTTP, Origine SOAP
reassembleAllegati
receiptDestinazione AS2
receipt_urlDestinazione AS2
recipient_certs_dirDestinazione diretta
reconnectOrigine AMQP, Origine Broker, Origine MQTT, Origine Pub Sub
record_lengthImpostazione del framing TCP
refresh_tokenAutenticazione e-mail
regionAccesso AWS, Autenticazione FHIR, Destinazione S3
reject_on_warningDestinazione FHIR
relaxedDelimitato
reopen_afterOrigine seriale
replyOrigine seriale, Origine TCP
reply_textOrigine seriale, Origine TCP
request_mdnDestinazione diretta
require_agreementDestinazione CDA
require_signatureRicezione PGP
response_elementOrigine SOAP
response_namespaceOrigine SOAP
response_transformerDestinazione
results_toDestinazione PAS, Destinazione TEFCA
retainDestinazione MQTT
retain_hoursDestinazione, Configurazione della coda
retryDestinazione
returnOrigine query DICOM
rootOrigine FTP, Origine del file, Origine SMB
s3Destinazione, Origine
sampleOmbra
sasAccesso Azure Blob
saslDestinazione Kafka, Origine Kafka
schemeCodice XDS
scopeAutenticazione e-mail, Autenticazione FHIR
scriptCanale, Destinazione Java Script, Origine Java Script
scriptsCanale
secret_access_keyAccesso AWS, Autenticazione FHIR, Destinazione S3
securityIMAP diretto, Origine e-mail, Destinazione FTP, Origine FTP
selectorOrigine Broker
sender_deviceOpzioni HL7v3
sender_oidOpzioni HL7v3
serialOrigine
server_side_encryptionDestinazione S3
session_timeoutOrigine Kafka
session_tokenAccesso AWS, Autenticazione FHIR, Destinazione S3
sftpDestinazione, Origine
shadowCanale
shareOrigine SMB
sign_withInvio PGP
smbOrigine
smtpDestinazione
smtp_hostDestinazione diretta, Origine diretta
snsDestinazione
soapDestinazione, Origine
sop_classesOrigine DICOM
sort_byPoll del file
sourceCanale, Destinazione ECR
source_idDestinazione XDS
splitDelimitato, Opzioni EDIFACT, Opzioni X12
sqsDestinazione, Origine
ssn_systemDestinazione MPI
stable_forPoll del file, Origine SFTP
start_blockImpostazione del framing TCP
starttlsDestinazione SMTP
stateStruttura ECR
statementDestinazione del database
stop_bitsOrigine seriale
storage_classDestinazione GCS, Destinazione S3
subjectDestinazione AS2, Destinazione diretta, Destinazione SMTP, Destinazione SNS
subscriptionOrigine Pub Sub
subscription_idOrigine Broker
success_on_undefinedDestinazione Java Script
success_statusDestinazione HTTP
suffixOrigine Azure Blob, Origine GCS, Origine S3
tablesCanale
takeOrigine e-mail
tcpDestinazione, Origine
tefcaDestinazione
temp_suffixDestinazione, Destinazione del documento, Destinazione FTP, Destinazione SFTP
templateOrigine del database, Destinazione del documento
tenantAutenticazione e-mail
tenant_idAutenticazione FHIR
textDestinazione diretta
tierDestinazione Azure Blob
timeoutConnessione AMQP, Destinazione Broker, Origine Broker, Destinazione DICO Mweb, Destinazione DICOM, Origine query DICOM, Destinazione del database, Destinazione, Destinazione diretta, Destinazione del documento, Destinazione FTP, Origine FTP, Connessione IBMMQ, Destinazione Java Script, Origine Java Script, Destinazione Kafka, Origine Kafka, Connessione MQTT, Destinazione S3, Destinazione SFTP, Origine SFTP, Origine SMB, Destinazione SMTP, Destinazione SOAP, Script, Ombra, Destinazione TCP, Origine Web DAV, Destinazione XDS
timezoneDestinazione FHIR
titleDestinazione del documento
tlsConnessione AMQP, Destinazione AS2, Origine AS2, Destinazione Broker, Origine Broker, Destinazione DICO Mweb, Origine DICO Mweb, Destinazione DICOM, Origine query DICOM, Origine DICOM, Destinazione, IMAP diretto, Origine e-mail, Destinazione HTTP, Origine HTTP, Connessione IBMMQ, Destinazione Kafka, Origine Kafka, Connessione MQTT, Destinazione SOAP, Origine SOAP, Origine, Destinazione TCP, Origine TCP, Destinazione XDS
tls_certOrigine diretta, XDR diretto
tls_keyOrigine diretta, XDR diretto
toDestinazione AS2, Destinazione diretta, Destinazione SMTP
tokenDestinazione DICO Mweb, Origine DICO Mweb, Origine HTTP, Origine SOAP, Destinazione XDS
token_urlAutenticazione e-mail, Autenticazione FHIR
topicDestinazione Kafka, Destinazione MQTT, Origine MQTT, Destinazione Pub Sub
topic_arnDestinazione SNS
topicsOrigine Kafka
transfer_syntaxesDestinazione DICOM, Origine DICOM
transformationsCanale, Opzioni DICOM, Delimitato, Opzioni HL7v3, Opzioni NCPDP, Opzioni script, Opzioni X12
transformerScript
trim_paddingImpostazione del framing TCP
trim_spaceDelimitato
typeDestinazione, Autenticazione FHIR, Origine
undeployScript
unencryptedDestinazione AS2
unsignedDestinazione AS2
unsigned_receiptDestinazione AS2
urlDestinazione AS2, Destinazione CDA, Destinazione DICO Mweb, Destinazione FHIR, Destinazione HTTP, Connessione IBMMQ, Destinazione SOAP, Origine Web DAV, Destinazione XDS
userDestinazione FTP, Origine FTP, Destinazione SFTP, Origine SFTP, Origine SMB, Origine Web DAV
usernameConnessione AMQP, Destinazione AS2, Destinazione DICO Mweb, Origine DICO Mweb, Destinazione diretta, IMAP diretto, Origine diretta, Origine e-mail, Destinazione HTTP, Connessione IBMMQ, Autenticazione SASL Kafka, Connessione MQTT, Destinazione SMTP, Destinazione SOAP, Origine SOAP, Destinazione XDS
validate_before_sendDestinazione FHIR
verify_withRicezione PGP
versionDestinazione CDA, Destinazione FHIR, Destinazione SOAP, Origine SOAP
visibility_timeoutOrigine SQS
wait_secondsOrigine SQS
warnings_are_errorsDestinazione SOAP
webdavOrigine
whenAck
windowOrigine query DICOM
writeDestinazione CDA
wsdlOrigine SOAP
x12Canale
x12_asDestinazione
xdmDestinazione diretta
xdm_source_idDestinazione diretta
xdrOrigine diretta
xdsDestinazione