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:
- Tutto è configurabile dall'interfaccia web. Una funzionalità raggiungibile solo da un terminale o da un file modificato manualmente è trattata come un difetto, non come una scelta di progettazione.
- I messaggi possono essere tracciati un trasformazione alla volta, mostrando cosa ogni passaggio abbia letto, cosa abbia modificato e cosa abbia saltato e perché.
- È possibile generare traffico di test che corrisponda alla forma di un flusso reale senza contenere alcun dato.
- Un canale può essere proposto da un singolo messaggio di esempio, con una dichiarazione esplicita di cosa il campione non possa dirti.
- Prima di sostituire un motore esistente, la sua uscita e quella di Perfuse possono essere confrontate messaggio per messaggio, con le differenze raggruppate per campo.
1.2 Cosa contiene
Tutto ciò che segue è nel singolo file binario. Ogni riga nomina il capitolo che lo copre.
- Formati. HL7 v2, FHIR R4, R4B e R5, DICOM, X12 (837, 835, 270/271, 276/277, 834, 278, 275), C-CDA e CDA, HL7 v3, NCPDP Telecommunication e SCRIPT, SMART Health Links e Cards, delimitati e grezzi. Vedi formati di messaggio.
- Collegamenti. 28 tipi di sorgente e 32 tipi di destinazione, tra cui MLLP, file, SFTP, database, DICOM, Kafka, AMQP 1.0, MQTT, IBM MQ e archiviazione e messaggistica AWS, Azure e Google Cloud. Vedi la documentazione della sorgente e la documentazione della destinazione.
- Modifica dei messaggi. Filtri, undici passaggi di trasformazione dichiarativi, JavaScript (incluso il dialetto di Mirth) e Lua, tabelle di mappatura condivise e insiemi di codici, e suggerimenti di mappatura. Vedi filtraggio e trasformazione.
- Consegna. Una coda durevole e ordinata per destinazione, ritentativi, lettere morte che mantengono il messaggio e conferme inviate dopo la consegna. Vedi consegna e conferme.
- Monitoraggio. Dashboard, dashboard di squadra, mappa di flusso, undici tipi di allarme, metriche, tracciamento e un archivio di messaggi che trova i messaggi di un paziente tra formati. Vedi allarmi, l'archivio di messaggi e debugging.
- Modifica di un'interfaccia live in modo sicuro. Modalità ombra, contratti di alimentazione, test di canale e confronto del motore. Vedi testing.
- Abbandono di Mirth. Canali Mirth, Open Integration Engine e BridgeLink spiegati, tradotti ed esportati nuovamente. Vedi migrazione.
- Pagatori e sanità pubblica. Le quattro API CMS-0057, Da Vinci CRD, DTR, PAS, PDex e Plan-Net, CARIN Blue Button, un servizio di decisione opzionale, eCR e ELR. Da Vinci CRD, DTR e PAS rispondono sia alle loro versioni 2.2.x che 2.1.0. Vedi CMS-0057.
- Chi può fare cosa. SAML, OpenID Connect, LDAP, passkeys, SCIM, TLS reciproco, sei ruoli, gruppi di canali con un ruolo in ciascuno, tenant, un server di autorizzazione SMART, TEFCA e UDAP e un registro di audit. Vedi sicurezza.
- Esecuzione. Un binario statico per Linux, macOS e Windows, come servizio, con una visualizzazione della flotta di più server. Vedi operazioni, l'interfaccia web, la riga di comando e opzioni del server.
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
| Standard | Versione | Verificata |
|---|---|---|
| HL7 v2 | qualsiasi versione: i messaggi vengono letti dai propri separatori, non da uno schema di versione; le conferme predefinite sono 2.5.1 | Validatore HL7 v2 NIST; traffico reale Mirth e OIE |
| HL7 v2 a FHIR | mappatura 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 |
| FHIR | R4 (4.0.1), con R4B e R5 letti e scritti | Validatore FHIR HL7; Inferno |
| C-CDA e CDA | C-CDA 2.1 | SITO ONC (campioni C-CDA inviati e ricevuti tramite XDR); non da uno schematron CDA |
| HL7 v3 | PIX e PDQ (IHE ITI-44, 45, 47) | Schemi NE2008 IHE e messaggi di esempio |
| DICOM e DICOMweb | DIMSE C-STORE, C-FIND, C-MOVE, C-GET, C-ECHO; QIDO-RS, WADO-RS, WADO-URI, STOW-RS | Orthanc |
| X12 (HIPAA) | 005010: 837, 835, 270/271 (X279A1), 276/277 (X212), 834, 278 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 MTOM | Un sistema UM sostitutivo scritto dalle regole CAQH |
| NCPDP | Telecommunicazione D.0; SCRIPT 2023011 (e 2017071) con ePA; Real-Time Prescription Benefit v13 | Scritto dalle guide di accompagnamento pubbliche Surescripts e dai loro esempi; non contro gli schemi NCPDP con licenza |
| UN/EDIFACT | sintassi 3 e 4, CONTRL | pydifact 0.1.8 |
| Condivisione di documenti IHE | XDS.b, XCA, XDR, MHD 4.2.2, PIXm, PDQm, XDM | Toolkit XDS NIST; SITO ONC |
| Messaggistica sicura Direct | Dichiarazione di applicabilità 1.2, XDR e XDM per Direct, DNS e LDAP discovery certificate | SITO ONC; Strumento di discovery del certificato ONC (18 su 18) |
| AS2 | RFC 4130, compressione RFC 5402 | pyas2lib |
| Allegati firmati | HL7 DSDR, XAdES-X-L | xmlsec1, OpenSSL |
1.3.2 Guide all'implementazione di FHIR
| Guida | Rilascio | Verificato |
|---|---|---|
| US Core | conversioni in 9.0.0 (USCDI v6); server FHIR contro 6.1.0 e 7.0.0 | il validatore HL7; Inferno US Core |
| SMART App Launch | 2.2 | Inferno: 80 di 80 (app pubblica) |
| Bulk Data Access | 2.0.0 | Inferno: 48 di 48 |
| Abbonamenti R5 Backport | per R4 | un ricevitore HTTP reale; i test di notifica del kit PAS |
| Da Vinci CRD | 2.2.1 e 2.1.0 | Inferno 2.2.1: 92 superati, nessuno fallito; 2.1.0 dagli esempi della guida stessa |
| Da Vinci DTR | 2.2.0 e 2.1.0 | Inferno 2.2.0: 43 superati, 2 falliti (un difetto del kit); 2.1.0 dagli esempi della guida stessa |
| Da Vinci PAS | 2.2.1 e 2.1.0 | Inferno 2.2.1: 82 di 84; 2.1.0 dagli esempi della guida stessa |
| Da Vinci PAS, invio (lato fornitore) | 2.2.1 | l'implementazione di riferimento del pagatore Da Vinci PAS; non un pagatore di produzione |
| Da Vinci PDex | 2.2.0 | Inferno PDex 2.0: pagatore a pagatore 19 di 19 |
Da Vinci HRex $member-match | 1.2.0 | Inferno PDex pagatore a pagatore |
| Da Vinci ATR | 2.1.0 | non verificato da uno strumento esterno |
Da Vinci CDex $submit-attachment | 2.1 | non verificato da uno strumento esterno |
| Da Vinci Plan-Net | 1.1.0 | Inferno: 199 superati, 10 falliti (un difetto del kit) |
| Da Vinci US Drug Formulary | 2.1.0 | il validatore HL7 |
| ISiK (ospedali tedeschi), server FHIR | Stufe 5, modulo di base | suite di test ISiK di gematik 3.0.9: 421 di 421 |
| PACIO Transizioni di assistenza, Profilo farmacologico, Direttive anticipate, Funzionamento | 1.0.0, 1.0.0, 2.0.0-ballot, 2.0.0 | kit 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 Button | 2.2.0 | il validatore HL7 |
| eCR | 2.1.2 | il validatore HL7 |
| ELR | HL7 2.5.1 ELR Release 1 con le sue errate | strumento ELR di ONC: 28 di 28 |
| Riepilogo internazionale del paziente | 2.0.0 | il validatore HL7 |
| DEQM | 5.0.0 | il validatore HL7 |
| SQL su FHIR | v2 | la suite di test ufficiale: 144 di 144 |
| SMART Health Cards e Links | Cards 1.4, Links STU 1 | la carta di esempio delle specifiche; una libreria di visualizzazione SMART Health Links pubblicata |
| Sicurezza UDAP | STU 1 | un server di autorizzazione reale e una comunità di trust |
| FHIR facilitato da TEFCA | SOP v2.0 | non 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.
| Profilo | Rilascio | Risorse valide |
|---|---|---|
| UK Core | STU2 2.0.2 | 185 di 187 |
| FR Core | 2.2.0 | 138 di 156 |
| ISiK Basismodul | 4.0.3 (Stufe 4) | 18 di 47; 42 di 47 con lo script del bundle dell'ospedale |
| Nictiz nl-core | 0.12.1-beta.1 (zib 2020) | 12 di 24; 18 di 24 con lo script del bundle dell'ospedale |
| HL7 Europe Laboratory Report | 2.1.0 | 106 di 426 (la guida si aspetta un documento a v2 risultato non è) |
| HL7 Europe Hospital Discharge Report | 1.0.0 | 68 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.
-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:
- Il blocco sorgente è piatto per MLLP.
listensi trova direttamente susource, non all'interno di un bloccosource.mllp. I trasporti che necessitano di più di un indirizzo — HTTP, SOAP, DICOM — hanno il loro proprio blocco secondario, e quelli sono elencati nel riferimento della sorgente. - Una destinazione file necessita sia di
rootche didir.rootè il confine che i percorsi sono risolti contro e non possono uscire;dirè dove i messaggi arrivano all'interno di esso. - Non c'è trasformazione e non c'è filtro. Entrambi sono opzionali, e un canale con nessuno dei due passa semplicemente i messaggi.
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:
- 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.
- Da qualcosa che già funziona. Un set di canali completi che necessitano solo degli indirizzi compilati.
- 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
- Canali spiega cosa è un canale e come si incastrano le sue parti.
- Flusso di messaggio segue un messaggio dall'arrivo alla consegna, che è il modo più veloce per capire dove inserire una modifica.
- Allarmi vale la pena configurarli prima che un flusso vada live piuttosto che dopo il primo incidente.
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:
- Autorizzazione preventiva: richieste PAS decise entro 72 ore (accelerato) o 7 giorni (standard) di CMS-0057, decise in ritardo, in attesa e scadute adesso, con il tempo mediano di decisione. Inoltre, come sono state risposte le richieste di servizi (approvate, modificate, negate, sospese), come stanno adesso, nell'arco di 30 giorni.
- Immagini: oggetti ricevuti da C-STORE per modalità e quelli non consegnati. Inoltre, il ritardo di routing per canale (mediana e percentuale del 95%), query C-FIND e fallimenti per canale di query, e referti di immagini (un ORU il cui OBR-24 è una sezione di immagini o un MDM) che non hanno raggiunto ogni destinazione.
- Ciclo di fatturazione: insiemi di transazioni 999 accettati, accettati con errori e rifiutati, e richieste di rimborso 277CA accettate e rifiutate (A3, A4, A6, A7, A8). Inoltre, richieste di rimborso 835 abbinate al numero di account del paziente alle 837 inviate tramite questo server e le ragioni di rifiuto più comuni.
- Laboratorio: tempo di consegna dei risultati, dalla ricezione all'acknowledgement dell'ultima destinazione, e risultati critici (OBX-8 HH, LL, AA, > o <) che non hanno raggiunto ogni destinazione.
- Privacy e sicurezza: chi ha aperto messaggi, cercato pazienti o letto autorizzazioni preventive nella console negli ultimi 7 giorni, dal registro di audit (l'apertura di un messaggio è registrata come
message.read). Inoltre, ogni token API attivo e quando è stato utilizzato l'ultima volta; un token non utilizzato per 90 giorni è contrassegnato.
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.
3.4.6 Collegamenti sanitari
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:
- Le quattro API: se Patient Access, Provider Access, Payer-to-Payer e Prior Authorization sono pronte in questa istanza,
e cosa ancora necessita ciascuna.
- Coda di revisione: le richieste PAS in attesa di un operatore, elencate in base alla scadenza, con i documenti inviati per ciascuna; approvare, negare o
certificare meno unità. Vedi la coda di revisione.
- Richieste di rimborso a CARIN BB: un 837 e il suo 835 convertiti in bundle CARIN Blue Button.
- Autorizzazione preventiva a PDex: una risposta PAS convertita in un'autorizzazione preventiva PDex.
- Metriche di autorizzazione preventiva: la pagina delle metriche pubbliche annuali di autorizzazione preventiva, anticipata da un CSV di decisioni.
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:
| Parte | Chiave | Obbligatorio | Cosa fa |
|---|---|---|---|
| Identità | name | sì | Nomina il canale. Deve essere unico. |
| Tipo di dati | dataType | no | Come analizzare i messaggi. Predefinito HL7 v2. |
| Sorgente | source | sì | Dove arrivano i messaggi. Esattamente uno. |
| Filtro | filter | no | Decide quali messaggi accettare. |
| Trasformazioni | transformations | no | Modifiche ordinate al messaggio. |
| Destinazioni | destinations | sì | 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.
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.
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
- 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.
- 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. - 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.
- 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. - Trasformazione. Le trasformazioni (
transformations) del canale vengono eseguite in ordine, ciascuna contro il risultato dell'ultima. - Distribuzione. Ogni destinazione riceve una copia del messaggio trasformato, applica le proprie trasformazioni se ne ha, e consegna.
- Registrazione dell'esito. Per ogni destinazione: consegnato, in coda, fallito o filtrato.
- 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.
5.4 Dove viene registrato il messaggio
Prima del filtro e quindi prima di qualsiasi trasformazione. Tre conseguenze:
- Un messaggio che il filtro ha rifiutato è ancora presente nell'archivio. È possibile vedere cosa è arrivato e confermare che il filtro abbia agito correttamente.
- La riproduzione e l'elaborazione ripetuta partono sempre da ciò che è effettivamente arrivato, non da una versione parzialmente trasformata.
- Una modifica alle trasformazioni può essere testata contro il traffico storico reale, perché l'originale è ancora presente. Vedi testing.
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
| Fase | Come si presenta un errore | Cosa succede |
|---|---|---|
| Arrivo | Errore di strutturazione, connessione interrotta a metà messaggio | Registrato, connessione chiusa, mittente ritenta |
| Analisi | Non valido per il tipo dichiarato | Registrato come errore di analisi, conferma negativa se la sorgente se lo aspetta |
| Filtro | Il filtro stesso genera un errore | Trattato come un rifiuto, registrato con l'errore |
| Trasformazione | Un passaggio ha esito negativo | Dipende dal on_error del passaggio; vedere trasformazione |
| Consegna | Destinazione irraggiungibile o rifiuta | Inserito 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.
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
| Passaggio | Cosa fa |
|---|---|
set | Scrive un valore letterale in un percorso, creandolo se assente. |
copy | Copia un percorso in un altro, con un valore predefinito opzionale quando la sorgente è assente. |
clear | Svuota un campo, lasciandolo presente. |
remove | Rimuove completamente un campo. |
map | Cerca il valore corrente in una tabella e lo sostituisce. |
replace | Sostituzione con espressione regolare all'interno di un campo. |
pad | Riempe un valore fino a una larghezza fissa. |
date | Converte una data o un timestamp tra formati. |
trim | Rimuove gli spazi bianchi circostanti. |
case | Converte 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:
setcrea il percorso che indica, compresa la struttura intermedia. Ciò è comodo e significa chesetnon può mai dimostrare che un campo era assente — dopo il passaggio esiste. Per testare cosa succede quando un campo è mancante, utilizzarecopyda un percorso che non esiste.- Un percorso senza indice si riferisce a tutte le ripetizioni e a tutte le occorrenze, come fa in un filtro (dove
PID-3.5 == "SS"è vero quando qualsiasi ripetizione lo è). Su un messaggio con cinque segmenti OBX,setsuOBX-5modifica tutti e cinque, esetsuPID-3.4rinomina ogni identificatore in PID-3, compreso quello del numero nazionale. Per modificare uno solo, fornire il suo indice:PID-3(1).4,OBX(2)-5.
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:
fail— il valore predefinito. Il messaggio si ferma e viene registrato come un fallimento di trasformazione.keep— lasciare il valore originale intatto.clear— svuotare il campo.
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:
- Un
mapdopo uncasevede il valore convertito dal caso, quindi le chiavi della sua tabella devono corrispondere alla forma convertita. Una tabella diM/Fdopo un passaggio in minuscolo non corrisponde a nulla, silenziosamente, perché un valore non nella tabella viene lasciato invariato. - Un
copyda un campo che un passaggio successivo rimuove funziona comunque, perché è stato eseguito per primo. Il contrario non è vero.
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à:
- Valori di esempio per un campo sorgente, dopo un segno di uguaglianza:
ZPI-1 = MRN00412, MRN00998 - Il tipo di valore che un campo di destinazione tiene, nello stesso modo:
PID-3.1 = mrn. I tipi sonomrn,npi,ssn,phone,dateeemail.
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:
| Valore | Cosa rappresenta |
|---|---|
javascript | Il valore predefinito. Uno script non contrassegnato è JavaScript. |
lua | La scelta migliore quando nessuno sta eseguendo una migrazione. |
wasm | I 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ò.
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: [...]
statusèapproved(predefinito),draft(utilizzato da nulla) oretired
(conservato per la registrazione, utilizzato da nulla).
- Due edizioni di uno stesso nome con la stessa versione, o due edizioni approvate
che iniziano lo stesso giorno, vengono rifiutate quando il file viene caricato.
- Salvare una nuova versione senza data di inizio mentre un'altra è approvata la data
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.
- I propri
defaultestrictdi un passaggio di mappatura vengono utilizzati quando il passaggio li imposta;
altrimenti vengono utilizzati quelli della tabella.
- Nello schermo Tabelle, Mostra versioni elenca ogni edizione con il suo stato,
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:
| Formato | File | Sistema |
|---|---|---|
loinc | Loinc.csv dalla tabella di rilascio LOINC | http://loinc.org |
icd10cm | il file di ordinamento CMS (icd10cm_order_*.txt) o il file dei codici | http://hl7.org/fhir/sid/icd-10-cm |
rxnorm | RXNCONSO.RRF dal rilascio completo RxNorm | http://www.nlm.nih.gov/research/umls/rxnorm |
snomed | lo snapshot delle descrizioni RF2 (sct2_Description_Snapshot-en_*.txt) | http://snomed.info/sct |
snomed-rf2 | un 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} |
claml | un file ClaML: ICD-10 dell'OMS, ICD-10-GM e OPS (BfArM), CIM-10 FR (ATIH) | dal titolo del file o dal system fornito |
icd11 | la tabulazione MMS semplice dell'ICD-11 dell'OMS (separata da tab, con colonne Code e Title) | http://id.who.int/icd/release/11/mms |
csv | qualsiasi 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:
- una tabella che nomina
source_systemotarget_systemha le sue voci controllate quando
viene salvata e i codici che non sono nel sistema vengono elencati nella versione;
- Trova un codice cerca per codice o per parole nel nome;
- il server FHIR risponde a
CodeSystem/$lookupeCodeSystem/$validate-code
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:
- A broker source takes a
selector, which filters at the broker. Messages this channel does not want never cross the network at all. On a shared queue that is the difference between reading a hundred messages a day and a hundred thousand. - A database source's query decides what it returns.
- A file source's pattern decides which files it picks up.
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.
| Valore | Formato |
|---|---|
hl7 | HL7 v2, lo standard delimitato da pipe. Il valore predefinito. |
hl7v3 | Documenti HL7 v3 e CDA, che sono XML. |
x12 | ASC X12, utilizzato per l'idoneità e le richieste di rimborso. |
ncpdp | Standard di telecomunicazione NCPDP D.0 per le richieste di rimborso farmaceutiche. |
script | NCPDP SCRIPT, prescrizioni elettroniche. XML. |
dicom | Oggetti di imaging DICOM. |
delimited | CSV e altri testi delimitati. |
raw | Nessun 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.
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:
x12: { arrives_as: xml }su un canale X12 prende quell'XML e lo gestisce come l'X12 che rappresenta (la scelta Arriva come del costruttore);x12_as: xmlsu una destinazione invia l'X12 come quell'XML (la scelta Invia come X12 XML di Mirth del costruttore);perfuse x12 xml [file]eperfuse x12 from-xml [file]convertono a riga di comando.
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.
| Valore | Comportamento |
|---|---|
require | Rifiuta lo scambio. Il valore predefinito. |
warn | Elaboralo, e registra il guasto contro il messaggio. |
ignore | Non 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.
| Transazione | Ciò che trasporta |
|---|---|
835 | Consiglio di rimborso: ciò che è stato pagato, ciò che è stato negato e i motivi di aggiustamento. |
275 | Allegati di richiesta: documentazione clinica a supporto di una richiesta. |
277 | Stato della richiesta, compresa la richiesta del pagatore di documentazione aggiuntiva. |
278 | Autorizzazione preventiva: la richiesta di revisione e la decisione del pagatore. |
999 | Conferma funzionale, che Perfuse genera anche. |
271 | Eleggibilità: se un paziente è coperto e i relativi importi di co-pagamento, co-assicurazione, deducibile e fuori tasca, in rete e fuori rete. |
|---|---|
834 | Iscrizione: membri aggiunti, modificati e terminati, con ogni linea di copertura e relative date. |
837 | Richieste, 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 è arrivato | Ciò che significa | Ciò che fare |
|---|---|---|
HCR con azione A3 | Il pagatore ha considerato la richiesta e non la certificherà. | Appellare, o cambiare il piano di cura. |
Un segmento AAA | Il 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:
- Nessuna decisione viene aggiornata. La certificazione parziale rimane parziale e una richiesta che il pagatore ha rifiutato di considerare non diventa un rifiuto. Entrambe le compressioni sono disponibili nella mappatura ovvia e entrambe sono errate nella direzione costosa.
- Nessun campo obbligatorio viene inventato. Un evento certificato senza numero di autorizzazione viene segnalato come tale, non gli viene assegnato un numero plausibile — un numero inventato produce una richiesta che viene successivamente rifiutata per un motivo che nessuno può rintracciare.
- Viene utilizzata una decisione portata solo a livello di riga. Un pagatore che risponde per servizio può lasciare l'evento senza una decisione propria; leggere solo il livello dell'evento lo segnalerebbe come in sospeso e un'attività aspetta una risposta che già ha mentre l'approvazione scade. Quando le righe sono in disaccordo, vince la meno favorevole, perché un evento con una riga rifiutata non è un'approvazione.
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 andava | Dove 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.
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.
- Il payload è in
BDS, nonBIN.BDS01nomina un filtro,ASCoB64.BDS02è la lunghezza eBDS03i dati. - Il payload è un'entità MIME, con intestazioni che dicono cosa è il documento e un corpo base64. Con
B64l'entità stessa è anche base64.
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.
- Dove le due guide concordano, Perfuse le segue.
- Dove differiscono, soddisfa entrambe se possibile.
CAT02èHLper un documento HL7, che esMD utilizza, eIAper un'immagine, che UnitedHealthcare utilizza. - Altrimenti, invia il segmento opzionale solo quando viene fornito il valore: l'identificatore di richiesta di rimborso
REF*X1di esMD e la data di servizioDTP*472di UnitedHealthcare.
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.
- Cosa viene firmato. L'intero documento tranne i partecipanti
legalAuthenticatoreauthenticator, in modo che ogni firmatario successivo lasci intatte le firme precedenti. La firma lo afferma con un filtro XPath 2.0 di trasformazione che ogni libreria di firme XML può valutare. - Dove va. In base64 in
sdtc:signatureTextsul partecipante firmatario, con una descrizione in testo normale su una riga. Il firmatario è l'autenticatore legale del documento se ne ha uno non firmato, altrimenti un nuovoauthenticator. - Cosa afferma. Il certificato del firmatario, l'ora in UTC, un ruolo dalla tassonomia dei fornitori NUCC e uno scopo da ASTM E1762. Lo scopo predefinito è *Firma dell'autore* per un autenticatore legale e *Firma del coautore* altrimenti, come nell'esempio della guida.
- Quanto dura. La guida chiede XAdES-X-L, che trasporta tutto ciò che un pagatore necessita per verificare la firma anni dopo senza raggiungere la rete. Ciò include il percorso di certificazione, una risposta OCSP o CRL dal CA e due timestamp da un'autorità di timestamp. Perfuse recupera i dati di revoca dagli indirizzi nel certificato e i timestamp da
-tsa-url.
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:
- Una lunghezza dichiarata che non corrisponde ai dati viene rifiutata, nominando entrambi i numeri. La domanda utile è se il conteggio del mittente era errato o se il file è stato troncato durante il trasferimento, e solo i due numeri forniscono la risposta.
BDS, il segmento binario006020, mantiene il proprio conteggio inBDS02e i propri dati inBDS03. È stato rifiutato fino a quando non è stato possibile confermarlo da una fonte pubblicata piuttosto che ricordata, e due fonti lo confermano ora: la tabellaBDSdella guida esMD dei CMS e la guida di UnitedHealthcare.
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.
| v2 | FHIR |
|---|---|
ADT | Paziente, 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. |
ORU | DiagnosticReport 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, OMG | ServiceRequest. |
SIU | Appuntamento, con il paziente, i professionisti da AIP e le sedi da AIL. |
MDM | DocumentReference che trasporta il documento. |
VXU | Immunizzazione, 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ù.
- Stato. Lo stato del filler in
SCH-25decide, e l'evento trigger viene utilizzato solo quando quello è vuoto. - Fasce orarie bloccate. Una fascia oraria bloccata non è un appuntamento con un paziente e non produce nulla.
- Ora di inizio. Viene letta da
AIS,AIG,AILoAIPper prima, poiSCH-11, perché la versione 2.5 lo ha spostato e i feed non lo hanno fatto tutti. - Durate. Una durata in un'unità che Perfuse non riconosce viene omessa, non indovinata.
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.
- Embedded documents. An embedded PDF, TIFF or JPEG (
ED) is carried byte for byte. Base64 that is not valid base64 is refused rather than passed on. - Types. The document type in
TXA-2is kept as sent and, where there is a clear equivalent, given the LOINC code US Core uses. - Signing. A note nobody has signed is
preliminary, andT11makes the documententered-in-error. - No content. A notification with no content (
T01,T03and the other odd-numbered events) produces no DocumentReference. FHIR requires content, and an empty attachment would look like the note while saying nothing.
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.
- Dosi rifiutate. Una dose rifiutata o non somministrata (
RXA-20REoNA) ènot-done, con il motivo daRXA-18. - Cancellazioni. Una cancellazione (
RXA-21D) èentered-in-error. - Registri storici. Un registro trascritto da un'altra fonte (
RXA-9diverso da00) non è una fonte primaria. - Quantità sconosciute. Una quantità di
999significa sconosciuta, non 999. - Route e siti. Ogni dose prende la route e il sito da
RXRsuccessivo, quindi un messaggio con due dosi non assegna la route della prima dose alla seconda.
Input scomodo. Ognuno di questi viene segnalato nelle note piuttosto che deciso silenziosamente:
- Identificatori.
PID-2ePID-4, ritirati dopo la versione 2.7 ma ancora inviati, vengono mantenuti comePID-3.CX.7eCX.8diventanoIdentifier.period. Un'autorità di assegnazione che trasporta un OID ISO (AUSHIC&2.16.840.1.113883.3.879&ISO) diventaurn:oid:. Un codice di tipo al di fuori della tabella HL7 0203 viene mantenuto come testo, non etichettato come tale. - Unioni.
MRGsu un evento di unione (A40e suoi simili) invia anche il record ritirato, inattivo, conPatient.linkin entrambe le direzioni. Su qualsiasi altro evento, come unA08, nulla viene unito e un avviso indica che l'identificatore precedente è ancora attivo. - Tempi. Un'ora di nascita in
PID-7va all'estensionepatient-birthTime. Un timestamp senza offset prende il fuso orario configurato, altrimenti l'offset suMSH-7(v2 presume il tempo locale del mittente), altrimenti UTC. Un'ora di nascita è l'eccezione: senza offset da uno dei tre viene omessa piuttosto che etichettata come UTC, perché un offset errato può spostare una nascita in un altro giorno.birthDateviene mantenuto e un avviso indica che l'ora è stata eliminata e che impostare un fuso orario per il feed la mantiene. - Risultati. Le ripetizioni di un risultato di testo vengono unite con interruzioni di riga. Un risultato
ED, o un risultato codificato il cui valore è chiaramente Base64, diventa un DocumentReference che l'Osservazione punta inderivedFrom, poiché un'Osservazione R4 non ha un valore di allegato. Un comparatoreSNdi=viene eliminato come ridondante;<>mantiene il testo, perché nessuna quantità può dire "non uguale". - Visite. Un
A08con una data di dimissione (PV1-45) è un incontro terminato. Una classe di paziente mancante o sconosciuta è il sapore nulloUNK, perché R4 richiede una classe. - Segmenti Z vengono nominati in un avviso, poiché non esiste una mappa standard per essi.
- Nomi. Quando il mittente divide un cognome (
XPN.1,XCN.2) nelle sue parti - un prefisso del cognome e un cognome, quello della persona e quello del partner, come vengono inviati i nomi olandesi e fiamminghi -familyè il nome completo e le parti vanno nelle estensioni del cognome di HL7 (humanname-own-prefix,-own-name,-partner-prefix,-partner-name). - Procedure.
PR1diventa una Procedura con statounknown, poiché un ADT non specifica se è stata eseguita o pianificata; l'anestesista (PR1-8) e il chirurgo (PR1-11) sono esecutori con ruoli SNOMED CT. Un codice OPS ottiene anche la sua categoria SNOMED CT dal suo capitolo, tramite la mappaOPS-SNOMED-Categorydi HL7 Deutschland, richiesta da ISiK.
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 v6 | Da | Come |
|---|---|---|
| Dati demografici del paziente | PID | Nome, 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'incontro | PV1 | Incontro con tipo, classe, periodo, sede e partecipanti |
| Informazioni sulla struttura | PV1-3 | Sede, con la struttura come sua organizzazione di gestione |
| Problemi, data di insorgenza | DG1 | Condizione (diagnosi dell'incontro). DG1-5 è l'insorgenza, come mappato da HL7 v2 a FHIR |
| Allergie e intolleranze, reazione | AL1 | AlergiaIntolleranza con categoria, criticità e reazione |
| Laboratorio | ORU | Referto diagnostico, Osservazioni, Campione (da SPM), Richiesta di servizio |
| Ordini | ORM, OML | Richiesta di servizio |
| Immunizzazioni | VXU | Immunizzazione |
| Note cliniche | MDM | Riferimento a documento |
| Membri del team di cura | PV1, TXA, DG1 | Professionista |
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:
- Le registrazioni contrassegnate come
entered-in-errorsono escluse. - Una condizione risolta rientra sotto le malattie passate, non i problemi.
- Un ordine di medicinale che è stato interrotto o completato è storia, non un medicinale corrente.
- Le tre sezioni richieste dall'IPS (problemi, allergie, medicinali) sono sempre presenti. Quando una di esse non contiene nulla, la sezione
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".
- I professionisti sanitari, le organizzazioni, i medicinali e le località a cui si riferiscono le voci sono inclusi, in modo che il documento possa essere letto autonomamente.
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.
- Ogni una delle quindici sezioni della guida è presente, ognuna con il proprio testo, nell'ordine della guida: direttive anticipate, allergie, salute comportamentale, stato funzionale, immunizzazioni, istruzioni di dimissione, dispositivi medici, farmaci, piano di cura, problemi, procedure, motivo di rimando, risultati, storia sociale e segni vitali.
- Una sezione del documento che non è presente viene indicata come mancante, mai compilata. Viene inviata vuota, con il motivo codificato
unavailablee la frase "Il documento di invio non aveva una sezione ...". Una sezione di allergie vuota non deve essere interpretata come "nessuna allergia nota". - Una sezione trasportata come testo solo mantiene il proprio testo e non riceve voci. La prosa non viene convertita in dati codificati. Stato funzionale, salute comportamentale (la sezione di stato mentale del C-CDA), direttive anticipate, dispositivi medici, piano di cura, istruzioni di dimissione, motivo di rimando e storia sociale vengono inviati in questo modo attualmente; le note lo specificano per ognuna.
- Le voci codificate diventano risorse secondo le stesse regole della conversione ordinaria: allergie (US Core AllergyIntolerance), problemi e diagnosi di dimissione (US Core Condition, elenco dei problemi o diagnosi di incontro), procedure, immunizzazioni, risultati, segni vitali e farmaci come un elenco di farmaci PACIO di MedicationStatements (
104204-3, elenco dei farmaci dimessi, da una sezione di farmaci di dimissione;104202-7, elenco dei farmaci attivi, altrimenti). - Segni vitali nella forma FHIR. Una pressione sistolica e una pressione diastolica prese insieme diventano un pannello di pressione sanguigna (
85354-9) con due componenti, e un codice più specifico (peso corporeo misurato,3141-9) porta anche il codice dei profili dei segni vitali di FHIR (29463-7), oltre all'originale. - Chi e da dove. L'autore del documento diventa l'autore della Composizione (un Practitioner, con il NPI quando il suo cifra di controllo è valido), il suo custode l'organizzazione custode, l'incontro che la comprende il soggiorno che la sintesi chiude. Un documento senza un autore o senza un custode viene rifiutato: la guida richiede entrambi, e Perfuse non metterà un nome su un record clinico che nessuno ha fornito.
- La negazione mantiene il proprio significato. "Nessuna allergia nota" (un'allergia negata a qualsiasi sostanza) viene inviata come SNOMED CT
716186003; un'allergia negata a un farmaco viene rifiutata, perché FHIR non può dirlo e la risorsa direbbe il contrario; un problema negato èrefuted.
Tre modi per crearne uno:
- A channel: a
cdadestination withwrite: transferposts each document's transfer summary to the FHIR server's
Bundle endpoint (url), or writes <document>.transfer.json to dir. In the channel builder: Emit › A PACIO transfer summary.
- The command line:
perfuse fhir transfer [-authority OID=URI] [-out dir] <document.xml>.... - The console: Documents, turn on Also make a PACIO transfer summary, and read the document.
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à:
| Argomento | Si attiva in | Filtri |
|---|---|---|
https://perfuse.health/fhir/SubscriptionTopic/encounter | Incontro creato o aggiornato | patient, status, class |
https://perfuse.health/fhir/SubscriptionTopic/appointment | Appuntamento creato o aggiornato | patient, 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:
- An acknowledged change is never a lost notification. The notification is recorded in the same database transaction as the change it describes, and delivered from there, so it survives a restart. A test writes an Encounter, starts a new server on the same database, and checks the notification arrives.
- Notifications arrive in order, and gaps are visible. Event 2 is not sent before event 1 is accepted, and each notification carries the running count, so a receiver can tell when it has missed one.
- The server decides when a subscription is active. A new subscription is
requested, and becomesactiveonly when the endpoint accepts a handshake. A client that asks foractivegetsrequested. A refused handshake is tried again four times over about fifteen seconds before the subscription is anerror: it goes out the moment the subscription is stored, often before the client that created it is listening. - A full-resource notification carries the version that changed. A discharge notification carries the discharge, not whatever the Encounter had become by the time delivery succeeded.
- Failure is bounded. A refused delivery is retried with a growing delay. After ten consecutive failures the subscription goes to
error: later changes are counted but not queued, and updating the subscription resumes delivery from the oldest held notification. The count then shows how many were missed.
Ciò che un client può far fare al server è limitato di proposito:
- Gli endpoint devono essere
httpsa meno che l'operatore non passi-fhir-subscriptions-allow-http, che è per un ricevitore di test. - La politica di uscita viene applicata quando una sottoscrizione viene creata, nuovamente ad ogni consegna e sull'indirizzo che ogni connessione raggiunge effettivamente (quindi un nome che cambia ciò a cui si risolve tra il controllo e la connessione viene comunque rifiutato); i reindirizzamenti non vengono seguiti.
- Il payload predefinito è
id-only, che indica cosa è cambiato e consente al ricevitore di recuperarlo con le proprie credenziali. - Nulla di ciò che un ricevitore invia indietro viene mostrato a chicchessia, solo il suo codice di stato.
È 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:
- canali diversi da
rest-hook - battiti cardiaci
- notifiche su cancellazione
- le operazioni
$statuse$events
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.
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)
| Indirizzo | Attore | Transazioni |
|---|---|---|
/xds/repository | Document Repository | ITI-41 Fornire e registrare il set di documenti-b, ITI-43 Recuperare il set di documenti |
/xds/registry | Document Registry | ITI-18 Query di archiviazione del registro (tutte le tredici query di archiviazione), ITI-42 Registrare il set di documenti-b |
/xca/gateway | XCA Responding Gateway | ITI-38 Query tra gateway, ITI-39 Recuperare tra gateway, con -xds-home-community urn:oid:... |
/mhd | MHD Document Recipient and Responder | ITI-65 Fornire il bundle di documenti, ITI-66 Trovare elenchi, ITI-67 Trovare riferimenti a documenti, ITI-68 Recuperare documento |
/mhd/Patient | PDQm Supplier and PIXm Manager | ITI-78 Query sui dati demografici del paziente, ITI-83 Patient/$ihe-pix, dal negozio FHIR dei Pazienti |
/pixv3 | PIX Manager (HL7 v3) | ITI-44 Feed di identità del paziente HL7 V3, ITI-45 Query PIXV3, dall'indice del paziente (-mpi) |
/pdqv3 | PDQ 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:
periodStarteperiodEnd: obbligatori. Una data significa l'intera giornata.reportType:summary,subjectosubject-list.subject:Patient/<id>.reporter:Organization/<id>. Quando è assente, il report contiene un'organizzazione denominata daserve -measure-reporter.measure: una misura inviata in linea, come parametro POST.
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:
- 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.
- 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.
- 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 soli | Inseriti davanti a un revisore con la persona giusta | Mancati | Collegamenti errati | |
|---|---|---|---|---|
| Collegamento automatico disattivato (predefinito) | 0 | 2.649 di 3.000 | 351 | 0 |
| Attivato, pesi predefiniti | 1.637 | 1.012 | 351 | 0 |
| Attivato, pesi stimati dai record | 1.622 | 1.070 | 308 | 0 |
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.
8.16 Collegamenti e carte di salute SMART
*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.
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:
| Valore | Cosa viene inviato |
|---|---|
none | Niente. Il valore predefinito. |
999 | Acknowledgement di implementazione. Sostituisce il 997 per le transazioni HIPAA. |
997 | Acknowledgement funzionale. Più vecchio e ancora ciò che molti collegamenti dei pagatori si aspettano. |
ta1 | Acknowledgement 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.
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
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:
| Chiave | Cosa fa |
|---|---|
enabled | Se i messaggi non riusciti sono messi in coda. |
max_attempts | Quante volte provare prima di desistere. |
backoff | Attendere prima del primo ritentativo. |
max_backoff | Limite massimo dell'attesa crescente. |
max_depth | Numero massimo di messaggi da mantenere. Non impostato significa nessun limite. |
retain_hours | Quanto 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.
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 risponde | Registri 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 CR | Fallito, nello stesso modo. |
| Una fault SOAP (password errata, messaggio troppo grande) | Fallito, con il motivo del registro. |
| Qualcosa che non è un messaggio HL7 | Fallito. |
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
| Esito | Significato |
|---|---|
Delivered | La destinazione ha accettato il messaggio. Per MLLP, è stato ricevuto un acknowledgement positivo. |
Queued | La consegna ha avuto esito negativo e il messaggio sarà ritentato. |
Failed | La consegna ha avuto esito negativo e non sarà ritentato, sia perché la coda è disabilitata sia perché i tentativi sono esauriti. |
Filtered | La 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.
framing | Ciò che scrive |
|---|---|
mllp | 0x0b prima, 0x1c 0x0d dopo. Lo stesso framing utilizzato da una destinazione MLLP. |
delimited | Un delimiter dopo ogni messaggio, e un start_block opzionale prima di esso. |
fixed | Record padding o troncati a record_length. |
length | Un prefisso length_bytes. big_endian e length_includes_header hanno entrambi due convenzioni nel mondo reale e la differenza è silenziosa. |
whole | Un 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.
- Su una sorgente, l'intero file, oggetto, allegato di posta elettronica o corpo della richiesta viene
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.
- Su una destinazione, ciò che sarebbe stato consegnato viene crittografato (con uno di
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.
| Confermato | Presente a valle in seguito | Confermato ma mancante |
|---|---|---|
| 255 | 255 | 0 |
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 dopo | Confermato | Presente a valle | Perso |
|---|---|---|---|
| 5 | 5 | 1 | 4 |
| 25 | 25 | 1 | 24 |
| 75 | 75 | 2 | 73 |
| 110 | 110 | 2 | 108 |
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
| Tipo | Si attiva quando |
|---|---|
error-rate | I fallimenti superano una proporzione del traffico. |
queue-depth | Una coda ha più di N messaggi in attesa. |
queue-age | Il messaggio più vecchio in coda è più vecchio di una durata. |
queue-stuck | Una coda non si sta svuotando affatto. |
no-traffic | Nulla è arrivato per un periodo fisso. |
below-rhythm | Il traffico è ben al di sotto di ciò che questo flusso di lavoro fa normalmente *in questo momento della settimana*. |
channel-down | Un canale che dovrebbe essere in esecuzione non lo è. |
script-errors | Uno script sta fallendo. |
rows-quarantined | Una sorgente del database sta mettendo da parte le righe. |
slow-delivery | Le consegne stanno avendo successo ma stanno impiegando troppo tempo. |
contract | Un messaggio viola il contratto dichiarato del canale. |
phi-volume | Un canale trasporta diverse volte la sua tariffa abituale per l'ora. |
phi-after-hours | Un canale che trasporta solo traffico diurno trasporta alcuni di notte. |
phi-new-destination | Un canale consegna a un indirizzo a cui non ha inviato prima. |
phi-bulk-reads | Una 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.
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:
below-rhythm— il feed si è fermato quando non dovrebbe essere silenzioso.error-rate— i messaggi stanno arrivando e fallendo.queue-age— qualcosa è bloccato piuttosto che semplicemente occupato.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.
- Picchi (
phi-volume). La velocità di ogni canale viene confrontata con la sua storia alle stesse ore del giorno, quindi una mattina impegnata non è una notizia. La soglia è un multiplo della velocità normale, tre per default. Un picco è solitamente un ritardo rilasciato dopo un'interruzione e assomiglia anche a come vengono estratti i record attraverso un flusso. - Traffico notturno su un canale diurno (
phi-after-hours). Un canale viene considerato diurno quando meno del 2 per cento di ciò che ha trasportato è caduto al di fuori delle ore 07:00-19:00, nel fuso orario del server. - Una nuova destinazione (
phi-new-destination). L'indirizzo è ciò che la destinazione nomina: un host e una porta, un URL, una cartella. Rinominare una destinazione non è una notizia; puntarla verso un nuovo host è. Gli indirizzi a cui ogni canale ha inviato sono conservati inaccess-watch.jsonaccanto al database, quindi una destinazione modificata mentre il server era spento viene comunque segnalata. - Lettura in blocco (
phi-bulk-reads). Conteggiate dal registro di controllo: messaggi aperti, pazienti cercati o cercati (PDQm, PIXm, ricerca di identità), documenti e immagini letti (XDS, MHD, DICOMweb), autorizzazioni precedenti lette, riassunti e viste eseguite. La lettura dello stesso record più volte non viene conteggiata due volte. La soglia è il numero di record diversi in un minuto, dieci per default, per un account da un indirizzo.
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.
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:
- Cosa legge il filtro. Quali campi ha esaminato e quali valori ha trovato. Un filtro che rifiuta tutto di solito legge un percorso che non esiste in questo flusso di dati e questo lo indica.
- Ogni trasformazione. Cosa ha modificato, da cosa a cosa.
- Cosa decide ogni destinazione. Se accetterebbe il messaggio e perché no se non lo accetterebbe.
- L'output. Il messaggio come ogni destinazione lo invierebbe.
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
| Esito | Significato |
|---|---|
changed | Il passaggio è stato eseguito e ha modificato il messaggio. |
no-effect | Il passaggio è stato eseguito e il messaggio non è stato modificato. |
skipped | La condizione when del passaggio era falsa, quindi non è stato eseguito. |
failed | Il 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.
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:
- Attiva eventi di trigger nelle proporzioni effettivamente osservate, con almeno uno di ciascuno in modo che un evento raro appaia ancora.
- Campi popolati alle velocità in cui sono effettivamente popolati — quindi il caso in cui un campo è *assente* viene testato, che è il caso che rompe le cose.
- Ripetizioni dove si verificano ripetizioni, struttura composita dove si verifica.
- Codici tratti dalle tabelle di codici effettivamente visualizzate.
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.
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.
| Contenitore | Controlli | Cosa ha trovato |
|---|---|---|
| Keycloak 26 | web/e2e-saml/, e fixture internal/saml | Un 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 Entra | Test e fixture internal/saml live | Due 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 FHIR | go test ./internal/engine/ -run HAPI | Un 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 |
| ActiveMQ | go test ./internal/engine/ -run RealBroker | Corretto, 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 client | go test ./internal/engine/ -run ClientCertificate | Corretto |
| Orthanc (un vero PACS) | go test ./internal/engine/ -run RealPACS | Corretto. Un C-STORE arriva e il nome del paziente, l'identificatore, la data di studio, la modalità e la classe SOP sopravvivono |
| PostgreSQL | go test ./internal/engine/ -run RealPostgres | Corretto, 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-server | go test ./internal/engine/ -run OpenSSHServer | Corretto. 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.2 | go test ./internal/mirth/ -run RealMirth | Corretto 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:
- SMB contro una condivisione Windows reale — il codice del protocollo è completo e testato per la sicurezza del percorso e la gestione degli argomenti, ma nessun test apre un socket a un server associato a un dominio.
- Un portale seriale reale.
- L'importatore Mirth contro XML di un Mirth reale. Testato contro Mirth 4.5.2 in un contenitore, e il risultato è stato su questo repository: l'unico fixture di migrazione qui presente è stato scritto a mano e Mirth non lo caricherà — memorizza il canale come non valido e scarta ogni connettore. Ciò che è stato stabilito è che gli attributi
versionche il Mirth reale scrive su ogni elemento analizzano lo stesso canale, quindi non sono un pericolo; ciò che non è stabilito è tutto il resto che un'esportazione reale contiene. - SAML contro un provider di identità commerciale ospitato. Keycloak è verificato; un provider dimostra che un'implementazione corrisponde a un fornitore.
- Una richiesta NCPDP attraverso un interruttore di farmacia reale.
- Un messaggio SCRIPT attraverso Surescripts, dove la certificazione è un processo commerciale piuttosto che tecnico.
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.
| Risultato | Conteggio |
|---|---|
| Risorse convalidate senza riscontri | 13.723 |
| Risorse segnalate non valide | 0 |
| File rifiutati come tipo di risorsa non implementato | 753 |
| Voci del bundle saltate come tipo non implementato | 1.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:
| Esportazione | Dall'amministratore | Ciò che viene trasferito |
|---|---|---|
| Un canale | Esporta canale | Il canale |
| Un gruppo di canali | Esporta gruppo | Ogni canale in esso, ciascuno che mantiene il gruppo |
| Modelli di codice | Esporta modelli di codice | Ogni libreria come un file di script |
| Un backup del server | Backup configurazione o GET /api/server/configuration | Tutti 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.
15.4.1 Quattro numeri, non una percentuale di passaggio
| Risultato | Significato |
|---|---|
| Identico | Byte per byte lo stesso. |
| Solo cosmetico | Differisce in modi che non portano informazioni - campi vuoti alla fine, un terminatore finale. |
| Differente | Il valore di un campo è diverso. |
| Non eseguibile | Perfuse 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
- Importare i canali e risolvere tutto ciò che viene segnalato come illeggibile.
- Per ogni canale, esaminare gli avvisi. La maggior parte saranno script.
- Esportare alcune migliaia di coppie di messaggi da Mirth per il canale più trafficato e eseguire il confronto.
- Lavorare sui risultati. Quelli sistematici sono una decisione ciascuno.
- Eseguire nuovamente fino a quando le sole differenze sono quelle che si sono deciso siano corrette.
- 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.
- 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.
| Pacchetto | Classi |
|---|---|
java.util | ArrayList, 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.lang | String, StringBuilder, StringBuffer, Integer, Long, Short, Byte, Double, Float, Boolean, Math, System (solo tempo e separatore di riga) |
java.text, java.math, java.net, java.nio | SimpleDateFormat e DateFormat (lettere del modello di Mirth), BigDecimal (come un double), URLEncoder, URLDecoder, StandardCharsets |
| Apache Commons | lang3.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
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
| API | Che serve | Guide | Attivato da |
|---|---|---|---|
| Accesso paziente | Le richieste, i dati clinici e le autorizzazioni precedenti di un membro, a un'app che sceglie | CARIN Blue Button 2.2.0, PDex 2.2.0, US Core, SMART App Launch | -fhir e un emittente SMART (-smart-issuer) |
| Accesso fornitore | Lo stesso per i membri attribuiti a un fornitore, in blocco | PDex 2.2.0, Da Vinci ATR 2.1.0, Bulk Data | -fhir-payer-apis e -fhir-bulk-export |
| Payer-to-Payer | Il record di un membro a un altro pagatore, dopo averlo abbinato | HRex 1.2.0 $member-match, PDex 2.2.0 | -fhir-payer-apis |
| Autorizzazione preventiva | Ciò di cui un ordine ha bisogno, la documentazione, quindi la richiesta e la decisione | Da 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:
- 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); - dalla registrazione del chiamante:
davinci_version: "2.1"su un client SMART (-smart-clients) o un client CDS (-cds-clients); - 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:
billing_codes: i codici da addebitare.details: limiti e costi, come ad esempioallowed-periodoin-network-copay.contact: chi contattare.expiry_days: per quanto tempo la risposta rimane valida.depends_on: codici di altri ordini di cui la risposta dipende, in modo che il sistema EHR richieda nuovamente se cambiano.doc_purpose: lo scopo della documentazione (withclaim,withorder,retain-doc).withpaviene rifiutato, poiché l'invariante crd-ci-q4 di CRD 2.2.1 lo rifiuta.
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:
- un paziente che non è un membro riceve la risposta
no-member-found; - un membro la cui copertura non corrisponde riceve la risposta
coverage-not-found; - un'autorizzazione preventiva già approvata per il servizio (una ClaimResponse con un
preAuthRef) fa si che la risposta siasatisfied,
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:
- Il sistema di identificatori. CARIN richiede che l'identificatore del membro nomini lo spazio dei nomi del pagatore.
-systemè richiesto; non c'è un valore predefinito, perché un valore predefinito darebbe a ogni pagatore che utilizza Perfuse lo stesso spazio dei nomi. - Lo stato di rete. Nessuna delle due transazioni dice se il fornitore di fatturazione è in rete e decide cosa paga il membro. Senza
-networklo stato di pagamento del beneficio èothere la conversione nota il motivo. - Un reclamo che l'835 non menziona. Un ExplanationOfBenefit CARIN è un reclamo giudicato. Senza l'835 non c'è un numero di reclamo del pagatore, non c'è pagamento e non c'è responsabilità del membro, quindi il reclamo viene segnalato come saltato e non convertito.
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:
POST /fhir/Patient/$member-match— abbinamento dei membri HRex. Gli identificatori di copertura si restringono a pochi candidati e il cognome e la data di nascita devono essere concordi; un nome proprio è confrontato per iniziale e il genere solo quando entrambi i lati lo indicano. Più di un candidato superstite non è un abbinamento e la risposta è 422 anziché un'ipotesi, poiché un'ipotesi rivela le pretese di uno sconosciuto. È richiesto un consenso attivo che consente la divulgazione, poiché l'API di comunicazione tra pagatori è opt-in per il membro;-fhir-member-match-without-consentlo disattiva per i test.GEToPOST /fhir/Group/{id}/$davinci-data-export— l'esportazione bulk Da Vinci del gruppo corrente.exportTypesceglie il pubblico:hl7.fhir.us.davinci-pdex#provider-downloado#provider-deltaper l'accesso ai fornitori,#payertopayerper la comunicazione tra pagatori.GET /fhir/Group/{id}/$export— l'esportazione standard dei dati del gruppo, trattata come accesso ai fornitori.
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:
| Richiesta | Risposta |
|---|---|
PAInitiationRequest | Closed 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. |
PARequest | Deciso come una richiesta PAS: Approved con il numero di autorizzazione e il periodo, Denied con il motivo, o Open in revisione. |
PAAppealRequest | Un caso respinto deciso di nuovo, sul motivo in PANote (un appello senza uno viene richiesto). |
PACancelRequest | Approved 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:
| Trasporto | Cosa viene inviato | Autenticazione |
|---|---|---|
x12 (predefinito) | La 278 inviata come application/edi-x12; la risposta è il corpo della risposta | Un token bearer, OAuth, HTTP Basic, un certificato client |
core-soap | La 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 MTOM | vC2.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-mime | La busta CAQH CORE vC2.2.0 HTTP MIME multipart, il payload come parte del file | Il nome utente e la password della busta o un certificato client |
sftp | Ogni 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:
| Stato | Significato |
|---|---|
| Pronto qui | Perfuse lo fornisce e è attivato. |
| Pronto, con un divario | È attivato e parte del criterio è al di fuori di esso (nominato sullo schermo). |
| Costruito, non attivato | Perfuse lo fornisce; lo schermo nomina l'impostazione o il flag che lo attiva. |
| Da fare | La parte dell'organizzazione: un accordo, una certificazione, pubblicazione nell'elenco dei fornitori nazionali. |
| Non costruito | Il software lo farebbe e Perfuse no. |
Ciò di cui hanno bisogno i quattro in vigore da questo server:
| Criterio | In Perfuse | Attiva |
|---|---|---|
| 13 API FHIR, US Core, Bulk Data | L'endpoint FHIR con il suo CapabilityStatement e $export | -fhir, -fhir-bulk-export |
| 14 Documenti come allegati FHIR | DocumentReference con Binary e IHE MHD sul registro XDS | -fhir (MHD anche -xds) |
| 15 Notifiche di incontro e appuntamento | Sottoscrizioni basate su argomento (R5 Backport per R4) dai feed ADT e SIU | -fhir-subscriptions |
| 16 Indicatore di registrazione | Il 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.
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:
| Ruolo | Può |
|---|---|
| Monitor | Vedere 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. |
| Viewer | Leggere anche i messaggi, file di canale, tracce e registro di attività. |
| Operator | Rinviare anche: riprocessare un messaggio, riprodurre un canale e ritentare le consegne in coda. |
| Editor | Creare e modificare anche i canali e eseguire confronti. |
| Admin | Avviare 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:
- Token API Perfuse, creati in Utenti → Credenziali macchina o con
perfuse token create. Ognuno ha un ruolo e può essere
limitato ai Gruppi FHIR. Questo è l'impostazione predefinita quando non è configurato un server di autorizzazione SMART.
- Token di accesso SMART, dal server di autorizzazione di Perfuse (
-smart-clients) o da uno esterno (-smart-issuer). Ognuno
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:
- Scrive un minuto da un client (
-fhir-writes-per-minute): crea, aggiorna e cancella da un indirizzo client. Oltre ad esso, una
scrittura viene risposta 429 con Retry-After: 60. Le letture e le ricerche, incluse le ricerche tramite POST, non vengono mai conteggiate.
- Risorse più tenute (
-fhir-max-resources): superato questo limite, nuove risorse vengono rifiutate con 507, mentre aggiornamenti e cancellazioni continuano a funzionare.
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>" } } } }
| Strumento | Ruolo | Funzionalità |
|---|---|---|
server_status, list_channels, queue, alerts | monitor | Verifica se tutto funziona, senza contenuti dei messaggi |
get_channel, search_messages, get_message, find_patient, fhir_search | viewer | Canali, messaggi (con contenuti), messaggi di un paziente su più formati, ricerca FHIR |
retry_delivery, reprocess_message | operator, e mcp:write | Ritenta la consegna in coda, invia nuovamente un messaggio attraverso il suo canale |
start_channel, stop_channel | admin, e mcp:write | Avvia 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:
| Archiviazione | Trovato da |
|---|---|
| Messaggi | l'indice di identità (Impostazioni → Dati → Indice degli identificatori dei pazienti); senza di esso, i messaggi non possono essere trovati per identificatore |
| La coda di consegna | leggendo gli identificatori di ogni messaggio in coda |
| L'archiviazione FHIR | le risorse Paziente che contengono un identificatore e ogni risorsa le cui referenze indicizzate puntano a uno |
| Richieste di autorizzazione preventiva | gli identificatori del paziente della richiesta |
| L'indice dei pazienti | l'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.
- Accesso e portabilità: Scarica la copia fornisce un file zip: ogni messaggio come ricevuto con il suo record, ogni risorsa FHIR con ogni versione memorizzata, le richieste di autorizzazione precedenti e le loro risposte, e i record dell'indice dei pazienti, tutto in formato JSON, con un file README che spiega cosa rappresenta ogni parte. Segna come risposto chiude la richiesta.
- Cancellazione: un secondo amministratore approva la richiesta (chi l'ha registrata non può farlo). Cancella ora elimina tutto ciò che è stato trovato: messaggi interi (record, corpo, consegne, identificatori, allegati che non vengono utilizzati da altri messaggi), consegne in coda (non vengono inviate), le risorse FHIR con la loro storia, le richieste di autorizzazione precedenti con le loro risposte, allegati e numeri di tracciamento, e la persona nell'indice dei pazienti con ogni record collegato e la sua storia (un evento registra che una cancellazione è avvenuta e da parte di chi).
- Restrizione: registrata come una richiesta di blocco legale, in modo che nulla venga cancellato o scada mentre dura.
- Rifiuta chiude una richiesta con il suo motivo, che deve essere comunicato alla persona.
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.
- Canali: quanti canali il tenant può avere. La creazione di uno in più viene rifiutata, con il conteggio e il limite.
- Messaggi al minuto: quanti messaggi i suoi canali possono ricevere insieme in un minuto.
- Archiviazione: quanti contenuti di messaggi archiviati può conservare, in megabyte.
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:
- Solo il certificato configurato è attendibile. Un certificato contenuto all'interno di una risposta non viene mai utilizzato. Un attaccante che può inviare un documento può anche inserire il proprio certificato in esso, e un verificatore che lo legge è uno che chiunque può autenticare come chiunque.
- Una risposta deve rispondere a un accesso avviato da questo server. Perfuse ricorda la richiesta che ha inviato e rifiuta una risposta che nomina qualcos'altro, o nomina una richiesta che ha già risposto. Senza questo controllo, una risposta valida è un token di portatore per chi lo detiene: qualcuno si accede come se stesso, mantiene la risposta e la invia nel tuo browser, e poi sei all'interno del suo account con il registro di audit che registra il suo nome.
- Gli accessi avviati dal provider di identità sono quindi disabilitati per default. Attiva *Accetta accessi avviati dal provider di identità* solo se hai bisogno di un riquadro del portale, e sapendo che è ciò che rende possibile quanto sopra.
- L'attributo di gruppo non ha un valore predefinito e è obbligatorio. Entra invia
groups, Okta invia ciò che l'applicazione è stata configurata per inviare, ADFS invia un URI di attestazione. Una supposizione produrrebbe un accesso che funziona e non concede nulla a nessuno. Se un accesso viene rifiutato per non avere un ruolo, il registro del server nomina gli attributi che sono effettivamente arrivati — che è di solito la risposta completa. - L'URL di risposta deve corrispondere esattamente a ciò che è registrato presso il provider. Una risposta dice dove è destinata e una risposta indirizzata altrove viene rifiutata, perché accettarla significherebbe accettare una risposta destinata a un servizio diverso.
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.
| Provider | Di solito invia | Note |
|---|---|---|
| Keycloak | groups | Richiede un mapper di appartenenza al gruppo aggiunto al client. |
| Entra ID | un URI di attestazione che termina /claims/groups | Invia oggetti ID di gruppo a meno che l'applicazione non sia configurata per inviare nomi. Mappa gli ID o modifica il provider. |
| Okta | ciò che l'applicazione è stata configurata per inviare | Di solito groups, con un filtro che decide quali vengono inviati. |
| ADFS | un URI di attestazione | Firma 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.
- La disabilitazione di un account termina immediatamente le sue sessioni, e il server verifica che nessuna sia sopravvissuta prima di rispondere. Un fornitore non viene mai informato che un account è stato disabilitato quando non lo è stato, perché un fornitore non ritenta ciò che gli è stato detto di aver avuto successo.
- Un eliminazione disabilita prima, quindi elimina, quindi un errore a metà strada lascia un account con cui nessuno può accedere. La storia di audit di un account rimosso viene conservata.
- Il ruolo deriva dai gruppi o ruoli della persona, abbinati per nome: un gruppo il cui nome contiene *admin*, *editor*, *operator*,
*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.
- Nessuna password. Un account creato da SCIM accede tramite il provider di identità; una seconda password che nessuno a monte conosce sopravviverebbe a una disabilitazione.
/scim/v2/ServiceProviderConfigindica cosa è supportato: creazione, lettura, sostituzione, patch e eliminazione di Utenti, e filtri fino a 200
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.
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
- L'agente risponde a GET, GETNEXT e GETBULK, e solo dalle reti in
-snmp-allow: la community di v2c è una password inviata in chiaro, quindi non è mai aperta a tutti. Una community con meno di 6 caratteri, opublic/private, ferma il server all'avvio. - Fornisce il gruppo di sistema (sysDescr, sysUpTime, sysName dal label della flotta, sysContact, sysLocation), totali sotto
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.
- Le trappole vanno a ogni gestore in
-snmp-traps:BASE.0.1un allarme attivato,BASE.0.2si è risolto, trasportando il tipo di allarme,
gravità, canale, destinazione e riassunto. Mai il contenuto del messaggio. Un allarme riconosciuto non invia trappole.
BASEè1.3.6.1.4.1.8072.9999.9999.16(spazio sperimentale di Net-SNMP) a meno che-snmp-base-oidnon lo metta sotto il proprio
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.
active-passive: il leader esegue ogni canale e ogni lavoro che deve essere eseguito una volta (notifiche di abbonamento FHIR). Gli
altri aspettano. Il più semplice da capire, e ciò che un sito con un server occupato e uno di riserva vuole.
active-active: i canali sono distribuiti sui server attivi, più o meno uniformemente. Un server che si ferma passa i propri canali
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:
| Test | Messaggi | Confermati ma persi | Copie | Tempo più lungo atteso da un mittente |
|---|---|---|---|---|
| Attivo-passivo, il server che esegue il flusso ucciso due volte (Linux, poi Windows), destinatario che rifiuta nel frattempo | 2.000 | 0 | 0 | 15 s |
| Un leader Linux tagliato fuori dal database (firewall), il suo processo lasciato in esecuzione | 3.000 | 0 | 1 | 16 s |
| Un leader Windows tagliato fuori dal database | 3.000 | 0 | 0 | 20 s |
| Il leader ucciso mentre un orologio del server correva 2 minuti avanti e un altro 90 secondi indietro | 2.000 | 0 | 0 | 18 s |
| Attivo-attivo, quattro flussi su tre server, uno ucciso e riportato | 6.000 | 0 | 2 | 24 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.
-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:
- Lo stesso sale produce sempre lo stesso corpus, quindi un corpus condiviso può essere rigenerato invece di essere archiviato.
- Mantieni il sale segreto. I pseudonimi sono derivati da valori reali, quindi chiunque detenga il sale può confermare un'ipotesi su chi si riferisce a un record.
-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.
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:
-measure FILE, o-measure example:IDper un esempio fornito: obbligatorio.-exampleselenca gli esempi.-period-starte-period-end: obbligatori.-type summary|subject|subject-list.-subject Patient/ID.-reporter NAME.-o FILE.
Vedi misure di qualità digitali.
19.6.5 Flag FHIR su perfuse serve
| Flag | Effetto |
|---|---|
-fhir | Servire l'endpoint FHIR a /fhir. Attivato per default. |
-fhir-version | La versione servita. R4 per default. |
-fhir-read-only | Rifiutare le scritture. |
-fhir-api-tokens | Con SMART configurato, accettare i token API Perfuse oltre ai token SMART (disattivato per default; anche sotto Impostazioni → FHIR). |
-fhir-bulk-export | Abilitare $export. Disattivato per default. |
-fhir-subscriptions | Abilitare 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-http | Consentire alle sottoscrizioni di consegnare a http semplice. Per un ricevitore di test, mai per i dati dei pazienti su una rete. |
-fhir-patient-directory-search | Consentire a un token limitato a un paziente di cercare la directory (operatori sanitari, organizzazioni, località), all'interno dei suoi ambiti. Disattivato per default. |
-fhir-declares | Guide 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
| Option | Takes | Default | What it does | In the console |
|---|---|---|---|---|
-addr | string | 127.0.0.1:8080, or 127.0.0.1:8443 with -tls-cert | address to serve the interface on | — |
-alert-severity | string | warning | minimum severity to send to the webhook: warning or critical | Settings › Alerts › Delivery: Only send alerts at least this serious |
-alert-webhook | string | — | POST alerts to this URL as JSON. Works with Slack, Teams, Mattermost, Alertmanager or anything that accepts a webhook. The payload carries channel names, counts and thresholds; never message content | Settings › Alerts › Delivery: Send alerts to this address |
-alerts | string | — | YAML file of alert rules. Default: alerts.yaml beside the database, written when the rules are first saved in the console; until then a conservative default set is used | — |
-allow-metadata-egress | on/off | — | permit destinations pointed at cloud instance metadata addresses, which hold this machine's credentials | Settings › Security › What may leave: Allow destinations at cloud instance metadata addresses |
-cds-clients | string | — | the EHRs trusted to call the CDS services with signed JWTs (issuer and jwks_url) | Settings › Payers › Prior authorization: EHRs trusted to call the CDS services |
-channels | string | ./channels | directory holding channel files | — |
-cluster | string | — | share the work with other servers on the same PostgreSQL -db: active-passive (one runs everything, another takes over when it stops) or active-active (channels spread over all) | — |
-cluster-lease | duration | 15s | how long a crashed server holds its work before another takes it over; renewed five times as often | — |
-crd-advisor-ca | string | — | a PEM file of certificate authorities to trust for -crd-advisor-url beside the system's (Vaglio's is its DATA/tls/ca.crt) | Settings › Payers › Decision service: Certificate authorities to trust for the advice service |
-crd-advisor-token-env | string | — | name of an environment variable holding a bearer token for -crd-advisor-url (the token itself is never a flag) | Settings › Payers › Decision service: Environment variable holding the advice service's token |
-crd-advisor-url | string | — | with -crd-rules, ask the decision service at this URL (such as Vaglio's /api/pas/advise) what a prior authorization request for each order needing one would be told as the record stands, shown as one more CRD card; the prefetched record is POSTed to it. No answer, or any failure, leaves the cards as they are without it | Settings › Payers › Decision service: Advice before submitting (CRD) |
-crd-rules | string | — | a Da Vinci CRD rules file: serve coverage requirements over CDS Hooks at /cds-services | Settings › Payers › Prior authorization: Coverage rules file (Da Vinci CRD) |
-dashboards | string | — | a file mapping directory groups and roles to the dashboard each opens on | Settings › Monitoring › Dashboards: Which dashboard each group opens on (file) |
-data | string | — | directory for this server's own files (settings, alerts, sign-in configuration, the log): default beside -db when it is a file, the current directory when it is a PostgreSQL URL | — |
-davinci-version | string | 2.2 | the Da Vinci CRD, DTR and PAS release answered when neither a request nor its client's registration says: 2.2 (CRD 2.2.1, DTR 2.2.0, PAS 2.2.1) or 2.1 (2.1.0) | — |
-db | string | ./perfuse.db | database for users, messages and stored resources: a file, or a postgres:// URL for servers that share one store (a cluster) | — |
-demo-account | string | — | for a public demonstration server: username:password of a shared viewer account shown on the sign-in page | — |
-dicomweb-archive | string | — | keep imaging objects in this directory and serve them over DICOMweb (QIDO-RS, WADO-RS, WADO-URI, STOW-RS) at /dicomweb | Settings › Data › Imaging archive: Keep images in this folder and serve them over DICOMweb |
-dicomweb-cors | string | — | comma-separated browser origins, such as an OHIF viewer's, allowed to call /dicomweb | Settings › Data › Imaging archive: Browser origins allowed to call it |
-drain-for | duration | — | after SIGTERM, report not-ready for this long before shutting down (for rolling deploys) | Settings › Engine › Shutdown: Wait for in-flight messages on shutdown |
-ecr-agency | string | — | play a public health agency for testing eCR: answer case reports at $process-message with a Reportability Response, using the agency YAML file given (name, phone, address, endpoint; optional rctc, reply) | Settings › Public health › Case reporting: Act as a test public health agency |
-ecr-responses | on/off | — | accept eCR Reportability Responses at the FHIR endpoint's $process-message, storing each as DocumentReference/<id> derived from the eICR it answers | Settings › Public health › Case reporting: Receive Reportability Responses |
-engine | on/off | true | run the channel engine in this process, so the interface can start, stop and monitor channels | — |
-epa-payer-id | string | — | this payer's identifier on the prescribing network, the From of every RTPB and ePA response (default: the formulary's payer id) | Settings › Payers › Drug formulary: Payer ID on the prescribing network |
-epa-reply-channel | string | — | route ePA decisions made after the request was answered (a reviewer's, an appeal's) to this channel, which delivers them to the prescriber's network | Settings › Payers › Drug formulary: Channel that sends later ePA decisions |
-fhir | on/off | true | serve a FHIR endpoint at /fhir | Settings › FHIR › The FHIR server: Serve a FHIR endpoint at /fhir |
-fhir-api-tokens | on/off | — | with SMART configured, accept Perfuse API tokens on the FHIR endpoint as well (unscoped; the console's FHIR settings can switch it) | Settings › FHIR › Access: Accept Perfuse API tokens beside SMART tokens |
-fhir-bulk-export | on/off | — | enable $export, which produces a file holding every record the FHIR endpoint serves | Settings › FHIR › Bulk data: Bulk Data export ($export) |
-fhir-declares | string | — | guides this FHIR server declares in its capability statement, comma-separated: a CapabilityStatement address, or Type=profile address | Settings › FHIR › Capability statement: Guides this server declares |
-fhir-max-resources | int | — | for a public server: refuse new FHIR resources once this many are held (0: no limit) | Settings › FHIR › Access: Most resources held |
-fhir-member-match-without-consent | on/off | — | let $member-match answer without an active Consent; the Payer-to-Payer API is opt-in, so only for testing | Settings › Payers › CMS-0057-F: Answer $member-match without the member's consent |
-fhir-open | on/off | — | serve the FHIR endpoint with no authentication at all, exposing every stored record | Settings › FHIR › Access: Let anyone read the FHIR endpoint without signing in |
-fhir-patient-directory-search | on/off | — | let a token limited to one patient search the directory (practitioners, organisations, locations) within its scopes | Settings › FHIR › Access: Let a patient's app search the directory |
-fhir-payer-apis | on/off | — | enable the CMS-0057 payer operations: $member-match (Payer-to-Payer) and Group $davinci-data-export (Provider Access); the Group exports also need -fhir-bulk-export | Settings › Payers › CMS-0057-F: The CMS-0057-F payer APIs |
-fhir-read-only | on/off | — | refuse writes to the FHIR endpoint | Settings › FHIR › Access: Refuse writes to the FHIR endpoint |
-fhir-subscriptions | on/off | — | enable topic-based subscriptions, which send encounter and appointment notifications to URLs FHIR clients choose | Settings › FHIR › Notifications: FHIR subscriptions (encounter and appointment notifications) |
-fhir-subscriptions-allow-http | on/off | — | let subscriptions deliver to plain-http endpoints; for a test receiver, never for patient data on a network | Settings › FHIR › Notifications: Allow subscriptions to notify plain-HTTP addresses |
-fhir-version | string | 4.0.1 | FHIR release to serve: R4, R4B or R5 | Settings › FHIR › The FHIR server: FHIR version clients see |
-fhir-writes-per-minute | int | — | for a public server: writes one client address may make to the FHIR endpoint a minute (0: no limit) | Settings › FHIR › Access: Writes a minute from one client |
-fleet-label | string | — | how this instance names itself in a fleet view (default: hostname) | Settings › Fleet › This server: Name for this server |
-formulary | string | — | publish this drug formulary over the Da Vinci US Drug Formulary API at /formulary/fhir and answer NCPDP Real-Time Prescription Benefit and SCRIPT electronic prior authorization from it | Settings › Payers › Drug formulary: Drug formulary file |
-icd11-client-id | string | — | a WHO ICD API client: ICD-11 codes not imported are looked up there | Settings › Data › Code systems: WHO ICD API client ID |
-icd11-client-secret | string | — | the WHO ICD API client's secret | Settings › Data › Code systems: WHO ICD API client secret |
-icd11-release | string | 2025-01 | the ICD-11 MMS release the WHO ICD API is asked about | Settings › Data › Code systems: ICD-11 release to ask for |
-icd11-url | string | — | the ICD API's address when it is not the WHO's: the WHO's ICD-API container on your network needs no client | Settings › Data › Code systems: ICD API address |
-index-identity | on/off | true | index patient identifiers from message contents so a message can be found by MRN, name or accession in any format; has no effect when -store-payloads is off | Settings › Data › What is kept: Index patient identifiers |
-insecure | on/off | — | serve over plain HTTP on a non-loopback address (not recommended) | — |
-inventory | string | — | write a Markdown inventory of every interface to this file, and keep it current | Settings › Monitoring › Inventory: Write an interface inventory to |
-inventory-every | duration | 24h0m0s | how often to rewrite the interface inventory | Settings › Monitoring › Inventory: Rewrite the inventory every |
-json-logs | on/off | — | emit structured JSON logs | Settings › Monitoring › Logging: Write logs as JSON |
-ldap | string | — | YAML file configuring directory (LDAP) sign-in (default: ldap.yaml beside the database, once saved in the console) | — |
-log-file | string | — | append the log, and the first administrator's one-time password, to this file (mode 0600) instead of the console. A Windows service has no console, so there it defaults to perfuse.log beside the database | — |
-mcp | on/off | — | serve the Model Context Protocol at /mcp, so AI agents with an API token can read status, messages, the queue, alerts and the FHIR store with that token's own access | Settings › Security › AI agents (MCP): Let AI agents connect over MCP |
-measure-reporter | string | Perfuse | the reporting organisation's name on MeasureReports from $evaluate-measure when the request names no reporter | — |
-metrics-open | on/off | — | serve /metrics to anybody who can reach the port. Only safe where that port is genuinely private: metric labels name your channels, and on a multi-tenant server they name every tenant's | Settings › Security › Metrics: Serve /metrics without a token |
-metrics-token | string | — | credential the Prometheus scrape endpoint requires. Give the scraper the same value in bearer_token_file. Without this, only a signed-in operator can read /metrics | Settings › Security › Metrics: Token a metrics scraper presents |
-mpi | on/off | — | keep a patient index (master patient index) in mpi.db beside the database: patient records from every system linked into one enterprise identifier per person, fed by mpi destinations and the PIX v3 identity feed, answering Patient/$match, PIXm, PIX v3 (/pixv3) and PDQ v3 (/pdqv3) | Settings › Data › Patient index: Keep a patient index |
-multi-tenant | on/off | — | keep each tenant's channels in their own subdirectory of -channels, so one server can run integration for several organisations without them being able to see each other | — |
-node-address | string | — | this server's console URL as the other servers and a load balancer reach it | — |
-node-name | string | — | this server's name in the cluster (default: an id kept in -data) | — |
-oidc | string | — | YAML file configuring OpenID Connect sign-in (default: oidc.yaml beside the database, once saved in the console) | — |
-pas | on/off | — | serve Da Vinci PAS 2.2.1 and 2.1.0 (Claim/$submit, $inquire, $decide) on the FHIR endpoint; decisions come from -crd-rules, and what no rule decides is pended for a reviewer. With -fhir-subscriptions, the PAS topic delivers each pended request's result | Settings › Payers › Prior authorization: Da Vinci PAS prior authorization server |
-pas-278-ca | string | — | a PEM file of certificate authorities to trust for the UM system beside the system's | Settings › Payers › Utilization management link: Certificate authorities to trust for the UM system |
-pas-278-cert | string | — | a PEM client certificate for X.509 mutual TLS with the UM system (CORE's authentication) | Settings › Payers › Utilization management link: Client certificate file |
-pas-278-core-receiver | string | — | the CORE envelope's ReceiverID, as the UM system's connectivity guide gives it (default: -pas-278-receiver) | Settings › Payers › Utilization management link: CORE envelope ReceiverID |
-pas-278-core-rule-version | string | — | what to write in the CORE envelope's CORERuleVersion when the UM system's guide asks for something other than the version itself (CMS esMD's sample says v2.2.0) | Settings › Payers › Utilization management link: CORERuleVersion written in the envelope |
-pas-278-core-sender | string | — | the CORE envelope's SenderID, as the UM system's connectivity guide gives it (default: -pas-278-sender) | Settings › Payers › Utilization management link: CORE envelope SenderID |
-pas-278-core-version | string | 2.2.0 | the CAQH CORE Connectivity Rule the UM system runs, for core-soap and core-mime: 2.2.0 (payload in the envelope) or C4.0.0 (payload as an MTOM attachment; SOAP only) | Settings › Payers › Utilization management link: CAQH CORE Connectivity Rule |
-pas-278-key | string | — | the private key (PEM) for -pas-278-cert | Settings › Payers › Utilization management link: Client certificate key file |
-pas-278-oauth-client-id | string | — | the OAuth client ID for -pas-278-oauth-token-url | Settings › Payers › Utilization management link: OAuth client ID |
-pas-278-oauth-scope | string | — | the scope asked for with the OAuth token, when the UM system wants one | Settings › Payers › Utilization management link: OAuth scope |
-pas-278-oauth-secret-env | string | — | name of an environment variable holding the OAuth client secret (the secret itself is never a flag) | Settings › Payers › Utilization management link: Environment variable holding the OAuth client secret |
-pas-278-oauth-token-url | string | — | an OAuth 2.0 token endpoint: a token got with the client-credentials grant is sent as a bearer token (CORE vC4.0.0's authorization) | Settings › Payers › Utilization management link: OAuth token endpoint |
-pas-278-password-env | string | — | name of an environment variable holding the password for -pas-278-user (the password itself is never a flag) | Settings › Payers › Utilization management link: Environment variable holding the password |
-pas-278-payer-id | string | — | the UMO's payer ID (NM1*X3) when the request's insurer carries no identifier | Settings › Payers › Utilization management link: Payer ID for the 278s |
-pas-278-production | on/off | — | mark the 278s sent as production (ISA15 P) rather than test | Settings › Payers › Utilization management link: Mark the 278s as production |
-pas-278-receiver | string | — | ISA08/GS03 receiver ID on the 278s sent to the UM system | Settings › Payers › Utilization management link: Receiver ID on the 278s |
-pas-278-sender | string | PERFUSE | ISA06/GS02 sender ID on the 278s sent to the UM system | Settings › Payers › Utilization management link: Sender ID on the 278s |
-pas-278-sftp | string | — | host:port of the UM system's SFTP server, for -pas-278-transport sftp | Settings › Payers › Utilization management link: SFTP server |
-pas-278-sftp-every | duration | 1m0s | how often the SFTP inbound folder is read | Settings › Payers › Utilization management link: Read the SFTP inbound folder every |
-pas-278-sftp-inbound | string | — | the SFTP folder the UM system's 278 responses, 999s and TA1s are collected from | Settings › Payers › Utilization management link: SFTP inbound folder |
-pas-278-sftp-key | string | — | an OpenSSH private key file for the SFTP user, instead of a password | Settings › Payers › Utilization management link: SFTP key file |
-pas-278-sftp-known-hosts | string | — | an OpenSSH known_hosts file holding the SFTP server's key; required, so requests never go to whoever answers | Settings › Payers › Utilization management link: SFTP known_hosts file |
-pas-278-sftp-outbound | string | — | the SFTP folder the 278 requests (and the 999s for the answers) are put in | Settings › Payers › Utilization management link: SFTP outbound folder |
-pas-278-sftp-password-env | string | — | name of an environment variable holding the SFTP password (the password itself is never a flag) | Settings › Payers › Utilization management link: Environment variable holding the SFTP password |
-pas-278-sftp-user | string | — | the SFTP user name | Settings › Payers › Utilization management link: SFTP user |
-pas-278-token-env | string | — | name of an environment variable holding a bearer token for the UM system (the token itself is never a flag) | Settings › Payers › Utilization management link: Environment variable holding the token |
-pas-278-transport | string | x12 | how the 278s reach the UM system: x12 (POSTed as application/edi-x12), core-soap (a CAQH CORE SOAP envelope), core-mime (CAQH CORE HTTP MIME multipart), or sftp (batch files over -pas-278-sftp, answers collected from its inbound folder) | Settings › Payers › Utilization management link: How the 278s travel |
-pas-278-url | string | — | forward every PAS request to the payer's utilization management system as an X12 278 request sent to this URL (by -pas-278-transport), and answer with its 278 response; later 278 responses go to Claim/$decide-278 | Settings › Payers › Utilization management link: Send PAS requests on to the UM system at |
-pas-278-user | string | — | user name for the UM system: CORE's UserName (WS-Security UsernameToken in SOAP), or HTTP Basic for x12 | Settings › Payers › Utilization management link: User name |
-pas-decider-ca | string | — | a PEM file of certificate authorities to trust for -pas-decider-url beside the system's, such as the payer's own authority or the decision service's (Vaglio's is its DATA/tls/ca.crt) | Settings › Payers › Decision service: Certificate authorities to trust for the decision service |
-pas-decider-token-env | string | — | name of an environment variable holding a bearer token for -pas-decider-url (the token itself is never a flag) | Settings › Payers › Decision service: Environment variable holding the decision service's token |
-pas-decider-url | string | — | ask the decision service at this URL (such as Vaglio) to decide each PAS item on the request's clinical evidence, when -crd-rules leave it to a reviewer; the PAS request Bundle is POSTed to it. Cannot be combined with -pas-278-url | Settings › Payers › Decision service: Decision service URL |
-passkey-allowed-models | string | — | comma-separated authenticator AAGUIDs that may enrol; requires -passkey-attestation-roots | — |
-passkey-attestation-roots | string | — | a PEM file of authenticator vendor certificates; passkey attestation is verified against these | — |
-passkey-domain | string | — | the bare domain passkeys are registered for, such as perfuse.example.org. No scheme, no port, no path. Setting it turns passkeys on; leaving it empty leaves them off | Settings › Sign-in › Passkeys: Domain passkeys are bound to |
-passkey-name | string | Perfuse | the name an authenticator shows a person when they register a passkey | Settings › Sign-in › Passkeys: Name shown on the device |
-passkey-origins | string | — | comma-separated origins the console is reached at, with scheme and port: https://perfuse.example.org. Defaults to https:// plus the domain | Settings › Sign-in › Passkeys: Other origins passkeys are accepted from |
-peers | string | — | YAML file listing other Perfuse instances to show in a fleet view | Settings › Fleet › Fleet: Other Perfuse servers to show (file) |
-public-url | string | — | the https address patients' phones and other organisations reach this server at, for the SMART Health Links it hosts (default: the listen address) | Settings › FHIR › The FHIR server: Address others reach this server at |
-rctc | string | — | eCR trigger codes for the case report preview: a FHIR ValueSet or Bundle of them, such as the eRSD | Settings › Public health › Case reporting: Trigger codes file (RCTC or eRSD) |
-residency | string | — | cloud regions this server's data may go to or come from: areas (eea, uk, ch) and region codes (eu-central-1), comma-separated; channels with connectors elsewhere are refused | Settings › Data › Data protection: Where data may go (cloud regions) |
-retention-days | int | 30 | how long to keep recorded messages; 0 keeps them for ever, which will eventually fill the disk | Settings › Data › How long it is kept: Delete records after |
-saml | string | — | YAML file configuring SAML 2.0 sign-in (default: saml.yaml beside the database, once saved in the console) | — |
-scim | on/off | — | accept SCIM 2.0 provisioning from an identity provider at /scim/v2. Okta, Entra ID and Google Workspace use it to create accounts and, more importantly, to disable them when somebody leaves | Settings › Sign-in › Automatic accounts: Let the identity provider manage accounts |
-scim-default-role | string | viewer | role for an account the identity provider does not describe. Defaults downward on purpose: an account whose role could not be determined should be able to read and nothing else | — |
-settings | string | — | settings file the web interface may edit (default: perfuse-settings.yaml beside the database) | — |
-shl-allow-http | on/off | — | let a received SMART Health Link point at plain HTTP; for testing only | Settings › Public health › Health links: Allow SMART Health Links over plain HTTP |
-signing-cert | string | — | certificate for signing documents (defaults to -tls-cert) | Settings › Security › Document signing: Certificate for signing documents |
-signing-key | string | — | key for signing documents (defaults to -tls-key) | Settings › Security › Document signing: Key for signing documents |
-smart-audience | string | — | the audience a SMART token must be issued for, normally the FHIR base URL | Settings › SMART › Authorization: Audience tokens must name |
-smart-authorize | string | — | the authorization endpoint to advertise to SMART apps | Settings › SMART › Authorization: Authorization endpoint |
-smart-backend-services | on/off | — | advertise that the SMART authorization server issues backend-services (client_credentials, signed JWT) tokens | Settings › SMART › Built-in server: Backend Services (system-to-system tokens) |
-smart-clients | string | — | run Perfuse's own SMART authorization server at /auth for the apps registered in this YAML file | Settings › SMART › Built-in server: Registered apps file (turns on the built-in server) |
-smart-issuer | string | — | accept SMART on FHIR access tokens from this authorization server | Settings › SMART › Authorization: Accept SMART access tokens from this authorization server |
-smart-jwks | string | — | where to fetch the SMART issuer's signing keys, when not from its published metadata (split DNS, a private address) | Settings › SMART › Authorization: Key set file |
-smart-jwks-uri | string | — | the authorization server's public key set URL, advertised to SMART apps (needed to claim OpenID Connect sign-in) | Settings › SMART › Authorization: Key set address |
-smart-key | string | smart-signing.key | the built-in authorization server's RSA signing key (PEM, mode 0600), created if missing | Settings › SMART › Built-in server: Signing key file |
-smart-oidc | string | — | with -smart-users, let people sign in at this OpenID Connect provider (YAML: issuer, client_id, client_secret_file or client_secret_env, label); each is linked by oidc_subject | Settings › SMART › Built-in server: Sign people in through the OpenID Connect provider |
-smart-token | string | — | the token endpoint to advertise to SMART apps | Settings › SMART › Authorization: Token endpoint |
-smart-users | string | — | with -smart-clients, the people who may sign in to authorize apps (YAML: username, password_hash, fhir_user) | Settings › SMART › Built-in server: People who sign in to authorize apps (file) |
-snmp-allow | string | — | comma-separated networks or addresses the SNMP agent answers, such as 10.0.5.0/24; required with -snmp-listen | Settings › Monitoring › SNMP: Networks that may ask |
-snmp-base-oid | string | 1.3.6.1.4.1.8072.9999.9999.16, Net-SNMP's experimental space | where Perfuse's values sit, under your enterprise number | Settings › Monitoring › SNMP: Base OID |
-snmp-community | string | — | the SNMPv2c community (a password sent in clear: at least 6 characters, not public or private) | Settings › Monitoring › SNMP: SNMP community |
-snmp-contact | string | — | sysContact the SNMP agent reports | Settings › Monitoring › SNMP: Contact (sysContact) |
-snmp-listen | string | — | answer SNMPv2c GET/GETNEXT/GETBULK on this UDP address, such as :161 (off when empty). Read-only: channel states, counts and queue depths | Settings › Monitoring › SNMP: Answer SNMP on this address |
-snmp-location | string | — | sysLocation the SNMP agent reports | Settings › Monitoring › SNMP: Location (sysLocation) |
-snmp-traps | string | — | comma-separated managers (host or host:port, default port 162) that receive an SNMPv2 trap when an alert fires or resolves | Settings › Monitoring › SNMP: Send traps to |
-store-messages | on/off | true | record every message handled, which is what makes the message browser work | Settings › Data › What is kept: Keep a record of each message |
-store-payloads | on/off | true | store message contents as well as their outcomes; turn this off where PHI must not be held at rest | Settings › Data › What is kept: Keep message contents |
-tls-cert | string | — | TLS certificate file | Settings › Security › Encryption: TLS certificate file |
-tls-key | string | — | TLS private key file | Settings › Security › Encryption: TLS private key file |
-trace-endpoint | string | — | OTLP/HTTP base URL to export message traces to, for example http://localhost:4318 | Settings › Monitoring › Tracing: Send traces to |
-trace-instance | string | — | name for this instance in traces; defaults to the hostname, which is what distinguishes replicas | Settings › Monitoring › Tracing: This instance's name in traces |
-trace-sample | float | 1 | fraction of traces to record, 0 to 1 | — |
-tsa-url | string | — | RFC 3161 time-stamping authority for DSDR signatures on claims attachments | Settings › Security › Document signing: Time-stamping authority |
-vpn | string | — | partner VPN tunnels to report on the Connections dashboard (YAML: AWS Site-to-Site VPN, Azure VPN Gateway or strongSwan, and both sides' settings); see examples/vpn.yaml | Settings › Monitoring › Connections: VPN tunnels to watch (file) |
-watch-access | on/off | true | watch traffic and reads of patient data for what a breach looks like (bursts, night traffic, new destinations, bulk reads) and raise alerts | — |
-xds | string | — | keep clinical documents here as an IHE XDS.b registry and repository with this repository uniqueId (an OID), answering ITI-41, ITI-42, ITI-18 and ITI-43 at /xds/repository and /xds/registry | Settings › Data › Document sharing (IHE XDS): Keep documents here as an XDS registry and repository |
-xds-home-community | string | — | this community's home community id (urn:oid:...), so /xca/gateway answers XCA ITI-38 and ITI-39 for it | Settings › Data › Document sharing (IHE XDS): Home community id, for XCA |
21 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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
name | testo | sì | — |
description | testo | no | — |
group | testo | no | — |
attachments | Allegati (un blocco, omesso per non includerlo) | no | — |
delimited | Delimitato (un blocco, omesso per non includerlo) | no | — |
tables | elenco di testo | no | — |
contract | ContractRef (un blocco, omesso per non includerlo) | no | — |
enabled | true o false (un blocco, omesso per non includerlo) | no | — |
dataType | DataType | no | hl7 |
hl7v3 | HL7v3Options (un blocco, omesso per non includerlo) | no | — |
x12 | X12Options (un blocco, omesso per non includerlo) | no | — |
ncpdp | NCPDPOptions (un blocco, omesso per non includerlo) | no | — |
edifact | EDIFACTOptions (un blocco, omesso per non includerlo) | no | — |
script | ScriptOptions (un blocco, omesso per non includerlo) | no | — |
dicom | DICOMOptions (un blocco, omesso per non includerlo) | no | — |
source | Sorgente | sì | — |
filter | testo | no | — |
transformations | elenco di transform.Step | no | — |
scripts | Scripts (un blocco, omesso per non includerlo) | no | — |
shadow | Shadow (un blocco, omesso per non includerlo) | no | — |
destinations | elenco di Destination | sì | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
prefetch | numero intero | no | 10 |
reconnect | durata, ad esempio 30s o 5m | no | 5s |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
listen | testo | sì | — |
path | testo | no | — |
tls | tlsconf.Settings (un blocco, omesso per non utilizzarlo) | no | — |
id | testo | sì | — |
cert_file | testo | sì | — |
key_file | testo | sì | — |
partners | elenco di AS2Partner | sì | — |
max_message_size | numero intero | no | — |
duplicate_window | durata, ad esempio 30s o 5m | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
prefix | testo | sì | — |
suffix | testo | no | — |
after_read | testo | no | — |
move_to | testo | no | processed/ |
error_prefix | testo | no | error/ |
poll_interval | durata, ad esempio 30s o 5m | no | 30s |
max_object_size | numero intero | no | 16 MiB |
framed | true o false | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
addr | testo | sì | — |
destination | testo | sì | — |
login | testo | no | — |
passcode | testo | no | — |
host | testo | no | l'host dell'indirizzo |
selector | testo | no | — |
subscription_id | testo | no | il nome del canale |
heartbeat | durata, ad esempio 30s o 5m | no | trenta secondi |
reconnect | durata, ad esempio 30s o 5m | no | cinque secondi |
timeout | durata, ad esempio 30s o 5m | no | trenta secondi |
tls | tlsconf.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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
address | testo | sì | — |
called_ae | testo | sì | — |
calling_ae | testo | no | — |
level | testo | no | STUDY |
patient_root | vero o falso | no | — |
match | mappatura di testo su testo | no | — |
return | elenco di testo | no | — |
interval | durata, ad esempio 30s o 5m | sì | — |
window | durata, ad esempio 30s o 5m | no | — |
overlap | durata, ad esempio 30s o 5m | no | un'ora |
limit | numero intero | no | 500 |
timeout | durata, ad esempio 30s o 5m | no | due minuti |
tls | tlsconf.Settings (un blocco, omesso per lasciare fuori) | no | — |
emit_on_first_poll | vero o falso | no | falso |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
listen | testo | sì | — |
ae_title | testo | no | — |
allowed_calling_ae | elenco di testo | no | — |
sop_classes | elenco di testo | no | — |
transfer_syntaxes | elenco di testo | no | — |
max_object_bytes | numero intero | no | — |
idle_timeout | durata, ad esempio 30s o 5m | no | — |
tls | tlsconf.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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
listen | testo | sì | — |
path | testo | no | /dicom-web |
token | testo | no | — |
username | testo | no | — |
password | testo | no | — |
max_object_bytes | numero intero | no | — |
tls | tlsconf.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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
driver | testo | sì | — |
dsn | testo | sì | — |
query | testo | sì | — |
after_query | testo | no | — |
key_column | testo | no | — |
template | testo | no | — |
column | testo | no | — |
poll_interval | durata, come 30s o 5m | no | — |
batch_size | numero intero | no | 100 |
max_attempts | numero intero | no | 3 |
query_timeout | durata, come 30s o 5m | no | 30s |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
listen | testo | no | — |
tls_cert | testo | no | — |
tls_key | testo | no | — |
max_bytes | numero intero | no | — |
smtp_host | testo | no | — |
username | testo | no | — |
password | testo | no | — |
imap | DirectIMAP (un blocco, omesso per non utilizzarlo) | no | — |
xdr | DirectXDR (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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
protocol | testo | no | — |
host | testo | sì | — |
port | numero intero | no | — |
security | testo | no | — |
tls | tlsconf.Settings (un blocco, omesso per lasciare fuori) | no | — |
username | testo | sì | — |
password | testo | no | — |
oauth | EmailOAuth (un blocco, omesso per lasciare fuori) | no | — |
mailbox | testo | no | — |
take | testo | no | — |
attachment_names | elenco di testo | no | — |
allowed_senders | elenco di testo | no | — |
after_read | testo | no | — |
move_to | testo | no | — |
error_folder | testo | no | — |
poll_interval | durata, ad esempio 30s o 5m | no | — |
max_message_size | numero intero | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
host | testo | sì | — |
user | testo | no | — |
password | testo | no | — |
security | ftpconn.Security | no | esplicito |
insecure_skip_verify | true o false | no | — |
root | testo | no | — |
timeout | durata, ad esempio 30s o 5m | no | trenta 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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
root | testo | sì | — |
follow_symlinks | true o false | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
prefix | testo | sì | — |
suffix | testo | no | — |
after_read | testo | no | — |
move_to | testo | no | processed/ |
error_prefix | testo | no | error/ |
poll_interval | durata, ad esempio 30s o 5m | no | 30s |
max_object_size | numero intero | no | 16 MiB |
framed | true o false | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
listen | testo | sì | — |
path | testo | no | "/" |
tls | tlsconf.Settings (un blocco, omesso per lasciare fuori) | no | — |
token | testo | no | — |
max_message_size | numero intero | no | — |
read_timeout | durata, ad esempio 30s o 5m | no | — |
ack | Ack | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
poll_interval | durata, ad esempio 30s o 5m | no | 2s |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
script | testo | sì | — |
poll_interval | durata, ad esempio 30s o 5m | no | — |
timeout | durata, ad esempio 30s o 5m | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
brokers | elenco di testo | sì | — |
topics | elenco di testo | sì | — |
group | testo | sì | — |
from_beginning | true o false | no | — |
commit_after_delivery | true o false (un blocco, omesso per lasciare fuori) | no | — |
max_message_size | numero intero | no | il limite del canale |
session_timeout | durata, ad esempio 30s o 5m | no | quarantacinque secondi |
timeout | durata, ad esempio 30s o 5m | no | trenta secondi |
sasl | KafkaSASL (un blocco, omesso per lasciare fuori) | no | — |
tls | tlsconf.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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
topic | testo | sì | — |
reconnect | durata, ad esempio 30s o 5m | no | 5s |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
subscription | testo | sì | — |
max_messages | numero intero | no | 10 |
reconnect | durata, ad esempio 30s o 5m | no | 5s |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
bucket | testo | sì | — |
path_style | vero o falso | no | — |
prefix | testo | no | — |
suffix | testo | no | — |
after_read | testo | no | — |
move_to | testo | no | processed/ |
error_prefix | testo | no | error/ |
poll_interval | durata, ad esempio 30s o 5m | no | 30s |
max_object_size | numero intero | no | 16 MiB |
framed | vero o falso | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
host | testo | sì | 22 |
user | testo | sì | — |
password | testo | no | — |
key_file | testo | no | — |
key_passphrase | testo | no | — |
known_hosts_file | testo | no | — |
insecure_skip_host_key_check | vero o falso | no | — |
dir | testo | sì | — |
pattern | testo | no | tutto |
poll_interval | durata, ad esempio 30s o 5m | no | — |
after_read | testo | no | — |
move_to | testo | no | — |
error_dir | testo | no | — |
stable_for | durata, ad esempio 30s o 5m | no | 5s |
framed | vero o falso | no | — |
max_file_size | numero intero | no | 64MB |
timeout | durata, ad esempio 30s o 5m | no | 60s |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
host | testo | sì | — |
share | testo | sì | — |
user | testo | no | — |
password | testo | no | — |
domain | testo | no | — |
root | testo | no | — |
timeout | durata, ad esempio 30s o 5m | no | trenta 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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
listen | testo | sì | — |
profile | testo | no | — |
path | testo | no | "/" |
version | testo | no | 1 |
element | testo | no | — |
base64 | vero o falso | no | — |
response_element | testo | no | "AckResponse" |
response_namespace | testo | no | — |
wsdl | testo | no | — |
tls | tlsconf.Settings (un blocco, omesso per lasciare fuori) | no | — |
token | testo | no | — |
username | testo | no | — |
password | testo | no | — |
max_message_size | numero intero | no | — |
read_timeout | durata, ad esempio 30s o 5m | no | — |
ack | Ack | no | — |
fault_on_nak | vero o falso | no | — |
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.
| Chiave | Tipo | Richiesto | Default |
|---|---|---|---|
queue_url | testo | sì | — |
wait_seconds | numero intero | no | 20: una coda vuota costa una richiesta ogni venti secondi |
max_messages | numero intero | no | 10 |
visibility_timeout | durata, come 30s o 5m | no | l'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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
port | testo | sì | — |
baud | numero intero | sì | — |
data_bits | numero intero | no | 8 |
parity | testo | no | none |
stop_bits | testo | no | 1 |
flow_control | testo | no | none |
max_message_size | numero intero | no | — |
quiet_after | durata, ad esempio 30s o 5m | no | — |
reply | testo | no | — |
reply_text | testo | no | — |
reopen_after | durata, ad esempio 30s o 5m | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
type | SourceType | sì | — |
listen | testo | sì | — |
max_message_size | numero intero | no | — |
idle_timeout | durata, ad esempio 30s o 5m | no | — |
max_connections | numero intero | no | — |
tls | tlsconf.Settings (un blocco, omesso per non utilizzarlo) | no | — |
http | HTTPSource (un blocco, omesso per non utilizzarlo) | no | — |
soap | SOAPSource (un blocco, omesso per non utilizzarlo) | no | — |
dicomweb | DICOMwebSource (un blocco, omesso per non utilizzarlo) | no | — |
direct | DirectSource (un blocco, omesso per non utilizzarlo) | no | — |
dicom | DICOMSource (un blocco, omesso per non utilizzarlo) | no | — |
file | FileSource (un blocco, omesso per non utilizzarlo) | no | — |
tcp | TCPSource (un blocco, omesso per non utilizzarlo) | no | — |
ftp | FTPSource (un blocco, omesso per non utilizzarlo) | no | — |
smb | SMBSource (un blocco, omesso per non utilizzarlo) | no | — |
webdav | WebDAVSource (un blocco, omesso per non utilizzarlo) | no | — |
serial | SerialSource (un blocco, omesso per non utilizzarlo) | no | — |
dicom_query | DICOMQuerySource (un blocco, omesso per non utilizzarlo) | no | — |
broker | BrokerSource (un blocco, omesso per non utilizzarlo) | no | — |
kafka | KafkaSource (un blocco, omesso per non utilizzarlo) | no | — |
sqs | SQSSource (un blocco, omesso per non utilizzarlo) | no | — |
s3 | S3Source (un blocco, omesso per non utilizzarlo) | no | — |
amqp | AMQPSource (un blocco, omesso per non utilizzarlo) | no | — |
azure_blob | AzureBlobSource (un blocco, omesso per non utilizzarlo) | no | — |
email | EmailSource (un blocco, omesso per non utilizzarlo) | no | — |
as2 | AS2Source (un blocco, omesso per non utilizzarlo) | no | — |
pgp | PGPReceive (un blocco, omesso per non utilizzarlo) | no | — |
mqtt | MQTTSource (un blocco, omesso per non utilizzarlo) | no | — |
ibm_mq | IBMMQSource (un blocco, omesso per non utilizzarlo) | no | — |
pubsub | PubSubSource (un blocco, omesso per non utilizzarlo) | no | — |
gcs | GCSSource (un blocco, omesso per non utilizzarlo) | no | — |
database | DatabaseSource (un blocco, omesso per non utilizzarlo) | no | — |
sftp | SFTPSource (un blocco, omesso per non utilizzarlo) | no | — |
javascript | JavaScriptSource (un blocco, omesso per non utilizzarlo) | no | — |
ack | Ack | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
listen | testo | sì | — |
max_message_size | numero intero | no | — |
idle_timeout | durata, ad esempio 30s o 5m | no | — |
max_connections | numero intero | no | — |
reply | testo | no | — |
reply_text | testo | no | — |
tls | tlsconf.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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
url | testo | sì | — |
user | testo | no | — |
password | testo | no | — |
insecure_skip_verify | vero o falso | no | — |
timeout | durata, ad esempio 30s o 5m | no | sessanta 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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
content_type | testo | no | il 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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
url | testo | sì | — |
from | testo | sì | — |
to | testo | sì | — |
cert_file | testo | no | — |
key_file | testo | no | — |
partner_cert_file | testo | no | — |
unsigned | vero o falso | no | — |
unencrypted | vero o falso | no | — |
compress | vero o falso | no | — |
receipt | testo | no | — |
unsigned_receipt | vero o falso | no | — |
receipt_url | testo | no | — |
content_type | testo | no | — |
file_name | testo | no | — |
subject | testo | no | — |
username | testo | no | — |
password | testo | no | — |
tls | tlsconf.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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
blob | testo | no | ${data}/${canale}/${id_controllo} |
tier | testo | no | — |
content_type | testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
addr | testo | sì | — |
destination | testo | sì | — |
login | testo | no | — |
passcode | testo | no | — |
host | testo | no | l'host dell'indirizzo |
content_type | testo | no | text/plain per HL7 |
headers | mappatura di testo su testo | no | — |
persistent | vero o falso (un blocco, omesso per lasciare fuori) | no | vero |
timeout | durata, ad esempio 30s o 5m | no | — |
tls | tlsconf.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.
| Chiave | Tipo | Richiesto | Predefinito |
|---|---|---|---|
url | testo | no | — |
dir | testo | no | — |
write | testo | no | — |
version | testo | no | R5 |
identifier_systems | mappatura di testo su testo | no | — |
require_agreement | true o false | no | — |
on_no_document | testo | no | — |
headers | mappatura di testo su testo | no | — |
bearer_token | testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
name | testo | sì | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
address | testo | sì | — |
called_ae | testo | no | — |
calling_ae | testo | no | — |
transfer_syntaxes | elenco di testo | no | — |
timeout | durata, ad esempio 30s o 5m | no | — |
tls | tlsconf.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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
url | testo | sì | — |
token | testo | no | — |
username | testo | no | — |
password | testo | no | — |
headers | mappa di testo su testo | no | — |
tls | tlsconf.Settings (un blocco, omesso per non utilizzarlo) | no | — |
timeout | durata, ad esempio 30s o 5m | no | — |
23.9 Destinazione del database
DatabaseDestination scrive ogni messaggio su un database.
Definito come DatabaseDestination in internal/config.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
driver | testo | sì | — |
dsn | testo | sì | — |
statement | testo | sì | — |
params | elenco di testo | no | — |
timeout | durata, ad esempio 30s o 5m | no | 30s |
max_open_conns | numero intero | no | 4 |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
name | testo | sì | — |
type | DestinationType | sì | — |
enabled | true o false (un blocco, omesso per lasciare fuori) | no | — |
filter | testo | no | — |
address | testo | no | — |
dir | testo | no | — |
file_name | testo | no | — |
temp_suffix | testo | no | " |
append | true o false | no | — |
retain_hours | numero intero | no | — |
tls | tlsconf.Settings (un blocco, omesso per lasciare fuori) | no | — |
fhir | FHIRDestination (un blocco, omesso per lasciare fuori) | no | — |
cda | CDADestination (un blocco, omesso per lasciare fuori) | no | — |
http | HTTPDestination (un blocco, omesso per lasciare fuori) | no | — |
database | DatabaseDestination (un blocco, omesso per lasciare fuori) | no | — |
sftp | SFTPDestination (un blocco, omesso per lasciare fuori) | no | — |
tcp | TCPDest (un blocco, omesso per lasciare fuori) | no | — |
smtp | SMTPDestination (un blocco, omesso per lasciare fuori) | no | — |
channel | ChannelDestination (un blocco, omesso per lasciare fuori) | no | — |
s3 | S3Destination (un blocco, omesso per lasciare fuori) | no | — |
ftp | FTPDestination (un blocco, omesso per lasciare fuori) | no | — |
document | DocumentDestination (un blocco, omesso per lasciare fuori) | no | — |
soap | SOAPDestination (un blocco, omesso per lasciare fuori) | no | — |
dicomweb | DICOMwebDestination (un blocco, omesso per lasciare fuori) | no | — |
xds | XDSDestination (un blocco, omesso per lasciare fuori) | no | — |
direct | DirectDestination (un blocco, omesso per lasciare fuori) | no | — |
as2 | AS2Destination (un blocco, omesso per lasciare fuori) | no | — |
mpi | MPIDestination (un blocco, omesso per lasciare fuori) | no | — |
tefca | TEFCADestination (un blocco, omesso per lasciare fuori) | no | — |
pas | PASDestination (un blocco, omesso per lasciare fuori) | no | — |
x12_as | testo | no | — |
dicom | DICOMDestination (un blocco, omesso per lasciare fuori) | no | — |
javascript | JavaScriptDestination (un blocco, omesso per lasciare fuori) | no | — |
broker | BrokerDestination (un blocco, omesso per lasciare fuori) | no | — |
kafka | KafkaDestination (un blocco, omesso per lasciare fuori) | no | — |
sqs | SQSDestination (un blocco, omesso per lasciare fuori) | no | — |
sns | SNSDestination (un blocco, omesso per lasciare fuori) | no | — |
amqp | AMQPDestination (un blocco, omesso per lasciare fuori) | no | — |
azure_blob | AzureBlobDestination (un blocco, omesso per lasciare fuori) | no | — |
mqtt | MQTTDestination (un blocco, omesso per lasciare fuori) | no | — |
ibm_mq | IBMMQDestination (un blocco, omesso per lasciare fuori) | no | — |
pubsub | PubSubDestination (un blocco, omesso per lasciare fuori) | no | — |
gcs | GCSDestination (un blocco, omesso per lasciare fuori) | no | — |
elr | ELRDestination (un blocco, omesso per lasciare fuori) | no | — |
pgp | PGPSend (un blocco, omesso per lasciare fuori) | no | — |
response_transformer | testo | no | — |
timeout | durata, ad esempio 30s o 5m | no | — |
retry | Retry | no | — |
queue | QueueConfig (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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
to | elenco di testo | sì | — |
subject | testo | no | — |
text | testo | no | — |
attach_name | testo | no | — |
xdm | vero o falso | no | — |
xdm_source_id | testo | no | — |
recipient_certs_dir | testo | no | — |
dns | testo | no | — |
ldap | testo | no | — |
smtp_host | testo | sì | — |
username | testo | no | — |
password | testo | no | — |
request_mdn | vero o falso | no | — |
timeout | durata, ad esempio 30s o 5m | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
dir | testo | sì | — |
format | DocumentFormat | no | |
template | testo | sì | — |
title | testo | no | — |
file_name | testo | no | — |
font_size | numero | no | 10 |
landscape | vero o falso | no | — |
temp_suffix | testo | no | " |
timeout | durata, ad esempio 30s o 5m | no | 30s |
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.
| Chiave | Tipo | Richiesto | Predefinito |
|---|---|---|---|
rctc | testo | no | — |
source | testo | sì | — |
facility | ECRFacility | sì | — |
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.
| Chiave | Tipo | Richiesto | Predefinito |
|---|---|---|---|
config | testo | sì | — |
rctc | testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
url | testo | sì | — |
version | testo | no | R5 |
timezone | testo | no | — |
default_identifier_system | testo | no | — |
identifier_systems | mappatura di testo su testo | no | — |
claim_us_core | vero o falso | no | — |
validate_before_send | vero o falso (un blocco, omesso per lasciare fuori) | no | vero: 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_warning | vero o falso | no | — |
headers | mappatura di testo su testo | no | — |
bearer_token | testo | no | — |
auth | FHIRAuth (un blocco, omesso per lasciare fuori) | no | — |
ecr | ECRDestination (un blocco, omesso per lasciare fuori) | no | — |
bundle_script | testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
host | testo | sì | 21 |
user | testo | no | — |
password | testo | no | — |
security | FTPSecurity | no | implicito anziché none |
insecure_skip_verify | true o false | no | — |
allow_clear_password | true o false | no | — |
dir | testo | sì | — |
file_name | testo | no | — |
temp_suffix | testo | no | " |
framed | true o false | no | — |
timeout | durata, ad esempio 30s o 5m | no | 60s |
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.
| Chiave | Tipo | Richiesto | Default |
|---|---|---|---|
object | testo | no | ${data}/${canale}/${control_id} |
storage_class | testo | no | — |
content_type | testo | no | — |
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.
| Chiave | Tipo | Richiesto | Default |
|---|---|---|---|
url | testo | sì | — |
method | testo | no | — |
content_type | testo | no | — |
headers | mappatura di testo su testo | no | — |
bearer_token | testo | no | — |
username | testo | no | — |
password | testo | no | — |
tls | tlsconf.Settings (un blocco, omesso per lasciare fuori) | no | — |
success_status | elenco di numero intero | no | qualsiasi 2xx |
fail_on_body | elenco di testo | no | — |
follow_redirects | vero o falso | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
non_persistent | true o false | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
script | testo | sì | — |
timeout | durata, ad esempio 30s o 5m | no | — |
success_on_undefined | true o false (un blocco, omesso per lasciare fuori) | no | true |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
brokers | elenco di testo | sì | — |
topic | testo | sì | — |
key | testo | no | — |
acks | testo | no | all |
compression | testo | no | snappy |
headers | mappatura di testo su testo | no | — |
timeout | durata, ad esempio 30s o 5m | no | trenta secondi |
sasl | KafkaSASL (un blocco, omesso per lasciare fuori) | no | — |
tls | tlsconf.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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
authorities | mappatura di testo su testo | no | — |
id_type | testo | no | — |
ssn_system | testo | no | — |
no_merge | vero o falso | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
topic | testo | sì | — |
retain | vero o falso | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
payer | testo | sì | — |
bearer_token | testo | no | — |
auth | FHIRAuth (un blocco, omesso per lasciare fuori) | no | — |
results_to | testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
topic | testo | sì | — |
order_by | testo | no | — |
23.26 Destinazione S3
S3Destination scrive ogni messaggio come un oggetto.
Definito come S3Destination in internal/config.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
bucket | testo | sì | — |
region | testo | sì | — |
key | testo | no | un percorso partizionato per data più l'ID di controllo |
access_key_id | testo | no | — |
secret_access_key | testo | no | — |
session_token | testo | no | — |
endpoint | testo | no | — |
path_style | vero o falso | no | — |
server_side_encryption | testo | no | — |
content_type | testo | no | application/hl7-v2 per HL7 e testo/piano otherwise |
framed | vero o falso | no | — |
timeout | durata, ad esempio 30s o 5m | no | 60s |
storage_class | testo | no | — |
format | testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
host | testo | sì | 22 |
user | testo | sì | — |
password | testo | no | — |
key_file | testo | no | — |
key_passphrase | testo | no | — |
known_hosts_file | testo | no | — |
insecure_skip_host_key_check | vero o falso | no | — |
dir | testo | sì | — |
file_name | testo | no | un timestamp più l'ID di controllo |
temp_suffix | testo | no | " |
framed | vero o falso | no | — |
append | vero o falso | no | — |
timeout | durata, ad esempio 30s o 5m | no | 60s |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
host | testo | sì | — |
from | testo | sì | — |
to | elenco di testo | sì | — |
cc | elenco di testo | no | — |
bcc | elenco di testo | no | — |
subject | testo | no | — |
body | testo | no | — |
attach | vero o falso | no | — |
attach_name | testo | no | l'ID di controllo con un |
username | testo | no | — |
password | testo | no | — |
starttls | vero o falso (un blocco, omesso per lasciare fuori) | no | — |
insecure_skip_verify | vero o falso | no | — |
timeout | durata, ad esempio 30s o 5m | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
topic_arn | testo | sì | — |
subject | testo | no | — |
group_by | testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
url | testo | sì | — |
profile | testo | no | — |
facility_id | testo | no | — |
warnings_are_errors | true o false | no | — |
action | testo | no | — |
version | testo | no | 1 |
body | testo | sì | — |
header | testo | no | — |
headers | mappatura di testo su testo | no | — |
username | testo | no | — |
password | testo | no | — |
tls | tlsconf.Settings (un blocco, omesso per non utilizzarlo) | no | — |
fault_is_success | elenco di testo | no | — |
timeout | durata, ad esempio 30s o 5m | no | 30s |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
queue_url | testo | sì | — |
group_by | testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
address | testo | sì | — |
max_message_size | numero intero | no | — |
timeout | durata, ad esempio 30s o 5m | no | — |
expect_reply | vero o falso | no | — |
keep_alive | vero o falso | no | — |
tls | tlsconf.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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
purpose | testo | sì | — |
results_to | testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
url | testo | sì | — |
source_id | testo | sì | — |
patient_domain | testo | no | — |
facility_type | XDSCode | sì | — |
practice_setting | XDSCode | sì | — |
class | XDSCode (un blocco, omesso per non utilizzarlo) | no | — |
content_type | XDSCode (un blocco, omesso per non utilizzarlo) | no | — |
token | testo | no | — |
username | testo | no | — |
password | testo | no | — |
headers | mappatura di testo su testo | no | — |
tls | tlsconf.Settings (un blocco, omesso per non utilizzarlo) | no | — |
timeout | durata, ad esempio 30s o 5m | no | — |
direct_from | testo | no | — |
direct_to | elenco di testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
extract | elenco di attach.Rule | sì | — |
reassemble | vero o falso (un blocco, omesso per lasciare fuori) | no | vero |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
delimiter | testo | no | — |
quote | testo | no | virgolette doppie |
comment | testo | no | — |
has_header | vero o falso | no | — |
columns | elenco di testo | no | — |
trim_space | vero o falso | no | — |
relaxed | vero o falso | no | — |
split | vero o falso (un blocco, omesso per lasciare fuori) | no | vero |
keep_blank_lines | vero o falso | no | — |
filter | testo | no | — |
transformations | elenco di passaggi.Step | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
filter | testo | no | — |
acknowledge | vero o falso (un blocco, omesso per lasciare fuori) | no | — |
sender_device | testo | no | — |
sender_oid | testo | no | — |
transformations | elenco di passaggi hl7v3.Step | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
framing | testo | sì | — |
delimiter | testo | no | — |
start_block | testo | no | — |
keep_delimiter | true o false | no | — |
record_length | numero intero | no | — |
trim_padding | true o false (un blocco, omesso per non utilizzarlo) | no | — |
length_bytes | numero intero | no | — |
big_endian | true o false | no | — |
length_includes_header | true o false | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
envelope | EnvelopePolicy | no | require |
split | vero o falso | no | — |
acknowledge | testo | no | — |
ack_sender_id | testo | no | — |
ack_sender_qualifier | testo | no | — |
arrives_as | testo | no | — |
transformations | elenco di x12.Step | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
addr | testo | sì | — |
address | testo | sì | — |
username | testo | no | — |
password | testo | no | — |
hostname | testo | no | l'host di addr |
tls | tlsconf.Settings (un blocco, omesso per non utilizzarlo) | no | — |
timeout | durata, ad esempio 30s o 5m | no | 30s |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
id | testo | sì | — |
cert_file | testo | sì | — |
allow_unsigned | vero o falso | no | — |
allow_unencrypted | vero o falso | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
region | testo | sì | — |
access_key_id | testo | no | — |
secret_access_key | testo | no | — |
session_token | testo | no | — |
endpoint | testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
when | AckWhen | no | — |
application | testo | no | — |
facility | testo | no | — |
include_trigger_event | vero o falso | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
account | testo | sì | — |
container | testo | sì | — |
key | testo | no | — |
sas | testo | no | — |
endpoint | testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
file | testo | sì | — |
check_every | testo | no | 15 minuti |
over | numero intero | no | 500 |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
transformations | elenco di dicom.Step | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
address | testo | sì | — |
cert_file | testo | sì | — |
key_file | testo | sì | — |
anchors_file | testo | sì | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
host | testo | sì | — |
port | numero intero | no | — |
security | testo | no | — |
username | testo | sì | — |
password | testo | no | — |
mailbox | testo | no | — |
after_read | testo | no | — |
move_to | testo | no | — |
error_folder | testo | no | — |
poll_interval | durata, ad esempio 30s o 5m | no | — |
tls | tlsconf.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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
listen | testo | sì | — |
tls_cert | testo | no | — |
tls_key | testo | no | — |
client_ca_file | testo | no | — |
25.11 Struttura ECR
ECRFacility è l'organizzazione che invia rapporti di casi.
Definito come ECRFacility in internal/config.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
name | testo | sì | — |
npi | testo | no | — |
phone | testo | sì | — |
line | testo | no | — |
city | testo | sì | — |
state | testo | sì | — |
postal_code | testo | no | — |
25.12 Opzioni EDIFACT
EDIFACTOptions sono le impostazioni che si applicano solo a un canale EDIFACT.
Definito come EDIFACTOptions in internal/config.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
envelope | testo | no | — |
split | vero o falso | no | — |
acknowledge | testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
provider | testo | sì | — |
tenant | testo | no | — |
token_url | testo | no | — |
client_id | testo | sì | — |
client_secret | testo | no | — |
refresh_token | testo | no | — |
scope | testo | no | — |
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:
- aws: AWS HealthLake, che accetta richieste firmate con Signature Version 4 per il servizio "healthlake" - nessun token. - azure: Azure Health Data Services, che accetta un token Microsoft Entra ID per il pubblico del servizio FHIR, ottenuto con la concessione client-credenciali di una registrazione dell'app che detiene il ruolo FHIR Data Contributor. - client_credentials: qualsiasi endpoint del token OAuth 2.0 - Keycloak, Okta, un servizio backend SMART con un segreto client.
I token vengono recuperati quando necessario e riutilizzati fino a un minuto prima della scadenza.
Definito come FHIRAuth in internal/config.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
type | testo | sì | — |
region | testo | no | — |
access_key_id | testo | no | — |
secret_access_key | testo | no | — |
session_token | testo | no | — |
tenant_id | testo | no | — |
token_url | testo | no | — |
client_id | testo | no | — |
client_secret | testo | no | — |
scope | testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
dir | testo | sì | — |
pattern | testo | no | — |
poll_interval | durata, come 30s o 5m | no | — |
after_read | testo | no | — |
move_to | testo | no | — |
error_dir | testo | no | — |
stable_for | durata, come 30s o 5m | no | — |
max_file_size | numero intero | no | — |
framed | vero o falso | no | — |
raw | vero o falso | no | — |
batch_size | numero intero | no | — |
sort_by | testo | no | nome |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
project | testo | no | — |
credentials_file | testo | no | — |
endpoint | testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
bucket | testo | sì | — |
25.18 Connessione IBMMQ
IBMMQConnection è una coda raggiunta attraverso l'API REST di messaggistica del gestore di code.
Definito come IBMMQConnection in internal/config.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
url | testo | sì | — |
queue_manager | testo | sì | — |
queue | testo | sì | — |
username | testo | no | — |
password | testo | no | — |
tls | tlsconf.Settings (un blocco, omesso per non utilizzarlo) | no | — |
api_version | testo | no | — |
timeout | durata, ad esempio 30s o 5m | no | 30s |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
mechanism | testo | sì | — |
username | testo | sì | — |
password | testo | sì | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
addr | testo | sì | — |
client_id | testo | no | — |
username | testo | no | — |
password | testo | no | — |
tls | tlsconf.Settings (un blocco, omesso per non utilizzarlo) | no | — |
qos | numero intero (un blocco, omesso per non utilizzarlo) | no | — |
timeout | durata, ad esempio 30s o 5m | no | 30s |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
transformations | elenco di ncpdp.Step | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
decrypt_with | testo | no | — |
passphrase | testo | no | — |
verify_with | elenco di testo | no | — |
require_signature | true o false | no | — |
allow_unencrypted | true o false | no | — |
pass_plain | true o false | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
encrypt_to | elenco di testo | no | — |
sign_with | testo | no | — |
passphrase | testo | no | — |
armor | true o false | no | — |
no_compress | true o false | no | — |
file_name | testo | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
enabled | vero o falso | no | — |
max_attempts | numero intero | no | — |
backoff | durata, ad esempio 30s o 5m | no | — |
max_backoff | durata, ad esempio 30s o 5m | no | — |
max_depth | numero intero | no | — |
retain_hours | numero intero | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
attempts | numero intero | no | — |
backoff | durata, ad esempio 30s o 5m | no | — |
max_backoff | durata, ad esempio 30s o 5m | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
transformations | elenco di hl7v3.Step | no | — |
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.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
filter | testo | no | — |
transformer | testo | no | — |
preprocessor | testo | no | — |
deploy | testo | no | — |
undeploy | testo | no | — |
postprocessor | testo | no | — |
language | testo | no | — |
timeout | durata, ad esempio 30s o 5m | no | — |
include | elenco di testo | no | — |
file_roots | elenco di testo | no | — |
allow | elenco di testo | no | — |
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:
- L'ombra non consegna mai. Le sue destinazioni non vengono costruite, quindi non c'è un percorso di codice da un canale shadow a un ricevitore e nessuna impostazione può crearne uno per errore. - L'ombra non influisce mai sul canale live. Esegue dopo che il messaggio live è stato consegnato e confermato e un'ombra che si blocca, si blocca o si blocca viene registrata come un errore di ombra e nulla di più.
Definito come Shadow in internal/config.
| Chiave | Tipo | Obbligatorio | Predefinito |
|---|---|---|---|
channel | testo | sì | — |
sample | numero | no | 1 |
compare | elenco di testo | no | — |
ignore | elenco di testo | no | — |
max_differences | numero intero | no | 100 |
timeout | durata, ad esempio 30s o 5m | no | 5s |
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.
| Chiave | Tipo | Richiesto | Predefinito |
|---|---|---|---|
code | testo | sì | — |
scheme | testo | sì | — |
display | testo | no | — |
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:
- Il tipo di contenuto dichiarato viene ignorato. I byte vengono sniffati e il risultato deve essere in un elenco di controllo. Un file chiamato logo.png che contiene HTML è HTML. - L'SVG è accettato, perché è ciò che le aziende hanno effettivamente, ma è un formato di documento eseguibile: può contenere elementi di script, attributi di gestione degli eventi, riferimenti esterni e oggetti esterni incorporati. Viene riscritto per rimuovere tutti questi prima di essere memorizzato, e la riscrittura viene verificata piantando ogni attacco in un test. - Viene servito con un criterio di sicurezza del contenuto che non consente nulla, con sniffing disabilitato e come un'immagine in linea senza allegati solo. Anche un bug di sanificazione non dovrebbe diventare esecuzione di script nell'origine della console stessa. - Il nome del file caricato non viene mai utilizzato per costruire un percorso. Il nome memorizzato è derivato dal tipo sniffato, quindi un nome come ../../etc/perfuse non può sfuggire da nessuna parte.
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:
- active-passive: un lease, "leader". Il suo detentore esegue ogni canale e ogni lavoro che deve essere eseguito una volta (notifiche di abbonamento, avvisi). Gli altri aspettano e il primo che lo vede scadere prende il controllo. - active-active: il leader esegue ancora i lavori e ogni canale ha un lease proprio, distribuito uniformemente sui server attivi. Un server che esce consegna i suoi canali agli altri; uno che si unisce prende la sua quota quando sono liberi.
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:
- Il digest è sull'intero documento, escludendo ogni elemento legalAuthenticator e authenticator (sezione 3.1.2), in modo che i firmatari successivi non rompano le firme precedenti. Espresso nella firma come un filtro di trasformazione XPath 2.0, che qualsiasi implementazione di XML-DSig può valutare. - La firma è XAdES-X-L (3.1.1, ESMD-1 a ESMD-6): il certificato di firma, l'ora di firma UTC, un ruolo dalla tassonomia dei fornitori NUCC, uno scopo di firma da ASTM E1762, il percorso di certificazione in CertificateValues e una risposta OCSP o CRL in RevocationValues, con i timestamp X-L su cui è costruito. - È trasportato in base64 in sdtc:signatureText sul partecipante che ha firmato, con un'anteprima in testo normale (3.3, ESMD-7 a ESMD-16), all'interno di digitalSignature/authorizedSigner.
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.
- Una decisione non viene mai aggiornata. La certificazione parziale non diventa approvazione, e una richiesta che il pagatore ha rifiutato di considerare non diventa un rifiuto. Entrambe queste cadute sono disponibili nella mappatura ovvia e entrambe sono sbagliate nella direzione che costa a qualcuno settimane: un appello presentato contro una decisione che nessuno ha preso, o sei sessioni prenotate contro tre approvate. - Nulla viene inventato per riempire un campo obbligatorio. Dove il formato di destinazione richiede qualcosa che la sorgente non trasporta, la mappatura segnala come una nota piuttosto che fornire un valore predefinito plausibile. Un numero di autorizzazione contraffatto è peggiore di uno assente. - Ogni giudizio viene segnalato. Le note tornano con il risultato, in modo che una persona possa leggere il pugno che ha bisogno di una decisione piuttosto che l'intero output. - I viaggi di andata e ritorno sono testati, non assunti. Una mappatura che perde un campo in una direzione viene trovata convertendo indietro e confrontando, che è l'unico modo per vedere un campo che nessuno ha pensato di affermare.
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.
- ITI-44, Patient Identity Feed HL7 V3: una sorgente aggiunge un paziente (PRPA_IN201301UV02), ne revisiona uno (PRPA_IN201302UV02) o dice che due record sono la stessa persona (PRPA_IN201304UV02). Risposto con MCCI_IN000002UV01. - ITI-45, PIXV3 Query: gli altri identificatori della persona che detiene uno (PRPA_IN201309UV02 -> PRPA_IN201310UV02). - ITI-47, PDQV3 Query: le persone che corrispondono a qualche dato demografico (PRPA_IN201305UV02 -> PRPA_IN201306UV02), con continuazione (QUQI_IN000003UV01) e annullamento (QUQI_IN000003UV01_Cancel).
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:
- ELR: messaggi HL7 2.5.1 ORU^R01 che trasportano i risultati dei laboratori alle agenzie di sanità pubblica (elr.go). - eCR: segnalazioni di casi elettroniche iniziali basate su FHIR (eICR) quando viene diagnosticata una condizione segnalabile. - Registro di immunizzazione: VXU^V04 per segnalare le vaccinazioni somministrate, e VXQ^V01 per interrogare la storia di immunizzazione di un paziente.
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:
- Impostare active su false termina ogni sessione immediatamente, non alla scadenza successiva. Una scheda del browser lasciata aperta su un laptop che è tornato a casa con un dipendente licenziato deve smettere di funzionare e una sessione che sopravvive fino a quando non scade è una sessione che sopravvive al licenziamento. - Un errore è un errore. SCIM non ha semantica di ritento che un'applicazione possa utilizzare, quindi restituire 200 per qualcosa che non è successo significa che il provider di identità registra la disattivazione come completata e non tenta più. - L'eliminazione di un utente è trattata allo stesso modo della disabilitazione: l'accesso termina. La storia di audit viene conservata comunque, perché un record che nomina qualcuno che non esiste più è peggiore di uno contrassegnato come ritirato.
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:
- Un'ombra non può consegnare. Contiene una pipeline di trasformazione e nessun mittente, quindi non c'è un percorso di codice da qui a un ricevitore. Un'impostazione non può crearne uno e un errore non può abilitarne uno. - Un'ombra non può influenzare il canale live. Viene chiamata dopo che il messaggio live è stato consegnato e confermato, le sue panic sono state recuperate e i suoi timeout sono suoi.
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
26.110 umlink
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:
- Un valore che non può essere mappato viene preservato come testo, mai ipotizzato. Un codice locale trasformato in un codice standard plausibile è peggiore di un valore non codificato, perché il destinatario ci crede. - Ogni decisione di mappatura che ha richiesto un giudizio viene segnalata come una nota, in modo che un essere umano possa controllare quelle che contano invece di leggere l'intero output. - I timestamp vengono convertiti, non copiati. I timestamp HL7 v2 non sono ISO 8601, e un dateTime che trasporta un'ora locale senza offset è il motivo più comune per cui una risorsa convertita viene rifiutata. - Le unità mantengono il testo originale e acquisiscono un codice UCUM solo quando la mappatura è certa. Un codice unità errato è un difetto di sicurezza per il paziente, non un problema di formattazione.
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:
- Un file che viene scritto e un file che ha finito di essere scritto sono indistinguibili. Non c'è un lucchetto, una bandiera o una notifica su nessuno di questi trasporti - c'è una dimensione e un tempo di modifica, e entrambi sono veri per un file scritto a metà. La lettura troppo presto raccoglie metà messaggio, e HL7 non ha un terminatore, quindi metà messaggio è spesso ancora parsabile. L'MSH è integro, i segmenti che sono arrivati sono ben formati, quelli che non sono arrivati sono semplicemente assenti. Viene accettato, confermato, archiviato, consegnato e nulla lo menzionerà mai. - Un file non deve essere eliminato fino a quando ogni messaggio in esso non sia stato accettato, perché il file è l'unica copia. - Un file che non è riuscito non deve essere ripreso nuovamente nel prossimo sondaggio per sempre e non deve essere eliminato silenziosamente.
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 è:
- L'algoritmo di firma è fisso alla registrazione e memorizzato con la chiave. Nulla durante l'accesso legge un algoritmo dal client, perché questo è confusione dell'algoritmo e non c'è funzione qui che possa farlo. - L'origine è confrontata esattamente, mai per prefisso o suffisso. Un controllo che accetta qualsiasi cosa che termina nel dominio corretto accetta un subdominio dell'attaccante. - Una sfida è ad uso singolo ed è scaduta. Viene eliminata quando viene consumata, quindi un'asserzione catturata non può essere riprodotta. - L'attestazione non è affidabile per nulla. La dichiarazione di attestazione viene analizzata per estrarre le credenziali e poi la sua firma viene ignorata, perché verificarla correttamente richiede un archivio radice mantenuto e fingere di verificarla è peggio che non affermarlo. - Il contatore di firma viene controllato quando l'autenticatore fornisce uno, e la sua assenza non viene trattata come sospetta. Molti autenticatori lasciano legittimamente a zero.
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
| Chiave | Appare in |
|---|---|
access_key_id | Accesso AWS, Autenticazione FHIR, Destinazione S3 |
account | Accesso Azure Blob |
ack | Origine HTTP, Origine SOAP, Origine |
ack_sender_id | Opzioni X12 |
ack_sender_qualifier | Opzioni X12 |
acknowledge | Opzioni EDIFACT, Opzioni HL7v3, Opzioni X12 |
acks | Destinazione Kafka |
action | Destinazione SOAP |
addr | Connessione AMQP, Destinazione Broker, Origine Broker, Connessione MQTT |
address | Connessione AMQP, Destinazione DICOM, Origine query DICOM, Destinazione, Indirizzo diretto, Destinazione TCP |
ae_title | Origine DICOM |
after_query | Origine del database |
after_read | Origine Azure Blob, IMAP diretto, Origine e-mail, Poll del file, Origine GCS, Origine S3, Origine SFTP |
allow | Script |
allow_clear_password | Destinazione FTP |
allow_unencrypted | Partner AS2, Ricezione PGP |
allow_unsigned | Partner AS2 |
allowed_calling_ae | Origine DICOM |
allowed_senders | Origine e-mail |
amqp | Destinazione, Origine |
anchors_file | Indirizzo diretto |
api_version | Connessione IBMMQ |
append | Destinazione, Destinazione SFTP |
application | Ack |
armor | Invio PGP |
arrives_as | Opzioni X12 |
as2 | Destinazione, Origine |
attach | Destinazione SMTP |
attach_name | Destinazione diretta, Destinazione SMTP |
attachment_names | Origine e-mail |
attachments | Canale |
attempts | Retry |
auth | Destinazione FHIR, Destinazione PAS |
authorities | Destinazione MPI |
azure_blob | Destinazione, Origine |
backoff | Configurazione della coda, Retry |
base64 | Origine SOAP |
batch_size | Origine del database, Poll del file |
baud | Origine seriale |
bcc | Destinazione SMTP |
bearer_token | Destinazione CDA, Destinazione FHIR, Destinazione HTTP, Destinazione PAS |
big_endian | Impostazione del framing TCP |
blob | Destinazione Azure Blob |
body | Destinazione SMTP, Destinazione SOAP |
broker | Destinazione, Origine |
brokers | Destinazione Kafka, Origine Kafka |
bucket | Accesso GCS, Destinazione S3, Origine S3 |
bundle_script | Destinazione FHIR |
called_ae | Destinazione DICOM, Origine query DICOM |
calling_ae | Destinazione DICOM, Origine query DICOM |
cc | Destinazione SMTP |
cda | Destinazione |
cert_file | Destinazione AS2, Partner AS2, Origine AS2, Indirizzo diretto |
channel | Destinazione, Ombra |
check_every | Riferimento contratto |
city | Struttura ECR |
claim_us_core | Destinazione FHIR |
class | Destinazione XDS |
client_ca_file | XDR diretto |
client_id | Autenticazione e-mail, Autenticazione FHIR, Connessione MQTT |
client_secret | Autenticazione e-mail, Autenticazione FHIR |
code | Codice XDS |
column | Origine del database |
columns | Delimitato |
comment | Delimitato |
commit_after_delivery | Origine Kafka |
compare | Ombra |
compress | Destinazione AS2 |
compression | Destinazione Kafka |
config | Destinazione ELR |
container | Accesso Azure Blob |
content_type | Destinazione AMQP, Destinazione AS2, Destinazione Azure Blob, Destinazione Broker, Destinazione GCS, Destinazione HTTP, Destinazione S3, Destinazione XDS |
contract | Canale |
credentials_file | Accesso GCP |
dataType | Canale |
data_bits | Origine seriale |
database | Destinazione, Origine |
decrypt_with | Ricezione PGP |
default_identifier_system | Destinazione FHIR |
delimited | Canale |
delimiter | Delimitato, Impostazione del framing TCP |
deploy | Script |
description | Canale |
destination | Destinazione Broker, Origine Broker |
destinations | Canale |
dicom | Canale, Destinazione, Origine |
dicom_query | Origine |
dicomweb | Destinazione, Origine |
dir | Destinazione CDA, Destinazione, Destinazione del documento, Destinazione FTP, Poll del file, Destinazione SFTP, Origine SFTP |
direct | Destinazione, Origine |
direct_from | Destinazione XDS |
direct_to | Destinazione XDS |
display | Codice XDS |
dns | Destinazione diretta |
document | Destinazione |
domain | Origine SMB |
driver | Destinazione del database, Origine del database |
dsn | Destinazione del database, Origine del database |
duplicate_window | Origine AS2 |
ecr | Destinazione FHIR |
edifact | Canale |
element | Origine SOAP |
elr | Destinazione |
email | Origine |
emit_on_first_poll | Origine query DICOM |
enabled | Canale, Destinazione, Configurazione della coda |
encrypt_to | Invio PGP |
endpoint | Accesso AWS, Accesso Azure Blob, Accesso GCP, Destinazione S3 |
envelope | Opzioni EDIFACT, Opzioni X12 |
error_dir | Poll del file, Origine SFTP |
error_folder | IMAP diretto, Origine e-mail |
error_prefix | Origine Azure Blob, Origine GCS, Origine S3 |
expect_reply | Destinazione TCP |
extract | Allegati |
facility | Ack, Destinazione ECR |
facility_id | Destinazione SOAP |
facility_type | Destinazione XDS |
fail_on_body | Destinazione HTTP |
fault_is_success | Destinazione SOAP |
fault_on_nak | Origine SOAP |
fhir | Destinazione |
file | Riferimento contratto, Origine |
file_name | Destinazione AS2, Destinazione, Destinazione del documento, Destinazione FTP, Invio PGP, Destinazione SFTP |
file_roots | Script |
filter | Canale, Delimitato, Destinazione, Opzioni HL7v3, Script |
flow_control | Origine seriale |
follow_redirects | Destinazione HTTP |
follow_symlinks | Origine del file |
font_size | Destinazione del documento |
format | Destinazione del documento, Destinazione S3 |
framed | Origine Azure Blob, Destinazione FTP, Poll del file, Origine GCS, Destinazione S3, Origine S3, Destinazione SFTP, Origine SFTP |
framing | Impostazione del framing TCP |
from | Destinazione AS2, Destinazione SMTP |
from_beginning | Origine Kafka |
ftp | Destinazione, Origine |
gcs | Destinazione, Origine |
group | Canale, Origine Kafka |
group_by | Destinazione SNS, Destinazione SQS |
has_header | Delimitato |
header | Destinazione SOAP |
headers | Destinazione Broker, Destinazione CDA, Destinazione DICO Mweb, Destinazione FHIR, Destinazione HTTP, Destinazione Kafka, Destinazione SOAP, Destinazione XDS |
heartbeat | Origine Broker |
hl7v3 | Canale |
host | Destinazione Broker, Origine Broker, IMAP diretto, Origine e-mail, Destinazione FTP, Origine FTP, Destinazione SFTP, Origine SFTP, Origine SMB, Destinazione SMTP |
hostname | Connessione AMQP |
http | Destinazione, Origine |
ibm_mq | Destinazione, Origine |
id | Partner AS2, Origine AS2 |
id_type | Destinazione MPI |
identifier_systems | Destinazione CDA, Destinazione FHIR |
idle_timeout | Origine DICOM, Origine, Origine TCP |
ignore | Ombra |
imap | Origine diretta |
include | Script |
include_trigger_event | Ack |
insecure_skip_host_key_check | Destinazione SFTP, Origine SFTP |
insecure_skip_verify | Destinazione FTP, Origine FTP, Destinazione SMTP, Origine Web DAV |
interval | Origine query DICOM |
javascript | Destinazione, Origine |
kafka | Destinazione, Origine |
keep_alive | Destinazione TCP |
keep_blank_lines | Delimitato |
keep_delimiter | Impostazione del framing TCP |
key | Accesso Azure Blob, Destinazione Kafka, Destinazione S3 |
key_column | Origine del database |
key_file | Destinazione AS2, Origine AS2, Indirizzo diretto, Destinazione SFTP, Origine SFTP |
key_passphrase | Destinazione SFTP, Origine SFTP |
known_hosts_file | Destinazione SFTP, Origine SFTP |
landscape | Destinazione del documento |
language | Script |
ldap | Destinazione diretta |
length_bytes | Impostazione del framing TCP |
length_includes_header | Impostazione del framing TCP |
level | Origine query DICOM |
limit | Origine query DICOM |
line | Struttura ECR |
listen | Origine AS2, Origine DICO Mweb, Origine DICOM, Origine diretta, XDR diretto, Origine HTTP, Origine SOAP, Origine, Origine TCP |
login | Destinazione Broker, Origine Broker |
mailbox | IMAP diretto, Origine e-mail |
match | Origine query DICOM |
max_attempts | Origine del database, Configurazione della coda |
max_backoff | Configurazione della coda, Retry |
max_bytes | Origine diretta |
max_connections | Origine, Origine TCP |
max_depth | Configurazione della coda |
max_differences | Ombra |
max_file_size | Poll del file, Origine SFTP |
max_message_size | Origine AS2, Origine e-mail, Origine HTTP, Origine Kafka, Origine SOAP, Origine seriale, Origine, Destinazione TCP, Origine TCP |
max_messages | Origine Pub Sub, Origine SQS |
max_object_bytes | Origine DICO Mweb, Origine DICOM |
max_object_size | Origine Azure Blob, Origine GCS, Origine S3 |
max_open_conns | Destinazione del database |
mechanism | Autenticazione SASL Kafka |
method | Destinazione HTTP |
move_to | Origine Azure Blob, IMAP diretto, Origine e-mail, Poll del file, Origine GCS, Origine S3, Origine SFTP |
mpi | Destinazione |
mqtt | Destinazione, Origine |
name | Canale, Destinazione del canale, Destinazione, Struttura ECR |
ncpdp | Canale |
no_compress | Invio PGP |
no_merge | Destinazione MPI |
non_persistent | Destinazione IBMMQ |
npi | Struttura ECR |
oauth | Origine e-mail |
object | Destinazione GCS |
on_no_document | Destinazione CDA |
order_by | Destinazione Pub Sub |
over | Riferimento contratto |
overlap | Origine query DICOM |
params | Destinazione del database |
parity | Origine seriale |
partner_cert_file | Destinazione AS2 |
partners | Origine AS2 |
pas | Destinazione |
pass_plain | Ricezione PGP |
passcode | Destinazione Broker, Origine Broker |
passphrase | Ricezione PGP, Invio PGP |
password | Connessione 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 |
path | Origine AS2, Origine DICO Mweb, Origine HTTP, Origine SOAP |
path_style | Destinazione S3, Origine S3 |
patient_domain | Destinazione XDS |
patient_root | Origine query DICOM |
pattern | Poll del file, Origine SFTP |
payer | Destinazione PAS |
persistent | Destinazione Broker |
pgp | Destinazione, Origine |
phone | Struttura ECR |
poll_interval | Origine Azure Blob, Origine del database, IMAP diretto, Origine e-mail, Poll del file, Origine GCS, Origine IBMMQ, Origine Java Script, Origine S3, Origine SFTP |
port | IMAP diretto, Origine e-mail, Origine seriale |
postal_code | Struttura ECR |
postprocessor | Script |
practice_setting | Destinazione XDS |
prefetch | Origine AMQP |
prefix | Origine Azure Blob, Origine GCS, Origine S3 |
preprocessor | Script |
profile | Destinazione SOAP, Origine SOAP |
project | Accesso GCP |
protocol | Origine e-mail |
provider | Autenticazione e-mail |
pubsub | Destinazione, Origine |
purpose | Destinazione TEFCA |
qos | Connessione MQTT |
query | Origine del database |
query_timeout | Origine del database |
queue | Destinazione, Connessione IBMMQ |
queue_manager | Connessione IBMMQ |
queue_url | Destinazione SQS, Origine SQS |
quiet_after | Origine seriale |
quote | Delimitato |
raw | Poll del file |
rctc | Destinazione ECR, Destinazione ELR |
read_timeout | Origine HTTP, Origine SOAP |
reassemble | Allegati |
receipt | Destinazione AS2 |
receipt_url | Destinazione AS2 |
recipient_certs_dir | Destinazione diretta |
reconnect | Origine AMQP, Origine Broker, Origine MQTT, Origine Pub Sub |
record_length | Impostazione del framing TCP |
refresh_token | Autenticazione e-mail |
region | Accesso AWS, Autenticazione FHIR, Destinazione S3 |
reject_on_warning | Destinazione FHIR |
relaxed | Delimitato |
reopen_after | Origine seriale |
reply | Origine seriale, Origine TCP |
reply_text | Origine seriale, Origine TCP |
request_mdn | Destinazione diretta |
require_agreement | Destinazione CDA |
require_signature | Ricezione PGP |
response_element | Origine SOAP |
response_namespace | Origine SOAP |
response_transformer | Destinazione |
results_to | Destinazione PAS, Destinazione TEFCA |
retain | Destinazione MQTT |
retain_hours | Destinazione, Configurazione della coda |
retry | Destinazione |
return | Origine query DICOM |
root | Origine FTP, Origine del file, Origine SMB |
s3 | Destinazione, Origine |
sample | Ombra |
sas | Accesso Azure Blob |
sasl | Destinazione Kafka, Origine Kafka |
scheme | Codice XDS |
scope | Autenticazione e-mail, Autenticazione FHIR |
script | Canale, Destinazione Java Script, Origine Java Script |
scripts | Canale |
secret_access_key | Accesso AWS, Autenticazione FHIR, Destinazione S3 |
security | IMAP diretto, Origine e-mail, Destinazione FTP, Origine FTP |
selector | Origine Broker |
sender_device | Opzioni HL7v3 |
sender_oid | Opzioni HL7v3 |
serial | Origine |
server_side_encryption | Destinazione S3 |
session_timeout | Origine Kafka |
session_token | Accesso AWS, Autenticazione FHIR, Destinazione S3 |
sftp | Destinazione, Origine |
shadow | Canale |
share | Origine SMB |
sign_with | Invio PGP |
smb | Origine |
smtp | Destinazione |
smtp_host | Destinazione diretta, Origine diretta |
sns | Destinazione |
soap | Destinazione, Origine |
sop_classes | Origine DICOM |
sort_by | Poll del file |
source | Canale, Destinazione ECR |
source_id | Destinazione XDS |
split | Delimitato, Opzioni EDIFACT, Opzioni X12 |
sqs | Destinazione, Origine |
ssn_system | Destinazione MPI |
stable_for | Poll del file, Origine SFTP |
start_block | Impostazione del framing TCP |
starttls | Destinazione SMTP |
state | Struttura ECR |
statement | Destinazione del database |
stop_bits | Origine seriale |
storage_class | Destinazione GCS, Destinazione S3 |
subject | Destinazione AS2, Destinazione diretta, Destinazione SMTP, Destinazione SNS |
subscription | Origine Pub Sub |
subscription_id | Origine Broker |
success_on_undefined | Destinazione Java Script |
success_status | Destinazione HTTP |
suffix | Origine Azure Blob, Origine GCS, Origine S3 |
tables | Canale |
take | Origine e-mail |
tcp | Destinazione, Origine |
tefca | Destinazione |
temp_suffix | Destinazione, Destinazione del documento, Destinazione FTP, Destinazione SFTP |
template | Origine del database, Destinazione del documento |
tenant | Autenticazione e-mail |
tenant_id | Autenticazione FHIR |
text | Destinazione diretta |
tier | Destinazione Azure Blob |
timeout | Connessione 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 |
timezone | Destinazione FHIR |
title | Destinazione del documento |
tls | Connessione 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_cert | Origine diretta, XDR diretto |
tls_key | Origine diretta, XDR diretto |
to | Destinazione AS2, Destinazione diretta, Destinazione SMTP |
token | Destinazione DICO Mweb, Origine DICO Mweb, Origine HTTP, Origine SOAP, Destinazione XDS |
token_url | Autenticazione e-mail, Autenticazione FHIR |
topic | Destinazione Kafka, Destinazione MQTT, Origine MQTT, Destinazione Pub Sub |
topic_arn | Destinazione SNS |
topics | Origine Kafka |
transfer_syntaxes | Destinazione DICOM, Origine DICOM |
transformations | Canale, Opzioni DICOM, Delimitato, Opzioni HL7v3, Opzioni NCPDP, Opzioni script, Opzioni X12 |
transformer | Script |
trim_padding | Impostazione del framing TCP |
trim_space | Delimitato |
type | Destinazione, Autenticazione FHIR, Origine |
undeploy | Script |
unencrypted | Destinazione AS2 |
unsigned | Destinazione AS2 |
unsigned_receipt | Destinazione AS2 |
url | Destinazione AS2, Destinazione CDA, Destinazione DICO Mweb, Destinazione FHIR, Destinazione HTTP, Connessione IBMMQ, Destinazione SOAP, Origine Web DAV, Destinazione XDS |
user | Destinazione FTP, Origine FTP, Destinazione SFTP, Origine SFTP, Origine SMB, Origine Web DAV |
username | Connessione 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_send | Destinazione FHIR |
verify_with | Ricezione PGP |
version | Destinazione CDA, Destinazione FHIR, Destinazione SOAP, Origine SOAP |
visibility_timeout | Origine SQS |
wait_seconds | Origine SQS |
warnings_are_errors | Destinazione SOAP |
webdav | Origine |
when | Ack |
window | Origine query DICOM |
write | Destinazione CDA |
wsdl | Origine SOAP |
x12 | Canale |
x12_as | Destinazione |
xdm | Destinazione diretta |
xdm_source_id | Destinazione diretta |
xdr | Origine diretta |
xds | Destinazione |