1 Introduction
Perfuse déplace des messages cliniques entre des systèmes qui n'ont jamais été conçus pour communiquer entre eux. Un laboratoire envoie des résultats en HL7 v2 ; le système de gestion de pratique attend ces résultats avec des positions de champ différentes, un identifiant de patient différent et un accusé de réception dans les cinq secondes. Quelque chose doit se situer au milieu, et ce quelque chose est un moteur d'intégration.
Ce manuel décrit ce que Perfuse fait, chaque option qu'il accepte, et — lorsque une décision n'est pas évidente — pourquoi il fonctionne de cette manière.
1.1 À quoi sert Perfuse
Une interface unique entre deux systèmes cliniques est généralement facturée en dizaines de milliers, avec quinze à vingt pour cent de cela encore chaque année en maintenance. Une grande partie de ce coût n'est pas le travail ; c'est que le travail nécessite quelqu'un qui a déjà travaillé avec HL7, et la plupart des pratiques n'emploient pas une telle personne.
Perfuse est conçu sur l'hypothèse que la personne qui le configure a un problème à résoudre et aucune expérience préalable avec HL7. Cette hypothèse se manifeste dans des endroits spécifiques :
- Tout est configurable à partir de l'interface web. Une fonctionnalité accessible uniquement à partir d'un terminal ou d'un fichier édité à la main est considérée comme un défaut, et non comme un choix de conception.
- Les messages peuvent être tracés étape par étape, en montrant ce que chaque étape a lu, ce qu'elle a modifié, ce qu'elle a sauté et pourquoi.
- Un trafic de test peut être généré qui correspond à la forme d'un flux réel sans contenir ses données.
- Un canal peut être proposé à partir d'un seul message d'exemple, avec une déclaration explicite de ce que l'exemple ne peut pas vous dire.
- Avant de remplacer un moteur existant, sa sortie et celle de Perfuse peuvent être comparées message par message, avec les différences regroupées par champ.
1.2 Qu'est-ce qui est dedans
Tout ce qui suit est dans le même fichier binaire. Chaque ligne nomme le chapitre qui le couvre.
- Formats. HL7 v2, FHIR R4, R4B et R5, DICOM, X12 (837, 835, 270/271, 276/277, 834, 278, 275), C-CDA et CDA, HL7 v3, NCPDP Telecommunication et SCRIPT, SMART Health Links et Cards, délimités et bruts. Voir formats de message.
- Connecteurs. 28 types de sources et 32 types de destinations, parmi lesquels MLLP, fichiers, SFTP, bases de données, DICOM, Kafka, AMQP 1.0, MQTT, IBM MQ, et stockage et messagerie AWS, Azure et Google Cloud. Voir la référence de source et la référence de destination.
- Modification des messages. Filtres, onze étapes de transformation déclaratives, JavaScript (y compris le dialecte Mirth) et Lua, tables de mappage partagées et jeux de codes, et suggestions de mappage. Voir filtrage et transformation.
- Livraison. Une file d'attente durable et ordonnée par destination, réessais, lettres mortes qui conservent le message, et accusés de réception envoyés après livraison. Voir livraison et accusés de réception.
- Surveillance. Tableaux de bord, tableaux de bord d'équipe, une carte de flux, onze types d'alerte, métriques, traçage et un magasin de messages qui trouve les messages d'un patient dans différents formats. Voir alertes, le magasin de messages et débogage.
- Modification d'une interface en direct de manière sécurisée. Mode d'ombre, contrats d'alimentation, tests de canal et comparaison de moteur. Voir tests.
- Sortie de Mirth. Canaux Mirth, Open Integration Engine et BridgeLink expliqués, traduits et exportés à nouveau. Voir migration.
- Payeurs et santé publique. Les quatre API CMS-0057, Da Vinci CRD, DTR, PAS, PDex et Plan-Net, CARIN Blue Button, un service de décision facultatif, eCR et ELR. Da Vinci CRD, DTR et PAS répondent aux versions 2.2.x et 2.1.0. Voir CMS-0057.
- Qui peut faire quoi. SAML, OpenID Connect, LDAP, passkeys, SCIM, TLS mutuel, six rôles, groupes de canaux avec un rôle chacun, locataires, un serveur d'autorisation SMART, TEFCA et UDAP, et un journal d'audit. Voir sécurité.
- Exécution. Un binaire statique pour Linux, macOS et Windows, en tant que service, avec une vue de flotte de plusieurs serveurs. Voir opérations, l'interface web, la ligne de commande et options de serveur.
1.3 Normes et versions
Quelle version de chaque norme Perfuse met en œuvre, et comment cela a été vérifié. « Vérifié » nomme l'outil ou la référence externe qui a jugé le résultat ; si rien n'a été jugé, cela le mentionne. Les résultats proviennent de données de test, et non d'un site de production.
1.3.1 Messagerie et documents
| Norme | Version | Vérifié |
|---|---|---|
| HL7 v2 | toute version : les messages sont lus par leurs propres séparateurs, et non par un schéma de version ; les accusés de réception par défaut sont 2.5.1 | validateur HL7 v2 de NIST ; trafic Mirth et OIE réel |
| HL7 v2 vers FHIR | mappage V2-FHIR d'HL7 (ADT, ORU, SIU, MDM, VXU et les segments qui les composent) | validateur FHIR d'HL7 contre US Core, UK Core, FR Core, ISiK, nl-core et HL7 Europe |
| FHIR | R4 (4.0.1), avec R4B et R5 lus et écrits | validateur FHIR d'HL7 ; Inferno |
| C-CDA et CDA | C-CDA 2.1 | SITE ONC (échantillons C-CDA envoyés et reçus via XDR) ; non par un schématron CDA |
| HL7 v3 | PIX et PDQ (IHE ITI-44, 45, 47) | schémas et échantillons de messages NE2008 d'IHE |
| DICOM et 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 demande (X217) et requête (X215) ; 275 dans 006020 (X314) | guides d'accompagnement des payeurs publiés ; échantillons esMD de CMS |
| CAQH CORE connectivité | vC2.2.0 SOAP et MIME, vC4.0.0 avec MTOM | système UM de remplacement écrit à partir des règles de CAQH |
| NCPDP | Télécommunication D.0 ; SCRIPT 2023011 (et 2017071) avec ePA ; Avantage de prescription en temps réel v13 | écrit à partir des guides d'accompagnement publics de Surescripts et de leurs exemples ; non contre les schémas NCPDP sous licence |
| UN/EDIFACT | syntaxe 3 et 4, CONTRL | pydifact 0.1.8 |
| Partage de documents IHE | XDS.b, XCA, XDR, MHD 4.2.2, PIXm, PDQm, XDM | NIST XDS Toolkit ; SITE ONC |
| Messagerie sécurisée Direct | Déclaration d'applicabilité 1.2, XDR et XDM pour Direct, découverte de certificat DNS et LDAP | SITE ONC ; Outil de découverte de certificat ONC (18 sur 18) |
| AS2 | RFC 4130, compression RFC 5402 | pyas2lib |
| Pièces jointes signées | HL7 DSDR, XAdES-X-L | xmlsec1, OpenSSL |
1.3.2 Guides d'implémentation FHIR
| Guide | Version | Vérifié |
|---|---|---|
| US Core | conversions en 9.0.0 (USCDI v6) ; serveur FHIR contre 6.1.0 et 7.0.0 | le validateur HL7 ; Inferno US Core |
| SMART App Launch | 2.2 | Inferno : 80 sur 80 (application publique) |
| Bulk Data Access | 2.0.0 | Inferno : 48 sur 48 |
| Abonnements R5 Backport | pour R4 | un récepteur HTTP réel ; les tests de notification du kit PAS |
| Da Vinci CRD | 2.2.1 et 2.1.0 | Inferno 2.2.1 : 92 réussites, 0 échecs ; 2.1.0 par les exemples propres au guide |
| Da Vinci DTR | 2.2.0 et 2.1.0 | Inferno 2.2.0 : 43 réussites, 2 échecs (un défaut du kit) ; 2.1.0 par les exemples propres au guide |
| Da Vinci PAS | 2.2.1 et 2.1.0 | Inferno 2.2.1 : 82 sur 84 ; 2.1.0 par les exemples propres au guide |
| Da Vinci PAS, envoi (côté fournisseur) | 2.2.1 | la référence de mise en œuvre du payeur Da Vinci PAS ; pas un payeur de production |
| Da Vinci PDex | 2.2.0 | Inferno PDex 2.0 : payeur à payeur 19 sur 19 |
Da Vinci HRex $member-match | 1.2.0 | Inferno PDex payeur à payeur |
| Da Vinci ATR | 2.1.0 | non vérifié par un outil externe |
Da Vinci CDex $submit-attachment | 2.1 | non vérifié par un outil externe |
| Da Vinci Plan-Net | 1.1.0 | Inferno : 199 réussites, 10 échecs (un défaut du kit) |
| Da Vinci US Drug Formulary | 2.1.0 | le validateur HL7 |
| ISiK (hôpitaux allemands), serveur FHIR | Stufe 5, module de base | le jeu de tests ISiK de gematik 3.0.9 : 421 sur 421 |
| PACIO Transitions of Care, Profil de médicament, Directives avancées, Fonctionnement | 1.0.0, 1.0.0, 2.0.0-balle, 2.0.0 | les kits Inferno de PACIO avec les données propres à PACIO : chaque échec dans les données ou le kit. C-CDA à document TOC : le validateur HL7 sur les exemples HL7, une erreur restante, le guide propre |
| CARIN Blue Button | 2.2.0 | le validateur HL7 |
| eCR | 2.1.2 | le validateur HL7 |
| ELR | HL7 2.5.1 ELR Release 1 avec ses errata | l'outil ELR d'ONC : 28 sur 28 |
| Résumé international du patient | 2.0.0 | le validateur HL7 |
| DEQM | 5.0.0 | le validateur HL7 |
| SQL sur FHIR | v2 | le jeu de tests officiel : 144 sur 144 |
| SMART Health Cards et Liens | Cartes 1.4, Liens STU 1 | la carte d'exemple propre aux spécifications ; une bibliothèque de visualiseur de liens SMART Health publiée |
| UDAP Sécurité | STU 1 | un serveur d'autorisation réel et une communauté de confiance |
| TEFCA Facilitated FHIR | SOP v2.0 | non vérifié contre un QHIN réel |
1.3.3 Profils nationaux et européens
Vérifié en convertissant des messages HL7 v2 publiés ou inventés et en validant chaque ressource ; les résultats complets et les raisons de chaque échec se trouvent dans le dossier conformance/national du référentiel.
| Profil | Version | Ressources valides |
|---|---|---|
| UK Core | STU2 2.0.2 | 185 sur 187 |
| FR Core | 2.2.0 | 138 sur 156 |
| ISiK Basismodul | 4.0.3 (Stufe 4) | 18 sur 47 ; 42 sur 47 avec le script de bundle propre à l'hôpital |
| Nictiz nl-core | 0.12.1-beta.1 (zib 2020) | 12 sur 24 ; 18 sur 24 avec le script de bundle propre à l'hôpital |
| HL7 Europe Laboratory Report | 2.1.0 | 106 sur 426 (le guide attend un document, un résultat v2 n'est pas) |
| HL7 Europe Hospital Discharge Report | 1.0.0 | 68 sur 69 |
Aucun de ces éléments n'est une certification. Perfuse n'a pas été certifié par l'ONC, le CMS, gematik, Nictiz, NHS England ou quiconque d'autre.
1.4 Ce qu'il remplace
Perfuse couvre le terrain occupé par Mirth Connect, et peut importer des exports de canal Mirth directement. Le chapitre sur la migration décrit ce qui se traduit proprement, ce qui nécessite une décision, et comment prouver que le résultat correspond avant de passer à la version suivante.
Les différences qui comptent dans l'utilisation quotidienne sont le débogage et le silence. Dans Mirth, voir ce qu'un transformateur a fait à un message signifie généralement redeployer le canal avec la journalisation ajoutée. Dans Perfuse, tout message enregistré peut être rejoué à travers la configuration actuelle et inspecté étape par étape, sans toucher au canal en cours d'exécution. Et là où une alerte Mirth sur « pas de trafic » est un seuil fixe qui est inutile sur tout flux qui est calme la nuit, Perfuse apprend à quoi ressemble une semaine normale pour chaque flux et alerte en conséquence.
1.5 Comment lire ce manuel
Les premiers chapitres sont conceptuels et valent la peine d'être lus dans l'ordre : canaux, flux de message, puis transformation. Tout ce qui suit peut être lu au besoin.
Les chapitres de référence vers la fin listent chaque clé de configuration, son type, si elle est requise et sa valeur par défaut. Ces chapitres sont générés à partir de la source, ils ne peuvent donc pas décrire une option qui n'existe pas ou omettre une qui existe. Si une clé apparaît dans un fichier de configuration et non dans l'index, il ne s'agit pas d'une clé Perfuse.
1.6 Conventions
La configuration est en YAML. La plupart des clés sont en snake_case sur le fil — max_message_size, idle_timeout — et ce manuel donne toujours la forme sur le fil, car c'est ce que vous tapez. Il y a une exception de longue date, dataType sur un canal, qui est en camelCase ; elle est documentée de cette façon dans la référence de canal et acceptée uniquement dans cette orthographe.
Les références de champ dans HL7 utilisent la notation habituelle : PID-5 est le cinquième champ du segment PID, PID-5.1 son premier composant, et PID-3(2) la deuxième répétition du troisième champ. Un chemin écrit sans répétition s'adresse à chaque répétition (voir chemins).
Les durées sont écrites sous la forme d'un nombre et d'une unité — 30s, 5m, 2h. Un nombre nu n'est pas une durée et sera refusé plutôt que deviné.
2 Premiers pas
Perfuse est un binaire unique avec une interface web intégrée. Il n'y a pas de serveur d'application à installer, pas de base de données à provisionner et pas de console d'administration distincte.
2.1 Exécution
perfuse serve -channels ./channels -db ./perfuse.db -addr 0.0.0.0:8443 \
-tls-cert ./cert.pem -tls-key ./key.pem
-channels est un répertoire de fichiers YAML, un par canal. -db est un fichier SQLite contenant les messages enregistrés, les utilisateurs et l'historique d'audit ; il est créé s'il n'existe pas.
Au premier démarrage sans utilisateurs configurés, un compte administrateur est créé et son mot de passe est écrit dans le journal une fois. Ce mot de passe n'est pas récupérable par la suite.
-tls-cert et -tls-key sert le HTTP non chiffré. C'est acceptable sur une adresse de bouclage pour un premier aperçu et n'est pas acceptable ailleurs : l'interface web contient des informations d'identification et du contenu de message, les deux étant lisibles sur le fil sans TLS. Voir sécurité.2.2 Le premier canal
Un canal nécessite un nom, une source et au moins une destination. Le plus petit canal utile reçoit HL7 sur MLLP et écrit chaque message dans un fichier :
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
Enregistrez-le sous channels/first-feed.yaml et il est pris en compte sans redémarrage.
Trois choses à propos de ce fichier sont dignes d'intérêt, car elles sont la forme de chaque canal :
- Le bloc source est plat pour MLLP.
listenest directement sursource, et non à l'intérieur d'un blocsource.mllp. Les transports qui nécessitent plus qu'une adresse — HTTP, SOAP, DICOM — ont leur propre sous-bloc, et ceux-ci sont répertoriés dans la référence de source. - Une destination de fichier nécessite à la fois
rootetdir.rootest la limite que les chemins sont résolus contre et ne peuvent pas s'échapper ;direst où les messages atterrissent à l'intérieur. - Il n'y a pas de transformation et de filtre. Les deux sont facultatifs, et un canal avec aucun des deux passe simplement les messages.
2.3 Construction d'un canal à partir de l'interface
Tout ce qui précède peut être fait à partir de l'interface web à la place, et pour un premier canal, c'est la meilleure voie car le formulaire ne vous laissera pas produire un fichier qui ne charge pas.
Le constructeur offre trois moyens d'y accéder :
- À partir d'un message que quelqu'un vous a envoyé. Collez l'exemple que le laboratoire ou le fournisseur vous a envoyé par courrier électronique. Perfuse le lit et propose un canal, ainsi que trois listes distinctes : ce que l'exemple montre, ce qui a été deviné et ce que aucun exemple ne peut vous dire. Cela est décrit dans testing.
- À partir de quelque chose qui fonctionne déjà. Un ensemble de canaux complets qui n'ont besoin que de leurs adresses remplies.
- À partir de rien. Un formulaire vide. Disponible, mais c'est le plus lent des trois et le plus facile à mal faire.
2.4 Vérification qu'il fonctionne avant de connecter quoi que ce soit
Deux choses peuvent être faites avant que le système d'envoi n'existe.
Envoyez un message à la main à partir de l'interface — l'expéditeur de message accepte le texte collé et signale ce qui lui est arrivé, y compris quels destinations l'ont accepté et ce que chaque transformation a fait.
Ou générer du trafic de test. Si le canal a traité des messages, Perfuse peut en apprendre la forme et produire plus de messages similaires, dans les mêmes proportions, sans contenu d'origine. Voir testing.
2.5 Que faire ensuite
- Canaux explique ce qu'est un canal et comment ses parties s'emboîtent.
- Flux de message suit un message de l'arrivée à la livraison, ce qui est la façon la plus rapide de comprendre où mettre une modification.
- Alertes vaut la peine d'être configuré avant qu'un flux ne devienne actif plutôt qu'après le premier incident.
3 L'Interface Web
Perfuse est conçu sur l'hypothèse que tout est faisable depuis le navigateur, et une fonctionnalité qui ne peut être atteinte que par l'édition d'un fichier est considérée comme un défaut. Ce chapitre est une visite de ce qui se trouve derrière chaque partie de la navigation, organisé de la même manière que l'interface : par la question que vous posez.
La barre affiche Tableau de bord et Canaux directement, car ce sont les endroits où la plupart des sessions commencent et se terminent. Tout le reste est regroupé, et les groupes sont nommés d'après des questions plutôt que d'après des sous-systèmes — vous n'allez pas au « sous-système d'audit », vous allez trouver qui a modifié quelque chose.
3.1 Lecture de l'en-tête
Cinq choses dans l'en-tête sont faciles à manquer.
Chaque vue a une adresse. La barre d'adresse suit la vue — #/channels, #/messages, #/settings — donc une actualisation revient à celle-ci, un signet l'ouvre, un lien envoyé à un collègue l'amène sur celle-ci, et le bouton de retour se déplace entre les vues plutôt que de quitter la console. Une adresse nommant une vue au-dessus de votre rôle ouvre le tableau de bord à la place.
Recherche, ou ⌘K. Elle recherche à travers les canaux, les paramètres, les messages et le manuel, ce qui signifie qu'elle est généralement plus rapide que la navigation — en particulier pour un paramètre dont vous vous souvenez à moitié du nom.
Thème. Trois d'entre eux : Minuit, Sombre et Clair. Minuit est presque noir et est ce que l'on veut généralement pour un affichage mural dans une salle de serveurs ; Sombre est un gris neutre plus doux ; Clair est pour un ordinateur portable à côté d'une fenêtre. Le choix est stocké dans le navigateur plutôt que contre le compte, car un thème est une propriété de l'endroit où quelqu'un est assis, et non de qui il est — le même opérateur veut Minuit sur le mur et Clair dans un train. La préférence d'une machine est consultée une fois, pour choisir une valeur par défaut sensée la première fois.
Langue. La console en anglais (ordre de date UK ou US), allemand, français, néerlandais, espagnol, italien, portugais, polonais, suédois, danois, norvégien ou finnois, avec des dates et des nombres écrits de la manière dont cette locale les écrit. Le choix est conservé dans le navigateur, et la langue propre du navigateur est utilisée jusqu'à ce qu'un choix soit effectué. Les traductions ont été effectuées par machine et n'ont pas encore été examinées par des locuteurs natifs ; l'anglais est la référence, et le sélecteur le indique. Le code, les messages, les charges utiles, les noms de canal et tout ce qui est tapé ne sont jamais traduits. Le manuel est publié dans les mêmes langues à https://perfuse.health/manual/<language>/ (le Manuel de ce serveur est celui en anglais).
Manuel. Le document que vous lisez, servi par le serveur en cours d'exécution. Il s'agit du même fichier que le binaire peut écrire sur disque, donc il décrit toujours la version qui se trouve devant vous plutôt que la dernière version publiée.
3.2 Surveillance — si cela fonctionne et ce qui s'est passé
3.2.1 Tableau de bord
L'état de chaque canal, le débit, et tout ce qui ne va pas actuellement. C'est l'écran à laisser ouvert.
3.2.2 Messages
Chaque message qui est arrivé, en ce qu'il a été transformé, par destination, et ce qui lui est arrivé. Recherchable, y compris par une expression de filtre, donc « montrez-moi ceux de cet expéditeur qui ont été rejetés » est une requête plutôt qu'un après-midi.
Un message peut être rejoué à partir d'ici, et rétraité à travers la *configuration actuelle* plutôt que celle qui était active au moment de l'incident — ce qui est la façon de confirmer qu'une correction fonctionne contre le trafic qui l'a provoqué. Voir le magasin de messages pour savoir ce qui est conservé et pour combien de temps.
3.2.3 File d'attente
Ce qui attend d'être livré, et pourquoi. Une file d'attente qui ne se vide pas est l'avertissement le plus utile qu'un moteur d'intégration produit, et il vaut la peine de l'associer à une règle d'alerte pour que personne n'ait à surveiller. Voir livraison.
3.2.4 Alertes
Ce qui a déclenché et quelles sont les règles. Les règles sont éditées ici plutôt que dans un fichier. Voir alertes.
3.2.5 Métriques
Débit, latence et taux d'erreurs dans le temps. Utile pour les questions de capacité et, plus souvent, pour les rapports du conseil d'administration — c'est pourquoi le logo du site apparaît sur celui-ci si l'un a été téléchargé.
3.2.6 SQL sur FHIR
SQL sur les vues FHIR : choisissez un exemple ou une vue enregistrée, ou écrivez-en une, exécutez-la sur le magasin FHIR de ce serveur (tous les patients ou un) ou sur des ressources collées, voyez les lignes avec leurs types, et téléchargez CSV, NDJSON ou Parquet. Enregistrer la conserve pour l'endpoint FHIR $sql-run. Voir formats de message.
3.2.7 Mesures de qualité
Mesures de qualité numériques : choisissez un exemple ou une mesure dans le magasin FHIR, ou écrivez-en une avec des critères FHIRPath. Choisissez une période de mesure et un rapport (résumé, résumé avec des listes de patients, ou un patient) et évaluez-le sur le magasin FHIR ou des ressources collées. L'écran affiche le décompte de chaque population, les patients, le score et les strates. Télécharger MeasureReport enregistre le résultat FHIR, et Enregistrer dans le magasin FHIR conserve la mesure pour Measure/$evaluate-measure. Les mesures en CQL sont refusées : Perfuse n'a pas de moteur CQL. Voir mesures de qualité numériques.
3.2.8 Carte de flux
Une image de la façon dont les messages se déplacent réellement : quels sont les sources qui alimentent quels canaux, et quels sont les destinations qu'ils atteignent.
Sa valeur n'est pas une décoration. Chaque domaine accumule un canal que personne ne se souvient d'avoir commandé et une destination que personne ne réalisait qu'il recevait encore, et les deux sont visibles ici d'une manière qui ne l'est pas dans une liste de fichiers de canal.
3.2.9 Tableaux de bord d'équipe
Un tableau de bord pour chaque type de personne qui surveille les interfaces : Opérations, Connexions, Analyste d'interface, Autorisation préalable, Imagerie, Cycle de revenu, Laboratoire, Confidentialité et sécurité, et un résumé de département en termes clairs. Les tuiles affichent des décomptes, des états et des temps, mais jamais un message ou un patient, afin qu'un tableau de bord puisse être envoyé à un gestionnaire ou à un écran mural sans élargir l'accès aux données de patient.
Chaque personne ouvre sur le tableau de bord le répertoire de groupe ou le rôle qui lui est attribué. -dashboards dashboards.yaml les mappe :
groups: {PACS-Admins: imaging, Network-Team: connections}
roles: {viewer: manager}
Un groupe l'emporte sur un rôle, et toute personne non associée ouvre sur les Opérations. Organiser les tuiles masque et réorganise les tuiles, le sélecteur de canal les filtre, et Enregistrer comme ma vue les conserve comme votre propre tableau de bord jusqu'à Réinitialiser.
Exporter vers Grafana télécharge le tableau de bord sous forme de JSON Grafana sur /metrics, avec une variable de source de données et un filtre de canal, pour toute personne qui a besoin de plus que de légères configurations. Les tuiles sans métrique sous-jacente sont exclues, et la description de l'exportation les nomme.
La tuile Connexions vérifie chaque destination réseau en couches. Elle recherche le nom, ouvre une connexion TCP, complète le TLS lorsque celui-ci est utilisé, et lit la dernière livraison et la dernière défaillance de la destination à partir du trafic réel. Chaque défaillance indique ce qu'elle signifie, par exemple « refusé : le moteur du partenaire est probablement arrêté », « temps d'attente : un pare-feu ou un tunnel VPN qui est bas », ou « un certificat d'une autorité que ce serveur ne fait pas confiance ». Rien n'est envoyé au partenaire, à une exception près : un registre d'immunisation qui n'a eu aucun trafic pendant sept jours est invité à exécuter le test de connectivité CDC connectivityTest, qui ne soumet rien. Avec -vpn tunnels.yaml la tuile Tunnels VPN à côté d'elle lit l'état de chaque tunnel de partenaire à partir d'AWS Site-to-Site VPN, d'une connexion Azure VPN Gateway ou de strongSwan sur cet hôte, afin qu'une défaillance puisse être distinguée d'un tunnel qui est bas. Elle compare également les paramètres IKE et IPsec des deux côtés, car le cloud rapporte les nôtres et le fichier liste les leurs, et indique où ils ne peuvent pas être d'accord. Feuille de connexion télécharge les paramètres d'un partenaire côte à côte sous forme de Markdown pour les envoyer ; elle ne contient jamais de clé partagée. Les chiffres dont un tableau de bord a besoin qui ne sont pas encore enregistrés sont répertoriés sous Non encore mesuré au lieu d'être représentés par des tuiles vides.
Les tableaux de bord de département calculent leurs propres chiffres sur le serveur, et chacun indique la fenêtre et la source qu'il couvre :
- Autorisation préalable : Les demandes PAS décidées dans les 72 heures (accélérées) ou 7 jours (standard) de CMS-0057, décidées tardivement, en attente et en retard, ainsi que le temps médian pour prendre une décision. Aussi, la manière dont les services demandés ont été traités (approuvés, modifiés, rejetés, en attente), tel qu'il en est actuellement, sur 30 jours.
- Imagerie : Les objets reçus par C-STORE par modalité, et ceux qui n'ont pas été livrés. Aussi, le retard de routage par canal (la médiane et le 95e centile), les requêtes C-FIND et les échecs par canal de requête, et les rapports d'imagerie (un ORU dont l'OBR-24 est une section d'imagerie, ou un MDM) qui n'ont pas atteint chaque destination.
- Cycle de revenu : Les ensembles de transactions 999 acceptés, acceptés avec erreurs et rejetés, et les réclamations 277CA acceptées et rejetées (A3, A4, A6, A7, A8). Aussi, les réclamations 835 appariées par numéro de compte de patient aux 837 envoyés via ce serveur, et les raisons de rejet les plus courantes.
- Laboratoire : Le temps de livraison des résultats, de la réception à l'acknowledgement de la dernière destination, et les résultats critiques (OBX-8 HH, LL, AA, > ou <) qui n'ont pas atteint chaque destination.
- Confidentialité et sécurité : Qui a ouvert des messages, a recherché des patients ou a lu des autorisations préalables dans la console au cours des 7 derniers jours, à partir du journal d'audit (l'ouverture d'un message est audité comme
message.read). Aussi, chaque jeton API actif et la date de sa dernière utilisation ; un jeton inutilisé pendant 90 jours est signalé.
3.2.10 Partage de ce que contient réellement un flux
Profiler ce flux rapporte ce qui arrive réellement : quels sont les événements déclencheurs, quels champs sont remplis et à quelle fréquence, quelle forme prennent les valeurs, et quels codes un expéditeur utilise réellement. Ce dernier est généralement le fait le plus utile dans celui-ci.
Un profil peut être téléchargé et envoyé à quelqu'un d'autre. Il nécessite un nom et — obligatoire — quel système a produit le flux, car la question que quelqu'un pose à un profil partagé est de savoir s'il décrit son système, et un champ facultatif ferait de « Inconnu » la réponse la plus courante dans toute collection partagée.
Il ne contient aucune donnée de patient, et cela est vérifié plutôt que supposé. Un profil est statistique : nombres, taux, longueurs, formes. Les valeurs sont conservées uniquement pour les champs que la norme définit comme des tables de codes, car une valeur de table de codes n'est pas identifiable. Les valeurs d'identifiant ne sont jamais répertoriées.
Deux choses découlent du fait que c'est une promesse plutôt qu'un espoir. Le serveur reconstruit le profil à partir des messages stockés lors de l'exportation, plutôt que d'envoyer celui qui est sur votre écran — donc ce qui quitte le bâtiment a été assemblé par le profilier, qui a un test prouvant cette propriété, et non par un navigateur. Et l'exportation refuse catégoriquement si un profil liste des valeurs pour un champ qui n'est pas une table de codes, en nommant le champ mais pas les valeurs.
Un profil qui arrive d'ailleurs est vérifié de la même manière à l'entrée, pour une raison différente : il a été produit par quelqu'un dont les soins sont inconnus, et afficher les identifiants de ses patients serait une divulgation de ce serveur. L'importation d'un profil ne change rien — un profil décrit un flux, et décider ce qu'il faut en faire est une décision distincte.
3.3 Construire — modifier ce qu'un canal fait, et essayer avant qu'il ne soit en ligne
3.3.1 Canal
Le constructeur de canal. Sources, destinations, filtres, transformations, scripts et tests, avec le YAML généré affiché à côté du formulaire pendant que vous travaillez — donc le fichier n'est jamais un mystère, et quiconque préfère le fichier peut suivre.
Voir canaux pour connaître les composants, et transformation pour comprendre les étapes effectuées.
3.3.2 Scripts
Un atelier pour les scripts, séparé du constructeur car écrire un script et connecter un script sont des activités différentes.
Les sept emplacements sont proposés — filtre, transformateur, préprocesseur, postprocesseur, écrivain, cycle de vie et lecteur — et choisir le bon emplacement est important, car l'emplacement décide ce que le script reçoit et ce qu'on attend de lui. Vérifier un script comme étant du mauvais type n'est pas une solution de contournement ; il compile une chose différente.
JavaScript, Lua et WebAssembly sont tous disponibles. Voir transformation.
3.3.3 Contrats
Attentes sur l'apparence d'un flux, créées et vérifiées ici ainsi que depuis perfuse contract. Voir la ligne de commande.
3.3.4 Tableaux
Tableaux de correspondance et ensembles de codes : les mappages qui transforment les codes d'un système en ceux d'un autre. Éditables ici pour que l'ajout d'un code ne nécessite pas de déploiement.
3.3.5 AI Mapper
Propose des mappages de champs avec un score de confiance pour chacun, et s'abstient plutôt que de deviner. Malgré son nom, il n'utilise aucun modèle de langage et ne fait aucune appel réseau : les suggestions proviennent de règles, de noms de champs et du contenu de l'échantillon, sur ce serveur. Il propose également un canal à partir d'un seul message échantillon, et indique explicitement ce que l'échantillon ne peut pas lui dire. Cette deuxième partie est celle qui le rend digne de confiance — une proposition qui semblait complète vous inviterait à croire des choses que le message n'a jamais dites.
3.3.6 Playground
Un bloc-notes pour les messages et les transformations. Collez un message, appliquez des étapes, voyez le résultat.
Rien n'est envoyé nulle part une fois la page chargée, ce qui est la raison pour laquelle il existe sous cette forme : il est sécuritaire de coller quelque chose de réel dedans, en comprenant que cela reste dans le navigateur.
3.3.7 Ombre
Exécute le trafic via une configuration candidate aux côtés de la configuration live et signale les différences, de sorte qu'un changement puisse être établi avant d'être approuvé. Le même concept que perfuse compare, appliqué à un changement plutôt qu'à une migration. Voir testing.
3.4 Échange — les normes que ce serveur parle aux autres organisations
3.4.1 Lab FHIR
Convertir HL7 v2 en FHIR, valider une ressource et inspecter le résultat. Les échantillons couvrent les admissions, les résultats de laboratoire, les rendez-vous, les notes cliniques, les immunisations et une visite déclarable. La validation inclut US Core, qui est le profil contre lequel la réglementation américaine est écrite, donc cela répond à « est-ce que ce qu'ils nous ont envoyé est vraiment conforme » sans adopter quoi que ce soit.
Rapport de cas de santé publique construit le rapport eCR eICR qu'une destination de rapport de cas enverrait pour le message. Il montre quel code de déclenchement a rendu la visite déclarable, ce que le rapport devait marquer comme manquant, et le document lui-même. Un message sans rien de déclarable obtient la raison à la place. Rien n'est envoyé à partir d'ici.
3.4.2 Abonnements
Abonnements FHIR et si leurs notifications arrivent : événements, acceptés, en attente et la dernière raison pour laquelle l'un a été refusé. Les abonnements sont créés par les clients FHIR via l'API FHIR, et non à partir de cette page, et les informations d'identification qu'ils ont fournies au serveur ne sont jamais affichées. Voir formats de message.
3.4.3 Documents
Documents cliniques — CDA et la forme imprimable d'un document. Utile lorsque l'objet échangé est un résumé de sortie plutôt qu'un message.
3.4.4 Partage de documents
Le registre et le référentiel XDS.b de l'IHE a commencé avec -xds : combien de documents, de patients et d'ensembles de soumission il contient et combien ont été remplacés ; les adresses du référentiel, du registre, de la passerelle XCA et de MHD ; une recherche de documents d'un patient dans ce registre ou dans un autre (un registre ITI-18 ou une passerelle ITI-38, avec un jeton pour celle-ci) ; et la publication d'un document CDA à la main, avec le type d'établissement et le contexte de pratique qu'un document ne dit pas. Voir formats de message.
3.4.5 Direct
Messagerie sécurisée directe. Les adresses Direct de ce serveur répertorie chaque adresse qu'un canal envoie ou reçoit, avec son certificat, sa date d'expiration, les ancres qu'il fait confiance, et tout problème (un fichier manquant, un certificat expiré). Le carnet d'adresses conserve les correspondants et les certificats dont leur messagerie est chiffrée : collez-en un de leur HISP, ou Enregistrez-le avec le certificat de DNS ; un certificat qui n'est pas pour l'adresse ou son domaine est refusé. Recherchez un certificat dans DNS demande sans enregistrer. Voir formats de message.
3.4.6 Liens de santé
Liens et cartes de santé SMART, pour *Tuer le presse-papiers* de CMS. Recevoir un lien de santé SMART lit le lien ou le code QR qu'un patient montre à l'accueil, vérifie les cartes de santé à l'intérieur et l'envoie à un canal. Partager un enregistrement de visite crée un lien hébergé par ce serveur, éventuellement avec un code d'accès, et un code QR pour le patient ; Utiliser le résumé du patient le remplit avec le résumé du patient International Patient Summary du magasin FHIR de ce serveur. Les liens hébergés par ce serveur les listent avec la fréquence à laquelle chacun a été récupéré, quand il expire et les tentatives de code d'accès restantes, et révoque un lien. Vérifier une carte de santé SMART vérifie la signature et l'émetteur d'une carte de manière autonome. Voir CMS-0057 pour les options de serveur dont il a besoin.
3.4.7 Imagerie
L'archive que ce serveur conserve lorsqu'il s'exécute avec -dicomweb-archive : les comptes d'études, de séries, d'instances et d'espace utilisé, l'adresse DICOMweb et le bloc de source de données pour un visionneur OHIF, et une recherche d'étude par nom de patient, ID, accession et date effectuée avec la même requête QIDO-RS qu'un visionneur effectue. Une étude s'ouvre sur ses séries et instances, et une instance est téléchargée sous forme de fichier DICOM. Rien n'est rendu : Perfuse déplace les images et un visionneur les affiche. Sans archive, l'écran indique comment l'activer. Voir DICOMweb.
3.4.8 TEFCA
Le journal d'audit pour l'échange via un réseau d'information sur la santé qualifié, et les règles d'utilisation qui le régissent.
Deux transports, à des stades réellement différents, et l'écran indique lequel est lequel. Un indicateur couvrant les deux serait incorrect dans un sens ou dans l'autre.
Le FHIR facilité est implémenté, et n'a jamais parlé à un QHIN réel. Il suit la procédure opérationnelle standard du projet Sequoia en vigueur à compter du 8 mars 2026 : découvrir les métadonnées UDAP du partenaire, les vérifier, s'inscrire dynamiquement, obtenir un jeton d'accès portant l'objectif d'utilisation, et interroger. UDAP est une infrastructure à clés publiques sur OAuth 2.0 — une communauté de confiance délivre des certificats X.509 à ses membres, et un membre s'authentifie en signant des JWT avec la clé privée et en attachant la chaîne de certificats.
La couche de sécurité est vérifiée contre une implémentation de quelqu'un d'autre, qui est la seule vérification qui vaille la peine ici. Un enregistrement signé par cette version a été envoyé à un serveur de référence tiers en direct et refusé avec unapproved_software_statement — Untrusted: Certificate is not a member of community. Pour produire cette réponse, le serveur a décodé la requête, analysé l'énoncé de logiciel en tant que JWT, vérifié sa signature, parcouru la chaîne de certificats et pris une décision sur l'appartenance. C'est la différence entre être rejeté à la porte et se voir renvoyer une lettre illisible.
Ce qui reste ne peut pas être fait à partir d'ici. Le certificat qui prouve l'appartenance à la communauté sort de l'intégration QHIN et n'est pas quelque chose que le logiciel produit. Jusqu'à ce qu'il en existe un, aucun échange avec un partenaire réel ne se termine.
Comment une chaîne demande. Une destination de type tefca demande au partenaire FHIR facilité dans les Paramètres, TEFCA (tefca.partnerFHIRBase) pour chaque message du patient : par identifiant lorsque le message en a un (PID-3, ou un identifiant de patient FHIR), sinon par nom de famille avec la date de naissance, et jamais par un nom seul, car une correspondance incorrecte sur un nom renvoie le dossier de quelqu'un d'autre sans erreur. La destination définit l'objectif d'utilisation (traitement, paiement, opérations, santé publique, accès individuel) ; un objectif que le participant ne déclare pas est refusé avant que quoi que ce soit ne soit envoyé. Les objectifs sont transmis sous la forme des codes d'échange TEFCA (T-TRTMNT, T-PYMNT, T-HCO, T-PH, T-IAS, système urn:oid:2.16.840.1.113883.3.7204.1.5.2.1), ou avec tefca.purposeCodes: hl7 comme codes d'utilisation HL7 pour les communautés qui les utilisent. Le Bundle trouvé est la réponse de la destination et peut être transmis à une autre chaîne avec results_to. Chaque requête, y compris celles refusées, est dans la traçabilité sur cet écran, qui nomme le partenaire.
L'ensemble du chemin, de la découverte à un jeton que le serveur FHIR du partenaire accepte, est testé contre le serveur de référence udap-dotnet (voir vérification).
L'échange QHIN-à-QHIN plus ancien basé sur les profils IHE n'est pas implémenté. Une tentative est refusée avec une erreur indiquant cela, et le refus est audité comme une défaillance. C'est délibéré plutôt que en attente d'un nettoyage : un échange tronqué signalant une réussite mettrait des entrées dans le journal d'audit pour des échanges qui n'ont jamais eu lieu, et un journal qui ne correspond pas à ce qui s'est passé est pire que rien, car c'est le journal qui est cru.
Tout au long, les points de terminaison utilisés pour l'échange proviennent de la partie signée des métadonnées d'un partenaire, et non du corps du document. Vérifier une signature, puis lire les points de terminaison à partir de la copie non signée serait une façon élaborée de faire confiance au réseau : un attaquant capable de réécrire la réponse laisse l'élément signé seul, pointe le point de terminaison du jeton vers son propre serveur et collecte les assertions clientes de tous ceux qui ont vérifié la signature, puis ignoré ce qu'elle couvrait.
Un bundle de référence d'ancrage est requis et son absence est refusée au démarrage. La vérification des métadonnées signées d'un partenaire contre le certificat qui se trouve à l'intérieur prouve seulement qu'une partie a créé les deux — une erreur que cette base de code a commise auparavant, dans SAML, où le vérificateur a préféré le certificat intégré et a authentifié un attaquant en tant qu'administrateur alors que tous les tests ont abouti. Incluez les intermédiaires dans le bundle : un serveur UDAP n'a besoin de transmettre que son certificat feuillet, et le serveur de référence public le fait exactement.
3.5 Payeurs — réclamations, autorisations préalables, médicaments et règles de payeur CMS
3.5.1 Réclamations et authentification
Construisez un fichier X12 275 de pièce jointe de réclamation dans le formulaire 006020 adopté par le CMS-0053-F, à partir d'un C-CDA collé ou d'un PDF, TIFF ou JPEG téléchargé, et voyez-le lu à rebours. Lisez un 275 et téléchargez le document à l'intérieur. Convertissez une décision X12 278 en une réponse de réclamation Da Vinci PAS ClaimResponse. Rien sur cette page n'est stocké ou envoyé. Voir formats de message pour savoir à partir de quoi le 275 est construit et ce qu'il ne fait pas.
3.5.2 Médicaments
La formule de formule médicamenteuse chargée avec -formulary, et les deux normes NCPDP répondues à partir de celle-ci. Formule répertorie les plans et les médicaments avec leur niveau et leurs exigences, et où se trouvent l'API publique Da Vinci US Drug Formulary et les points de terminaison NCPDP. Vérification de prix (RTPB) prix un médicament pour un membre comme une demande de bénéfice de prescription en temps réel d'un prescripteur : le statut de couverture, les restrictions en mots avec leurs codes, la part du membre et celle du plan, et les alternatives moins chères. Autorisation préalable (ePA) envoie une initiation de SCRIPT à la propre terminaison de ce serveur, affiche l'ensemble de questions sous forme de formulaire, envoie les réponses et affiche la décision ; ci-dessous, chaque cas avec son état et si le prescripteur a été informé, les réponses du cas, un bouton pour renvoyer une décision non envoyée, et les chiffres de médicament que CMS-0062-P propose. Voir CMS-0057.
3.5.3 CMS-0057
Le côté payeur de la règle d'interopérabilité et d'autorisation préalable de CMS, sous forme de cinq outils :
- Les quatre API : si Patient Access, Provider Access, Payer-to-Payer et Prior Authorization sont prêts sur cette instance,
et ce dont chaque API a encore besoin.
- File d'attente de l'examinateur : les demandes PAS en attente d'un examinateur, classées par date d'échéance, avec les documents joints pour chaque demande ; approuver, refuser ou certifier un nombre réduit d'unités. Voir la file d'attente de l'examinateur.
- Réclamations vers CARIN BB : une réclamation 837 et sa réponse 835 converties en bundles CARIN Blue Button.
- Autorisation préalable vers PDex : une réponse PAS convertie en autorisation préalable PDex.
- Métriques d'autorisation préalable : la page de métriques d'autorisation préalable publique annuelle, prévisualisée à partir d'un fichier CSV de décisions.
Les conversions ne stockent rien et n'envoient rien.
3.5.4 Réseau aligné CMS
Préparation pour le cadre d'interopérabilité du CMS : chaque critère, regroupé comme le fait le CMS, avec ce que Perfuse fournit, si cela est activé ici, le paramètre qui l'active et ce que l'organisation doit faire. Les comptes en haut filtrent la liste. Voir CMS-0057.
3.6 Administrer — qui peut faire quoi, et comment ce serveur est configuré
3.6.1 Utilisateurs
Comptes, rôles (surveillant, observateur, opérateur, éditeur, administrateur) et groupes de canaux. Les groupes de canaux de chaque personne sont édités sur place dans la liste ; vide signifie tous les canaux, et lab=editor, adt donne un rôle différent dans un groupe. Un administrateur limité à certains groupes ne voit que les personnes de ces groupes. L'en-tête affiche vos propres groupes à côté de votre rôle lorsque vous en avez. Voir sécurité.
Les informations d'identification de la machine se trouvent également ici. Un jeton est pour une machine plutôt que pour une personne : il n'expire pas et n'est pas affecté par la déconnexion de quelqu'un, ce dont a besoin un serveur qui interroge son voisin. Seul un hachage est stocké, donc un jeton est affiché une seule fois lorsqu'il est créé et ne peut pas être récupéré — une base de données volée ne donne aucun jeton utilisable. Accordez-lui le rôle le plus bas qui fait le travail.
Avec MCP activé, la section affiche également l'adresse à laquelle un agent IA se connecte, une configuration client à copier et chaque outil avec le rôle dont il a besoin ; la délivrance d'un jeton avec Laisser un agent IA agir avec celui-ci lui donne la portée mcp:write. Voir sécurité.
3.6.2 Locataires
Sur un serveur partagé, la liste des organisations de l'opérateur de plate-forme : pour chacune, le nombre de canaux et la taille stockée à côté de ses limites (canaux, messages par minute, stockage), qui sont définies sur place. Affiché uniquement au rôle de plate-forme. Voir sécurité pour savoir ce que fait chaque limite.
3.6.3 Certificats
Les certificats TLS en cours d'utilisation et leur date d'expiration. Les dates d'expiration sont le point : un certificat qui a expiré un dimanche est une classe de défaillance qui est entièrement évitable et qui n'est généralement pas prévenue.
3.6.4 Activité
Qui a modifié quoi, et quand. Chaque modification de configuration est enregistrée, ce qui permet de répondre à « cela a commencé à échouer mardi ».
3.6.5 Protection des données
Les demandes d'une personne en vertu du GDPR et du GDPR du Royaume-Uni, les retenues légales, le registre d'effacement, la rétention et l'enregistrement des activités de traitement ; seuls les administrateurs. Voir protection des données.
3.6.6 Flotte
Chaque instance de Perfuse sur une page.
Mirth vend ce produit séparément ; ici, il s'agit d'un fichier de configuration et d'un jeton en lecture seule. La raison pour laquelle il vaut la peine de l'avoir est étroite et importante : un serveur mort ne ressemble pas à un serveur silencieux. Le tableau de bord d'une instance unique ne peut pas vous indiquer qu'un deuxième site a cessé de signaler, et une vue de flotte ne peut pas non plus.
3.6.7 Migrer
Insérez une exportation de canal Mirth ou OIE et voyez combien de vos canaux fonctionneraient ici sans modification. La même analyse que perfuse explain et perfuse translate, sans avoir besoin d'un terminal. Voir migration.
3.6.8 Paramètres
Chaque paramètre du serveur, avec un contrôle pour chacun — y compris ceux qui vivraient traditionnellement uniquement dans un fichier. Chacun indique s'il prend effet immédiatement ou nécessite un redémarrage, et s'il a été défini explicitement ou s'il est à sa valeur par défaut.
Les paramètres couvrent chaque option perfuse serve qui active une fonctionnalité : le point de terminaison FHIR et sa version, les API de payeur, PAS et les règles CRD, le pont X12 278, eCR, le serveur d'autorisation SMART, TLS et signature, métriques, flotte et VPN. Ils sont regroupés comme FHIR, payeurs, santé publique, SMART, sécurité, etc. Chacun est également affiché avec le flag correspondant.
Redémarrage à partir de la console. Un paramètre marqué *Nécessite un redémarrage* est enregistré immédiatement mais lu uniquement lorsque le serveur démarre. Tant qu'il y en a en attente, une bannière en haut des paramètres les liste avec un bouton Redémarrer le serveur (l'éditeur de connexion et les fichiers de paramètres offrent le même bouton après une sauvegarde). Il demande confirmation, car chaque canal s'arrête pendant quelques secondes : chaque canal termine le message qu'il traite, comme il le fait lorsque le service est arrêté, et les expéditeurs renvoient tout ce qui arrive entre-temps. La console attend ensuite que le serveur réponde à nouveau et lit les paramètres à nouveau. Seul un administrateur peut redémarrer, et chaque redémarrage est enregistré dans le journal d'activité sous la forme server.restart.
Sous Linux et macOS, le processus se remplace par une copie fraîche du même programme et des mêmes arguments, en conservant son identifiant de processus, de sorte que systemd, launchd ou un runtime de conteneur ne remarque rien. Sous Windows, le serveur redémarre à l'intérieur du même processus, qui conserve un service Windows sous le gestionnaire de services. Si le serveur n'a pas répondu après deux minutes, la console le signale ; la raison se trouve dans le journal du serveur.
Flags et fichier de paramètres. La première fois que le serveur démarre, les flags qu'il a reçus sont écrits dans le fichier de paramètres. À partir de ce moment, le fichier l'emporte sur les flags, donc la modification d'un paramètre se fait dans la console (ou le fichier), et non en éditant la ligne de commande du service. Un flag que le fichier ne mentionne pas encore est enregistré lorsque le serveur démarre avec lui. La suppression d'un flag de la ligne de commande plus tard ne désactive pas sa fonctionnalité : la désactiver dans les paramètres.
SNMP a un panneau ci-dessous les paramètres : si l'agent répond et à quelle adresse, les réseaux auxquels il répond, combien de pièges d'alerte ont été envoyés ou ont échoué, et Télécharger le MIB pour l'OID de base en cours d'utilisation. Les valeurs sont définies sous Monitoring, SNMP.
Personnalisation est également ici : un site peut définir le nom du produit, une phrase d'accroche, une couleur d'accent, et télécharger un logo. Le logo apparaît ensuite dans l'en-tête, sur la page de connexion, sur le tableau de bord et sur les écrans de rapport. Si aucun logo n'est téléchargé, rien ne est substitué — une installation non personnalisée reste non personnalisée plutôt que d'acquérir une décoration.
3.7 Ce que les couleurs signifient
Quatre registres, et chacun dit quelque chose de différent. La distinction vaut la peine d'être mentionnée car c'est la différence entre un écran que l'on peut lire d'un seul coup d'œil et un écran où tout se dispute l'attention.
Texte brut est un fait sur la façon dont Perfuse fonctionne. La plupart de l'interface. Rien n'est coloré pour vous dire qu'il est important.
Vert signifie que quelque chose a réussi à l'instant, à cause de quelque chose que vous avez fait. Il apparaît après une action et ne persiste pas.
Amber est une mise en garde : cela vaut la peine de le savoir avant d'agir, et ce n'est pas une erreur. Une fonctionnalité qui n'est pas activée, un paramètre dont les modifications sont auditées, une conversion qui approxime plutôt que reproduit, un transport que Perfuse gère mais ne peut pas vérifier entièrement. Amber est la couleur de "lisez ceci avant de continuer".
Rouge signifie que quelque chose ne va pas à l'instant. Une valeur qui a été rejetée, une demande qui a échoué, un certificat qui a expiré, une alerte critique qui se déclenche. Rien d'autre n'utilise cela.
C'est pourquoi un écran ne s'ouvre pas en rouge. Le rouge est la seule couleur qui porte une instruction — arrêtez, et cela peut être quelque chose que vous avez fait — et un écran qui le dépense en décoration n'a plus rien à dire lorsque la saisie est vraiment incorrecte. Ce n'était pas toujours vrai : l'écran des utilisateurs ouvrait autrefois avec "le serveur a envoyé une réponse qui ne pouvait pas être lue" sur chaque installation qui n'avait pas configuré les passkeys, et l'écran des paramètres marquait les valeurs auditées de la même couleur qu'une valeur rejetée. Un test dans web/src/RedMeansWrong.test.ts échoue maintenant si une phrase décrivant quelque chose d'absent ou d'approximatif est donnée un style rouge.
À l'intérieur d'une boîte de code, le vocabulaire est différent. Là, le rouge est un type de jeton — un nom de segment HL7, un élément XML — et ne porte aucun jugement du tout.
4 Canal
Un canal est un flux de messages : quelque part d'où ils proviennent, des changements optionnels et un ou plusieurs endroits où ils vont. C'est l'unité de configuration, l'unité de surveillance et l'unité de déploiement. Tout le reste dans Perfuse existe pour servir les canaux.
4.1 Anatomie
Un fichier de canal comporte ces parties, dans l'ordre où elles prennent effet :
| Partie | Clé | Requis | Fonction |
|---|---|---|---|
| Identité | name | oui | Nomme le canal. Doit être unique. |
| Type de données | dataType | non | Comment analyser les messages. Par défaut, HL7 v2. |
| Source | source | oui | D'où proviennent les messages. Exactement un. |
| Filtre | filter | non | Décide quels messages accepter. |
| Transformations | transformations | non | Changements ordonnés du message. |
| Destinations | destinations | oui | Où vont les messages. Un ou plusieurs. |
Plus plusieurs qui s'appliquent à l'ensemble du canal : scripts, shadow, contract, tables, attachments, group et enabled. Chacun est dans la référence de canal.
4.2 Une source, plusieurs destinations
Cette asymétrie est délibérée et il est utile de la comprendre tôt, car c'est la source de confusion la plus courante lorsqu'on vient d'un autre moteur.
Un canal a exactement une source. Si les messages proviennent de deux endroits, ce sont deux canaux. Essayer de l'exprimer en un canal produit une configuration où une défaillance dans l'un ou l'autre transport ressemble à la même chose de l'extérieur, et où le trafic des deux flux est mélangé dans les statistiques — donc une chute dans l'un est cachée par l'autre.
Un canal a un nombre quelconque de destinations, et elles sont indépendantes. Une défaillance n'arrête pas les autres, et chacune a sa propre file d'attente, sa propre politique de réessai et son propre enregistrement de livraison. Un message qui a atteint trois des quatre destinations est enregistré comme exactement cela, et non comme un succès ou une défaillance.
4.3 Les destinations ne forment pas une chaîne
Chaque destination reçoit le message tel qu'il était après les transformations du canal. Une destination ne reçoit pas la sortie de la destination précédente.
Cela compte lorsqu'une destination a ses propres transformations, ce qui peut arriver. Celles-ci s'appliquent uniquement à la copie de cette destination. Une erreur courante consiste à placer un changement sur la première destination et à s'attendre à ce que la seconde le voie.
Si vous avez réellement besoin d'une chaîne — la sortie d'un flux alimentant un autre — utilisez une destination de canal, qui envoie à un autre canal par nom. C'est explicite, apparaît dans l'historique du message comme deux canaux, et peut être surveillé comme deux choses, ce que une chaîne cachée ne peut pas.
4.4 Nommage
Le nom est l'identité du canal partout : dans le fichier, dans le magasin de messages, dans les alertes, dans le journal d'audit et dans l'URL. Le changer n'est pas un renommage ; c'est un nouveau canal, et l'historique de l'ancien reste sous l'ancien nom.
group est séparé et existe pour organiser l'interface. Un groupe n'a aucun effet sur le comportement, et regrouper les canaux ne les fait pas partager quoi que ce soit.
adt-inbound.4.5 Activation et désactivation
enabled: false arrête un canal de démarrer sans le supprimer. Sa configuration, son historique et ses statistiques restent.
Un canal désactivé n'est pas un canal en pause. Sa source n'est pas à l'écoute, donc un expéditeur qui tente de se connecter obtient une connexion refusée plutôt qu'une connexion bloquée. Pour MLLP, c'est le comportement correct — l'expéditeur mettra en file d'attente et réessayera — mais cela signifie que le journal d'erreurs de l'expéditeur se remplira, donc un canal désactivé n'est pas un substitut pour organiser une interruption avec l'expéditeur.
4.6 Où vivent les canaux
Un fichier YAML par canal, dans le répertoire donné par -channels. Le nom du fichier n'est pas le nom du canal ; la clé name l'est. Il est fortement conseillé de les garder identiques et rien ne les force.
Les fichiers sont rélus sans redémarrage. Un fichier qui n'analyse pas est signalé et la version précédemment chargée continue à fonctionner, donc une erreur de syntaxe ne peut pas mettre un flux de travail en panne.
4.7 Chiffrer l'écouteur propre d'un canal
Un canal qui écoute sur un port est son propre serveur, et son TLS est séparé du TLS de l'interface web de Perfuse. La configuration de l'un n'affecte pas l'autre. Pour une source HTTP, les paramètres se trouvent sous TLS et limites sur la source.
Activer le TLS demande un certificat et une clé privée. Exiger un certificat client le transforme en TLS mutuel : l'expéditeur doit présenter un certificat signé par une autorité que vous nommez, ce qui constitue une authentification, donc un écouteur avec cela activé n'a pas besoin d'un jeton partagé — bien que avoir les deux ne soit pas incorrect.
L'autorité n'est demandée qu'une fois qu'un certificat client est exigé, et est laissée en dehors du fichier jusqu'alors. Un canal nommant une autorité qui n'est jamais consultée ressemble à un canal qui vérifie les expéditeurs alors qu'il ne le fait pas.
Un écouteur MLLP a les mêmes paramètres sous Chiffrer cet écouteur, avec une différence notable : sur MLLP, un certificat client est la seule authentification disponible. Il n'y a pas de jeton et pas d'en-tête, donc un écouteur sans certificat client accepte les messages de n'importe quel hôte qui peut atteindre le port.
Deux limites se trouvent à côté. Abandonner la lecture après une durée, car un expéditeur qui ouvre une connexion et cesse d'écrire la maintient ouverte. Et plus grand message accepté, en octets, car zéro signifie pas de limite et la limite est alors la mémoire — un expéditeur qui publie un gigaoctet est refusé plutôt que d'être absorbé.
4.8 Validation
Un canal est vérifié lorsqu'il se charge, et les vérifications sont des refus plutôt que des avertissements lorsque l'alternative serait un canal qui fonctionne et fait la mauvaise chose.
Exemples de choses refusées purement et simplement : une destination sans type, une transformation qui s'adresse à un chemin qui ne peut pas exister dans le type de données déclaré, un mode d'accusé de réception que le transport source ne peut pas livrer, et une ordonnance de classe II avec des renouvellements.
La distinction que Perfuse tente de maintenir est que tout ce qui pourrait produire un résultat faux plausible est refusé, et tout ce qui est simplement inhabituel est autorisé et signalé. Un canal qui ne peut pas être faux est plus précieux qu'un canal qui démarre.
5 Flux de messages
Ce chapitre suit un message du moment où il arrive au moment où il est livré ou abandonné. Connaître cet ordre est le moyen le plus rapide de déterminer où une modification appartient et pourquoi quelque chose ne se produit pas.
5.1 L'ordre des événements
- Arrivée. La source accepte les octets. Pour un transport de flux, cela inclut le décodage - trouver où se termine un message et où commence le suivant.
- Analyse. Les octets deviennent un arbre selon le
dataTypedu canal. Un message qui ne peut pas être analysé s'arrête ici et est enregistré comme une erreur d'analyse. - Enregistrement. Le message est écrit dans le magasin de messages tel qu'il a été reçu, avant que quoi que ce soit ne le modifie. C'est ce qui permet la lecture et le retraitement.
- Filtre. Si le canal a un
filter, il décide si le message doit être accepté. Un message rejeté est enregistré comme filtré, ce qui est un résultat normal et non une erreur. - Transformation. Les
transformationsdu canal s'exécutent dans l'ordre, chacune contre le résultat de la dernière. - Distribution. Chaque destination reçoit une copie du message transformé, applique ses propres transformations si elle en a, et livre.
- Enregistrement du résultat. Par destination : livré, en file d'attente, échoué ou filtré.
- Accusé de réception. Si la source attend un accusé de réception, il est généré et envoyé. Par défaut, cela se produit ici, après la livraison - voir ci-dessous.
5.2 Lorsque l'accusé de réception est envoyé
Ceci est le paramètre le plus conséquent dans un canal, car il décide de ce que l'expéditeur est promis. C'est ack.when, et il a deux valeurs.
on_delivery est la valeur par défaut. L'accusé de réception n'est envoyé qu'après que chaque destination activée ait accepté le message. Un accusé de réception positif signifie donc que les données sont réellement arrivées quelque part, ce qui est la promesse la plus forte qu'un moteur intermédiaire peut honnêtement faire.
on_receipt accuse réception dès que le message est analysé et en file d'attente, avant que toute destination n'ait été écrite.
Perfuse utilise par défaut on_delivery car promettre la livraison et puis perdre le message est pire que d'être lent. Sous on_receipt, un message qui a été accusé réception peut toujours être perdu si le processus meurt avec des travaux en file d'attente — l'expéditeur croit qu'il est livré, rien en amont ne le renverra, et le seul enregistrement qu'il a existé est dans le magasin de Perfuse.
5.3 Lorsque choisir à la réception
Le cas de figure est réel, et il s'agit des délais d'attente. Un expéditeur MLLP qui n'obtient pas d'accusé de réception dans quelques secondes va généralement renvoyer, donc une destination lente sous on_delivery produit des doublons plutôt que des retards. Si une destination est un archive lent ou un système qui est régulièrement indisponible, on_delivery couple le délai d'attente de l'expéditeur au pire cas de cette destination.
L'échange est explicite : on_receipt déplace le risque des doublons à la perte. Choisir cela signifie accepter qu'un message accusé réception peut être perdu en cas de panne, et il vaut la peine de le coupler avec une alerte de profondeur de file d'attente pour qu'une file d'attente qui a cessé de se vider soit remarquée. Voir alerting.
5.4 Là où le message est enregistré
Avant le filtre, et donc avant toute transformation. Trois conséquences :
- Un message que le filtre a rejeté est toujours stocké. Vous pouvez voir ce qui est arrivé et confirmer que le filtre était correct.
- La répétition et le retraitement commencent toujours par ce qui est réellement arrivé, et non par une version partiellement transformée.
- Un changement apporté aux transformations peut être testé contre un trafic historique réel, car l'original est toujours là. Voir testing.
La forme transformée est également enregistrée, par destination, aux côtés du résultat. Ainsi, le stock contient ce qui est arrivé, ce qui a été envoyé et ce qui s'est passé — ce dont une enquête a besoin.
5.5 Défaillance à chaque étape
| Étape | À quoi ressemble la défaillance | Ce qui se passe |
|---|---|---|
| Arrivée | Erreur de mise en forme, connexion interrompue en plein message | Enregistré, connexion fermée, l'expéditeur réessaie |
| Analyse | Non valide pour le type déclaré | Enregistré comme une défaillance d'analyse, accusé de réception négatif si la source s'y attend |
| Filtre | Le filtre lui-même génère une erreur | Traité comme un refus, enregistré avec l'erreur |
| Transformation | Une étape échoue | Dépend de l'étape on_error ; voir transformation |
| Livraison | Destination inaccessible ou rejetée | Mis en file d'attente et réessayé selon la politique de destination ; voir livraison |
L'asymétrie importante : une défaillance d'analyse est permanente et une défaillance de livraison ne l'est généralement pas. Réessayer un message non analysable ne servira à rien, il n'est donc pas réessayé. Réessayer une destination inaccessible servira généralement, il est donc réessayé.
5.6 Ordre
Dans une seule destination, les messages sont livrés dans l'ordre où ils sont arrivés, et un message qui échoue et entre dans la file d'attente conserve sa place — les messages suivants attendent derrière lui plutôt que de le dépasser.
C'est la configuration par défaut appropriée pour les données cliniques, où une admission suivie d'une sortie livrée dans le mauvais ordre est pire que les deux étant en retard. Cela signifie également qu'un message corrompu peut bloquer une file d'attente, ce qui est pourquoi la profondeur de la file d'attente vaut la peine d'être signalée.
Entre les destinations, il n'y a pas de garantie d'ordre, car elles sont indépendantes. Deux destinations ne recevront pas nécessairement le même message en même temps, et une destination rapide peut être plusieurs messages en avance sur une destination lente.
5.7 Concurrence
Une source peut gérer plusieurs connexions à la fois, limitées par max_connections. Les messages de différentes connexions sont traités de manière concurrente.
Cela signifie que l'ordre d'arrivée de deux messages envoyés simultanément via deux connexions n'est pas défini et ne peut pas l'être — ils sont réellement arrivés en même temps. Un expéditeur qui a besoin d'un ordre doit utiliser une connexion, ce que font la plupart d'entre eux.
6 Transformation
Les transformations modifient un message. Elles sont une liste, elles s'exécutent dans l'ordre, et chaque étape voit le résultat de l'étape précédente.
Les transformations de Perfuse sont déclaratives : chaque étape nomme une opération et le champ auquel elle s'applique. Il n'y a pas de langage de script dans le chemin ordinaire. C'est une limitation délibérée et la raison est dans why not a script ci-dessous.
6.1 Les étapes
| Étape | Ce qu'elle fait |
|---|---|
set | Écrit une valeur littérale dans un chemin, en le créant s'il est absent. |
copy | Copie un chemin vers un autre, avec une valeur par défaut optionnelle lorsque la source est absente. |
clear | Vide un champ, en le laissant présent. |
remove | Supprime entièrement un champ. |
map | Recherche la valeur actuelle dans une table et la remplace. |
replace | Substitution par expression régulière dans un champ. |
pad | Remplit une valeur à une largeur fixe. |
date | Convertit une date ou une horodatage entre les formats. |
trim | Supprime les espaces entourants. |
case | Convertit en majuscules ou en minuscules. |
Chaque étape accepte également description, qui apparaît dans la trace et dans l'interface, et when, qui rend l'étape conditionnelle.
Une étape est écrite sous la forme du nom de l'opération avec son propre bloc :
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 et value ne sont pas des frères et sœurs. set prend un bloc contenant path et value. Écrire set: PID-3.4 avec value: à côté est l'erreur la plus courante dans un canal manuscrit et produit une erreur de chargement plutôt qu'une configuration silencieuse incorrecte.6.2 Effacer, supprimer et la différence
clear laisse le champ présent et vide. remove le supprime complètement.
Pour HL7, cette distinction est réelle et elle atteint le récepteur. Un champ vide indique « J'ai ce champ et il n'a pas de valeur ». Un champ absent indique rien du tout. Certains systèmes récepteurs traitent le premier comme une instruction pour effacer leur valeur stockée et le second comme une instruction pour la laisser intacte — ce qui est la différence entre supprimer une allergie enregistrée d'un patient et ne pas la mentionner.
Si vous ne savez pas lequel le récepteur veut, demandez. Deviner a cinquante pour cent de chances de détruire silencieusement des données de l'autre côté.
6.3 Conditions
when prend une expression et l'étape s'exécute uniquement si elle est vraie :
- when: MSH-9.2 == "A08"
set:
path: EVN-1
value: A08
Une étape dont la condition est fausse est enregistrée comme ignorée, et cela est signalé séparément d'une étape qui s'est exécutée et n'a rien modifié. Cette distinction est l'objet du débogueur étape par étape et elle est abordée dans débogage : une condition fausse et un champ absent sont identiques de l'extérieur et signifient des choses opposées.
6.4 Chemins
Un chemin s'adresse à un champ : PID-5 est le cinquième champ de PID, PID-5.1 son premier composant, PID-3(2) la deuxième répétition de PID-3 et OBX(3)-5 le cinquième champ du troisième segment OBX.
Deux comportements à connaître :
setcrée le chemin qu'il s'adresse, y compris la structure intermédiaire. C'est pratique, et cela signifie quesetne peut jamais démontrer qu'un champ était absent — après l'étape, il existe. Pour tester ce qui se passe lorsque un champ est manquant, utilisezcopyà partir d'un chemin qui n'est pas là.- Un chemin sans index s'adresse à toute répétition et à chaque occurrence, comme il le fait dans un filtre (où
PID-3.5 == "SS"est vrai lorsque n'importe quelle répétition l'est). Sur un message avec cinq segments OBX,setsurOBX-5modifie les cinq, etsetsurPID-3.4relabelise chaque identifiant dans PID-3, y compris le numéro national. Pour modifier un seul, donnez son index :PID-3(1).4,OBX(2)-5.
6.5 Erreurs
La plupart des étapes n'ont rien qui puisse échouer. Définir une valeur, effacer un champ ou copier à partir d'un chemin absent avec une valeur par défaut sont tous définis pour chaque entrée.
date est l'exception, car une valeur qui n'est pas une date qu'il reconnaît n'a pas de conversion correcte. Il prend on_error :
fail— la valeur par défaut. Le message s'arrête et est enregistré comme une erreur de transformation.keep— laisse la valeur d'origine inchangée.clear— vide le champ.
La valeur par défaut est fail car un horodatage qui ne se convertit pas silencieusement est pire qu'un message qui n'est pas arrivé. Une date dans un format incorrect ressemble encore à une date, elle passe donc la validation du destinataire et atterrit dans l'enregistrement comme le mauvais jour.
keep est légitime lorsque le destinataire tolère les deux formats, et lorsqu'il est utilisé, la trace marque le changement comme délibéré afin qu'il ne soit pas lu comme une étape qui a échoué silencieusement.
6.6 L'ordre est important, et la trace le montre
Chaque étape voit la sortie de l'étape précédente. Deux conséquences qui prennent les gens :
- Un
mapaprès uncasevoit la valeur convertie par le cas, ses clés de tableau doivent donc correspondre à la forme convertie. Un tableau deM/Faprès une étape en minuscules ne correspond à rien, silencieusement, car une valeur qui n'est pas dans le tableau est laissée inchangée. - Un
copyà partir d'un champ que une étape ultérieure supprime fonctionne toujours, car il s'est exécuté en premier. L'inverse n'est pas vrai.
Les deux sont visibles dans la vue étape par étape, qui affiche l'ensemble du message après chaque étape plutôt que seulement le changement. Voir débogage.
6.7 Suggérer des mappages et ce qu'en faire
Le mappeur IA propose des mappages entre un ensemble de champs source et un ensemble de cibles. Son comportement définissant est qu'il décline : en dessous de son seuil de confiance, il s'abstient plutôt que de deviner, car un mappage erroné confiant dans un système clinique est pire qu'aucun mappage du tout.
6.7.1 Donnez-lui quelque chose dont il puisse être sûr
Un nom seul est une preuve faible, même lorsqu'il correspond exactement. PatientMRN contre PatientMRN obtient un score de 68, ce qui s'abstient au seuil par défaut de 70.
The engine knows what an HL7 path means — it will tell you PID-7 is Date/Time of Birth and score your field name against that rather than against the string PID-7, which shares no characters with anything. A locally defined Z segment means whatever your site decided, so nothing is claimed about it.
Cela obtient un mappage la plupart du chemin. Pour le terminer, fournissez les deux moitiés :
- Valeurs d'exemple pour un champ source, après un signe égal :
ZPI-1 = MRN00412, MRN00998 - Le type de valeur qu'une cible contient, de la même manière :
PID-3.1 = mrn. Les types sontmrn,npi,ssn,phone,dateetemail.
Avec ceux-ci, le moteur peut voir que les valeurs correspondent au type de la cible, et une suggestion repose sur plus qu'un nom.
6.7.2 L'approbation se fait une correspondance à la fois
Chaque suggestion a sa propre case d'approbation. Il n'y a pas de « accepter tout ce qui est supérieur à 80 % », délibérément : le moteur a déjà utilisé la confiance pour décider s'il propose la correspondance, et ce qui reste est un jugement sur ce champ dans cet flux. Un nombre n'est pas ce jugement.
Un abstention ne peut pas être approuvée du tout. Il n'a pas de case, pas même une case désactivée, et l'écran indique que le moteur ne connaît pas. Si vous connaissez la réponse, cartographiez-la manuellement — c'est un acte différent de celui de convenir d'une suggestion.
Une suggestion en dessous de votre seuil est affichée sans case non plus, marquée comme étant en dessous. Valeur de lecture — un quasi-échec est souvent la cartographie que vous vouliez, et la cacher vous laisserait vous demander si le moteur l'a considérée — mais non approuvable, car votre seuil est la ligne que vous avez tracée.
6.7.3 Deux choses à faire avec ce que vous avez approuvé
Ajouter à un canal transforme chaque correspondance en une étape de copie. Cela ne fonctionne que lorsque la source est un chemin dans le message, comme ZPI-1, car une étape copie d'un endroit dans un message à un autre. Les étapes vont dans le fichier de canal et prennent effet lors de la prochaine charge — rien ne change dans le trafic jusqu'alors. La description de chaque étape enregistre la confiance avec laquelle elle a été suggérée et qu'une personne l'a approuvée, ce qui la rend comptable six mois plus tard.
Télécharger sous forme de recette est la bonne réponse pour le cas le plus courant : une correspondance à partir d'un nom de colonne, d'une clé JSON ou d'un nom de champ propre à un fournisseur. Ce sont de véritables correspondances, et un canal ne peut pas lire directement un tel champ, donc une étape ne peut pas l'exprimer. La recette les enregistre comme approuvées et peut être partagée.
6.8 Pourquoi pas un script
Mirth place un transformateur JavaScript au centre de chaque canal, et c'est la conception la plus flexible disponible. Perfuse propose la scripting — voir la clé scripts dans la référence de canal — mais ne la rend pas le chemin ordinaire, pour trois raisons qui proviennent de ce qui va mal dans la pratique.
Une étape déclarative peut être inspectée. Perfuse peut vous dire qu'une étape lit PID-5 et écrit PID-8, avant de l'exécuter, et peut donc afficher une trace au niveau du champ, avertir qu'une étape s'adresse à un chemin que le type de données déclaré ne peut pas contenir, et générer une répétition par étape. Aucun de cela n'est possible pour un code arbitraire.
Une étape déclarative peut être raisonnée par l'interface. Le constructeur peut proposer les champs qui existent dans le trafic de ce canal, et un changement dans une étape peut être vérifié contre des messages historiques réels avant d'être enregistré.
Et une étape déclarative ne peut pas faire quelque chose de non lié au message. Un script peut appeler le réseau, lire le système de fichiers ou dépendre de l'heure de la journée. Lorsqu'un canal qui a fonctionné pendant deux ans commence à produire une sortie incorrecte, la cause étant en dehors du message est le cas le plus difficile à diagnostiquer, et supprimer la possibilité en vaut plus que la flexibilité qu'il coûte.
Lorsqu'une transformation réelle ne peut pas être exprimée de manière déclarative, utilisez un script et acceptez que la trace la montre comme une étape opaque.
6.9 Ce qu'un script est autorisé à faire
Un script est refusé tout ce qui est en dehors du message, sauf si cela lui est accordé, et les autorisations se trouvent dans la section Scripts du constructeur. C'est délibérément différent de Mirth, qui donne à chaque script toutes les autorisations — donc, là-bas, un transformateur peut commencer à lire le système de fichiers après une copie-coller.
Il y en a trois.
Lire et écrire des fichiers nécessite de nommer les répertoires qu'il peut utiliser, et un canal qui accorde l'accès aux fichiers sans répertoires est refusé lors du chargement. Cette exigence est la seule différence entre l'accès aux fichiers et l'accès aux fichiers non restreint : accorder cela sans répertoires une fois a atteint l'ensemble du système de fichiers, y compris la base de données de Perfuse, qui contient des hachages de mots de passe, le mot de passe du compte de service LDAP et le secret client OIDC. La création d'un canal nécessite uniquement le rôle d'éditeur, donc l'escalade s'est terminée le moment où un administrateur a démarré le canal.
Requêter une base de données utilise les connexions configurées sur le canal. Un script avec cela peut lire tout ce que ces informations d'identification peuvent.
Acheminer des messages vers d'autres canaux permet à un script d'envoyer un message dans un autre canal, ce qui est la façon dont une boucle entre deux canaux devient possible.
Accorder une capacité à un canal sans script ne fait rien, et le fichier généré omet le bloc entier dans ce cas.
6.10 Gérer une date qui ne correspond pas à son format
Une étape de date convertit d'un format à un autre, et la question intéressante est ce qui se passe lorsqu'une valeur ne correspond pas au format qu'elle prétend être.
La valeur par défaut est de stopper le message, et c'est la bonne valeur par défaut : un horodatage qui se convertit silencieusement n'est pas accepté en aval et est ensuite mal lu, ce qui est pire qu'un message qui a échoué bruyamment et se trouve là où quelqu'un peut le voir.
Laisser la valeur telle quelle la transmet dans son format d'origine. En aval, on voit alors deux formats dans un même champ, ce qui est la défaillance que l'étape existait pour prévenir — mais c'est le bon choix lorsque le champ est facultatif et qu'un partenaire l'envoie de manière incohérente.
Vider le champ est honnête et meilleur qu'un format incorrect, mais un récepteur qui nécessite le champ rejette alors le message à la place.
6.11 Les langages de script
Trois sont acceptés, et le choix dépend principalement de savoir si vous migrez. La valeur est placée dans la clé language d'un script :
| Valeur | Ce que c'est |
|---|---|
javascript | La valeur par défaut. Un script non marqué est JavaScript. |
lua | Le meilleur choix lorsque personne ne migre. |
wasm | Les octets d'un module WebAssembly compilé, et non le code source. |
JavaScript est la valeur par défaut, et un script non marqué est traité comme JavaScript. Il est présent ici pour des raisons de compatibilité plutôt que par préférence : les scripts Mirth sont en JavaScript et un site qui migre a des milliers de lignes de code. Cela inclut le support de E4X, une extension obsolète du langage que les scripts Mirth utilisent pour XML et qui doit être traduite avant que quoi que ce soit ne puisse être analysé.
Lua (lua) est le meilleur choix pour ceux qui ne migrent pas. Un temps d'exécution plus petit, pas de chaîne de prototypes à mal utiliser, et des tables indexées par entier qui correspondent plus naturellement à l'adressage des segments et des champs que les tables JavaScript. Sa bibliothèque standard est suffisamment petite pour être énumérée, ce qui est ce qui rend son bac à sable plus facile à utiliser avec confiance.
WebAssembly (wasm) n'est pas un langage, mais un module compilé, et le champ veut les octets d'un fichier .wasm plutôt que le code source. Utilisez-le lorsque la transformation existe déjà dans un langage compilé, ou lorsque cela est suffisamment lourd pour que le coût d'exécution soit important.
Son contrat est délibérément le plus simple disponible : un module lit le message sur l'entrée standard et écrit son résultat sur la sortie standard. Octets en entrée, octets en sortie — ce que chaque chaîne d'outils fait déjà, et ce que quelqu'un qui teste un module sur sa ligne de commande a déjà.
Tout ce qu'un module écrit sur la sortie d'erreur devient des lignes de journal, il peut donc s'expliquer de la même manière qu'un script appelant logger.
true ou false sur la sortie standard. Confondre les deux rendrait un module en panne indiscernable d'un module qui rejette intentionnellement le trafic.6.11.1 Ce que signifie la sortie
Les règles sont les mêmes pour les trois langages plutôt que de nouvelles règles par runtime, donc le comportement observable d'un script — ce qu'il peut voir, ce qu'il peut faire, combien de temps il peut prendre, ce qu'un verdict de filtre signifie — est défini une seule fois.
Pour un transformateur, un préprocesseur ou un écrivain, une sortie vide signifie que le message n'a pas changé. Tomber en fin de script laisse le message seul ; traiter aucune sortie comme « le message est maintenant vide » jetterait du trafic pour une question de technique.
Les modules WebAssembly sont compilés lorsque le canal se charge, et non au premier message. La compilation n'est pas gratuite — un module construit à partir d'un langage qui apporte son propre runtime peut prendre des centaines de millisecondes — et payer cela au moment du chargement signifie que le premier message qui passe par un canal n'est pas mystérieusement plus lent que le reste.
6.12 Tables de mappage partagées
L'autre moitié du même problème : les codes de sexe et les classes de patients d'un site sont traduits de manière identique dans chaque canal qui les touche, et une table à l'intérieur d'un canal est une table que seul ce canal peut utiliser.
# 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 provenance est le point clé. La plupart de ce qui rend une interface difficile à maintenir est que personne ne sait *pourquoi* une correspondance est telle qu'elle est, et la personne qui le savait est partie. Une correspondance avec une raison peut être discutée ; une sans raison devient quelque chose que personne n'ose modifier et que personne n'ose supprimer.
Les tables sont créées et modifiées sur Build → Tables ainsi que dans le fichier. La sauvegarde d'une table en vigueur redémarre les canaux en cours d'exécution qui chargent son fichier, de sorte que le prochain message l'utilise ; un brouillon ne redémarre rien.
6.12.1 Versions et dates d'effet
Une table peut conserver plusieurs éditions sous un seul nom, chacune avec sa propre version. L'édition qu'un message utilise est choisie lors de l'arrivée du message : parmi les éditions approuvées dont les dates couvrent ce jour (UTC), celle qui a commencé le plus tard. Ainsi, un changement de code convenu pour le premier du mois prochain est saisi maintenant et prend effet automatiquement.
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: [...]
statusestapproved(par défaut),draft(utilisé par rien) ouretired
(conservé pour les archives, utilisé par rien).
- Deux éditions d'un même nom avec la même version, ou deux éditions approuvées
commençant le même jour, sont refusées lors du chargement du fichier.
- L'enregistrement d'une nouvelle version sans date de début alors qu'une autre est approuvée la date
à partir d'aujourd'hui, ce qui remplace celle en vigueur. Celle qui n'avait elle-même commencé que aujourd'hui est retirée, puisque deux éditions commençant le même jour ne laissent aucune règle.
- Les
defaultetstrictpropres à une étape de mapping sont utilisés lorsque l'étape les définit ;
sinon, ceux de la table sont utilisés.
- À l'écran des Tables, Afficher les versions liste chaque édition avec son statut,
qui l'a enregistrée et qui l'a approuvée, et Comparer avec la version en vigueur montre ce qu'une édition ajoute, supprime et modifie.
6.12.2 Fin de la validation
Avec Settings → Data → Mapping tables "Les modifications apportées à une table de mappage nécessitent l'approbation d'une deuxième personne" (data.tableApproval) activé, chaque sauvegarde est un brouillon et la personne qui l'a sauvegardée ne peut pas l'approuver : quelqu'un d'autre le fait, en donnant éventuellement la date à laquelle il entre en vigueur. Une édition approuvée ne peut pas être modifiée sur place ; Nouvelle version à partir de celle-ci la copie dans la prochaine version. L'approbation, la mise à la retraite et la suppression d'un brouillon sont écrites dans le journal d'audit, et l'approbation redémarre les canaux en cours d'exécution qui chargent le fichier.
6.12.3 Valeurs sans table de correspondance
Chaque valeur que l'étape de mappage a recherchée et n'a pas trouvée est comptabilisée, par table, avec les canaux par lesquels elle est passée et lorsqu'elle a été vue pour la première fois et pour la dernière fois. L'écran des Tables les liste, les plus fréquentes en premier. Mapper ouvre la table avec cette valeur déjà ajoutée en tant que ligne ; Rejeter la supprime jusqu'à ce qu'elle soit à nouveau vue. Les valeurs plus longues que 64 caractères ne sont pas enregistrées (ce ne sont pas des codes), et la liste conserve ce qui a été vu dans la période de rétention des messages. La liste est conservée dans terminology.db à côté de la base de données principale.
6.12.4 Systèmes de codes
Les systèmes de codes publiés peuvent être importés à partir de leurs propres fichiers des éditeurs, sous Systèmes de codes sur l'écran des Tables (administrateurs) ou avec POST /api/terminology/import?format=… et le fichier en tant que corps :
| Format | Fichier | Système |
|---|---|---|
loinc | Loinc.csv à partir de la version de la table LOINC | http://loinc.org |
icd10cm | le fichier de commande CMS (icd10cm_order_*.txt) ou le fichier de codes | http://hl7.org/fhir/sid/icd-10-cm |
rxnorm | RXNCONSO.RRF à partir de la version complète de RxNorm | http://www.nlm.nih.gov/research/umls/rxnorm |
snomed | l'instantané de description RF2 (sct2_Description_Snapshot-en_*.txt) | http://snomed.info/sct |
snomed-rf2 | un package de version complète de SNOMED CT RF2 (le zip qu'un centre de publication national publie) | http://snomed.info/sct, version http://snomed.info/sct/{module}/version/{date} |
claml | un fichier ClaML : WHO ICD-10, ICD-10-GM et OPS (BfArM), CIM-10 FR (ATIH) | à partir du titre du fichier, ou du system donné |
icd11 | la tabulation MMS simple de l'OMS ICD-11 (séparée par des onglets, avec des colonnes Code et Title) | http://id.who.int/icd/release/11/mms |
csv | n'importe quel fichier délimité, avec system, codeColumn et displayColumn (CPT, HCPCS, codes locaux, tables nationales) | le system donné |
Aucun n'est livré avec Perfuse : LOINC, SNOMED CT, RxNorm et CPT ont chacun leur propre licence, et l'écran demande à l'importateur de confirmer que l'organisation la détient (enregistrée avec l'importation). Les codes importés sont utilisés de trois manières :
- une table nommant
source_systemoutarget_systema ses entrées vérifiées lors de la sauvegarde, et les codes qui ne sont pas dans le système sont répertoriés dans l'édition ; - Trouver un code recherche par code ou par mots dans le nom ;
- le serveur FHIR répond à
CodeSystem/$lookupetCodeSystem/$validate-codepour eux (voir les options du serveur FHIR). Les codes ICD-10-CM sont acceptés avec ou sans point.
Éditions et classifications nationales. Une édition de SNOMED CT est importée à partir de son package RF2 complet : concepts avec leur statut réel, chaque description active, et les ensembles de référence linguistique. L'édition est trouvée à partir du package (le module national avec le plus de concepts ; edition le nomme à la place) et devient l'URI de version. language choisit le terme préféré de chaque concept (sv, da, nl, de, fr, en-GB, en-US ... ; anglais sinon), et le terme préféré et le nom entièrement spécifié de chaque langue sont conservés en tant que désignations : $lookup les retourne, et son displayLanguage en choisit un (de-CH revient à de). Les éditions que Perfuse nomme (International, Royaume-Uni, Allemagne, Pays-Bas, Suède, Danemark, Belgique, Irlande, Norvège, Suisse, Estonie, Espagne) sont répertoriées par GET /api/terminology/editions, les ID de module non vérifiés contre une source publiée marquée comme telle ; toute autre édition est également importée, nommée par son module.
Les fichiers ClaML sont lus en UTF-8, ISO-8859-1, ISO-8859-15 ou Windows-1252, comme le déclare leur déclaration XML. Le titre de chaque catégorie est son rubrique préférée (termes imbriqués inclus) ; un modificateur (un cinquième caractère pour le site d'une fracture, par exemple) crée les codes qu'il ajoute, avec le titre du modificateur après celui de la catégorie, à moins que la catégorie ne l'exclue ; blocks=true importe également les chapitres et les blocs. Les colonnes de la tabulation ICD-11 sont trouvées par nom, puisque leur ordre a changé entre les versions, et les tirets qui montrent la profondeur sont supprimés des titres. Un fichier délimité prend delimiter (, ; | ou tab), encoding (utf-8, iso-8859-1, iso-8859-15, windows-1252) et noHeader=true, avec des colonnes numérotées à partir de 1. La console propose des paramètres pour les fichiers ICD-10 5e édition du Royaume-Uni et OPCS-4 (TRUD), le tableau de libellés CIM-10 FR de la France (ATIH) et une exportation ICD-10-BE ; leurs éditeurs ne documentent pas tous leurs colonnes, vérifiez-les donc contre l'en-tête du fichier.
Dates d'effet. effective=YYYY-MM-DD importe une version maintenant et l'utilise à partir de cette journée (ICD-10-GM, par exemple, chaque 1er janvier) : jusqu'alors, une recherche qui ne nomme pas de version est répondue par la version déjà en vigueur, et l'écran affiche la date.
ICD-11 de l'OMS. Avec un client enregistré à icd.who.int (Paramètres → Données → Systèmes de codes, serve -icd11-client-id et -icd11-client-secret ; -icd11-release, 2025-01 par défaut), les codes ICD-11 qui ne sont pas importés sont recherchés dans l'API ICD de l'OMS (codeinfo, puis le titre de l'entité) et conservés pendant une journée. Un code postcoordonné (NC72.2&XK9K) est vérifié dans son ensemble, donc une combinaison ICD-11 qui n'est pas autorisée est refusée, et ses noms d'affichage pour chaque partie ("Fracture du col du fémur (droite)").
ICD-11 sans envoyer de codes. L'OMS publie la même API sous forme de conteneur (whoicd/icd-api, gratuit, Intel et Arm). Exécutez-le sur votre propre réseau et fournissez son adresse (serve -icd11-url http://icd-api.local, ou Adresse de l'API ICD dans les mêmes paramètres) ; no client est nécessaire et aucun code ne quitte votre réseau. Testé contre ce conteneur (version 2.6.0, version 2025-01 en anglais et en français).
7 Filtrage
Un filtre décide quels messages un canal accepte. Il s'agit d'une expression sur le canal, évaluée après que le message ait été analysé et enregistré, avant toute transformation.
filter: MSH-9.1 == "ADT" && MSH-9.2 in ("A01", "A03", "A08")
Un message que le filtre rejette est enregistré avec le résultat filtré. C'est un résultat normal, pas une erreur, et il ne déclenche pas d'alerte ni de notification négative.
7.1 Filtré n'est pas échoué
Cette distinction est importante à établir car la confusion entre les deux peut cacher un véritable problème.
Un message filtré a été correctement rejeté : il n'était pas destiné à ce canal. Un message échoué est un message que ce canal aurait dû gérer et n'a pas pu. Si les deux étaient enregistrés de la même manière, un canal qui commence à échouer sur chaque message ressemblerait exactement à un canal qui filtre la plupart de ses messages, ce qui est l'état normal de nombreux canaux.
Ainsi, les statistiques les comptent séparément, les règles d'alerte les traitent différemment et l'interface les affiche en couleurs différentes. Une augmentation des messages filtrés peut signifier que l'expéditeur a commencé à envoyer quelque chose de nouveau ; une augmentation des échecs signifie que quelque chose est cassé.
7.2 Ce que peut lire un filtre
N'importe quel champ du message analysé, via les mêmes chemins que les transformations utilisent. Le filtre s'exécute avant les transformations, il voit donc le message tel qu'il est arrivé — et non tel qu'il sera envoyé.
Cet ordre est délibéré. Un filtre qui lirait les valeurs post-transformation déciderait d'accepter un message en fonction de modifications apportées en supposant qu'il était accepté, ce qui est circulaire et produit des canaux dont le comportement dépend de l'ordre de deux choses qui semblent indépendantes.
7.3 Expressions
Comparaisons : ==, !=, et pour les nombres <, <=, >, >=.
Appartenance : in ("A01", "A03"), ce qui est plus clair qu'une chaîne de || et est la forme que le constructeur produit.
Combinaison : &&, ||, et parenthèses. Négation avec !.
Absence : un chemin qui n'est pas présent se compare de manière non égale à toute valeur, y compris la chaîne vide. Pour tester explicitement l'absence, comparez contre absent. Cela est important car un champ absent et un champ vide sont différents, comme décrit dans transformation, et un filtre qui les traite de la même manière acceptera des messages qu'il était censé exclure.
7.4 Une erreur dans le filtre est un refus
Si le filtre lui-même échoue à évaluer — une expression malformée qui a passé la validation, ou une comparaison qui ne peut pas être effectuée — le message est refusé et l'erreur est enregistrée contre lui.
Refuser plutôt que d'accepter est le choix le plus sûr des deux, mais aucun des deux n'est bon, et le résultat est enregistré de manière distincte d'un refus de filtre ordinaire afin qu'il puisse être signalé. Un filtre qui erre sur chaque message abandonne silencieusement toute la source, et il ne doit pas ressembler à un filtre qui fonctionne.
7.5 Filtrez à la source lorsque vous le pouvez
Un filtre s'exécute après que le message ait traversé le réseau et ait été analysé. Certaines sources peuvent filtrer plus tôt et à moindre coût :
- Une source de courtier prend un
selector, qui filtre au niveau du courtier. Les messages que ce canal ne veut pas ne traversent jamais le réseau du tout. Sur une file d'attente partagée, c'est la différence entre lire cent messages par jour et cent mille. - Une source de base de données décide ce qu'elle retourne avec sa requête.
- Une source de fichier décide quels fichiers elle récupère avec son modèle.
Le filtrage à la source est une décision de performances, et non de correction, et il a un coût : un message filtré au niveau du courtier n'est jamais enregistré par Perfuse, il n'apparaît donc pas dans le magasin de messages et ne peut pas être inspecté plus tard. Si vous devez être en mesure de prouver ce que l'expéditeur a envoyé, filtrez ici plutôt que là.
7.6 Test d'un filtre
Un filtre peut être vérifié contre un trafic historique réel avant d'être enregistré. L'interface rapporte combien des N messages enregistrés les plus récents le filtre accepterait, refuserait et échouerait — ce qui est la façon la plus rapide de découvrir qu'une expression qui semble correcte n'accepte rien.
La trace montre également, par message, quels champs le filtre a lus et quelles valeurs il a trouvées. Un filtre qui rejette tout de manière inattendue lit généralement un chemin qui n'existe pas dans cette source, et la trace le nomme.
8 Formats de message
Le dataType d'un canal décide de la façon dont les octets deviennent un message. Cela affecte l'analyse, ce que les chemins signifient, la façon dont le message est réécrit et quels transformations sont valides.
| Valeur | Format |
|---|---|
hl7 | HL7 v2, la norme délimitée par des pipes. La valeur par défaut. |
hl7v3 | HL7 v3 et les documents CDA, qui sont au format XML. |
x12 | ASC X12, utilisé pour l'éligibilité et les réclamations. |
ncpdp | Norme de télécommunication NCPDP D.0 pour les réclamations de pharmacie. |
script | NCPDP SCRIPT, les prescriptions électroniques. XML. |
dicom | Objets d'imagerie DICOM. |
delimited | CSV et autres textes délimités. |
raw | Aucune analyse. Octets en entrée, octets en sortie. |
8.1 HL7 v2
La valeur par défaut, et celle utilisée par la plupart des exemples de ce manuel. Les segments sont terminés par un retour chariot, les champs par |, les composants par ^, les répétitions par ~.
Deux choses sur le codage sont importantes à connaître car elles provoquent des erreurs silencieuses.
Les délimiteurs ne sont pas fixes. Ils sont déclarés dans MSH-1 et MSH-2 de chaque message, et Perfuse les lit à partir de là plutôt que de supposer des pipes. Un expéditeur qui utilise un séparateur de champ différent analyse correctement.
La conséquence est qu'un message dont les séparateurs ont été remplacés — le plus souvent par un processeur de texte ou un client de messagerie qui substitue des caractères de séparation typographiques — analyse parfaitement en champs qui sont tous incorrects. Rien ne génère d'erreur. C'est pourquoi le lecteur d'exemple décrit dans testing signale quel caractère de séparateur il a trouvé et refuse de exprimer une confiance lorsqu'il est inhabituel.
8.2 HL7 v3 et CDA
XML plutôt que délimité. Les chemins sont des chemins d'éléments et d'attributs plutôt que des positions de champ.
Dans v3, une valeur est presque toujours un attribut plutôt que du texte d'élément. Une comparaison qui ne lit que le texte d'élément signalera que deux documents sont identiques lorsque la date de naissance, le sexe et chaque identifiant diffèrent. La comparaison de Perfuse lit les deux, et c'est pourquoi : l'alternative réussit silencieusement.
Les options hl7v3 sont dans la référence de format.
8.3 X12
Les segments sont terminés par ~ par convention, avec des délimiteurs déclarés dans le segment ISA. Comme HL7, ils sont lus à partir du message plutôt que supposés.
La structure de X12 est des enveloppes dans des enveloppes — échange, groupe fonctionnel, ensemble de transactions — et un seul échange peut contenir de nombreuses transactions.
Par défaut, un échange est un message. Tout le fichier obtient un enregistrement, un résultat et une ligne dans l'interface, quel que soit le nombre de transactions qu'il contient.
8.3.1 Le X12 XML de Mirth
Mirth Connect et Open Integration Engine affichent le X12 sous forme de XML : une racine X12Transaction (ou EDIMessage lorsque l'entrée ne commence pas par ISA) transportant les délimiteurs sous forme d'attributs, et un élément par segment et élément nommé ISA.01, NM1.03.1, etc. Les canaux et les récepteurs construits pour Mirth lisent et écrivent cette forme. Perfuse lit et écrit la même chose :
x12: { arrives_as: xml }on an X12 channel takes that XML in and handles it as the X12 it stands for (the builder's It arrives as choice);x12_as: xmlon a destination sends the X12 on as that XML (the builder's Send it as Mirth's X12 XML);perfuse x12 xml [file]andperfuse x12 from-xml [file]convert at the command line.
Le format a été écrit à partir de la sortie observée d'Open Integration Engine 4.6 et du format publié, et est vérifié par rapport à celui-ci : 25 échanges générés et 4 exemples conservés sont sortis octet par octet comme OIE les écrit, et inversement (voir vérification). Un DOCTYPE est refusé, comme dans tous les XML que Perfuse lit.
8.3.2 Division d'un échange
La définition de split rend chaque ensemble de transactions un message en soi, avec son propre enregistrement, ses propres métriques et sa propre ligne. Un opérateur qui recherche une réclamation trouve alors une réclamation plutôt qu'un fichier de quatre cents.
Il est désactivé par défaut car l'activation le multiplie tout en aval — comptes de messages, lignes, seuils d'alerte — et un seuil réglé pour des fichiers qui compte suddenly des réclamations ne signifiera plus ce qu'il signifiait. Cela devrait être une décision prise par quelqu'un plutôt qu'un paramètre par défaut hérité.
split et acknowledge ne peuvent pas être définis en même temps, et un canal avec les deux est refusé lors du chargement. Un accusé de réception est une déclaration sur un échange entier, donc la division enverrait un par ensemble de transactions, et un partenaire qui reçoit plusieurs 999 nommant le même groupe fonctionnel n'a aucun moyen de les concilier.8.3.3 Lorsque les comptes ne correspondent pas
X12 déclare ses propres comptes — combien de segments, combien de transactions — et la clé envelope indique ce qu'il faut faire lorsque ceux-ci ne correspondent pas à ce qui est réellement présent. Ces comptes sont le seul mécanisme que X12 a pour détecter qu'une partie d'un fichier de réclamations est arrivée.
| Valeur | Comportement |
|---|---|
require | Refuser l'échange. La valeur par défaut. |
warn | Le traiter, et enregistrer la faute contre le message. |
ignore | Ne pas vérifier du tout. |
warn existe pour une situation réelle : les logiciels de certains partenaires ont généré des comptes incorrects pendant des années dans des fichiers autrement complets, et un site qui doit traiter ceux-ci a besoin d'un moyen de le dire à haute voix dans la configuration plutôt que de désactiver la validation dans son ensemble.
ignore est nommé pour être inconfortable. La définition de celui-ci jette le seul moyen que X12 vous donne de remarquer un fichier tronqué, et un fichier de réclamations tronqué est indiscernable d'un petit fichier.8.3.4 Les transactions que Perfuse lit comme des données structurées
Tout échange X12 peut être acheminé, filtré et adressé par chemin. Ces transactions sont également analysées en champs nommés, de sorte qu'un canal peut demander ce qu'un payeur a décidé plutôt que de savoir quel élément se trouve à la position quatre.
| Transaction | Ce qu'il transporte |
|---|---|
835 | Avis de règlement : ce qui a été payé, ce qui a été refusé et les raisons d'ajustement. |
275 | Pièces jointes de réclamation : documentation clinique à l'appui d'une réclamation. |
277 | Statut de la réclamation, y compris la demande du payeur de documentation supplémentaire. |
278 | Autorisation préalable : la demande d'examen et la décision du payeur. |
999 | Accusé de réception fonctionnel, que Perfuse génère également. |
271 | Éligibilité : si un patient est couvert, et ses coûts de copaiement, de cotisation, de franchise et de dépenses hors réseau, en dehors du réseau. |
|---|---|
834 | Inscription : membres ajoutés, modifiés et résiliés, avec chaque ligne de couverture et ses dates. |
837 | Réclamations, professionnelles et institutionnelles (lire pour la conversion CARIN de CMS-0057). |
Perfuse construit également les requêtes d'admissibilité 270 et les demandes de statut de réclamation 276, sous Payers → Claims & auth ou via POST /api/x12/eligibility/build et /api/x12/claimstatus/build. Les deux sont les versions HIPAA 5010 (005010X279A1, 005010X212), lues et vérifiées avant d'être affichées, et aucune n'est envoyée à partir de cette page : la livraison d'une de ces requêtes est une tâche de canal, où le partenaire commercial et ses informations d'identification sont.
8.3.5 Éligibilité, et la règle de contenu de données CAQH CORE
Un 271 est une liste de segments EB, chacun représentant un fait unique : une couverture active, ou un co-paiement de 25 $ pour un type de service 30 en réseau, ou 800 $ du déductible individuel restant. Le lecteur les assemble pour obtenir la réponse que souhaite un guichet — « couverture active sous Gold PPO 2000 ; co-paiement en réseau 25 $ ; déductible individuel restant en réseau 800 $ » — et nomme un rejet (un segment AAA) en mots, avec ce que le payeur dit de faire ensuite.
Il vérifie également la réponse par rapport à la règle de contenu des données d'éligibilité et d'avantages de CAQH CORE : pour une demande d'information sur la couverture d'un plan de prestations de santé (type de service 30), une réponse active doit contenir les dates du plan, le nom du plan, la copaiement, la franchise, la participation et la franchise restante, ainsi que les types de services de base (1, 33, 35, 47, 48, 50, 86, 88, 98, AL, MH, UC). Chacun est répertorié comme respecté ou manquant. Il s'agit de l'interprétation de Perfuse de la règle, utile pour « pourquoi ce payeur ne nous indique-t-il jamais la franchise ? » - ce n'est pas une certification CORE, que les fournisseurs de tests autorisés par CAQH effectuent.
8.3.6 Autorisation préalable
Perfuse met en œuvre l'autorisation préalable deux fois, intentionnellement.
Le côté FHIR est ce que CMS-0057-F exige que les payeurs exposent à compter du 1er janvier 2027. Le 278 est ce que les payeurs acceptent aujourd'hui, et la règle ne le remplace pas — Da Vinci PAS est en pratique une mise en correspondance de cette transaction, car un 278 est ce qu'un système de gestion des soins parle. Un moteur qui ne lit que la moitié FHIR peut discuter avec les systèmes qui existeront et non avec ceux qui existent.
Une réponse 278 transporte le numéro d'autorisation, et c'est le champ que toute la transaction existe pour livrer. Sans cela, un service certifié n'est pas facturable : la réclamation est introduite sans numéro d'autorisation et est rejetée pour le manque de celui-ci, ce qui se lit en aval comme un refus clinique.
Un refus et un refus de considérer ne sont pas la même chose
C'est la confusion la plus coûteuse dans la transaction, et Perfuse signale les deux séparément.
| Ce qui est arrivé | Ce que cela signifie | Que faire |
|---|---|---|
HCR avec action A3 | Le payeur a examiné la demande et ne la certifiera pas. | Faire appel, ou modifier le plan de soins. |
Un segment AAA | Le payeur n'a pas examiné la demande — patient non trouvé, demandeur non reconnu, examen non couvert. Rien n'a été décidé. | Corriger la demande et l'envoyer à nouveau. |
Les deux sont lus comme « non approuvés » pour quiconque scanne, et les actions correctes sont opposées. Faire appel de quelque chose que personne n'a décidé ne donne rien ; resoumettre un refus produit le même refus. Le nom de l'issue analysée indique ce qui s'est produit — denied contre not-considered — et AAA04 contient les conseils du payeur sur la récupérabilité de la demande.
La certification partielle est signalée comme partially-certified plutôt que comme approuvée. Il y a un numéro d'autorisation à facturer, il est donc considéré comme approuvé, mais la quantité certifiée n'est pas la quantité demandée — et un cabinet qui réserve six séances contre trois approuvées le découvre à la quatrième réclamation.
Un code d'action que Perfuse ne reconnaît pas est signalé comme unknown, et non comme en attente. En attente se lit comme « attendre », et attendre est la mauvaise action pour la plupart de ce qu'un code non reconnu pourrait être.
Un canal peut acheminer sur la décision directement :
filter: HCR-1 == "A3"
Conversion entre les deux
Perfuse convertit un 278 analysé en une réponse de réclamation Da Vinci PAS ClaimResponse, et signale chaque jugement que la conversion a nécessité plutôt que seulement le résultat. La conversion suit trois règles :
- Aucune décision n'est mise à niveau. La certification partielle reste partielle, et une demande que l'assureur a refusé de prendre en compte ne devient pas un refus. Les deux réductions sont disponibles dans le mappage évident et les deux sont incorrectes dans le sens coûteux.
- Rien n'est inventé pour remplir un champ requis. Un événement certifié sans numéro d'autorisation est signalé comme tel, et non avec un numéro plausible — un numéro fabriqué produit une réclamation qui est refusée plus tard pour une raison que personne ne peut retracer.
- Une décision portée uniquement au niveau de la ligne est utilisée. Un assureur qui répond par service peut laisser l'événement sans décision propre ; la lecture uniquement du niveau de l'événement signalerait cela comme en attente, et une pratique attend une réponse qu'elle a déjà tandis que l'approbation expire. Lorsque les lignes sont en désaccord, la moins favorable l'emporte, car un événement avec une ligne refusée n'est pas une approbation.
La réduction à un vocabulaire à trois états — approuvé, refusé, en attente — est disponible et explicite sur ce qu'elle supprime. La réduction d'un refus de prendre en compte donne « refusé » et indique en mots que l'action correcte est une nouvelle soumission corrigée plutôt qu'un appel.
Vérifié contre PAS 2.2.1, et non seulement contre lui-même
La ClaimResponse est façonnée au profil Da Vinci PAS 2.2.1 et a été vérifiée avec le validateur officiel HL7 chargé du package PAS publié. La première version n'avait été vérifiée que par les propres tests de Perfuse, et le validateur l'a rejetée avec six à huit erreurs par ressource. Chacune d'elles est quelque chose qu'un point de terminaison PAS d'un assureur aurait également rejeté :
| Ce qui n'allait pas | Où PAS le met |
|---|---|
La décision était dans adjudication.category et reason. | L'extension reviewAction, sur une adjudication dont la catégorie est submitted. |
| Le code de motif nommé l'élément X12 1034. | La liste de codes externes X12 886. |
Une demande en attente répondait outcome: queued. | outcome concerne le traitement et PAS n'autorise que complete, error et partial. Une attente est complete, avec action de révision A4. |
processNote.type était un CodeableConcept. | R4 a un code : print. |
patient, created, insurer et request manquaient. | Les quatre sont requis. Ils sont donnés sous forme de références d'identifiant, car la réponse se tient seule plutôt que dans un paquet. |
La sortie corrigée se valide sans erreurs pour une certification, un refus et une attente. Les avertissements qui restent sont le validateur disant qu'il ne peut pas charger les systèmes de codes X12, que X12 licence. Le numéro d'autorisation est transporté dans reviewAction.number, où l'exemple propre du guide le met, et dans preAuthRef lorsque la réponse n'a qu'un seul.
Le validateur ne fait pas partie de make check, car il nécessite Java et un téléchargement du guide et de ses dépendances. Ce qu'il a trouvé est détenu par un test à la place : chaque règle qu'il a appliquée est affirmée, donc un changement qui réintroduit l'une de ces erreurs échoue.
La vue Claims & auth convertit un 278 collé et affiche les décisions, les notes et la ressource.
8.3.7 Les pièces jointes, et pourquoi elles nécessitent un traitement spécial
CMS-0053-F fait du 275 une norme HIPAA pour les pièces jointes de réclamation, avec une conformité requise pour le 26 mai 2028. Il transporte un document — une note opératoire, un rapport d'imagerie, un formulaire scanné — lié à la réclamation qu'il soutient.
Le 277 est l'autre moitié de la même conversation. Un assureur reçoit une réclamation, décide qu'il a besoin de documentation, et envoie un 277 pour la demander ; le fournisseur répond avec un 275.
Un canal peut acheminer sur le code de statut directement, car STC01 est un composite et sa deuxième composante est le statut. Écrit sous forme canonique, car un composant est adressé avec un point et les deux notations ne peuvent pas être mélangées — STC-1.2 est l'élément 1, composant 2 :
filter: STC-1.2 in ("227", "233", "252", "287")
Ce sont les codes qui signifient de manière non ambiguë qu'un document est souhaité. La catégorie de statut dans STC-1.1 n'est pas utilisée seule : R4 signifie une demande de documentation dans certains guides d'implémentation et « transféré ailleurs » dans d'autres, donc un filtre sur la catégorie seule mettrait les réclamations finalisées dans la file d'attente pour que quelqu'un les poursuive.
Deux identificateurs décident si une pièce jointe est jamais associée à sa réclamation, et les deux sont signalés : le numéro de contrôle de pièce jointe, que le fournisseur a mis sur la réclamation originale pour dire que la documentation suivrait, et le numéro de trace, qui correspond à la demande de l'assureur. Une pièce jointe arrivant avec aucun des deux est classée et jamais connectée à quoi que ce soit, tandis que la réclamation vieillit.
275 n'est pas interprété. Perfuse signale ses octets et ce que l'expéditeur dit qu'ils sont. Une pièce jointe peut être un PDF, un TIFF, un document CDA ou un message HL7, et un canal ayant besoin du contenu peut transmettre ces octets au format qui le lit.Le formulaire 006020, qui est celui que la règle adopte
CMS-0053-F adopte la version 006020, et son 275 diffère du formulaire 005010 de deux manières qui importent.
- La charge utile est dans
BDS, et nonBIN.BDS01nomme un filtre,ASCouB64.BDS02est la longueur etBDS03les données. - La charge utile est une entité MIME, avec des en-têtes indiquant ce qu'est le document et un corps base64. Avec
B64l'entité elle-même est également base64.
Perfuse déballe l'entité et signale le document qu'elle contient, avec son type de contenu et son nom de fichier. Les octets qu'il signale sont exactement ceux que l'expéditeur a emballés. Une entité qui ne peut pas être déballée laisse la charge utile brute en place, avec une note indiquant pourquoi.
Construire un 275. Perfuse construit également des pièces jointes 006020X314 : une pièce jointe non sollicitée pour accompagner une réclamation, ou une réponse à une demande de payeur 277. La différence réside dans BGN01 02 contre 11, et dans le fait que TRN02 transporte le PWK06 de la réclamation ou le TRN02 de 277. Chaque échange construit est analysé à nouveau avant d'être renvoyé, et la réponse indique si le document à l'intérieur est celui qui est entré.
La structure provient des deux guides d'accompagnement publiés pour 006020X314 : le guide esMD de la CMS et celui d'UnitedHealthcare. Elle ne provient pas du rapport technique X12, que X12 licence et que ce projet ne détient pas.
- Lorsque les deux guides sont d'accord, Perfuse les suit.
- Lorsqu'ils diffèrent, il satisfait les deux s'il le peut.
CAT02estHLpour un document HL7, que esMD utilise, etIApour une image, que UnitedHealthcare utilise. - Sinon, il n'envoie le segment facultatif que lorsqu'il reçoit la valeur : l'identifiant de réclamation
REF*X1d'esMD et la date de serviceDTP*472d'UnitedHealthcare.
Il n'y a pas de validation contre le rapport technique. Le guide d'accompagnement du partenaire régit.
8.3.8 Signatures électroniques sur les pièces jointes
CMS-0053-F adopte également une norme de signature, à 45 CFR 162.2002(e) : le guide de mise en œuvre HL7 pour CDA Release 2, Signatures numériques et délégation de droits, Release 1. Elle s'applique aux signatures apposées sur les informations de pièce jointe lorsqu'elles sont envoyées dans une transaction d'attachement HIPAA, à partir du 26 mai 2028. Un payeur ne peut pas demander plus que ce que le guide prévoit.
Perfuse signe un C-CDA de cette manière lorsqu'il entre dans un 275, et vérifie les signatures sur chaque C-CDA dans un 275 qu'il lit.
- Ce qui est signé. L'ensemble du document, à l'exception de ses participants
legalAuthenticatoretauthenticator, de sorte que chaque signataire ultérieur laisse les signatures antérieures intactes. La signature indique cela à l'aide d'une transformation XPath Filter 2.0 que toute bibliothèque de signature XML peut évaluer. - Où cela va. En base64 dans
sdtc:signatureTextsur le participant signataire, avec une description en texte brut d'une ligne. Le signataire est l'authentificateur juridique du document s'il en a un non signé, sinon un nouvelauthenticator. - Ce qu'il déclare. Le certificat du signataire, l'heure en UTC, un rôle de la taxonomie des fournisseurs NUCC et un objectif de l'ASTM E1762. L'objectif par défaut est *Signature de l'auteur* pour un authentificateur juridique et *Co-auteur* sinon, comme dans l'exemple propre du guide.
- Combien de temps cela dure. Le guide demande XAdES-X-L, qui transporte tout ce dont un payeur a besoin pour vérifier la signature des années plus tard sans atteindre le réseau. C'est le chemin de certification, une réponse OCSP ou une liste de révocation du CA, et deux horodatages d'une autorité d'horodatage. Perfuse récupère les données de révocation à partir des adresses du certificat et les horodatages à partir de
-tsa-url.
Si l'un de ces éléments n'est pas disponible, la signature est toujours créée et tient. Le résultat nomme la forme XAdES atteinte et indique ce qui l'a empêchée d'atteindre X-L : par exemple, un certificat auto-signé (pas de CA à interroger) ou pas d'autorité d'horodatage.
La clé est -signing-cert et -signing-key. Placez les certificats CA après celui du signataire dans le même fichier afin que le chemin se déplace avec la signature. Pour une signature qui signifie ce que DSDR signifie, le certificat doit nommer le clinicien, avec son NPI, plutôt que le serveur. La signature est une action d'administration, comme la signature de tout document.
Le guide ne nomme pas d'espace de noms pour ses propres éléments. Perfuse place digitalSignature, authorizedSigner et SignaturePurpose dans urn:hl7-org:sdtc. Il déclare également l'objectif en tant que type d'engagement XAdES avec l'OID ASTM, que les outils XAdES comprennent. La délégation de droits, où un délégué signe avec une assertion SAML de l'expéditeur autorisé, n'est pas produite, et un reçu est signalé comme non vérifié.
Le NPI du fournisseur est vérifié contre son chiffre de contrôle. Un payeur associe une pièce jointe à sa réclamation en partie sur ce numéro, et un numéro mal tapé laisse la pièce jointe non associée tandis que la réclamation est rejetée pour documentation manquante.
La vue Réclamations et auth construit un 275 à partir d'un C-CDA collé ou d'un fichier téléchargé, en signant facultativement le C-CDA, et en lisant un avec les résultats de chaque signature. Rien sur cette page n'envoie quoi que ce soit : l'échange est remis pour être livré via un canal, qui est où se trouvent le partenaire, les informations d'identification et la trace d'audit.
8.3.9 Segments binaires
Un segment BIN transporte des octets bruts, et les octets bruts contiennent des délimiteurs. Chaque autre segment X12 se termine par le terminateur de segment, donc un analyseur ordinaire trouve les segments en recherchant un octet ; une pièce jointe ne peut pas être trouvée de cette façon. Un PDF contenant un ~ serait découpé en morceaux, et chaque morceau est un segment structurellement valide — donc le document est tronqué, chaque segment après lui est désaligné, et rien ne signale d'erreur.
Perfuse lit le nombre d'octets que le segment déclare et prend exactement autant d'octets. Deux conséquences dignes d'intérêt :
- Une longueur déclarée qui ne correspond pas aux données est refusée, en nommant les deux numéros. La question utile est de savoir si le décompte de l'expéditeur était incorrect ou si le fichier a été tronqué pendant le transit, et seuls les deux numéros répondent à cette question.
BDS, le segment binaire006020, conserve son décompte dansBDS02et ses données dansBDS03. Il a été refusé jusqu'à ce que cela puisse être confirmé à partir d'une source publiée plutôt que rappelée, et deux sources confirment maintenant cela : le guide de companion de CMS esMD pourBDSet le guide de UnitedHealthcare.
Le guide esMD lui-même déclare 16 octets pour la même charge utile de 53 octets que sa table compte correctement comme 53. Perfuse refuse cet exemple, comme il se doit. Un test contient à la fois l'exemple de la table et l'erreur de frappe de l'exemple, donc un changement dans un sens ou dans l'autre est remarqué.
8.4 FHIR
8.4.1 Ce qu'un message HL7 v2 devient
Le type de message décide de ce qui est produit, et chaque conversion signale les jugements qu'il a nécessités sous forme de notes à côté du bundle.
| v2 | FHIR |
|---|---|
ADT | Patient, un Rendez-vous lorsqu'il y a une visite, une Condition par diagnostic DG1 (également répertorié dans le Rendez-vous diagnosis, un admit en tant que AD), une Procédure par PR1 et une AllergyIntolerance par AL1. A28, A31, A29 et A24 concernent la personne, ils ne produisent donc pas de Rendez-vous ou de diagnostics, mais portent des allergies. |
ORU | DiagnosticReport par OBR, avec ses Observations et Specimen, et la commande qu'il répond en tant que ServiceRequest (son demandeur OBR-16 ou ORC-12, son statut ORC-5); OBR-32 est l'interprète des résultats, OBR-34 et OBR-35 sont les performeurs. Les résultats sont regroupés sous le OBR avant eux par position, car OBX-4 n'est pas fiable. |
ORM, OML, OMG | ServiceRequest. |
SIU | Rendez-vous, avec le patient, les praticiens de AIP et les emplacements de AIL. |
MDM | DocumentReference contenant le document. |
VXU | Immunization, un par RXA. |
Tout autre produit donne le Patient et un avertissement indiquant le type qui n'a pas été mappé.
Planification. Une réservation, une réorganisation, une annulation et un non-présentation atterissent tous sur le même Appointment. Son identité provient des numéros de l'appointment lui-même dans SCH-1 et SCH-2, et non du message, donc une annulation met à jour la réservation. L'alternative serait un deuxième appointment annulé à côté d'un appointment actif, ce qui montre que le patient a réservé un créneau qui n'existe plus.
- État. Le statut de remplissage dans
SCH-25le décide, et l'événement déclencheur n'est utilisé que lorsque celui-ci est vide. - Créneaux bloqués. Un créneau bloqué n'est pas un appointment avec un patient, et ne produit aucun appointment.
- Heure de début. Elle est lue à partir de
AIS,AIG,AILouAIPen premier, puisSCH-11, car la version 2.5 l'a déplacée et les flux n'ont pas tous suivi. - Durées. Une durée dans une unité que Perfuse ne reconnaît pas est omise, et non devinée.
Documents. Les notes de texte (TX, FT, ST) conservent leurs sauts de ligne, y compris les lignes vides, car une répétition vide dans une note est une pause de paragraphe.
- 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.
C'est ce que le critère 14 du cadre d'interopérabilité CMS demande : les notes de dossier et les documents cliniques renvoyés en tant que pièces jointes FHIR.
Immunisations. Une dose n'est jamais signalée comme administrée lorsque le message indique le contraire.
- Doses refusées. Une dose refusée ou non administrée (
RXA-20REouNA) estnot-done, avec la raison issue deRXA-18. - Suppressions. Une suppression (
RXA-21D) estentered-in-error. - Enregistrements historiques. Un enregistrement transcrit d'ailleurs (
RXA-9autre que00) n'est pas une source principale. - Quantités inconnues. Une quantité de
999signifie inconnue, et non 999. - Voies et sites d'administration. Chaque dose prend la voie et le site de l'
RXRqui la suit, donc un message avec deux doses n'attribue pas la voie et le site de la première dose à la seconde.
Entrée gênante. Chacun de ces éléments est signalé dans les notes plutôt que décidé silencieusement :
- Identificateurs.
PID-2etPID-4, retirés après la version 2.7 mais toujours envoyés, sont conservés commePID-3.CX.7etCX.8deviennentIdentifier.period. Une autorité d'attribution portant un OID ISO (AUSHIC&2.16.840.1.113883.3.879&ISO) devienturn:oid:. Un code de type en dehors de la table 0203 d'HL7 est conservé comme texte, et non étiqueté comme tel. - Fusions.
MRGsur un événement de fusion (A40et ses variantes) envoie également l'enregistrement retiré, inactif, avecPatient.linkdans les deux sens. Pour tout autre événement, tel qu'unA08, rien n'est fusionné et un avertissement indique que l'identifiant précédent est toujours actif. - Heures. Une heure de naissance dans
PID-7va à l'extensionpatient-birthTime. Un horodatage sans décalage prend le fuseau horaire configuré, sinon le décalage surMSH-7(v2 suppose l'heure locale de l'expéditeur), sinon UTC. Une heure de naissance est l'exception : sans décalage des trois, elle est omise plutôt que d'être étiquetée UTC, car un décalage incorrect peut déplacer une naissance à un autre jour.birthDateest conservé, et un avertissement indique que l'heure a été supprimée et que la configuration d'un fuseau horaire pour l'alimentation la conserve. - Résultats. Les répétitions d'un résultat texte sont jointes avec des sauts de ligne. Un résultat
ED, ou un résultat codé dont la valeur est clairement Base64, devient une DocumentReference que l'Observation pointe dansderivedFrom, puisqu'une Observation R4 n'a pas de valeur d'attachement. Un comparateurSNde=est supprimé comme redondant ;<>conserve le texte, car aucune quantité ne peut dire « non égal ». - Visites. Un
A08avec une date de sortie (PV1-45) est une rencontre terminée. Une classe de patient manquante ou inconnue est la saveur nulleUNK, car R4 nécessite une classe. - Les segments Z sont nommés dans un avertissement, puisqu'il n'y a pas de carte standard pour eux.
- Names. When the sender splits a family name (
XPN.1,XCN.2) into its parts - a surname prefix and a surname, the person's
own and a partner's, as Dutch and Flemish names are sent - family is the whole name and the parts go in HL7's family-name extensions (humanname-own-prefix, -own-name, -partner-prefix, -partner-name).
- Procedures.
PR1becomes a Procedure with statusunknown, since an ADT does not say whether it was done or planned; the
anaesthetist (PR1-8) and surgeon (PR1-11) are performers with SNOMED CT roles. An OPS code also gets its SNOMED CT category from its chapter, by HL7 Deutschland's OPS-SNOMED-Category map, which ISiK requires.
8.4.2 Ce que le site ajoute : le script de bundle
Un profil national souhaite souvent ce qu'un message HL7 v2 ne contient pas : le numéro IK d'un hôpital ou le code ODS, qui est le niveau de contact d'une visite (ISiK), si un prénom est un prénom ou une initiale (le nl-core néerlandais). Perfuse ne devine pas ceux-ci. La destination fhir a un bundle_script où un site peut les écrire : JavaScript exécuté sur chaque bundle converti, en tant que bundle, avant qu'il ne soit validé et envoyé. Ce que le script laisse est ce qui est envoyé, vérifié comme toute conversion, et un script qui lance une exception échoue le message comme n'importe quel transformateur. La console l'a sous *Ajouter ce que vos systèmes savent* de la destination.
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 exécute le même script, donc un site peut l'essayer sur ses propres messages avant. Deux exemples fonctionnels se trouvent dans le référentiel : examples/isik/bundle-script.js (IKNR, Kontaktebene, numéro de patient de type MR, Diagnosetyp) et examples/nictiz/bundle-script.js (prénoms et initiales). Avec eux, les messages allemands et néerlandais inventés dans conformance/national passent de 18 à 42 ressources valides sur 47 contre ISiK et de 12 à 18 sur 24 contre nl-core ; ce qui reste est dans les messages ou le serveur de terminologie, et est répertorié là.
Le Bundle passe par le modèle Perfuse à l'aller, donc les modifications apportées par un script sont vérifiées et écrites dans la version FHIR de la destination. Les membres pour lesquels le modèle n'a pas de champ sont conservés comme le script les a écrits, à l'intérieur des types de données également.
8.4.3 US Core 9.0.0 et USCDI v6
-us-core (et claim_us_core sur une destination fhir) place un profil US Core dans meta.profile, mais uniquement sur une ressource qui a été vérifiée contre ce profil et trouvée conforme. Celle qui ne répond pas aux exigences est toujours convertie et envoyée sans la revendication, et une note donne la raison, telle que « US Core nécessite un type de rencontre, et cette Rencontre n'en a pas ». Les vérifications sont transcrites à partir de US Core 9.0.0, la version que le processus d'avancement des normes 2026 de l'ONC approuve pour USCDI v6. Elles couvrent Patient, Encounter, l'Observation et le DiagnosticReport de laboratoire, Specimen, Practitioner, Organization, Location, Immunization, DocumentReference, la Condition de diagnostic de rencontre et AllergyIntolerance.
Ce que le convertisseur transporte, par classe de données USCDI v6 :
| USCDI v6 | De | En tant que |
|---|---|---|
| Données démographiques du patient | PID | Nom, date de naissance, sexe, adresse, téléphone et courriel, identificateurs. La race et l'ethnicité (PID-10, PID-22) dans les extensions de US Core lorsque codées en Race et Ethnicity de CDC. Langue préférée (PID-15) en tant que BCP 47 |
| Informations sur le rendez-vous | PV1 | Rendez-vous avec type, classe, période, emplacement et participants |
| Informations sur les installations | PV1-3 | Emplacement, avec l'installation en tant qu'organisation gérante |
| Problèmes, date de début | DG1 | Condition (diagnostic de rendez-vous). DG1-5 est le début, comme l'a cartographié la carte HL7 v2-to-FHIR |
| Allergies et intolérances, réaction | AL1 | AllergyIntolerance avec catégorie, criticité et réaction |
| Laboratoire | ORU | DiagnosticReport, Observations, Specimen (à partir de SPM), ServiceRequest |
| Commandes | ORM, OML | ServiceRequest |
| Immunisations | VXU | Immunization |
| Notes cliniques | MDM | DocumentReference |
| Membres de l'équipe de soins | PV1, TXA, DG1 | Practitioner |
Non transmis, car les messages v2 de ces types ne les contiennent pas ou que Perfuse ne les mappe pas : Médicaments, Procédures, Objectifs et Préférences, Évaluations de l'état de santé, Plan de soins, Histoire médicale familiale, Appareils médicaux (UDI), Informations sur l'assurance maladie, Signes vitaux en tant que profil distinct, et Provenance.
8.4.4 R4 dans les deux sens
Un serveur FHIR déclarant R4 accepte R4. Ce n'était pas vrai des Rencontres jusqu'à cette version. Le serveur convertissait ce qu'il servait en R4 mais lisait ce qu'il recevait comme s'il était déjà dans sa forme interne, donc une Rencontre R4 était refusée avec un 400. De même, chaque bundle que la conversion ADT de Perfuse produisait était refusé, car chacun transporte Encounter.class, que R4 écrit comme un seul codage.
Cela a été découvert la première fois que quelque chose a publié une ADT convertie sur le serveur R4 de Perfuse. Un test effectue maintenant cela pour chaque type de message mappé, et un autre vérifie que tout ce qui est écrit en R4 est lu sans changement.
8.4.5 Résumé international du patient
GET /fhir/Patient/{id}/$summary, ou GET /fhir/Patient/$summary?identifier=system|value, renvoie un Résumé international de patient (HL7 IPS 2.0.0) : un bundle FHIR document dont la Composition répertorie les problèmes actifs du patient, les allergies, les médicaments, les immunisations, les résultats, les signes vitaux, les procédures, les appareils, les maladies passées, l'histoire sociale et les plans de soins, chacun avec une narration lisible. Il s'agit du dossier court que lit en premier un clinicien qui n'a jamais rencontré le patient, et du résumé que l'Espace de données de santé européen échange entre les pays à partir de 2029.
Il est construit à partir de ce que le magasin FHIR contient, et rien n'est inventé :
- Les enregistrements marqués
entered-in-errorsont exclus. - Une condition résolue est placée sous les antécédents de maladie, et non sous les problèmes.
- Une ordonnance de médicament qui a été arrêtée ou complétée est considérée comme un historique, et non comme un médicament actuel.
- Les trois sections requises par l'IPS (problèmes, allergies, médicaments) sont toujours présentes. Lorsqu'une section est vide, elle contient la raison codée
unavailableet indique que le serveur ne contient aucune information, « ce qui ne signifie pas qu'il n'y en a pas ». Une liste d'allergies vide ne doit jamais être interprétée comme « aucune allergie connue ». - Les praticiens, organisations, médicaments et lieux auxquels les entrées font référence sont inclus, afin que le document soit autonome.
Access follows $everything: a token limited to one patient gets a 403 for another, and an identifier that matches two patients is refused rather than guessed. Only the IPS profile is built; asking for another profile is refused. The document Perfuse produces from its test records validates against the IPS 2.0.0 Bundle profile with the HL7 validator, with no errors. A record built from real feeds can still fail where the feed's own codes do (a display name the code system does not use, for example), because the summary passes the data on as it was received.
Échange → Liens de santé → Partager remplit le contenu avec un résumé de patient : tapez l'ID FHIR du patient et choisissez Utiliser son résumé de patient, puis lisez-le et créez le lien. Sa construction est audité comme fhir.summary.
8.4.6 Résumés de transfert pour les soins post-aigus (PACIO)
Lorsqu'un patient quitte l'hôpital pour une maison de soins infirmiers, une unité de rééducation ou des soins à domicile, le dossier électronique de santé de l'hôpital envoie un C-CDA : un résumé de transfert, un résumé de sortie ou un CCD. Perfuse transforme ce document en un résumé de transfert que le guide Transitions of Care de PACIO décrit (hl7.fhir.us.pacio-toc 1.0.0) : un bundle FHIR R4 document, US Core 8.0.1 à l'intérieur, que le système de l'établissement récepteur peut classer sans que personne ne lise le XML.
- Chacune des quinze sections du guide est présente, chaque avec son propre texte, dans l'ordre du guide : directives anticipées, allergies, santé comportementale, état fonctionnel, immunisations, instructions de sortie, dispositifs médicaux, médicaments, plan de soins, problèmes, procédures, raison de renvoi, résultats, histoire sociale et signes vitaux.
- Une section qui n'est pas présente dans le document est considérée comme manquante, jamais remplie. Elle sort vide, avec la raison codée
unavailableet la phrase "Le document source n'avait pas de ... section". Une section d'allergie vide ne doit pas indiquer "pas d'allergies connues". - Une section transmise sous forme de texte seul conserve son texte et n'a pas d'entrées. La prose n'est pas convertie en données codées. L'état fonctionnel, la santé comportementale (la section d'état mental de la C-CDA), les directives anticipées, les dispositifs médicaux, le plan de soins, les instructions de sortie, la raison de renvoi et l'histoire sociale sont transmis de cette façon aujourd'hui ; les notes le précisent pour chacun.
- Les entrées codées deviennent des ressources selon les mêmes règles que la conversion ordinaire : allergies (US Core AllergyIntolerance), problèmes et diagnostics de sortie (US Core Condition, liste de problèmes ou diagnostic d'encounter), procédures, immunisations, résultats, signes vitaux et médicaments sous forme de liste de médicaments PACIO de MedicationStatements (
104204-3, liste de médicaments déchargés, à partir d'une section de médicaments de sortie ;104202-7, liste de médicaments actifs, sinon). - Signes vitaux sous forme FHIR. Une pression systolique et une pression diastolique prises ensemble deviennent un panneau de pression artérielle (
85354-9) avec deux composants, et un code plus spécifique (poids corporel mesuré,3141-9) porte également le code des profils de signes vitaux FHIR (29463-7), à côté de l'original. - Qui et d'où. L'auteur du document devient l'auteur de la Composition (un Practitioner, avec le NPI lorsque son chiffre de contrôle est valide), son gardien l'organisation gardienne, son encounter englobant le séjour que le résumé clôture. Un document sans personne en tant qu'auteur, ou sans gardien, est refusé : le guide exige les deux, et Perfuse ne mettra pas de nom sur un dossier clinique que personne n'a donné.
- La négation conserve son sens. "Pas d'allergies connues" (une allergie négative à toute substance) est transmise sous forme de SNOMED CT
716186003; une allergie négative à un médicament est refusée, car FHIR ne peut pas le dire et la ressource dirait le contraire ; un problème négatif estrefuted.
Trois façons de le faire :
- Un canal : une destination
cdaavecwrite: transferpublie le résumé de transfert de chaque document sur le point de terminaisonBundledu serveur FHIR (url), ou écrit<document>.transfer.jsondansdir. Dans le constructeur de canal : Émettre › Un résumé de transfert PACIO. - La ligne de commande :
perfuse fhir transfer [-authority OID=URI] [-out dir] <document.xml>.... - La console : Documents, activez Également créer un résumé de transfert PACIO, et lisez le document.
Vérifié avec le validateur officiel FHIR contre le profil de bundle TOC 1.0.0, sur les exemples de C-CDA d'HL7 (un résumé de transfert, un résumé de sortie et un CCD). L'erreur qu'il signale se trouve dans le guide : chaque signe vital correspond à la fois à sa section simple-observation et à sa section vital-signs de bundle, il ne peut donc être évité par aucun expéditeur. Pas encore réalisé : la conversion des sections de texte uniquement (état fonctionnel, état mental, plan de soins, appareils) en ressources codées, et la référence de document TOC du guide qui indexe un résumé de transfert stocké.
8.4.7 Abonnements
Avec -fhir-subscriptions, le point de terminaison FHIR envoie des notifications lorsque une Rencontre ou un Rendez-vous est créé ou modifié. Il suit les IG de rappel R5 pour R4, qui est ce que le cadre d'interopérabilité CMS et la feuille de route FHIR de TEFCA utilisent pour les notifications de rendez-vous et de rencontre.
Un client crée un Subscription en nommant un sujet, et éventuellement un filtre tel que Encounter?patient=Patient/123. Les sujets sont répertoriés dans l'énoncé de capacité :
| Sujet | Déclenche sur | Filtres |
|---|---|---|
https://perfuse.health/fhir/SubscriptionTopic/encounter | Rencontre créée ou mise à jour | patient, status, class |
https://perfuse.health/fhir/SubscriptionTopic/appointment | Rendez-vous créé ou mis à jour | patient, status |
Un filtre qui nomme autre chose est refusé, et non ignoré. Un filtre ignoré est un abonnement qui notifie sur chaque patient lorsque le client a demandé un seul patient.
Les propriétés autour desquelles l'implémentation est construite :
- 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.
Ce que le client peut faire faire au serveur est limité intentionnellement :
- Les points de terminaison doivent être
httpsà moins que l'opérateur ne passe-fhir-subscriptions-allow-http, qui est pour un récepteur de test. - La politique de sortie est appliquée lors de la création d'un abonnement, à nouveau à chaque livraison, et sur l'adresse que chaque connexion atteint réellement (un nom qui change ce qu'il résout entre la vérification et la connexion est toujours refusé) ; les redirections ne sont pas suivies.
- La charge utile par défaut est
id-only, qui indique ce qui a changé et permet au récepteur de le récupérer avec ses propres informations d'identification. - Rien de ce que le récepteur envoie en retour n'est montré à qui que ce soit, seul son code d'état est montré.
Il est désactivé à moins de demander, car une fois activé, un client FHIR peut faire en sorte que ce serveur envoie des données de patient à une URL de son choix. Il nécessite un point de terminaison R4 qui accepte les écritures, et refuse de démarrer sinon.
Non implémenté, donc personne n'a à le découvrir en essayant :
- les canaux autres que
rest-hook - les battements cardiaques
- les notifications de suppression
- les opérations
$statuset$events
La vue Abonnements affiche le sujet de chaque abonnement, le filtre et le point de terminaison, combien d'événements il a eu, combien ont été acceptés et combien sont en attente, ainsi que la dernière raison pour laquelle un a été refusé. Les valeurs d'en-tête et la chaîne de requête du point de terminaison sont retenues, car c'est là que vivent les informations d'identification de l'abonné.
8.5 Norme de télécommunication NCPDP
Réclamations de pharmacie. En-tête à largeur fixe suivi de segments variables.
Deux détails qui comptent, tous deux faciles à mal interpréter et à produire des résultats plausibles :
L'en-tête est exactement de 56 octets et de largeur fixe. Un en-tête court ne peut pas être détecté par la longueur seule, car un en-tête tronqué plus les segments suivants dépasse encore 56 octets. La détection est qu'un en-tête correct ne contient jamais d'octet séparateur, donc l'en-tête est analysé pour en trouver un et un message qui en contient un est refusé avec le nombre d'octets qu'il manque.
0x1E et 0x1C sont des marqueurs de début de groupe et de champ, et non des séparateurs. Les traiter comme des séparateurs décale chaque champ d'une place vers la gauche, et la plupart des valeurs résultantes restent plausibles — une quantité atterrit où une fourniture de jours était attendue et les deux sont des nombres.
0x1C, qui est l'octet de fin de bloc MLLP, donc encadrer une réclamation la tronquerait au premier marqueur de champ.8.6 NCPDP SCRIPT
Les ordonnances électroniques, en XML. Le paquet interne s'appelle eprescribe parce que script était pris par le moteur JavaScript.
La principale préoccupation de sécurité est le drapeau de substitution, et il se lit à l'envers de l'intuition : sur le fil, 0 signifie que la substitution est autorisée et 1 signifie dispenser tel quel.
Un drapeau de substitution absent est refusé plutôt que par défaut. Les deux défauts possibles atteignent le patient — l'un peut dispenser un générique où le prescripteur exigeait la marque, l'autre empêche une substitution que le prescripteur a permise — donc il n'y a pas d'hypothèse sûre et le message s'arrête.
Une ordonnance de classe II avec des renouvellements est refusée, et le constructeur n'en produira pas.
Les refus et les avertissements sont conservés comme des listes distinctes plutôt que comme une liste étiquetée de gravité, car un lecteur qui doit vérifier un champ de gravité pour savoir si le message a été envoyé finira par ne pas le vérifier.
L'autorisation préalable électronique (PAInitiationRequest, PARequest, PAAppealRequest, PACancelRequest) et le bénéfice de prescription en temps réel sont répondus par le côté payeur à /ncpdp/script et /ncpdp/rtpb, à partir de la formule de médicaments ; voir CMS-0057.
8.7 DICOM
Imagerie. Perfuse peut recevoir des objets DICOM, interroger un archive distant, et stocker vers un, sur les services réseau DICOM classiques ou sur DICOMweb, et il peut conserver un archive pour les visualiseurs.
DICOM n'est pas un format de message au même sens que les autres — les objets sont grands, et la poignée de main d'association compte plus que l'analyse de la charge utile. Les titres called_ae et calling_ae sont la raison la plus courante pour laquelle une première connexion échoue, et l'échec ressemble à un problème de réseau plutôt qu'à un problème de configuration.
8.7.1 Ce qu'un écouteur C-STORE accepte
Laisser ouvert, un écouteur DICOM accepte n'importe quoi de n'importe qui qui peut atteindre le port. Quatre paramètres sous Ce que cet écouteur accepte restreignent cela, et le premier est celui qui vaut la peine d'être compris.
N'accepter que ces titres AE appelants est la restriction. Le titre AE *appelé* — celui qui se trouve à côté de l'adresse — est le nom que le destinataire compose, donc il identifie cet écouteur plutôt que l'expéditeur, et il ne s'agit pas d'une restriction. N'importe qui qui peut atteindre le port peut utiliser le titre AE appelé correct, car il est publié pour eux. Sans liste d'appelants autorisés, n'importe quel hôte du réseau peut pousser des images dans un canal clinique.
N'accepter que ces classes SOP et n'accepter que ces syntaxes de transfert prennent des UID séparés par des virgules. Vide accepte tous les types d'objets et négocie toute compression que l'expéditeur offre, ce qui inclut des types que les destinations de ce canal ne peuvent pas gérer. Refuser à l'association est plus clair pour l'expéditeur que d'accepter l'objet et d'échouer par la suite.
Plus grand objet accepté est en octets, et zéro signifie pas de limite. Les images de lame entière et les séries longues peuvent atteindre des gigaoctets, donc la limite est autrement en mémoire.
8.7.2 DICOMweb
DICOMweb est DICOM sur HTTP : QIDO-RS recherche, WADO-RS et WADO-URI récupèrent, STOW-RS stocke. Les visionneuses de navigateur telles que OHIF ne parlent que DICOMweb, tout comme les services d'imagerie cloud (Google Cloud Healthcare, Azure Health Data Services, AWS HealthImaging). Perfuse l'utilise à trois endroits.
L'archive d'imagerie. Démarrez le serveur avec -dicomweb-archive DIR (Paramètres › Données › Archive d'imagerie) et il conserve les objets dans ce dossier, indexés dans SQLite, et les sert à /dicomweb sur l'adresse de la console elle-même : QIDO-RS au niveau de l'étude, de la série et de l'instance, WADO-RS pour les objets, les métadonnées, les trames et les données massives, WADO-URI à /dicomweb/wado, et STOW-RS. La lecture prend le rôle de visionneuse et le stockage le rôle d'opérateur, avec une session ou un jeton d'API ; chaque lecture et stockage est dans Activité comme dicomweb.read ou dicomweb.store. Un compte limité à un locataire ou à des groupes de canaux est refusé, car l'archive appartient à l'ensemble du serveur. Les objets sont conservés exactement tels qu'ils ont été reçus, donc ce que un visionneuse récupère est byte à byte ce qui a été stocké. Les trames sont renvoyées dans la syntaxe de transfert dans laquelle elles ont été stockées ; une demande qui nécessiterait une transcodification répond 406 plutôt qu'une image convertie.
Une recherche sur un attribut que l'archive n'indexe pas répond 400 plutôt que d'ignorer la condition et de renvoyer plus d'études que demandé. Indexé : nom du patient (caractères génériques, et correspondance floue avec fuzzymatching=true), ID du patient, date de naissance, sexe, date et heure de l'étude (plages), numéro d'accès, ID d'étude, description, médecin référent, étude, série et instance SOP UIDs (listes), modalité, partie du corps, numéro de série et description, classe SOP, numéro d'instance, lignes, colonnes et nombre de trames.
La source. type: dicomweb écoute STOW-RS, à /dicom-web/studies par défaut (le chemin que Orthanc et dcm4chee utilisent), et envoie chaque objet à travers le canal comme un message DICOM. Le canal a besoin de dataType: dicom. Définissez un jeton porteur ou un nom d'utilisateur et un mot de passe : sans cela, quiconque peut atteindre le port peut envoyer des images dans le canal. La réponse liste chaque objet comme stocké ou échoué, avec la raison d'échec DICOM, afin qu'un expéditeur sache lesquels renvoyer.
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 destination se trouve dans delivery, sous les archives DICOMweb.
Pointer OHIF vers l'archive
Utilisez une source de données DICOMweb avec qidoRoot et wadoRoot définis sur l'adresse de l'archive (l'écran Imagerie l'affiche, avec l'ensemble du bloc de source de données à copier), wadoUriRoot à cette adresse suivie de /wado, imageRendering et thumbnailRendering à wadors, et supportsFuzzyMatching true. Un visionneuse sur une autre origine nécessite cette origine dans -dicomweb-cors (Origines de navigateur autorisées à l'appeler), et ses demandes nécessitent un jeton d'API dans l'en-tête Authorization, car un navigateur sur une autre origine n'envoie pas le cookie de session de la console. Le service OHIF à partir de la même origine via un proxy inverse évite les deux.
Testé contre Orthanc avec son plugin DICOMweb, dans les deux sens : la destination stocke dans Orthanc, et le client DICOMweb d'Orthanc recherche l'archive de Perfuse et récupère une étude byte-identique à celle stockée. OHIF 3 liste les études de l'archive et affiche leurs trames avec les paramètres ci-dessus. OHIF et plusieurs autres clients envoient type= non cité dans les en-têtes Accept et Content-Type, ce que RFC 2045 n'autorise pas ; Perfuse l'accepte.
8.8 Partage de documents IHE : XDS.b, XCA, XDR, MHD, PIXm et PDQm
Les documents cliniques partagés entre organisations de la même manière que les échanges d'informations de santé, Carequality et eHealth Exchange : un référentiel les contient, un registre indexe leurs métadonnées, et une communauté répond aux requêtes d'autres communautés via une passerelle. Démarrez le serveur avec -xds REPOSITORY-OID (Paramètres › Données › Partage de documents) et il remplit les trois rôles, dans la base de données de ce serveur, aux adresses suivantes, chacune acceptant un jeton d'API comme jeton porteur (le rôle de visualisateur pour interroger et récupérer, le rôle d'opérateur pour soumettre ; la plupart des domaines d'affinité ajoutent un TLS mutuel à l'avant) :
| Adresse | Acteur | Transactions |
|---|---|---|
/xds/repository | Référentiel de documents | ITI-41 Fournir et enregistrer l'ensemble de documents-b, ITI-43 Récupérer l'ensemble de documents |
/xds/registry | Registre de documents | ITI-18 Requête de registre stockée (toutes les treize requêtes stockées), ITI-42 Enregistrer l'ensemble de documents-b |
/xca/gateway | Passerelle de réponse XCA | ITI-38 Requête interpasserelle, ITI-39 Récupérer interpasserelle, avec -xds-home-community urn:oid:... |
/mhd | Destinataire et répondant de documents MHD | ITI-65 Fournir le bundle de documents, ITI-66 Trouver les listes, ITI-67 Trouver les références de documents, ITI-68 Récupérer le document |
/mhd/Patient | Fournisseur PDQm et gestionnaire PIXm | ITI-78 Requête de données démographiques des patients, ITI-83 Patient/$ihe-pix, à partir du magasin FHIR des Patients |
/pixv3 | Gestionnaire PIX (HL7 v3) | ITI-44 Alimentation d'identité de patient HL7 V3, ITI-45 Requête PIXV3, à partir de l'index de patients (-mpi) |
/pdqv3 | Fournisseur PDQ (HL7 v3) | ITI-47 Requête PDQV3, avec continuation et annulation, à partir de l'index de patients |
Les transactions SOAP sont SOAP 1.2 avec WS-Addressing, et MTOM/XOP lorsque les documents voyagent (un document en ligne sous forme base64 est également accepté). Une transaction échouée est répondue avec une RegistryResponse contenant les codes d'erreur IHE, et non une erreur SOAP : XDSDuplicateUniqueIdInRegistry, XDSNonIdenticalHash, XDSPatientIdDoesNotMatch, XDSMissingDocument, XDSRegistryMetadataError (avec le champ manquant), XDSStoredQueryMissingParam, XDSUnknownStoredQuery, XDSUnknownRepositoryId, XDSUnknownCommunity, et UnresolvedReferenceException. Un remplacement (RPLC, XFRM_RPLC) rend obsolète le document qu'il remplace, qui répond ensuite uniquement aux requêtes demandant des documents obsolètes ; APND, XFRM et signs sont conservés comme associations. Le hachage et la taille sont calculés par le référentiel et vérifiés par rapport à ce que la soumission indique. Les documents et les métadonnées à la demande (ITI-57) ne sont pas pris en charge, et une soumission les demandant est refusée avec la raison.
MHD est le même registre dans FHIR : un document fourni via MHD est trouvé par ITI-18 et via XCA, et un document fourni via XDS.b est trouvé par ITI-67. L'identifiant d'une DocumentReference est l'UUID de l'entrée, son masterIdentifier est l'uniqueId, et l'URL de son attachment est l'adresse ITI-68 du document. Les patients sont résolus à l'identifiant du domaine d'affinité à partir du magasin FHIR : le premier identifiant dont le système est urn:oid:, ou le Patient transporté dans le Bundle. PIXm répond à chaque autre identifiant du Patient avec celui fourni (sourceIdentifier=system|value, étroitement lié à targetSystem), et 404 pour celui qu'il ne connaît pas ; PDQm recherche par identifiant, nom, date de naissance, sexe, adresse et télécom.
Publication. Une destination xds d'un canal publie chaque document clinique qu'il reçoit, un document CDA ou un document transporté dans un message HL7 v2, à tout référentiel XDS.b avec ITI-41. Les métadonnées sont lues à partir du document : le patient (l'identifiant dans patient_domain, l'autorité d'attribution du domaine d'affinité), le titre, le type (en tant que typeCode et, sauf si défini, classCode), les heures de création et de service, l'auteur, la confidentialité, la langue et le format (corps structuré C-CDA 2.1 ou 1.1, XDS-SD, ou mimeTypeSufficient, à partir de ses modèles) ; et complétées par ce que le document ne dit pas : l'identifiant source_id de l'expéditeur, le facility_type et le practice_setting que chaque registre nécessite. La réponse du registre du référentiel décide de la livraison : une erreur, ou une erreur dans un PartialSuccess, est une livraison échouée avec les codes d'erreur du registre.
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. Ajoutez direct_from (votre adresse Direct) et direct_to (celle des destinataires) et la même destination envoie XDR comme transport Direct, comme le décrit le projet Direct *XDR et XDM pour la messagerie Direct* : un bloc d'adressage Direct (urn:direct:addressing) dans l'en-tête SOAP nomme l'expéditeur et les destinataires, et la soumission intendedRecipient nomme chaque destinataire (||^^Internet^address). Pointez url vers le point de terminaison XDR du destinataire ou un HISP qui accepte XDR. XDR voyage sur TLS, généralement avec un certificat client (tls), et n'est pas S/MIME. Une source direct prend également XDR (voir Direct ci-dessous).
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 et PDQ dans HL7 version 3. Avec l'index des patients activé (-mpi), /pixv3 est un gestionnaire PIX et /pdqv3 un fournisseur PDQ sur SOAP 1.2, pour les hôpitaux et les échanges qui utilisent encore les profils v3 d'IHE. Une source alimente les patients avec ITI-44 (enregistrement ajouté PRPA_IN201301UV02, révisé PRPA_IN201302UV02, doublons résolus PRPA_IN201304UV02): le premier identifiant du patient est son enregistrement, les autres et ceux dans asOtherIDs sont les identifiants qu'il porte, et une fusion plie l'identifiant de l'enregistrement précédent dans le survivant, comme le fait un A40 HL7 v2. ITI-45 (PRPA_IN201309UV02) répond aux autres identifiants de la personne qui détient l'un, étroitement lié à dataSource, dans Patient.id; l'identifiant interrogé revient uniquement dans la requête répétée. ITI-47 (PRPA_IN201305UV02) correspond aux données démographiques (nom, sexe, heure de naissance, identifiant, adresse, télécom) avec l'index de son propre correspondant, minimumDegreeMatch comme score sur 100, otherIDsScopingOrganization limitant les domaines, et initialQuantity paginant la réponse: le reste vient avec QUQI_IN000003UV01 pendant dix minutes, ou est abandonné par son annulation. Les réponses suivent les cas des transactions: un patient inconnu ou un domaine est AE avec erreur 204 et l'emplacement du paramètre, un patient connu avec rien dans les domaines demandés est NF. v3 nomme une autorité par OID uniquement, donc un identifiant dont le système est une URL sans OID derrière (certains numéros nationaux) est laissé hors des réponses v3 et transmis via FHIR; définissez le système de l'identifiant d'entreprise sur un OID (urn:oid:..., dans les paramètres de l'index) pour l'EUID et le custode pour apparaître. Le rôle du visionneur interroge et le rôle de l'opérateur alimente; chaque transaction est audité avec un identifiant, jamais un nom. Un message v3 nu publié comme application/xml est répondu de la même manière, ce qui est pratique pour les tests manuels.
Échange › Partage de documents affiche ce que le registre contient et où il est accessible, trouve les documents d'un patient dans ce registre ou un autre (un registre ITI-18 ou une passerelle ITI-38), télécharge un document, et publie un document CDA manuellement avec les métadonnées qu'une destination lui donnerait.
Vérifié contre l'outil XDS de NIST 7.13.0, la mise en œuvre de référence IHE : ITI-41, ITI-18 et ITI-43 de Perfuse contre son simulateur de Registre/Référentiel (accepté sans erreur de validation, le document récupéré byte-identique), et son simulateur de passerelle d'initiation qui interroge et récupère à partir de la passerelle de réponse de Perfuse via XCA, sans erreur dans son journal. Chaque message SOAP que Perfuse écrit est valide par rapport aux schémas ebXML Registry 3.0 et XDS.b, et le DocumentReference et le SubmissionSet MHD par rapport à IHE MHD 4.2.2 avec le validateur FHIR HL7. Le XDR à partir d'une destination xds avec un bloc d'adressage Direct a été accepté par le simulateur de destinataire de document de l'outil, dont la validation des métadonnées a trouvé le défaut décrit dans docs/verification.md, et par le validateur XDR de SITE ONC, la liste de contrôle XDR Direct du test de certification (h)(2) applicable. Les réponses PIX et PDQ v3 sont valides par rapport aux schémas HL7 V3 IHE (NE2008 multicacheschemas), et les messages échantillons IHE (l'alimentation ITI-44, la fusion, la requête ITI-45, la requête ITI-47, la continuation et l'annulation) sont répondus comme le montrent leurs réponses publiées. Pas encore vérifié contre une mise en œuvre PIX ou PDQ v3 indépendante, Gazelle ou un Connectathon.
8.9 Messagerie sécurisée directe
Direct est la façon dont les prestataires de soins américains s'envoient des références, des résumés et des résultats par courrier électronique sécurisé: chaque message est signé avec le certificat de l'expéditeur et chiffré pour le certificat du destinataire (S/MIME), et voyage entre les HISP (Health Information Service Providers) qui émettent les adresses et les authentifient. Perfuse est le système de bord à côté de votre HISP, et non un HISP: le HISP émet votre adresse, son certificat et sa clé, et vous gardez son lot de confiance (tel que DirectTrust). Il suit la Déclaration d'applicabilité Direct pour le transport de santé sécurisé 1.2, le Guide de mise en œuvre pour la notification de livraison, IHE XDM (Annexe 15 du TF-1 d'IHE) pour les documents avec des métadonnées, le Guide de mise en œuvre de la découverte de certificat pour le projet Direct (DNS et LDAP), et XDR et XDM pour la messagerie 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
Réception. Une source direct est le serveur SMTP que le HISP utilise pour livrer le courrier à votre adresse. Il n'accepte que le courrier destiné à cette adresse (tout autre courrier est refusé au niveau RCPT), exige STARTTLS lorsqu'un certificat est fourni et ouvre chaque message avant que quoi que ce soit ne puisse le lire : il le déchiffre avec votre clé, vérifie la signature par rapport à vos ancres et vérifie que le certificat de signature est pour l'adresse From ou son domaine. Un message qui n'est pas chiffré S/MIME, qui est signé par un expéditeur que vous ne faites pas confiance ou qui est signé par un certificat pour quelqu'un d'autre est refusé au niveau DATA avec la raison, de sorte que le HISP le conserve et le signale à l'expéditeur ; Perfuse n'accepte jamais ce qu'il refuse ensuite. Un package XDM voit ses documents devenir des messages (vérifiés contre les hashes de ses métadonnées) ; sinon, chaque pièce jointe le devient, ou le texte si aucun n'existe. Avec smtp_host défini, chaque message pris en charge est répondu par une notification « traité » signée et chiffrée (MDN), et les notifications arrivant pour ce que vous avez envoyé sont consignées.
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
À partir de la boîte aux lettres du HISP. Un HISP qui conserve le courrier électronique au lieu de le livrer donne à l'adresse une boîte aux lettres IMAP : imap la lit (TLS ou STARTTLS, chaque sondage étant une nouvelle session), ouvre chaque message comme ci-dessus, déplace ce qui a été pris vers move_to (ou le supprime) et ce qui n'a pas pu être ouvert vers error_folder, afin que rien ne soit lu deux fois. listen peut alors être laissé de côté. Un HISP dont le serveur de messagerie a un certificat privé est confié avec tls.ca_file (son certificat, ou celui de son autorité) et tls.server_name; la vérification ne peut pas être désactivée.
imap:
host: imap.hisp.example
username: intake@direct.clinic.example
password: ${DIRECT_MAILBOX_PASSWORD}
move_to: Processed
XDR. xdr prend en charge XDR à l'adresse /xdr sur son propre adresse HTTPS, comme un HISP envoie Direct sous forme de SOAP ou qu'un partenaire envoie point à point : une demande ITI-41 Provide and Register dont chaque document devient un message. Une soumission dont le bloc d'adressage Direct nomme une autre adresse est refusée, et celle que le canal n'accepte pas est répondue avec une réponse de registre d'échec indiquant pourquoi. client_ca_file nécessite un certificat client de ces autorités. XDR est protégé par TLS, et non par S/MIME, donc une source qui n'accepte que XDR a besoin de l'adresse mais pas de son certificat, de sa clé ou de ses ancres. Chaque document devient un message du type de données dataType du canal : les documents CDA nécessitent raw (transmis tels quels) ou hl7v3, puisque la valeur par défaut, hl7, attend HL7 v2 et les refuse.
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 liste les adresses Direct que vos canaux envoient et reçoivent, avec leurs certificats, dates d'expiration et ancres ; conserve le carnet d'adresses des correspondants (nom, organisation, notes et certificat, collés à partir de leur HISP ou trouvés dans DNS ou LDAP, et refusés lorsqu'ils ne sont pas pour cette adresse ou ce domaine) ; et recherche les certificats d'une adresse dans DNS ou LDAP sans les enregistrer. Le carnet est le répertoire direct-certs à côté de la base de données, un fichier PEM par adresse ou domaine, que une destination lit à moins qu'elle ne nomme son propre recipient_certs_dir.
Vérifié contre OpenSSL 4.0 avec les commandes cms et smime dans les deux sens : ce que Perfuse signe et crypte, OpenSSL vérifie et déchiffre (PKCS#1 v1.5 et transport de clés OAEP), et Perfuse ouvre ce que OpenSSL signe et crypte (AES-128 et AES-256). Un message créé avec openssl smime et livré via SMTP est reçu, ouvert et stocké par un canal, et l'un envoie un message à un autre via un substitut HISP, qui répond avec un MDN que l'expéditeur ouvre. Les certificats sont trouvés dans OpenLDAP 2.4 (liés à une adresse et à un domaine, écrits par la commande ldapadd d'OpenLDAP) ; un message Direct est lu à partir d'une boîte de réception IMAP GreenMail et ouvert, et celui qui n'est pas Direct est déplacé vers le dossier d'erreurs ; XDR provenant d'une destination xds est pris en charge par une source direct et refusé lorsqu'il est adressé à quelqu'un d'autre, et accepté par le kit de outils Document Recipient de NIST XDS et le validateur XDR du site ONC ; l'outil de test Edge XDR Direct du site a envoyé ses messages de métadonnées minimaux et complets à une source direct, qui les a acceptés. Par rapport à l'outil de découverte de certificats Direct d'ONC, une destination Direct choisit le bon certificat, ou aucun, dans tous les 18 cas de découverte (D1 à D18 : certificats expirés, révoqués et émis par AIA, priorité et poids SRV, répertoire inaccessible). Une source Direct lit un message à partir du HISP propre au site (Apache James) via IMAP avec STARTTLS. Non encore testé : échange SMTP avec le HISP du site (AWS bloque le courrier sortant sur le port 25 pour les nouveaux comptes) ou avec un HISP agréé.
8.10 SQL sur les vues FHIR
Une ViewDefinition (HL7 SQL sur FHIR v2) transforme chaque ressource FHIR d'un type en lignes de colonnes nommées, chaque colonne étant une expression FHIRPath, de sorte que les données FHIR puissent être lues comme des tableaux par DuckDB, Athena, Spark, un entrepôt de données ou une feuille de calcul. Perfuse les exécute avec son propre moteur FHIRPath : column, select imbriqué, forEach, forEachOrNull, repeat et unionAll, where, constant (tous les types de valeur[x]), colonnes collection, %rowIndex et les clés de jointure getResourceKey() et 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" }
]}]
}
Surveiller › SQL sur FHIR exécute une vue sur le magasin FHIR de ce serveur (un patient, ou tous) ou sur des ressources collées (NDJSON à partir d'une exportation en bloc, un Bundle, un tableau JSON), affiche les lignes et les télécharge sous forme de CSV, NDJSON ou Parquet. Il commence avec cinq vues exemples (données démographiques des patients, observations avec une valeur, tension artérielle, affections, rencontres) et enregistre les vues dans le répertoire views à côté de la base de données, un fichier JSON chacune.
Le point de terminaison FHIR répond à la spécification $sql-run au niveau du système, par GET ou POST, pour une définition de vue donnée en ligne (subjectResource), par subjectReference (ViewDefinition/<name>, une vue enregistrée) ou par subjectCanonical (l'url d'une vue enregistrée), avec _format (csv, ndjson (par défaut), json ou parquet), header, patient, _since, _limit, et resource pour exécuter sur les ressources envoyées avec la demande au lieu du magasin. C'est une lecture : un jeton SMART nécessite une portée de lecture pour le type de ressource de la vue, un jeton lié à un patient n'obtient que les lignes de ce patient, et les portées granulaires restreignent les ressources lues, comme elles le font pour une recherche. Plus d'un million de lignes nécessite _limit, patient ou _since.
perfuse sof -view v.json [-format csv|ndjson|json|parquet] [-o out] files... exécute une vue sur des fichiers FHIR sans serveur : les fichiers NDJSON d'une exportation en bloc, des Bundles ou des tableaux.
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"
Les fichiers Parquet ont un groupe de lignes et des pages PLAIN non compressées ; les booléens sont BOOLEAN, les types entiers INT64, les décimales DOUBLE et tout le reste des chaînes UTF-8 (une colonne de collection en tant que JSON).
Vérifié avec le référentiel de tests officiel SQL sur FHIR (les 144 tests du référentiel sql-on-fhir.js tests/, exécutés sur chaque build : tous passent), et la sortie Parquet lue à nouveau par DuckDB 1.5.6 avec les types et les valeurs corrects. Non pris en charge : SQLQuery et les bibliothèques SQLView (SQL sur les tableaux des vues), $sql-export, _format=fhir et les paramètres source et group ; chacun est refusé avec la raison.
8.11 Mesures de qualité numériques
Une mesure de qualité numérique compte les patients dans chaque population d'une mesure FHIR (Measure) sur une période de mesure (population initiale, dénominateur, exclusions et exceptions du dénominateur, numérateur, exclusions du numérateur) et évalue le résultat. La réponse est un rapport de mesure FHIR (MeasureReport), conçu comme le guide Da Vinci Data Exchange pour les mesures de qualité (DEQM) le demande. C'est là que les programmes eCQM de la CMS et les mesures numériques HEDIS de la NCQA sont en train d'aller.
Dans Perfuse, les critères de population sont FHIRPath ("language": "text/fhirpath"), exécutés par le même moteur que SQL sur FHIR. Chaque critère est évalué une fois par patient. Son point de focalisation est un Bundle du dossier du patient (le compartiment Patient), et il dispose de ces variables : %subject (le Patient), %periodStart et %periodEnd (la période, sous forme de dateTimes) et %"Measurement Period". Un critère donne vrai ou faux ; une seule valeur existante compte comme vrai.
{
"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()"
}
}
Les populations sont imbriquées comme le spécifie la spécification de la mesure. Un patient n'est dans le dénominateur que s'il est dans la population initiale. Une exclusion du dénominateur retire le patient avant que le numérateur ne soit jugé. Une exception du dénominateur ne compte que pour un patient qui n'est pas dans le numérateur. Le score d'une proportion est (numérateur − exclusions du numérateur) / (dénominateur − exclusions − exceptions) ; celui d'un ratio est numérateur / dénominateur ; un regroupement a des comptes et aucun score. Les stratificateurs à critère unique divisent chaque population par leurs valeurs (le sexe, par exemple).
Perfuse n'a pas de moteur CQL. Les mesures eCQM publiées de la CMS et les mesures numériques HEDIS sont écrites en CQL, elles ne peuvent donc pas être exécutées telles quelles. Une mesure dont les critères sont CQL est refusée avec cette raison. Écrivez la logique en FHIRPath à la place. L'évaluation de variables continues, les stratificateurs multicomposants et les sujets de groupe ou de praticien sont refusés de la même manière.
Monitor › Mesures de qualité évalue une mesure sur le stockage FHIR de ce serveur ou sur des ressources collées, pour une période. Il offre trois rapports : un résumé, un résumé avec les patients de chaque population, ou un patient. L'écran affiche les populations, le score et les strates, et télécharge le MeasureReport. Il commence avec trois exemples : la pression artérielle sous contrôle, le diabète avec un test HbA1c, et les patients vus pendant la période. Ils sont illustratifs, écrits pour ce manuel, et ne sont pas des mesures eCQMs ou HEDIS de la CMS. Enregistrer dans le stockage FHIR vérifie la mesure et la stocke en tant que ressource Measure.
Le point de terminaison FHIR répond à Measure/[id]/$evaluate-measure et Measure/$evaluate-measure?measure=<url>, par GET ou par POST d'une ressource Parameters. Paramètres :
periodStartetperiodEnd: obligatoires. Une date signifie toute la journée.reportType:summary,subjectousubject-list.subject:Patient/<id>.reporter:Organization/<id>. Lorsqu'il est absent, le rapport contient une organisation nommée parserve -measure-reporter.measure: une mesure envoyée en ligne, en tant que paramètre POST.
Le rapport est renvoyé, pas stocké. L'opération est une lecture, donc un jeton SMART nécessite un accès en lecture à la mesure et au patient. Un jeton lié à un patient obtient un rapport individuel sur ce patient et sur aucun autre.
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... évalue une mesure sur des fichiers FHIR (une exportation bulk NDJSON, des bundles, des tableaux) sans serveur. -measure example:example-bp-control exécute un exemple expédié, et -examples les liste.
Vérifié. Le validateur HL7 FHIR vérifie les Mesures livrées par rapport à FHIR R4, sans erreurs. Il vérifie un résumé, un rapport de mesure individuel et un rapport de mesure de liste de sujets par rapport aux profils de résumé, individuel et de liste de sujets DEQM 5.0.0, également sans erreurs. Non vérifié : l'équivalence avec toute mesure eCQM publiée, puisqu'aucune ne peut être exécutée ici sans CQL.
8.12 l'index des patients
Un index de patients maîtres relie les enregistrements que chaque système conserve pour une personne (le MRN de l'hôpital, celui de la clinique, celui du laboratoire) en un identifiant d'entreprise unique, l'EUID. Il est désactivé jusqu'à ce que quelqu'un décide de le conserver, car il s'agit d'un tableau de noms de patients, de dates de naissance et d'identifiants : activez Paramètres → Données → Index de patients (ou serve -mpi) et redémarrez. Il se trouve dans mpi.db à côté de la base de données principale.
Alimentation. Ajoutez une destination de type mpi (L'index de patients dans le constructeur) aux canaux qui transportent les enregistrements. Il lit le PID de chaque message HL7 v2, ou un patient FHIR sur un canal brut. L'identifiant propre de l'enregistrement est la répétition PID-3 de type MR (id_type le modifie) ; les autres, et PID-19, deviennent ses autres identifiants. Une autorité d'attribution avec un identifiant universel (PID-3.4.2 avec type ISO) devient urn:oid:... ; une avec seulement un espace de noms est mappée par authorities, ou devient urn:perfuse:aa:<namespace>. Un A40, A34, A18 ou A39 fusionne la personne détenant l'identifiant de MRG-1 dans la personne détenant PID-3 (no_merge les ignore).
destinations:
- name: index
type: mpi
mpi:
authorities: { HOSP: "urn:oid:1.2.840.114350.1.13.1" }
Appariement. Un nouvel enregistrement est lié dans cet ordre :
- Identificateurs de confiance. Un enregistrement partageant un identifiant d'un système répertorié comme de confiance (un identifiant national, un numéro d'entreprise) est la même personne, sans notation. Ne jamais répertorier un système partagé par une famille, tel que le numéro d'abonné d'un payeur.
- Score. Sinon, les personnes dont les enregistrements pourraient correspondre sont trouvées par blocage (le nom de famille sonore et l'année de naissance, la date de naissance, ou le même numéro de téléphone) et notées avec des pondérations Fellegi-Sunter sur le nom de famille et le prénom (Jaro-Winkler et Soundex, accents et ponctuation ignorés, noms échangés détectés), la date de naissance (un jour et un mois échangés est un accord partiel), le sexe, le code postal, le téléphone et l'adresse. Seuls les champs que les deux enregistrements possèdent comptent. Le score est la preuve trouvée en tant que part de la preuve possible. Le blocage utilise cinq clés, donc une erreur ne cache pas une personne : sonorité du nom de famille et année de naissance, date de naissance, téléphone, sonorité des deux noms (dans n'importe quel ordre), et code postal avec la sonorité du prénom.
- Décision. Par défaut, rien ne relie sur un score seul. Un enregistrement noté à ou au-dessus du seuil d'examen (60 %) devient une nouvelle personne et le match possible attend sur la file d'attente d'examen ; ceux à ou au-dessus du seuil automatique (90 %) avec le nom de famille et la date de naissance tous deux en accord sont marqués *certain*. Le lien entre deux personnes en une seule (un chevauchement) place les résultats d'un patient dans le graphique d'un autre, donc le lien automatique est un commutateur qu'un administrateur active (Lier les correspondances certaines sans demander à personne) une fois que la file d'attente a montré que les certaines sont correctes. Avec cela activé, une correspondance certaine lie lorsqu'aucune deuxième personne n'obtient un score aussi élevé. En dessous du seuil d'examen, l'enregistrement est une nouvelle personne.
Numéros nationaux. Le numéro NHS (et l'Écosse CHI et le numéro de soins et de santé de l'Irlande du Nord), le PPSN et l'IHI d'Irlande, le KVNR d'Allemagne, le SVNR d'Autriche, le numéro AHV de Suisse, le BSN des Pays-Bas, le numéro du registre national de Belgique, le matricule du Luxembourg, l'INS (NIR et NIA) de France, le codice fiscale d'Italie, le DNI/NIE et le CIP-SNS d'Espagne, le numéro SNS du Portugal, les numéros personnels nordiques (Suède, Danemark, Norvège avec son numéro D, Finlande, Islande), les codes baltes, le PESEL de Pologne, les numéros de naissance tchèque et slovaque, et les numéros hongrois, roumain, bulgare, croate, slovène et grec sont connus de l'index. Chacun est stocké d'une seule façon : sous son système de schéma, espaces et points supprimés, donc le numéro NHS envoyé sous la forme urn:oid:2.16.840.1.113883.2.1.4.1|999 000 0018 par un système et sous la forme https://fhir.nhs.uk/Id/nhs-number|9990000018 par un autre est un identifiant unique. Une répétition PID-3 HL7 v2 dont le type d'identifiant est NN et un code de pays à trois lettres (NNDEU, NNNLD) est lu comme le numéro principal de ce pays, et le type NH de l'autorité NHS comme le numéro NHS. Le chiffre de contrôle de chaque numéro est testé : un qui échoue est conservé sur son enregistrement, signalé (masqué) dans la réponse, et n'est jamais utilisé pour relier ou trouver quelqu'un, puisque généralement un chiffre mal tapé fait le numéro de quelqu'un d'autre. Le CPR du Danemark est vérifié pour sa date uniquement, car les numéros délivrés depuis 2007 n'ont pas besoin de passer l'ancien modulus 11.
La liste des paramètres répertorie chaque schéma avec son format, sa vérification et le système dans lequel il est stocké. Les systèmes issus du guide FHIR propre au pays (UK Core, fhir.de, Nictiz, CH Core, ANS, HL7 Italia, MedCom, les registres OID suédois, norvégien et finlandais) sont marqués comme tels ; les autres sont des valeurs par défaut qui peuvent être modifiées pour correspondre à la valeur nationale, ce que chaque site peut faire pour chaque schéma (l'ancienne valeur est toujours reconnue). Faire confiance à un schéma nécessite un seul clic. Les numéros nationaux sont affichés en entier aux éditeurs et par défaut, et masqués (les derniers caractères) pour tous les autres ; Qui voit les numéros en entier modifie cela, jusqu'aux visionneurs ou uniquement aux administrateurs. Lorsqu'une loi d'un pays limite l'utilisation d'un numéro (Référentiel INS de la France, PPSN de l'Irlande, numéro de registre national de la Belgique, §290 SGB V de l'Allemagne), les paramètres le précisent. GET /api/mpi/schemes répertorie les schémas et POST /api/mpi/check vérifie un numéro sans le stocker. FHIR $match et PIXm répondent aux clients autorisés avec des numéros en entier.
Une date écrite jour- ou mois-premier (08/15/1972) est conservée telle quelle et ne correspond pas à une date écrite année-première : les ordres américain et européen ne sont pas d'accord, et deviner lierait les mauvaises personnes.
L'écran d'indexation des patients (Build) affiche les comptes, trouve des personnes par nom, numéro, EUID ou date de naissance, et ouvre chaque personne : leurs dossiers, chaque identifiant, et l'historique de ce qui leur est arrivé et qui l'a fait. Les éditeurs décident des examens (Même personne les lie ; Personnes différentes les garde séparées pour toujours), déplacent un dossier vers une autre personne, retirent un dossier (Pas cette personne), et fusionnent deux personnes. Les administrateurs définissent les seuils, les systèmes d'identifiant de confiance, les numéros nationaux et le système EUID. Chaque recherche et chaque personne lue sont écrites dans le journal d'audit.
Répondre aux autres. POST /fhir/Patient/$match (l'opération FHIR, comme IHE PDQm utilise ITI-119) prend un Patient et retourne les personnes qui pourraient être celles-ci, classées par ordre de pertinence, chaque Patient dont l'ID est l'EUID, avec chaque identifiant, search.score, et l'extension de grade de correspondance (certain, probable, possible) ; onlyCertainMatches et count sont respectés. PIXm (/mhd/Patient/$ihe-pix, ITI-83) répond à partir de l'index : chaque identifiant de chaque enregistrement lié à la personne, et l'EUID. De même pour PIX et PDQ dans HL7 v3 (/pixv3, /pdqv3 ; voir le partage de documents IHE), qui l'alimentent également.
L'API est /api/mpi (résumé et recherche), /api/mpi/persons/{euid}, /api/mpi/find, /api/mpi/reviews, /api/mpi/records (enregistrement, lien, délien), /api/mpi/merge et /api/mpi/settings.
Poids. Les poids Fellegi-Sunter par défaut proviennent de la littérature sur le rapprochement de dossiers pour les données d'enregistrement hospitalier. Estimer à partir de nos dossiers (dans les paramètres, administrateurs ; POST /api/mpi/estimate) les adapte à l'index propre du site avec une expectation-maximisation, sans paires examinées nécessaires : m (accord entre les correspondances réelles) à partir des paires regroupées par le blocage, u (accord par hasard) à partir de 20 000 paires tirées au hasard, puisque les paires bloquées s'accordent sur les noms et les dates par construction. L'estimation est affichée à côté des poids utilisés et ne change rien jusqu'à ce qu'elle soit utilisée et enregistrée. Un champ comparé sur trop peu de paires conserve son poids par défaut. L'ajustement suppose que les champs sont indépendants étant donné la classe, ce qui n'est pas tout à fait le cas, donc traitez un grand changement avec suspicion.
Mesuré. Sur le jeu de données FEBRL 3 (5 000 dossiers synthétiques de 2 000 personnes, les doublons portant des erreurs de frappe, des champs échangés, des valeurs manquantes et des surnoms ; PERFUSE_TEST_FEBRL), enregistrés dans l'ordre du fichier avec un examinateur répondant correctement à chaque paire en attente :
| Liés par eux-mêmes | Placés devant un réviseur avec la bonne personne | Manqués | Liens incorrects | |
|---|---|---|---|---|
| Liaison automatique désactivée (par défaut) | 0 | 2 649 sur 3 000 | 351 | 0 |
| Activée, poids par défaut | 1 637 | 1 012 | 351 | 0 |
| Activée, poids estimés à partir des enregistrements | 1 622 | 1 070 | 308 | 0 |
Aucun dossier n'a jamais été lié à la mauvaise personne, et aucune des 2 000 nouvelles personnes n'a été inutilement en attente. Les personnes manquantes diffèrent sur presque tous les champs (une date de naissance et une adresse toutes deux mal tapées, par exemple) et obtiennent un score inférieur au seuil d'examen. FEBRL est synthétique et comporte peu de noms identiques ; un index réel en comporte plus, son file d'attente d'examen sera donc plus longue, et ces chiffres constituent un plancher pour les soins, et non une promesse.
8.13 Délimité
CSV et ses dérivés. Les options sont sur la source dans le constructeur, et la référence de format liste les clés de fichier.
Les chemins d'accès aux colonnes. Une colonne nommée est disponible lorsque une rangée d'en-tête est déclarée ou que les noms sont donnés ; sinon, les colonnes sont positionnelles.
8.13.1 Nommer les colonnes
Il existe deux façons de procéder, et elles sont exclusives. Soit la première rangée du fichier les nomme — la première rangée nomme les colonnes — soit vous les énumérez vous-même, dans l'ordre. Déclarer un en-tête signifie que la rangée n'est pas traitée comme des données.
Si aucune des deux options n'est définie, les colonnes ne peuvent être adressées que par position, donc un filtre écrit contre un nom n'a rien à correspondre. L'activation de l'en-tête supprime la liste des noms plutôt que de conserver les deux : avec un en-tête, les noms proviennent du fichier, donc une liste laissée derrière serait ignorée, et un canal qui lit comme s'il avait choisi les noms lorsque le fichier les a choisis est plus difficile à déboguer que celui qui refuse.
8.13.2 Ce que voit un filtre ou un script
Un document délimité devient plusieurs messages, il faut donc le préciser avant de rédiger l'un ou l'autre.
Avec la division activée, tout fonctionne par rangée. Les étapes déclaratives, le filtre et le script de transformation voient une rangée, et un chemin signifie *la colonne de cette rangée*. Un filtre qui rejette une rangée rejette cette rangée et aucune autre, et le nombre de messages reçus est le nombre de rangées plutôt que de documents.
Avec la division désactivée, le message est l'ensemble du document et une écriture qui traverse les rangées est refusée plutôt que d'être appliquée à la première. Ce refus est délibéré : écrire silencieusement dans la première rangée est le comportement qui produit un fichier qui semble transformé et ne l'est pas.
8.13.3 Les trois qui changent ce qui constitue une erreur
Accepter les rangées avec le mauvais nombre de colonnes est désactivé par défaut. Une rangée avec trop de colonnes ou trop peu de colonnes est alors une erreur, ce qui permet de détecter un fichier dont la forme a changé sans avertissement. L'activation de cette option accepte la rangée et laisse les colonnes manquantes vides.
Supprimer les espaces autour de chaque valeur corrige le cas courant d'une valeur rembourrée à la largeur de la colonne. Laissez-le désactivé lorsque les espaces de fin sont significatifs, ce qui arrive occasionnellement dans un identifiant.
Conserver les lignes vides comme rangées est désactivé par défaut et devrait généralement l'être. Activé, une ligne vide devient une rangée de colonnes vides, ce qui ne compte que lorsque le nombre de messages doit correspondre exactement au fichier.
8.14 Brut
Aucune analyse n'est effectuée. Le message est un ensemble d'octets.
Utilisez cela lorsque le contenu n'est pas quelque chose que Perfuse comprend et n'a pas besoin de comprendre : un PDF déplacé entre les systèmes, un format propriétaire, un document déjà formé transmis inchangé.
Le coût est que rien de ce qui dépend de la structure ne fonctionne — aucune transformation au niveau du champ, aucun filtre sur un champ, aucune comparaison au niveau du champ dans le vérificateur de parité. Un canal brut est un tuyau, et il est honnête à ce sujet.
8.15 Choisir
Si le message est HL7 v2, utilisez hl7, même si vous n'avez l'intention de le transmettre inchangé. L'analyse vous donne la trace, les statistiques au niveau des champs, la possibilité de filtrer plus tard et la possibilité de comparer. raw sur du contenu analysable ne rapporte rien et fait perdre tout cela.
Utilisez raw lorsque l'analyse échouerait ou serait un mensonge sur le contenu.
8.16 Liens et cartes de santé SMART
*Kill the Clipboard* de CMS demande aux prestataires de soins d'accepter les dossiers d'un patient à partir d'un code QR lors de l'enregistrement, et de remettre le dossier de visite de la même manière. Le code QR contient un lien de santé SMART (shlink:/...) : une adresse, une clé de 256 bits et, facultativement, une étiquette, une date d'expiration et un indicateur de code d'accès. Échange → Liens de santé lit l'un d'eux.
Réception. Collez le lien ou scannez-le avec l'appareil photo lorsque le navigateur le peut (Chrome et Edge). Perfuse récupère le manifeste, déchiffre chaque fichier avec la clé du lien, résume tout paquet FHIR - qui est le patient, combien de chaque ressource - et vérifie toute carte de santé SMART à l'intérieur contre la clé publiée de son émetteur. *Livrer au canal* remet le contenu FHIR au canal en tant que message, c'est ainsi qu'il atteint le dossier électronique de santé. La récupération est limitée à la politique de sortie au moment de la connexion, le HTTP pur est refusé, et la réponse d'un serveur qui n'est pas un serveur de manifeste n'est jamais affichée, car l'adresse provient d'un code QR étranger.
Partage. *Partager* crypte un paquet FHIR, l'héberge et affiche le lien et son code QR une fois. Le serveur conserve le texte chiffré et non la clé - il ne peut pas ouvrir ce qu'il héberge, et ne peut pas afficher le lien à nouveau. Un code d'accès est haché ; dix codes d'accès incorrects désactivent le lien. Les liens expirent après 30 jours par défaut, peuvent être révoqués et répertorient combien de fois et par qui ils ont été récupérés. Démarrez le serveur avec -public-url défini sur l'adresse https que les téléphones des patients atteignent ; l'URL du manifeste qu'il construit doit correspondre aux 128 caractères de la spécification.
Vérifier une carte. *Vérifier une carte* prend un code QR numérique shc:/ (un bloc ou plusieurs), un fichier .smart-health-card ou un JWS, et indique si la signature correspond à la clé de l'émetteur.
8.17 UN/EDIFACT
dataType: edifact lit les échanges UN/EDIFACT (ISO 9735) : ORDERS, INVOIC, DESADV, IFTSTA et le reste, y compris les messages de santé européens et de laboratoire. La chaîne de service (UNA) est respectée, avec le caractère de fin et, pour la version de syntaxe 4, le séparateur de répétition ; les groupes fonctionnels (UNG/UNE) sont facultatifs. L'échange est livré exactement tel que l'expéditeur l'a écrit.
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"'
L'enveloppe. Le comptage de segments UNT et la référence, le comptage de messages UNE et la référence, et le comptage UNZ et la référence sont comparés à ce que contient l'échange. Avec require, la valeur par défaut, une erreur de correspondance refuse l'échange (c'est ainsi qu'une coupure de transfert est affichée) ; warn l'accepte et enregistre un avertissement ; ignore ne vérifie pas.
Chemins, pour les filtres de canal et de destination, comptent les éléments et les composants à partir de 1 dans l'ordre où le segment est écrit, comme les guides de mise en œuvre les numérotent : BGM-2 (le numéro de document), BGM-1.1, NAD(2)-2.1 (la partie du deuxième NAD), LIN-3(2).1 (une répétition), UNB-2.1 (l'expéditeur), UNH-2.1 (le type de message). Un chemin sans occurrence s'adresse à tous.
La division livre un échange par message, chacun avec l'UNB original (et l'en-tête de groupe) et les remorques qui comptent un, afin qu'une commande puisse être filtrée, recherchée et réessayée seule. Les filtres de destination voient chaque pièce. Une destination de fichier nomme les fichiers par type de message (ORDERS_INVOIC-20261017.edi), et ${control_id} est la référence d'échange.
CONTRL. Avec acknowledge: contrl, un expéditeur publiant via HTTP reçoit une réponse avec une syntaxe CONTRL et un rapport de service : action UCI 7 lorsque l'échange a été lu et livré, 4 lorsqu'il a été refusé ou n'a pas pu être delivré (HTTP 400 ou 502 alors). Il ne peut pas être combiné avec split, puisqu'un CONTRL répond à un échange complet. Via AS2, le reçu du partenaire est l'accusé de réception.
Non proposé : les répertoires de messages (qui segmentent les ORDERS D.96A), donc la structure est vérifiée, et non le contenu ; les transformations, qui réécriraient un document de partenaire ; et les scripts de filtre ou de transformation (un préprocesseur s'exécute avant l'analyse). Vérifié contre pydifact 0.1.8, un analyseur indépendant, dans les deux sens.
9 Accusés de réception
Un accusé de réception indique à l'expéditeur ce qui s'est passé. Pour HL7 v2 sur MLLP, c'est un message ACK; l'expéditeur n'enverra pas le prochain message jusqu'à ce qu'il arrive, et le renverra généralement s'il ne le fait pas.
Se tromper sur les accusés de réception est la façon la plus courante pour une intégration de perdre silencieusement des données, car un expéditeur qui est accusé de réception n'a aucune raison de se plaindre.
9.1 Chronométrage
Couvert dans flux de message, et le résumé est: ack.when est on_delivery par défaut, ce qui signifie que l'accusé de réception est envoyé uniquement après que chaque destination activée ait accepté le message. on_receipt l'envoie dès que le message est analysé et mis en file d'attente.
9.2 Ce que Perfuse envoie
Un AA lorsque le message a été accepté, un AE lorsqu'il a été rejeté pour une raison que l'expéditeur pourrait résoudre, et un AR lorsqu'il a été rejeté pour une raison que l'expéditeur ne peut pas résoudre.
La distinction entre AE et AR est qui doit faire quelque chose. AE signifie que le message avait un problème - un champ qui ne pouvait pas être analysé comme une date, un segment requis manquant - et que l'expéditeur peut le corriger et le renvoyer. AR signifie que Perfuse ne pouvait pas accepter le message, quel que soit son contenu, ce qui signifie généralement un problème de configuration ou de disponibilité à cette extrémité. Un expéditeur qui renvoie après un AR obtiendra la même réponse.
9.3 Identification de ce moteur
ack.application et ack.facility remplissent MSH-3 et MSH-4 de l'accusé de réception.
Lorsque les deux sont vides, l'accusé de réception reflète le récepteur d'origine — il utilise ce que le message entrant avait dans MSH-5 et MSH-6. C'est ce que la plupart des expéditeurs attendent, et c'est la valeur par défaut pour cette raison.
Définissez-les explicitement lorsque l'expéditeur les valide, ou lorsque plusieurs instances de Perfuse gèrent le même flux et que vous devez savoir laquelle a répondu.
9.4 L'événement déclencheur
ack.include_trigger_event envoie ACK^A01 plutôt qu'un simple ACK.
Certains récepteurs l'exigent et d'autres le rejettent, ce qui explique pourquoi il s'agit d'une option explicite sans valeur par défaut intelligente. Si un expéditeur refuse vos accusés de réception et que le contenu semble correct, c'est la première chose à essayer.
9.5 Les accusés de réception négatifs ne sont pas des échecs à cacher
Un NACK traité comme un succès est l'une des configurations les plus préjudiciables possibles, et il est suffisamment courant pour être digne d'être nommé. Cela se produit lorsque une destination envoie un accusé de réception négatif et que le côté expéditeur enregistre la *transmission* comme réussie parce que les octets sont sortis et que quelque chose est revenu.
Perfuse lit l'accusé de réception qu'il reçoit d'une destination MLLP et enregistre le résultat en conséquence. Un AE ou AR d'un système en aval est un échec de livraison, est réessayé conformément à la politique de la destination, et compte dans le taux d'échec qui déclenche les alertes.
9.6 Délais d'attente
L'attente d'un accusé de réception est limitée. Lorsqu'il n'arrive pas à temps, la livraison est un échec et est mise en file d'attente pour une nouvelle tentative.
Un délai d'attente n'est pas la même chose qu'un rejet et est enregistré différemment. Un rejet signifie que le côté distant a examiné le message et l'a rejeté ; un délai d'attente signifie que vous ne savez pas s'il a été traité. Cette distinction décide si une nouvelle tentative est sûre : réessayer après un rejet est inutile, et réessayer après un délai d'attente risque de créer un doublon. Perfuse réessaie après un délai d'attente, car un message clinique manquant est généralement pire qu'un doublon, et le système récepteur est généralement capable de détecter un ID de contrôle de message répété.
Que cet échange soit approprié pour un flux donné est un jugement, et il vaut la peine de le faire délibérément pour tout ce qui a une conséquence clinique — une commande, une administration de médicament — plutôt que d'accepter la valeur par défaut silencieusement.
9.7 Les sources qui ne font pas d'accusé de réception
Non tous les transports ont le concept. Une source de fichiers n'a nulle part où envoyer un accusé de réception ; une source de courtier en accuse réception au courtier plutôt qu'à l'expéditeur d'origine ; une source HTTP répond avec un code de statut.
Lorsque la source ne peut pas livrer le mode d'accusé de réception demandé par un canal, le canal est refusé au chargement plutôt que de démarrer et de ne pas accuser réception silencieusement. Un canal qui croit accuser réception et ne le fait pas est pire qu'un canal qui ne démarre pas.
9.8 Accusés de réception X12
Tout ce qui précède concerne HL7 v2. X12 a ses propres accusés de réception, et contrairement à v2, ils sont désactivés par défaut : un paramètre vide signifie aucun.
Cette valeur par défaut est la plus sûre, car un partenaire commercial qui n'attend pas d'accusé de réception et qui en reçoit un peut le traiter comme un échange non sollicité. La clé acknowledge sur un canal X12 prend l'une des quatre valeurs :
| Valeur | Ce qui est envoyé |
|---|---|
none | Rien. La valeur par défaut. |
999 | Accusé de réception d'implémentation. Remplace le 997 pour les transactions HIPAA. |
997 | Accusé de réception fonctionnel. Plus ancien, et toujours ce que de nombreux connecteurs de payeur attendent. |
ta1 | Accusé de réception d'échange, concernant l'enveloppe plutôt que son contenu. |
Laquelle envoyer est une propriété de la relation de partenaire commercial plutôt que du message, c'est pourquoi elle doit être configurée et ne peut pas être déduite. Un 999 remplace un 997 pour les transactions HIPAA, mais de nombreux partenaires — des connexions de payeur plus anciennes en particulier — sont configurés pour attendre un 997 et traiteront un 999 comme un fichier non reconnu.
9.9 Accusés de réception HL7 v3
Un canal HL7 v3 envoie un accusé de réception par défaut, ce qui est le contraire de X12 et vaut la peine de le savoir.
La raison est le transport plutôt que la norme : une interaction v3 arrive généralement sur une connexion synchrone avec l'application d'envoi en attente d'une réponse, et un expéditeur qui ne reçoit rien réessayera généralement. C'est ainsi qu'un patient est enregistré trois fois.
La désactivation est possible et doit être effectuée explicitement — « non défini » et « défini sur false » sont délibérément différents, donc la valeur par défaut est maintenue à moins que quelqu'un ne l'ait spécifié autrement.
10 Livraison, mise en file d'attente et nouvelle tentative
Une destination qui ne peut pas être atteinte est le cas normal, et non l'exception. Les systèmes redémarrent, les réseaux tombent, et un moteur d'interface hospitalier est indisponible pendant sa propre fenêtre de maintenance. La livraison est conçue autour de cela.
10.1 File d'attente par destination
Chaque destination a sa propre file d'attente. Une destination qui échoue n'affecte pas les autres, et chacune a sa propre profondeur, âge et état de nouvelle tentative.
La mise en file d'attente est effectuée par destination plutôt que par canal, car la défaillance est par destination. Une file d'attente pour l'ensemble du canal bloquerait la livraison à trois systèmes fonctionnels parce qu'un quatrième est hors service, et les deux situations — une destination indisponible, les quatre destinations indisponibles — sembleraient identiques dans les statistiques.
10.2 Paramètres de file d'attente
queue on a destination:
| Clé | Fonction |
|---|---|
enabled | Les messages échoués sont-ils mis en file d'attente ? |
max_attempts | Nombre de tentatives avant d'abandonner. |
backoff | Attente avant la première nouvelle tentative. |
max_backoff | Plafond de l'attente croissante. |
max_depth | Nombre maximum de messages à conserver. Non défini signifie pas de limite. |
retain_hours | Durée pendant laquelle un message livré est conservé. Non défini le conserve indéfiniment. |
Les deux derniers éléments manquaient à ce tableau et au constructeur, et ils constituent la paire qui empêche un disque de se remplir. Une file d'attente sans l'un ou l'autre de ces éléments grandit jusqu'à ce que le système de fichiers soit plein, et cette défaillance se manifeste comme une erreur sans rapport avec le problème de file d'attente — une erreur d'écriture se produisant ailleurs — plutôt que comme un problème de file d'attente.
L'attente croissante augmente entre les tentatives jusqu'à max_backoff. L'attente croissante plutôt que fixe, car une destination qui est hors service est généralement hors service pendant des minutes plutôt que des secondes, et réessayer toutes les secondes pendant dix minutes produit plusieurs centaines d'entrées de journal qui cachent celle qui compte.
10.3 L'ordre est préservé
Au sein d'une destination, les messages sont livrés dans l'ordre d'arrivée, et un message qui échoue conserve sa place. Les messages suivants attendent derrière lui plutôt que de le dépasser.
C'est le paramètre par défaut approprié pour les données cliniques — une admission et une sortie appliquées dans le mauvais ordre est pire que les deux étant en retard — et cela a une conséquence importante à comprendre : un message qui échoue toujours bloquera tout ce qui le suit.
C'est pourquoi la profondeur de la file d'attente et l'âge de la file d'attente sont des conditions d'alerte distinctes. Une file d'attente profonde qui se vide est un système occupé. Une file d'attente dont le message le plus ancien continue de vieillir est bloquée, et les types d'alerte queue-depth, queue-age et queue-stuck les distinguent.
max_attempts est ce qui limite les dégâts : après cela, le message est enregistré comme ayant échoué et la file d'attente passe à l'étape suivante. Définir max_attempts très élevé dans l'espoir d'une réussite éventuelle convertit un message échoué en un flux arrêté.10.4 Lorsque la mise en file d'attente est désactivée
Avec queue.enabled défini sur false, une livraison échouée est une livraison échouée. Elle est enregistrée et non réessayée.
C'est le choix approprié lorsque les données tardives sont pires que l'absence de données — un affichage en temps réel, un système de pagination, tout ce qui nécessite qu'un message livré quarante minutes après l'événement soit trompeur plutôt que simplement retardé.
C'est le mauvais choix pour tout ce qui va dans un dossier, où le message est tout aussi valide une heure plus tard.
10.5 Nouvelle tentative versus file d'attente
Il existe deux mécanismes et ils fonctionnent à des niveaux différents.
retry sur une destination contrôle les tentatives immédiates au sein d'une livraison — une connexion qui échoue est réessayée après une courte pause, sans quitter le chemin de livraison. Cela gère les défaillances transitoires : une connexion interrompue, un refus momentané.
queue contrôle ce qui se passe une fois que les tentatives immédiates sont épuisées. Le message quitte le chemin de livraison et est réessayé plus tard sur un calendrier plus long.
Les deux existent parce que les deux défaillances sont différentes. Une réinitialisation de connexion à la première tentative a généralement disparu à la deuxième, et passer par la file d'attente pour cela ajouterait des minutes de latence à une défaillance qui a duré des millisecondes. Une destination qui a été déconnectée pour maintenance ne reviendra pas dans les trois tentatives immédiates, et la solliciter sans arrêt est inutile.
10.6 Ce qu'un point de terminaison HTTP compte comme livré
Un point de terminaison HTTP comporte trois paramètres qui déterminent si un message est considéré comme envoyé, et tous les trois se trouvent sur la destination dans le constructeur.
Codes de statut qui signifient livré. Vide signifie n'importe quel code 2xx. Certains points de terminaison répondent 202 Accepted pour quelque chose qu'ils n'ont pas encore traité, et certains répondent 200 avec une erreur dans le corps — le second est ce pour quoi *Traiter comme échec si la réponse contient* est utilisé. Définir une liste explicite est utile lorsque un partenaire vous a indiqué quel code signifie quoi, car l'alternative consiste à découvrir la différence à partir d'un message qui n'a jamais été livré et jamais mis en file d'attente.
Suivre les redirections. Désactivé par défaut, et délibérément. Une redirection peut pointer vers un hôte différent, donc la suivre envoie le message ailleurs que personne n'a configuré et signale une réussite.
Jeton Bearer. Envoyé en tant qu'en-tête Authorization. Il est stocké avec le canal et n'est jamais affiché à nouveau, donc laisser la case vide lors de la modification d'un canal existant conserve le jeton déjà enregistré plutôt que de le supprimer.
10.7 Nommer et élaguer un dossier d'archive
Une destination de fichier ajoute par défaut à un fichier par jour et par type de message (20261012-ADT_A01.hl7), encadré par MLLP afin que le fichier puisse être rejoué avec perfuse send. Quatre paramètres de destination modifient cela.
Nom de fichier (file_name) crée un fichier par message au lieu de cela, nommé à partir de ${date}, ${timestamp}, ${control_id}, ${message_type} et ${destination}. Un nom déjà pris (la même référence de contrôle deux fois) reçoit un suffixe unique plutôt que d'écraser le message qui se trouve là.
Ajouter (append: true) écrit chaque message dans le fichier que Nom de fichier nomme, donc ${date}.hl7 est un fichier par jour pour chaque type.
Suffixe pendant l'écriture (temp_suffix, un fichier par message uniquement) est par défaut .part et est supprimé par un renommage une fois le fichier complet. Celui qui collecte ces fichiers ne devrait pas prendre un fichier à moitié écrit, et un renommage dans un dossier est atomique. Ne le modifiez que si le collecteur filtre sur une extension différente.
Supprimer après (retain_hours) élimine les fichiers du dossier plus anciens que le nombre d'heures donné, vérifié au maximum toutes les dix minutes pendant que les messages arrivent. Seuls les fichiers simples directement dans le dossier sont supprimés, jamais un sous-dossier. Vide ou zéro les conserve à jamais, ce qui est la valeur par défaut et constitue une décision plutôt qu'une omission — mais un archive que personne ne découpe remplit le disque, et un disque plein arrête le canal plutôt que l'archivage.
10.8 Envoi à un serveur FHIR
Trois paramètres déterminent combien de choses sont vérifiées avant qu'un lot ne parte.
Réclamer la conformité US Core ajoute le profil à chaque ressource. N'affirmez cela que lorsque la ressource transporte ce que le profil exige, car un destinataire peut valider contre l'affirmation et rejeter un lot qui aurait autrement été accepté.
Valider avant envoi vérifie chaque ressource ici plutôt que d'apprendre du destinataire. Un rejet à l'autre extrémité vous indique moins, plus tard, et souvent uniquement dans un journal que vous ne pouvez pas lire.
Traiter les avertissements comme des rejets n'a d'effet que lorsque la validation est activée, et le contrôle est indisponible jusqu'à ce qu'il le soit. Il est suffisamment strict pour arrêter un lot qu'un destinataire accepterait, il appartient donc à une alimentation en cours de mise en place plutôt qu'à une en service.
10.8.1 Services FHIR hébergés
Un bloc fhir de destination auth se connecte aux services hébergés, où un jeton Bearer collé cesse de fonctionner dans l'heure :
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 signe chaque demande pour AWS HealthLake avec la version 4 de la signature, avec la région lue à partir de l'URL. azure obtient un jeton d'ID Microsoft Entra pour Azure Health Data Services à partir de tenant_id, client_id et client_secret - un enregistrement d'application qui détient le rôle de contributeur de données FHIR - avec l'URL du service FHIR comme public. client_credentials fait de même contre n'importe quel token_url OAuth 2.0. Les jetons sont réutilisés jusqu'à une minute avant leur expiration. Les mêmes choix se trouvent sous Hosted service sign-in de la destination dans le constructeur de canal.
10.8.2 Déclaration de cas de santé publique
Cochez Rapporter les conditions déclarables à la santé publique sur une destination FHIR et il envoie des rapports de cas plutôt que des bundles. Chaque message est vérifié pour un code de déclenchement de condition déclarable : un diagnostic, un test de laboratoire ou un résultat codé. S'il en a un, le message devient un eICR HL7 eCR 2.1.2, enveloppé dans un message eCR et publié sur l'URL $process-message. S'il n'en a pas, rien n'est envoyé et rien n'échoue ; la destination le compte comme non déclarable.
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 est les codes de déclenchement des conditions déclarables, en tant que jeu de valeurs FHIR ou bundle eRSD. Il nécessite une licence UMLS, il n'est donc pas inclus ; sans cela, un court échantillon intégré est utilisé, uniquement pour les tests. source est l'endroit où l'agence envoie sa réponse de déclarabilité. L'établissement est obligatoire car eCR demande son téléphone et son adresse, et un message v2 n'en a pas.
Un rapport indique ce que le message manquait plutôt que de l'inventer, et chaque lacune est consignée. Essayez un message dans le panneau Rapport de cas de santé publique du laboratoire FHIR avant de pointer un flux en direct vers une agence.
10.8.3 Résultats de laboratoire à la santé publique : ELR
perfuse elr -config elr.yaml results.hl7 transforme les résultats d'un laboratoire en messages ELR HL7 2.5.1 que les départements de santé publique reçoivent, un pour chaque message avec un résultat déclarable, et uniquement les commandes qui en portent un : un comptage sanguin complet à côté d'un test SARS-CoV-2 positif n'est pas l'affaire de la santé publique. Les codes de déclenchement sont les mêmes que ceux du signalement de cas, les RCTC que vous chargez ou l'échantillon intégré.
ELR nomme tout le monde par OID ou numéro CLIA, que aucun flux de laboratoire ne contient pour l'expéditeur et le destinataire, ils proviennent donc du fichier :
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}
L'établissement d'ordonnance, le laboratoire d'exécution et les autorités d'attribution ne sont utilisés que lorsque le message du laboratoire les omet, et chaque utilisation est une note. Ce que seul le laboratoire sait n'est jamais rempli : un résultat sans type d'échantillon va avec SPM-4 vide et une note le disant, car un échantillon deviné dans un rapport à la santé publique est pire qu'une lacune que l'État peut demander. Commencez par processing: T pendant que l'équipe d'intégration de l'État teste le flux.
Ce que le laboratoire a bien fait est conservé tel quel. Une commande enfant (un panneau de sensibilité ou un test de réflexe dont l'OBR-29 nomme son parent et qui n'a pas d'ORC propre) est envoyée telle quelle, sans ORC ni spécimen inventé, et un enfant sans résultat rapportable propre est envoyé avec celui de son parent, puisque une sensibilité ne signifie rien sans la culture à laquelle elle appartient. Une note après le PID reste avec le patient, et l'ORC-14, le numéro de téléphone de rappel, est copié à partir de l'OBR-17 lorsque le laboratoire n'a mis que celui-ci. Les 28 exemples de messages que l'ONC publie pour son outil de certification ELR sont valides sans erreurs.
MSH-2 est écrit sous la forme ^~\&#, les cinq caractères que les errata d'ELR Release 1 exigent et que l'outil de certification de l'ONC vérifie. Si le guide de votre État affiche les anciens quatre, ajoutez encoding_characters: "^~\\&" au fichier.
Pour les envoyer à partir d'un canal plutôt que de la ligne de commande, donnez à la destination qui atteint l'État un bloc elr nommant le même fichier. Chaque résultat de laboratoire est remodelé en sortie, et celui qui n'a rien de rapportable n'est pas envoyé du tout, ce qui est comptabilisé comme livré, et non échoué : l'État a demandé uniquement des résultats rapportables.
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
Le bloc s'applique sur un canal HL7 v2, aux destinations qui livrent le message lui-même (mllp, http, tcp, fichier, sftp, ftp, S3, Azure Blob, soap, les courtiers de messages ou un autre canal) ; le canal refuse de charger sinon, et lorsque le fichier est manquant ou ne contient pas l'établissement d'expédition, l'application réceptrice ou l'établissement récepteur. Les notes sont écrites dans le journal avec l'ID de contrôle du message.
Le fichier ELR est le compagnon du canal, et non un canal : perfuse check et l'écran des canaux le sautent plutôt que de signaler un canal qui ne chargera pas. Dans le constructeur de canaux, les deux mêmes paramètres sont sous la destination, dans Lab reporting (ELR 2.5.1) ; le champ des codes de déclenchement s'ouvre une fois qu'un fichier ELR est nommé, et l'enregistrement refuse un fichier qui n'est pas à côté du canal.
10.8.4 Archives DICOMweb
type: dicomweb stocke chaque objet avec STOW-RS : Orthanc, dcm4chee, les services d'imagerie cloud, ou l'archive propre d'un serveur Perfuse. Donnez la racine du service (https://pacs.example/dicom-web) ; /studies est ajouté, et une URL se terminant déjà par /studies est refusée plutôt que de poster sur /studies/studies. Authentifiez avec token (un jeton porteur) ou username et password ; headers ajoute d'autres en-têtes, tels que l'en-tête de projet d'un service cloud. Le canal nécessite dataType: dicom.
La réponse du serveur décide du résultat, et non de son code de statut seul. Un objet que la réponse liste comme ayant échoué est une livraison échouée avec la raison d'échec DICOM, et il en va de même pour un 202 qui ne liste rien comme stocké : le serveur a pris la demande et n'a conservé aucune partie. Le délai d'attente par défaut est de deux minutes, car une série importante est lente.
10.8.5 Référentiels de documents (IHE XDS.b)
type: xds publie chaque document clinique sur un référentiel XDS.b avec ITI-41 Provide and Register : un document CDA, ou un document transporté par un message HL7 v2 (MDM, ORU). Les métadonnées proviennent du document et des paramètres de la destination (source_id, patient_domain, facility_type, practice_setting), et la réponse du référentiel décide de la livraison. Voir partage de documents IHE.
10.8.6 Registres d'immunisation
Chaque registre d'immunisation des États-Unis (IIS) accepte des messages HL7 2.5.1 sur la même interface SOAP, celle que les CDC ont publiée en 2011 (espace de noms urn:cdc:iisb:2011). Il comporte deux opérations : connectivityTest, qui prouve le point de terminaison, et submitSingleMessage, qui transporte le message. Un VXU^V04 signale une injection et revient sous la forme d'un ACK ; un QBP^Q11 demande l'historique et la prévision d'un patient et revient sous la forme d'un RSP^K11.
Choisissez Registre d'immunisation (service Web IIS CDC) comme service d'une destination SOAP, ou écrivez 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 construit l'enveloppe, il n'y a donc pas de corps à écrire. Le nom d'utilisateur et le mot de passe sont placés à l'intérieur de la demande, là où le WSDL des CDC les place, et non dans l'authentification HTTP. La version est SOAP 1.2, le lien du WSDL, à moins que vous ne définissiez version: "1.1" pour un registre dont le guide le demande. Lorsqu'un registre nécessite un certificat client, définissez le tls de la destination comme pour n'importe quel appel HTTPS.
L'accusé de réception du registre décide si le message a été livré, et non le statut HTTP. Un registre répond à une injection rejetée avec un HTTP 200 et un AR à l'intérieur, de sorte qu'une destination qui faisait confiance au statut signalerait une perte d'immunisation comme livrée.
| Le registre répond | Enregistrements Perfuse |
|---|---|
| AA (ou CA) | Livré. |
AE dont les segments ERR sont tous des avertissements (ERR-4 W ou I) | Livré. Les avertissements sont dans la réponse. |
AE avec tout ERR-4 E, ou un ERR sans gravité | Échec, avec l'emplacement, le code et le texte de chaque ERR dans l'erreur. |
| AR ou CR | Échec, de la même manière. |
| Une erreur SOAP (mot de passe incorrect, message trop volumineux) | Échec, avec la raison du registre. |
| Quelque chose qui n'est pas un message HL7 | Échec. |
warnings_are_errors: true (Traiter les avertissements comme des échecs) fait attendre chaque AE d'une personne. La réponse, que les scripts de réponse et un appelant HTTP en attente sur le canal lisent, est le message HL7 du registre : l'ACK, ou le RSP avec l'historique et la prévision. examples/iis contient trois canaux pour commencer : VXU à partir d'un EHR sur MLLP, des requêtes QBP sur HTTP et un substitut local pour un registre.
Le tableau de bord Connections demande à un registre son connectivityTest lorsque rien n'a été soumis pendant sept jours. Cette opération existe à cette fin et ne soumet rien, elle constitue donc le seul contrôle au niveau de l'application que Perfuse effectue. Elle vérifie l'adresse, le TLS et le lien SOAP, mais pas le nom d'utilisateur et le mot de passe ; seule une soumission réelle teste ceux-ci.
Une source SOAP peut répondre de la même manière : Répondre comme un registre d'immunisation, ou profile: cdc-iis sur la source. Il renvoie connectivityTest, prend le message de submitSingleMessage, renvoie l'accusé de réception du canal dans return et sert le WSDL des CDC à ?wsdl. Un nom d'utilisateur et un mot de passe, lorsqu'ils sont définis, sont vérifiés contre ceux de la demande, et une paire incorrecte obtient la SecurityFault du WSDL. Un message que le canal rejette est renvoyé sous la forme d'un NAK, et non d'une erreur, comme le guide des CDC le dit. Utilisez-le comme un double de test, ou pour recevoir des soumissions de la manière dont un registre le fait.
Non couvert : les parties spécifiques à l'état de l'intégration. Chaque registre a son propre point de terminaison, processus de compte et profil local du guide 2.5.1 (champs RXA et OBX requis, éligibilité VFC, codes de refus). Ce sont les contenus des messages, que les transformations du canal façonnent ; aucun point de terminaison d'état n'est intégré. Perfuse a été testé contre lui-même et contre des réponses de registre enregistrées, et non contre un registre d'état en direct.
10.9 Lorsque le transport dit oui et que le message n'est pas arrivé
« Est-ce que cela est arrivé » est souvent une question que le transport ne peut pas répondre. Un récepteur MLLP renvoie un accusé de réception d'application dont le sens est dans son texte. Un récepteur HTTP renvoie 200 avec un document d'erreur. Dans les deux cas, le transport a réussi et le message n'est pas arrivé.
Inspecter la réponse sur une destination prend un script donné la réponse du récepteur. Renvoyer faux, ou lancer une exception, et la livraison est marquée comme ayant échoué — ce qui signifie qu'elle sera réessayée, mise en file d'attente et apparaîtra dans le décompte des échecs au lieu d'être comptée en silence comme livrée.
Il n'est proposé que sur les destinations qui reçoivent une réponse. Sur celle qui ne le peut pas, il est refusé au chargement plutôt que laissé inactif.
10.10 Ce qu'un résultat de livraison signifie
| Résultat | Signification |
|---|---|
Delivered | La destination a accepté le message. Pour MLLP, un accusé de réception positif a été reçu. |
Queued | La livraison a échoué et le message sera réessayé. |
Failed | La livraison a échoué et ne sera pas réessayée, soit parce que la mise en file d'attente est désactivée, soit parce que les tentatives sont épuisées. |
Filtered | La destination a rejeté le message en fonction de son propre filtre. Ce n'est pas une erreur. |
Ces éléments sont enregistrés par destination et par message, donc un message qui a atteint trois des quatre destinations est enregistré comme exactement cela. Il n'y a pas de « succès » au niveau du canal, car cela ne signifierait rien.
10.11 Livraison lente
Une destination qui accepte des messages mais qui met du temps à le faire est un problème distinct de celle qui échoue, et il est facile de le manquer parce que chaque résultat est un succès.
Le type d'alerte slow-delivery existe pour cela. Il vaut la peine de le configurer sur tout ce pour quoi l'accusé de réception de l'expéditeur attend la livraison, car une destination dont le temps de réponse a doublé discrètement finira par dépasser le délai d'attente de l'expéditeur et commencera à produire des renvois — et à ce stade, le symptôme apparaît en amont, dans un système que vous n'administrez peut-être pas.
10.12 Écriture dans une base de données
type: database exécute une instruction par message avec des valeurs liées à partir du message.
Les espaces réservés sont ceux du pilote — $1 pour postgres, ? pour mysql et sqlite, @p1 pour sqlserver — et Perfuse ne les réécrit pas. C'est délibéré : une couche de traduction qui se trompait d'espace réservé lierait le nom d'un patient à la mauvaise colonne, et le résultat ressemblerait à des données valides plutôt qu'à une erreur.
Une instruction écrite dans le dialecte incorrect est refusée lorsqu'elle est enregistrée, en indiquant le style que le pilote souhaite. Avant l'existence de cette vérification, l'erreur apparaissait sous la forme d'un syntax error at or near "," du serveur lors de l'arrivée d'un message, qui nomme une instruction que vous avez réellement écrite et vous amène ainsi à rechercher une faute de frappe au lieu du dialecte.
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 paramètre entre guillemets est une constante plutôt qu'un chemin, c'est ainsi qu'un canal écrit son propre nom ou un code de système source dans une ligne à côté des données du message.
Les valeurs sont toujours liées en tant que paramètres. Une référence ${...} à l'intérieur de l'instruction est refusée : un nom contenant une apostrophe casserait l'instruction, et une valeur hostile la réécrirait.
10.13 Envoi à un socket brut
type: tcp écrit dans un socket avec un encadrement que vous choisissez, ce que souhaite généralement un appareil ou un instrument de laboratoire. MLLP est un encadrement parmi plusieurs ; cette destination propose les autres.
destinations:
- name: instrument
type: tcp
tcp:
address: instrument.lab:9100
framing: delimited
delimiter: \r
expect_reply: true
timeout: 30s
L'encadrement n'a pas de valeur par défaut, délibérément. Écrire avec un encadrement incorrect ne provoque pas d'erreur. L'extrémité distante lit des messages divisés aux mauvaises places, ou attend un terminateur qui n'arrive jamais, et le symptôme apparaît sur le système récepteur plutôt que ici.
framing | Ce qu'il écrit |
|---|---|
mllp | 0x0b avant, 0x1c 0x0d après. Le même encadrement qu'une destination MLLP utilise. |
delimited | Un delimiter après chaque message, et un start_block facultatif avant. |
fixed | Enregistrements complétés ou tronqués à record_length. |
length | Un préfixe length_bytes. big_endian et length_includes_header ont deux conventions dans la nature et la différence est silencieuse. |
whole | Un message par connexion, fermé pour marquer la fin. |
Seuls les paramètres utilisés par l'encadrement choisi sont acceptés. Une longueur d'enregistrement sur un flux délimité est refusée plutôt que d'être ignorée, car un paramètre qui est silencieusement ignoré est celui que quelqu'un croit être en vigueur.
expect_reply modifie ce que signifie livré. Sans cela, la réussite signifie que les octets ont atteint le tampon d'envoi du système d'exploitation — que un pair qui a planté un moment plus tard n'a jamais lu.
10.14 Amazon S3, SQS et SNS
Un canal peut lire à partir d'une file d'attente SQS ou d'un préfixe de bucket S3, et livrer à SQS, SNS ou S3. Les cinq sont des HTTP signés avec aucun SDK AWS dans le binaire, et les cinq prennent les mêmes paramètres d'accès : region, access_key_id, secret_access_key (écrivez ${AWS_SECRET_ACCESS_KEY} pour lire l'environnement), un session_token facultatif, et endpoint pour LocalStack, MinIO ou un point de terminaison VPC. Sous Canal → Nouveau canal, choisissez *Nous lisons à partir d'une file d'attente Amazon SQS*, *Nous collectons des objets à partir d'un bucket Amazon S3* , ou les types de destination SQS, SNS et S3.
Rien n'est reconnu à AWS jusqu'à ce que le canal l'ait traité. Un message SQS est supprimé après coup et réapparaît lorsqu'il atteint la fin de son délai de visibilité, donc la politique de réacheminement d'une file d'attente est ce qui déplace un message qui continue à échouer vers une file d'attente de lettres mortes. Un objet S3 est déplacé vers processed/ après coup, ou vers error/ s'il ne peut pas être traité, donc un seul fichier erroné n'arrête pas le reste.
Sur une file d'attente ou un sujet FIFO, les messages sont regroupés par patient par défaut - SQS conserve l'ordre dans un groupe et nulle part ailleurs - et dédoublonnés par contenu, donc une nouvelle tentative n'est pas livrée deux fois.
Un archive S3 peut être écrit directement à Glacier avec storage_class, et sous forme de lignes JSON pour Amazon Athena avec format: ndjson ; perfuse athena imprime le tableau. La référence contient chaque paramètre.
10.15 AMQP 1.0 et Azure
AMQP 1.0 est ce que parlent Azure Service Bus et Event Hubs, ainsi que RabbitMQ 4, ActiveMQ et Artemis en plus de leurs autres protocoles. Une source amqp reçoit d'une file d'attente ou d'un abonnement et accepte chaque message uniquement une fois que le canal l'a traité ; un message qui ne peut pas être traité est libéré comme une livraison échouée, donc le courtier le relivre et, au-delà de la limite de la file d'attente, le met dans une file d'attente de lettres mortes. Une destination amqp signale la réussite uniquement lorsque le courtier accepte le message. Pour Service Bus : addr est <namespace>.servicebus.windows.net:5671 avec tls, username le nom de la stratégie d'accès partagé, password sa clé, et address le nom de la file d'attente, ou <topic>/subscriptions/<name> pour recevoir.
Azure Blob Storage : une destination azure_blob écrit un blob par message dans le niveau d'accès choisi - Hot, Cool, Cold ou Archive - et une source azure_blob récupère des blobs à partir d'un préfixe, les déplaçant vers processed/ ou error/ comme la source S3 le fait. Préférez un jeton SAS limité au conteneur plutôt que la clé de compte.
10.16 MQTT
Une source mqtt s'abonne à un filtre de sujet (+ correspond à un niveau, # à tous les niveaux inférieurs) sur tout courtier MQTT 3.1.1 : Mosquitto, EMQX, HiveMQ, AWS IoT Core, Azure Event Grid. Au QoS 1, par défaut, chaque message est accusé de réception une seule fois que le canal l'a traité. MQTT n'a pas de moyen de refuser un seul message, donc celui qui ne peut pas être traité est laissé non accusé de réception et la connexion est rétablie ; le courtier conserve la session sous l'ID client (perfuse-<channel> à moins que client_id ne le spécifie autrement) et l'envoie à nouveau, en premier dans la file d'attente. Le QoS 0 est au plus une fois : tout ce qui est envoyé pendant que Perfuse est arrêté est perdu. Une destination mqtt publie et, au QoS 1, signale la réussite lorsque le courtier a le message.
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 veut un certificat client : donnez tls.cert_file et tls.key_file.
10.17 IBM MQ
ibm_mq lit et écrit des files d'attente IBM MQ via l'API REST de messagerie du gestionnaire de file d'attente (mqweb), que IBM MQ 9.1.5 et les versions ultérieures expédient sur chaque plate-forme, y compris z/OS, donc aucun client MQ n'est installé à côté de Perfuse. L'utilisateur a besoin du rôle MQWebUser et de l'autorité de mise, de récupération et de navigation sur la file d'attente. Une source parcourt le premier message, le remet au canal, et le supprime par son ID de message uniquement une fois qu'il a été traité ; un message qui échoue reste en premier sur la file d'attente. Exécutez un lecteur par file d'attente. Une destination met des messages persistants (à moins que non_persistent), avec l'ID de contrôle HL7 comme ID de corrélation.
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 est v3 pour MQ 9.3 et ultérieur (par défaut), v2 pour 9.1.5 à 9.2. Un gestionnaire de file d'attente avec un canal AMQP peut également être atteint avec le connecteur amqp.
10.18 Google Cloud Pub/Sub et Cloud Storage
Une source pubsub extrait d'un abonnement et reconnaît chaque message une fois traité ; un message qui échoue est remis immédiatement (sa date d'échéance de reconnaissance est fixée à zéro), avec le reste de son lot, donc Pub/Sub le livre à nouveau et, au-delà de la politique de lettres mortes de l'abonnement, le met dans une file d'attente de lettres mortes. Une destination pubsub publie avec le type de message HL7 et l'ID de contrôle comme attributs ; order_by: patient définit la clé d'ordre à partir de PID-3.1, donc un abonnement avec ordonnancement de messages conserve les messages de chaque patient dans l'ordre.
Une destination gcs écrit un objet par message, nommé comme une clé S3, dans la classe de stockage choisie (STANDARD, NEARLINE, COLDLINE, ARCHIVE). Une source gcs récupère des objets à partir d'un préfixe et les déplace vers processed/ ou error/ comme la source S3 le fait.
Les deux se connectent en tant que compte de service : credentials_file est sa clé JSON. Laissez-le vide sur Google Cloud (une VM, GKE ou Cloud Run) pour utiliser le compte de service attaché. endpoint nomme un émulateur (l'émulateur Pub/Sub, fake-gcs-server), qui n'a pas besoin de credenciaux.
source:
type: pubsub
pubsub:
project: hospital-integration
subscription: adt-to-perfuse
credentials_file: /etc/perfuse/gcp-key.json
10.19 Lecture d'une boîte de réception (IMAP et POP3)
Une source email lit une boîte de réception et convertit ce qu'elle trouve en messages : chaque pièce jointe (take: attachments, la valeur par défaut, étroite par les modèles attachment_names), le texte de l'email (take: body), ou l'email entier (take: raw) pour qu'un script le décompose. Les laboratoires, les centres d'imagerie et les petites pratiques envoient encore des résultats de cette manière.
Chaque vérification se connecte, lit les courriels non lus les plus anciens en premier, et se déconnecte. Sur IMAP, un courriel est récupéré sans être marqué comme lu, remis au canal, et uniquement une fois que chaque message de celui-ci a été accepté, il est déplacé vers move_to (Traités), marqué comme lu (after_read: flag) ou supprimé. Les courriels qui ont échoué, ou qui n'ont pas été pris (un expéditeur en dehors de allowed_senders, pas de pièce jointe correspondant à attachment_names, plus grand que max_message_size), sont déplacés vers error_folder (Erreur) avec la raison dans le journal. Les deux dossiers sont créés lorsqu'ils sont manquants. POP3 n'a pas de dossiers ou de drapeaux, donc il supprime : les suppressions sont validées par la commande QUIT à la fin de la vérification, donc une session qui se termine abruptement ne supprime rien et un courriel traité peut être lu à nouveau (jamais perdu). Les courriels POP3 qui ne sont pas pris restent sur le serveur et sont signalés une fois.
La connexion est un mot de passe (${MAIL_PASSWORD} ; un mot de passe d'application pour Gmail) ou OAuth 2.0 sur SASL XOAUTH2, que Microsoft 365 exige (il a désactivé la connexion par mot de passe) et que Gmail préfère :
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]
Avec client_secret et sans refresh_token, l'accès en mode application uniquement de Microsoft 365 est utilisé (la subvention de client-credentials, étendue à https://outlook.office365.com/.default): un administrateur enregistre l'application, lui accorde IMAP.AccessAsApp et la limite à une seule boîte aux lettres avec un principal de service Exchange. Avec un refresh_token (le consentement d'une personne), la portée déléguée IMAP.AccessAsUser.All ou POP.AccessAsUser.All est utilisée, et un jeton de rafraîchissement tourné est conservé pour la durée de vie du processus. Gmail nécessite un refresh_token: Google n'offre pas d'accès en mode application uniquement à une boîte aux lettres.
allowed_senders prend des adresses et des domaines. La ligne De de l'e-mail peut être falsifiée, il empêche donc les accidents et les courriels errants, et non un attaquant; une source qui doit être considérée comme fiable appartient à Direct (S/MIME signé), SFTP ou un VPN. security est tls (993 ou 995, la valeur par défaut), starttls (143 ou 110) ou none, qui n'est autorisé qu'à localhost. Les vérifications sont espacées d'au moins 10 secondes (60 par défaut), car les services de messagerie limitent les comptes qui vérifient plus rapidement.
Testé contre GreenMail 2.1.3 (IMAPS, IMAP, POP3S et POP3: refus de connexion avec un mot de passe incorrect, récupération sans marquer comme lu, MOVE, drapeau, suppression, e-mail trop volumineux refusé avant d'être lu) et contre l'IMAP de Gmail avec un mot de passe d'application (création d'un dossier, ajout, récupération, MOVE, suppression). OAuth a été testé contre un point de terminaison de jeton de remplacement uniquement: pas contre Microsoft ou Google.
10.20 AS2
AS2 (RFC 4130) est la façon dont de nombreux payeurs, organismes de compensation et fournisseurs échangent des EDI: une publication HTTP dont le corps est signé avec le certificat de l'expéditeur et chiffré pour le destinataire, répondue avec un reçu (un MDN) qui nomme un résumé de ce qui est arrivé. Le S/MIME est le même code que les messages Direct utilisent. Les deux extrémités sont sur le constructeur de canal: Les partenaires commerciaux nous envoient des EDI sur AS2 en tant que source, Un partenaire commercial sur AS2 en tant que destination.
# 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"
Réception. Un message destiné à tout autre AS2-To, ou provenant d'un expéditeur non présent dans partners, est refusé avec 403 et sans reçu. Le message d'un partenaire doit être signé et chiffré, sauf si son entrée définit allow_unsigned ou allow_unencrypted. La charge utile est déchiffrée, sa signature vérifiée contre le certificat du partenaire (les partenaires échangent généralement des certificats auto-signés, ce qui est acceptable: le certificat est la confiance), et transmise au canal comme le dit son format de message. Le partenaire reçoit le reçu qu'il a demandé: dans la réponse, ou publié sur son URL Receipt-Delivery-Option; signé lorsqu'il a demandé un signé. Un message qui échoue obtient un reçu indiquant pourquoi (decryption-failed, authentication-failed, insufficient-message-security, unexpected-processing-error).
Envoi. Chaque message est signé (SHA-256) et chiffré (AES-256-CBC). Avec receipt: sync, la valeur par défaut, il est considéré comme livré uniquement lorsque le reçu vérifie contre partner_cert_file, indique processed, et porte le même résumé (MIC) que ce qui a été envoyé; tout autre élément est une livraison échouée et est répétée. receipt: async demande le reçu à receipt_url, qui doit être une source AS2 sur ce serveur qui répertorie le partenaire: le message est considéré comme livré une fois que le partenaire accepte la demande, et un reçu qui désaccorde plus tard est consigné comme erreur. receipt: none ne demande rien. unsigned, unencrypted et unsigned_receipt assouplissent chaque partie pour un accord qui le dit; username et password ajoutent une authentification de base HTTP pour les passerelles qui l'exigent. Le type de contenu suit le format du canal (application/edi-x12 pour X12) sauf si content_type en définit un.
Triple DES, AES-128 et AES-192 sont lus ainsi que AES-256, puisque les partenaires les envoient encore, et le streaming BER (longueurs indéfinies) que les passerelles Java écrivent est également lu.
Compression (RFC 5402). Un message compressé est lu de quelque manière qu'il ait été construit : compressé avant signature ou chiffrement, ou un message signé compressé dans son ensemble. Le MIC du reçu suit la RFC : sur ce qui a été signé lorsque cela est signé, sur le contenu non compressé lorsqu'il ne l'est pas. Un message qui dépasserait dix fois la max_message_size de la source est refusé avec decompression-failed, donc quelques kilo-octets ne peuvent pas prétendre à des gigaoctets de mémoire. Une destination se compressera avec compress: true, avant signature et chiffrement, comme la plupart des passerelles ; demandez d'abord au partenaire.
Un message envoyé deux fois. Un partenaire qui n'a jamais reçu notre récépissé envoie le message à nouveau avec le même ID de message (RFC 4130 section 7.5). La source se souvient de chaque ID de message des partenaires pour duplicate_window (par défaut 720h, 30 jours ; au moins une heure) et répond à une renvoi avec un récépissé processed sans le transmettre à nouveau. L'enregistrement est conservé dans la base de données, afin qu'un redémarrage ne l'oublie pas. Un message dont le traitement a échoué n'est pas mémorisé, afin que la répétition du partenaire passe. Les copies arrivant en même temps s'attendent les unes les autres, et seule la première est transmise. Si l'enregistrement ne peut pas être lu, le message est refusé avec unexpected-processing-error et le partenaire réessaye plus tard, plutôt que de risquer une deuxième copie. Un message sans ID de message ne peut pas être reconnu et est enregistré comme tel.
L'interopérabilité est testée contre pyas2lib 1.4.3 dans les deux sens, avec Triple DES et AES-256, compressé et non, récépissés synchrones signés inclus.
10.21 OpenPGP
Les payeurs, les organismes de compensation et les agences étatiques prennent et envoient souvent des fichiers uniquement sous OpenPGP. Un bloc pgp sur une source ouvre ce qui arrive; un sur une destination protège ce qui part. Les deux sont sur le constructeur de canal: Messages chiffrés avec OpenPGP sous la source, Chiffrer avec OpenPGP sur chaque destination.
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}
Les fichiers de clés sont lus par rapport au fichier de canal et sont lus et déverrouillés lorsque le canal se charge: une clé manquante ou un mot de passe incorrect arrête le canal à cet endroit, et non sur le premier fichier.
- Sur une source, l'ensemble du fichier, de l'objet, de la pièce jointe d'email ou du corps de la requête est
ouvert en premier, puis divisé en messages, donc un lot chiffré en un seul fichier fonctionne. Celui qui ne s'ouvre pas est refusé : une source de fichier le déplace vers son dossier d'erreur, un expéditeur HTTP répond 400 avec la raison. require_signature refuse un message non signé par l'un de verify_with ; allow_unencrypted accepte un message qui n'est que signé ; pass_plain laisse passer un message qui n'est pas du tout PGP, inchangé, pour un dossier qui reçoit les deux.
- Sur une destination, ce qui aurait été livré est chiffré (à l'aide de l'un de
encrypt_to) et signé (avecsign_with), après chaque autre étape. Une destination de fichier, SFTP, FTP, S3, Azure Blob ou GCS nomme toujours le fichier à partir du message en clair,
donc ${control_id} fonctionne, et tout encadrement est à l'intérieur du chiffrement. armor: true écrit du texte .asc au lieu de binaire ; no_compress désactive la compression ; file_name est le nom transporté à l'intérieur du message.
Les messages sont écrits avec AES-256 dans le format RFC 4880 que les anciens récepteurs lisent, et le format RFC 9580 plus récent est lu également. La cryptographie est ProtonMail/go-crypto ; Perfuse n'implémente aucune primitive. L'interopérabilité est testée contre GnuPG dans les deux sens : gpg déchiffre et vérifie ce que Perfuse écrit, et Perfuse ouvre et vérifie ce que gpg écrit.
10.22 Livraison à un autre canal
Une destination de canal remet le message à un autre canal par nom. Le canal récepteur traite cela comme n'importe quelle autre arrivée : il l'enregistre, le filtre, le transforme et le distribue.
C'est la méthode prise en charge pour construire une chaîne. Elle est délibérément visible — deux canaux, deux ensembles de statistiques, deux entrées dans l'historique des messages — car une chaîne cachée à l'intérieur d'un canal est une chaîne que personne ne peut surveiller.
Le message est remis en mémoire plutôt que sur un réseau, afin qu'il n'y ait pas d'encadrement, d'acquittement ni de délai d'attente entre les deux.
10.23 Ce qui se passe lorsque le processus est tué
La question que chacun qui a exécuté un moteur d'interface pose en premier, et celle qui est rarement répondue, car la réponse honnête est généralement embarrassante.
Il a été répondu en tuant le processus avec SIGKILL à mi-chemin d'un lot — ce qui ressemble à une panne de courant, une suppression en cas de manque de mémoire et un réinitialisation de l'hyperviseur depuis l'intérieur — et en comptant ce qui a survécu contre ce qui avait été promis.
La propriété testée n'est pas « rien ne se perd ». Cela n'est pas réalisable et prétendre le contraire serait un mensonge. C'est la promesse plus étroite sur laquelle un expéditeur compte vraiment : un message qui a été positivement accusé de réception est un message qui est arrivé.
Avec ack.when: on_delivery, qui est la valeur par défaut, chaque destination est écrite avant que l'acquittement ne soit envoyé, donc un AA est une déclaration concernant la destination plutôt qu'au sujet d'une file d'attente. Un message supprimé avant son acquittement peut bien être perdu, et cela est correct : l'expéditeur n'a jamais rien été promis et le renverra à nouveau.
10.23.1 Accusé de réception à la livraison
Cinq exécutions, tuées après 5, 25, 40, 75 et 110 messages sur 120.
| Accusé de réception | Présent en aval par la suite | Accusé de réception mais manquant |
|---|---|---|
| 255 | 255 | 0 |
La promesse tenue à chaque point d'arrêt, et rien n'a été dupliqué. Une duplication aurait été acceptable et une perte ne l'aurait pas été : un A08 renvoyé est une nuisance que les récepteurs absorbent, et un résultat de laboratoire qui n'arrive jamais en silence est un événement de sécurité des patients.
10.23.2 Accusé de réception à la réception
on_receipt répond dès que le message est mis en file d'attente, avant qu'une destination ait été écrite. Ce chapitre a toujours dit qu'un message accusé de réception peut encore être perdu de cette façon. Voici la taille de cela.
| Tué après | Accusé de réception | Présent en aval | Perdu |
|---|---|---|---|
| 5 | 5 | 1 | 4 |
| 25 | 25 | 1 | 24 |
| 75 | 75 | 2 | 73 |
| 110 | 110 | 2 | 108 |
Essentiellement tout ce qui est en cours de transmission. Le paramètre n'est pas un défaut et il existe des flux pour lesquels c'est le bon choix, mais il devrait être choisi en sachant qu'une panne supprime ce qui a été accusé de réception et non encore écrit, et que c'est presque tout ce qu'il y a dans un burst.
Rien n'est récupéré au redémarrage, car perfuse run n'a pas de stockage durable. Une destination qui ne doit pas perdre de messages pendant une panne nécessite queue.enabled, qui nécessite la base de données que perfuse serve fournit — et perfuse run refuse maintenant un tel canal au lieu de le démarrer sans la file d'attente.
10.23.3 Un expéditeur qui meurt à mi-chemin d'un message
La plus dangereuse de ces erreurs, car un message HL7 tronqué peut généralement encore être analysé. Les segments avant la coupure sont complets et bien formés, donc un récepteur n'a aucun moyen de savoir que PID et PV1 sont arrivés et que les segments OBX contenant les résultats ne l'ont pas été.
Un cadre a été ouvert, six dixièmes d'un message ont été envoyés, et la connexion a été réinitialisée plutôt que fermée. Le message partiel n'a pas été livré, l'écouteur a survécu, et un message bien formé envoyé immédiatement après a été accepté normalement, donc le fragment n'a pas été reporté dans le message suivant.
Le journal de connexion signale maintenant le nombre d'octets d'un cadre non terminé qui ont été abandonnés, pour chaque mode de défaillance plutôt que seulement pour une fermeture propre. Auparavant, un expéditeur planté, un processus tué et un câble débranché ont tous signalé messages=0 et rien d'autre, ce qui ne peut pas distinguer un contrôle de santé vide d'un résultat de laboratoire jeté neuf dixièmes du chemin.
10.23.4 Un disque plein
L'épuisement de l'espace est détecté et signalé plutôt que supprimé. Deux choses à propos de cela valent la peine d'être connues.
L'expéditeur n'obtient pas de rejet immédiat. La livraison est réessayée selon le calendrier habituel — une seconde, deux, quatre, huit — et l'accusé de réception négatif arrive environ quinze secondes plus tard. Un expéditeur dont la durée d'attente est plus courte que celle-ci voit une connexion bloquée plutôt qu'un AE, et conclura que le réseau est en défaut plutôt que le disque.
Et un volume signalant zéro octet libre peut encore accepter de petites annexes pendant un certain temps, car l'ajout de quelques centaines d'octets à un fichier dont le dernier bloc a de l'espace n'a pas besoin d'une nouvelle allocation. La première erreur d'écriture se produit plus tard que le moment où le disque est plein.
10.23.5 Ce qui n'a pas été testé
Un répertoire de destination qui perd l'autorisation d'écriture. Il ne pouvait pas être injecté avec chmod : le moteur tient le fichier de sortie ouvert, et la modification du mode d'un fichier n'affecte pas un descripteur déjà ouvert contre lui. Le tester correctement nécessite le volume remonté en lecture seule ou supprimé sous le processus, ce qui n'a pas été fait. Il est nommé ici plutôt qu'omis, car un écart que personne ne mentionne lit comme un écart que personne n'a regardé.
11 Alerte
Rien en dehors de Perfuse ne vous dira qu'un flux s'est arrêté. L'expéditeur est en train d'être accusé réception et est satisfait ; le récepteur n'a aucun moyen de savoir qu'un message a été envoyé. L'alerte est la seule chose qui se trouve entre une interface cassée et quelqu'un qui s'en aperçoit des semaines plus tard.
11.1 Les types d'alertes
| Type | Se déclenche lorsque |
|---|---|
error-rate | Les échecs dépassent une proportion du trafic. |
queue-depth | Une file d'attente a plus de N messages en attente. |
queue-age | Le message le plus ancien en file d'attente a plus d'une durée. |
queue-stuck | Une file d'attente ne se vide pas du tout. |
no-traffic | Rien n'est arrivé depuis une période fixe. |
below-rhythm | Le trafic est bien en dessous de ce que cette alimentation fait normalement *à ce moment de la semaine*. |
channel-down | Un canal qui devrait fonctionner ne l'est pas. |
script-errors | Un script échoue. |
rows-quarantined | Une source de base de données met des lignes de côté. |
slow-delivery | Les livraisons réussissent mais prennent trop de temps. |
contract | Un message viole le contrat déclaré du canal. |
phi-volume | Un canal transporte plusieurs fois son taux habituel pour l'heure. |
phi-after-hours | Un canal qui ne transporte que du trafic de jour en transporte la nuit. |
phi-new-destination | Un canal livre à une adresse à laquelle il n'a jamais envoyé auparavant. |
phi-bulk-reads | Une personne lit plus de N dossiers de patients différents dans une minute. |
Les quatre derniers surveillent l'accès aux données des patients et sont décrits ci-dessous.
11.2 Le silence est la chose la plus difficile à détecter
Un canal qui a cessé de recevoir des données ne produit aucune erreur. Il n'y a rien à compter. C'est pourquoi no-traffic existe, et pourquoi il ne suffit pas à lui seul.
no-traffic est un seuil fixe : alerter si rien n'est arrivé pendant, disons, deux heures. Sur un flux qui ne s'arrête jamais vraiment, cela fonctionne. Sur un flux de laboratoire d'une clinique, cela est inutile — le flux est silencieux toutes les nuits et tous les week-ends, donc un seuil de deux heures déclenche une alerte à 1h du matin tous les soirs, et un seuil suffisamment long pour survivre au week-end ne remarquera pas une panne le mardi matin avant le mardi après-midi.
Il n'y a pas de nombre unique qui soit les deux. Ce n'est pas un problème de réglage ; c'est que la question « ce flux s'est-il arrêté » ne peut pas être répondue par une constante lorsque le flux normal varie d'un facteur de cent au cours de la semaine.
11.3 Détection sensible au rythme
below-rhythm compare le trafic actuel à ce que ce canal fait normalement à cette heure de ce jour de la semaine.
Perfuse apprend l'historique de chaque canal à partir de ses propres enregistrements : 168 buckets horaires, en commençant par lundi, de sorte qu'une semaine de travail soit contiguë. Pour chaque bucket, il conserve une médiane, un minimum, un maximum, un plancher et le nombre d'observations sur lesquelles il est basé.
Le seuil est une part du trafic normal, par défaut 0.8 (80 pour cent dans la console) — alerte lorsque le trafic chute en dessous des quatre cinquièmes de ce qui est normal pour cette heure.
11.3.1 Médiane, et non moyenne
Un seul déversement de backlog de 40 000 messages contre un normal de 300 déplace la moyenne suffisamment pour que le flux puisse devenir complètement silencieux par la suite sans jamais tomber en dessous. La médiane n'est pas affectée par une heure extraordinaire, ce qui est exactement la propriété nécessaire.
11.3.2 Le plancher est un centile, et non le minimum
La décision de savoir si le rythme d'un canal est suffisamment fiable pour alerter est prise en fonction de son extrémité inférieure, et non de son extrémité supérieure. Une alerte de déficit se déclenche lorsque le trafic est *faible*, donc seul l'extrémité inférieure peut vous dire si elle produira de faux positifs. Une version antérieure de cela comparait le maximum à la médiane et se trompait dans les deux sens à la fois : elle disqualifiait un flux parfaitement régulier pendant un mois après un backlog, et elle passait un flux réellement erratique qui oscillait entre deux et neuf cents messages dans la même heure parce que son maximum n'était que trois fois sa médiane.
Le plancher est le vingtième centile plutôt que le minimum, car le minimum est tiré vers zéro par un seul jour férié. Et le centile n'est pas interpolé — chaque nombre dans une alerte à 2 heures du matin devrait être un décompte que le flux a réellement produit, et non une moyenne de deux décomptes qu'il n'a pas produits.
11.3.3 Il dira lorsqu'il ne peut pas le dire
Un canal sans historique du tout est omis entièrement plutôt que d'être traité comme un canal qui s'est arrêté. Un nouveau canal ne doit pas ressembler à un canal défectueux.
Lorsque l'historique est trop mince ou trop erratique pour soutenir un jugement, la règle refuse de se déclencher plutôt que de deviner. « Je ne peux pas honnêtement le dire » est une réponse de première classe ici, et elle est préférée à une alerte qui a raison un peu plus souvent que par hasard.
Les heures absentes à l'intérieur de la fenêtre d'apprentissage sont enregistrées comme de vrais zéros, et non comme des données manquantes. La moitié du signal dans un flux de clinique est *lorsqu'il est légitimement silencieux*, et traiter ces heures comme inconnues jetterait cela.
11.4 Paramétrer les alertes
Depuis l'interface, sous Alertes, par canal ou sur tous. Chaque règle a un type, un seuil et où envoyer l'alerte. Les règles sont sauvegardées dans alerts.yaml à côté de la base de données (ou le fichier -alerts nomme) et prennent effet immédiatement ; jusqu'à la première sauvegarde, les règles intégrées s'appliquent. Le fichier peut également être édité manuellement : le changement est pris en compte dans les trente secondes, et un fichier qui ne charge plus est signalé dans le journal et les règles en vigueur sont conservées.
Vaut la peine de le faire avant qu'un flux ne devienne actif plutôt qu'après le premier incident. L'ensemble spécifique d'alertes qui vaut la peine d'avoir sur n'importe quel flux clinique :
below-rhythm— le flux est devenu silencieux lorsqu'il ne devrait pas l'être.error-rate— les messages arrivent et échouent.queue-age— quelque chose est coincé plutôt que simplement occupé.channel-down— le canal n'est pas en cours d'exécution du tout.
La première est celle qui attrape la défaillance que personne d'autre ne signalera.
11.5 Surveillance de l'accès aux données des patients
Une faille de sécurité se déclare rarement. Elle ressemble à une alimentation qui transporte plus que d'habitude, du trafic à trois heures du matin sur un canal qui ne fonctionne qu'en heures de bureau, une destination que personne n'a configurée, ou une personne qui ouvre patient après patient. Perfuse surveille ces quatre, activés par défaut (serve -watch-access=false les désactive), et signale ce qu'il voit via les règles d'alerte ci-dessus, afin qu'il soit configuré, reconnu et livré comme n'importe quelle autre alerte.
- Bursts (
phi-volume). Chaque taux de canal est comparé à son propre historique à la même heure de la journée, donc un matin chargé n'est pas une nouvelle. Le seuil est un multiple du taux habituel, trois par défaut. Un burst est généralement un retard libéré après une panne, et c'est également à quoi ressemblent les enregistrements extraits via un flux. - Trafic de nuit sur un canal diurne (
phi-after-hours). Un canal est considéré comme diurne uniquement lorsque moins de 2 pour cent de ce qu'il a transporté est tombé en dehors de 07h00 à 19h00, dans le fuseau horaire du serveur. - Une nouvelle destination (
phi-new-destination). L'adresse est ce que la destination nomme : un hôte et un port, une URL, un dossier. Renommer une destination n'est pas une nouvelle ; pointer une vers un nouvel hôte est. Les adresses auxquelles chaque canal a envoyé sont conservées dansaccess-watch.jsonà côté de la base de données, donc une destination modifiée pendant que le serveur était arrêté est toujours signalée. - Lectures en bloc (
phi-bulk-reads). Compté à partir de la trace d'audit : messages ouverts, patients recherchés ou consultés (PDQm, PIXm, recherche d'identité), documents et images lus (XDS, MHD, DICOMweb), autorisations préalables lues, résumés et vues exécutés. La lecture du même enregistrement à nouveau ne compte pas deux fois. Le seuil est le nombre d'enregistrements différents par minute, dix par défaut, par un compte à partir d'une adresse.
Rien n'est jugé pour un canal jusqu'à ce qu'il ait transporté 200 messages, car « inhabituel » ne signifie rien sans modèle. Le modèle est appris à partir des deux dernières semaines du magasin de messages lorsque le serveur démarre, donc un redémarrage ne rend pas chaque canal nouveau à nouveau. Tout ce qui est vu est conservé pendant quinze minutes, puis l'alerte se supprime elle-même.
Il ne fait que regarder et signaler. Il ne retarde jamais un message ou refuse une lecture : ce sont des heuristiques, et un flux arrêté parce qu'une supposition était fausse est un problème clinique. Chaque alerte indique ce qui a été vu et ce que cela pourrait être innocemment, car la plupart d'entre elles seront innocentes.
Les administrateurs voient ce que le moniteur a appris sur l'écran des alertes, sous Surveillance de l'accès aux données des patients : le modèle de chaque canal (toujours en apprentissage, diurne uniquement ou jour et nuit), le nombre de destinations qu'il connaît et tout ce qui a été vu au cours des quinze dernières minutes, y compris ce qui est en dessous d'un seuil de règle.
11.6 Où les alertes vont
Les alertes peuvent être envoyées sous forme de JSON à un webhook (-alert-webhook : Slack, Teams, Mattermost, PagerDuty, Alertmanager ou tout ce qui accepte un POST), envoyées sous forme de pièges SNMPv2 à des gestionnaires SNMP (-snmp-traps, voir SNMP), ou écrites dans le journal pour qu'un collecteur les récupère. Il n'y a pas de livraison de courrier électronique propre : pointez le webhook vers un relais si les alertes doivent arriver par courrier électronique.
Une alerte qui n'est écrite que dans un journal que personne ne lit n'est pas une alerte. Si Perfuse est la seule chose qui remarquera un flux arrêté, l'alerte doit atteindre une personne.
12 Le Magasin de Messages
Chaque message que Perfuse reçoit est enregistré, tel qu'il a été reçu, avant que quoi que ce soit ne le modifie. C'est également le cas de ce qui a été envoyé à chaque destination et de ce qui lui est arrivé. Le magasin est un fichier SQLite donné par -db.
12.1 Ce qui est conservé
Par message : les octets bruts tels qu'ils sont arrivés, le moment de leur arrivée, le canal, le type de message parsé et l'événement déclencheur, ainsi que le résultat du filtre.
Par destination par message : les octets qui ont été envoyés, le résultat, le temps pris et toute erreur ou accusé de réception négatif reçu.
C'est la forme qu'une enquête nécessite. « Qu'est-ce qu'ils nous ont envoyé », « qu'est-ce que nous leur avons envoyé » et « qu'est-ce qu'ils ont dit à ce sujet » sont trois questions différentes et chacune d'elles est posée.
12.2 Recherche
Par canal, par plage de temps, par résultat, par type de message et événement déclencheur, et par valeur de champ.
La recherche de champ fonctionne sur le message parsé, donc la recherche d'un numéro d'enregistrement le trouve où que ce champ vive dans le message, plutôt que de correspondre aux chiffres n'importe où dans le texte. Une recherche de texte pour 12345 dans un message contenant une quantité de 12345 trouve un message qui n'a rien à voir avec le patient que vous recherchez.
12.3 Relecture et retraitement
Puisque l'original est conservé, un message peut être à nouveau traité par la configuration actuelle.
Trace prend un message enregistré et montre ce que le canal ferait avec lui maintenant, sans envoyer quoi que ce soit. Voir débogage.
Reprocess le retraite réellement, y compris la livraison. C'est ce qui corrige un lot de messages qui ont échoué parce qu'une destination était mal configurée : corrigez la configuration, sélectionnez les messages affectés, retraitez.
12.4 Antériorité
Une trace d'un ancien message par rapport à la configuration actuelle répond à une hypothèse : qu'est-ce qui *se passerait* maintenant. C'est généralement ce que vous voulez, mais pas toujours — si vous enquêtez sur ce qui s'est mal passé la semaine dernière, le canal peut avoir changé depuis.
Perfuse détecte cela et le signale. Une trace d'un message qui est arrivé avant que le canal ne soit modifié pour la dernière fois est marquée comme telle, afin que la réponse ne soit pas confondue avec une reconstruction de ce qui s'est réellement passé.
12.5 Rétention
Le magasin grandit. cleanup.periodDays contrôle combien de temps les messages sont conservés.
Deux choses à peser. Les messages cliniques peuvent être soumis à des exigences de rétention plus longues que tout ce que vous choisiriez pour des raisons opérationnelles, et le magasin n'est pas le système d'enregistrement — le système récepteur l'est. La copie de Perfuse existe pour diagnostiquer et retraiter, et ces deux besoins diminuent fortement après quelques semaines.
La rétention décide également de la quantité d'historique dont dispose l'apprenant en rythme pour travailler. Voir alerting : une fenêtre de rétention inférieure à quelques semaines la rend incapable de distinguer un dimanche calme d'un flux arrêté.
12.6 Le magasin contient des données cliniques
Il s'agit de la partie de Perfuse qui contient des informations sur les patients, et elle doit être traitée en conséquence : stockage chiffré, sauvegarde en tant que données cliniques et contrôle d'accès. Voir sécurité.
Les messages de test générés décrits dans testing existent en partie pour que ces données n'aient pas à quitter l'environnement afin de reproduire un problème ailleurs.
13 Débogage
La question est presque toujours la même : ce message est arrivé, quelque chose de mal s'est passé, où a-t-il changé ? Perfuse répond en rejouant un message enregistré à travers la configuration actuelle et en montrant chaque étape.
Rien n'est envoyé pendant la traçage. Le canal continue de fonctionner sans modification, et aucune rédeployment n'est nécessaire.
13.1 Traçage d'un message
Sélectionnez n'importe quel message enregistré et traçez-le. Le résultat montre, dans l'ordre :
- Ce que le filtre a lu. Quels champs il a examinés et quelles valeurs il a trouvées. Un filtre qui rejette tout est généralement en train de lire un chemin qui n'existe pas dans cet alimentation, et cela le nomme.
- Chaque transformation. Ce qu'il a modifié, de quoi à quoi.
- Ce que chaque destination a décidé. S'il accepterait le message, et pourquoi pas si ce n'est pas le cas.
- La sortie. Le message tel que chaque destination l'aurait envoyé.
13.2 Étape par étape
La vue étape par étape exécute chaque transformation individuellement et prend un instantané du message entier après celle-ci. Un rail numéroté d'étapes, coloré en fonction de ce qui s'est passé, et le message tel qu'il se présentait à chaque point.
Le message entier plutôt que seulement le changement, car le changement n'est souvent pas là où se trouve le problème — une étape qui a modifié correctement le champ visé, sur un message où une étape antérieure avait déjà placé la mauvaise chose, semble parfaitement correcte en isolation.
13.3 Quatre résultats, et la distinction qui compte
| Résultat | Signification |
|---|---|
changed | L'étape s'est exécutée et a modifié le message. |
no-effect | L'étape s'est exécutée, et le message n'a pas changé. |
skipped | La condition when de l'étape était fausse, donc elle n'a pas été exécutée. |
failed | L'étape a échoué. |
no-effect et skipped sont signalés séparément, et c'est le point de cette fonctionnalité entière.
De l'extérieur, ils sont identiques : le message est le même après coup. Ils signifient des choses opposées. skipped signifie que la condition a fonctionné comme écrite et que ce message n'était pas celui auquel elle s'appliquait — généralement correct. no-effect signifie que l'étape s'est exécutée et n'a rien trouvé à faire, ce qui signifie généralement qu'elle vise un champ qui n'existe pas.
Un moteur qui signale les deux comme « rien ne s'est passé » vous empêche de distinguer une condition fonctionnelle d'un chemin cassé, et c'est le bogue de transformation le plus courant qui existe.
no-effect sur chaque message est presque toujours un chemin incorrect. L'en-tête de l'étape par étape compte combien d'étapes n'ont rien trouvé, ce qui est le moyen le plus rapide de le repérer : un canal avec trois étapes et trois résultats no-effect ne transforme rien du tout.13.4 Test d'un changement avant de l'enregistrer
Le constructeur peut exécuter une configuration candidate contre du trafic enregistré et signaler ce qui différerait. C'est le moyen le plus sûr de modifier un canal en direct : effectuez la modification, voyez ce qu'elle fait aux derniers messages réels, puis enregistrez.
C'est également la façon de découvrir qu'une modification qui semble évidemment correcte affecte des messages que vous n'aviez pas pensés — une étape conditionnée à un événement déclencheur, sur un flux qui s'avère transporter quatre.
13.5 Ce que la traçage ne peut pas vous dire
Elle exécute la configuration actuelle. Si le canal a été modifié depuis l'arrivée du message, la traçage est hypothétique plutôt que reconstructive, et Perfuse la marque comme telle plutôt que de laisser la distinction passer silencieusement.
Elle n'exerce pas non plus le transport. Une traçage montre ce qui serait envoyé, et non si la destination l'accepterait — un message correct et une destination qui refuse les connexions produisent une traçage propre et une livraison échouée. Ceux-ci sont visibles dans l'enregistrement de livraison à la place.
13.6 Scripts
Un script est une étape opaque dans la traçage. Perfuse peut montrer ce qui est entré et ce qui est sorti, et ne peut pas montrer ce qui s'est passé entre les deux ou quels champs ont été lus.
C'est le coût concret de l'utilisation d'un script plutôt que des étapes déclaratives, et il vaut la peine de le peser lors du choix. Voir transformation.
14 Test
Le conseil standard pour tester une interface est de construire des messages d'exemple qui reflètent votre propre environnement — les codes de votre laboratoire, votre mix de cas, les habitudes de votre expéditeur — et de supprimer les données de patient à la main. C'est lent, et le faire de manière incomplète est le résultat normal.
Perfuse offre trois choses à la place : du trafic généré qui correspond à la forme d'un flux sans son contenu, un canal proposé à partir d'un exemple que quelqu'un vous a envoyé, et une comparaison avec le moteur que vous remplacez.
14.1 Trafic de test généré
Si un canal a traité des messages, Perfuse peut produire davantage de messages similaires.
Ce qui est fidèle :
- Déclencher des événements dans les proportions réellement observées, avec au moins un de chaque, afin qu'un événement rare apparaisse encore.
- Les champs remplis aux taux réels — ainsi, le cas où un champ est *absent* est testé, ce qui est le cas qui casse les choses.
- Des répétitions où des répétitions se produisent, une structure composite où elle se produit.
- Des codes tirés des tables de codes réellement vues.
Ce qui n'est pas fidèle, et cela est indiqué plutôt qu'impliqué : la cohérence clinique. Un patient généré a un numéro de dossier non lié, une chaîne de caractères en forme de nom et un diagnostic sans rapport avec l'observation. Ces messages exercent une interface. Ils ne constituent pas un ensemble de tests cliniques et ne peuvent pas être utilisés pour valider la logique clinique.
14.1.1 Pourquoi il ne contient aucune donnée réelle
L'argument est structurel plutôt qu'une affirmation d'effort. Le générateur n'a que le profil de trafic du canal comme entrée, et un profil contient des taux de remplissage, des formes, des longueurs, des comptes de répétition et des fréquences de segments. Il ne contient aucune valeur.
La seule exception concerne les champs de tables de codes, et un code n'identifie personne.
Ceci est une garantie plus forte que la désidentification de messages réels, qui est un processus qui peut être effectué de manière incomplète et qui l'est généralement. Ici, il n'y a pas de chemin par lequel un nom pourrait atteindre la sortie, car le nom n'a jamais été dans l'entrée.
Chaque message généré est analysé avant d'être renvoyé — un corpus non analysable obligerait quelqu'un à rechercher un bogue dans son interface qui est en réalité un bogue dans le générateur — et chacun est marqué T dans MSH-11, avec une application et une installation d'envoi synthétiques délibérément.
T et l'expéditeur synthétique ne sont pas cosmétiques.14.2 Création d'un canal à partir d'un échantillon
Collez le message qu'un laboratoire, un hôpital ou un fournisseur vous a envoyé par courriel et Perfuse propose un canal pour celui-ci. Rien n'a besoin de fonctionner au préalable.
Il gère ce que les gens collent réellement : plusieurs messages dans un bloc, toute fin de ligne, un encadrement MLLP qui a survécu à la copie, et la note de couverture au-dessus du message. Refuser un échantillon parce qu'il est arrivé avec des fins de ligne Windows serait un obstacle plutôt qu'un contrôle.
14.2.1 Trois listes
La proposition vient avec ce que l'échantillon montre, ce qui a été deviné, et ce que l'échantillon ne peut pas vous dire — trois listes distinctes, pesées également dans l'interface.
Elles sont distinctes car un lecteur qui ne peut pas dire lesquelles sont lesquelles doit vérifier tout ou faire confiance à tout, et les deux sont pires que de savoir où regarder.
À partir d'un seul message, les limites sont nommées spécifiquement plutôt que de manière générale : quels champs sont facultatifs, quels segments se répètent, quels codes existent au-delà de ceux qui sont ici, si l'expéditeur envoie jamais un événement déclencheur différent. Une mise en garde générale est quelque chose que les gens survolent.
La confiance est un mot — faible, modérée, raisonnable — et non un pourcentage. Un pourcentage implique un calcul, et ceci est un jugement sur le nombre d'échantillons.
Les segments Z sont appelés par leur nom, car un segment local est la chose que aucune spécification ne mentionne et la raison la plus courante pour laquelle un canal construit à partir d'un modèle standard ne fonctionne pas.
14.2.2 L'avertissement de séparateur
Si le séparateur de champ de l'échantillon n'est pas le | habituel, cela apparaît en premier, et la confiance est réduite à faible.
La raison est une véritable défaillance silencieuse. HL7 prend son séparateur de champ à partir du message lui-même, donc un échantillon dont les pipes ont été remplacées par des similis typographiques — ce que fait un processeur de texte — analyse parfaitement en champs qui sont tous faux. Rien n'erre partout.
Refuser un tel échantillon serait incorrect, car un expéditeur peut légitimement utiliser un autre séparateur. Il est donc signalé, le caractère est nommé, et il est suggéré de demander une pièce jointe en texte brut.
14.3 Comparaison avec l'ancien moteur
Avant de déplacer un flux en direct, la question est de savoir si Perfuse produit les mêmes sorties que le système qui fonctionne depuis des années. Aucune quantité de qualité de conception ne répond à cela. Voir migration.
14.4 Vérification contre la chose réelle, dans des conteneurs
Trois vérifications sont effectuées contre des implémentations réelles plutôt que contre l'idée propre de Perfuse d'un protocole. Elles vivent en dehors de make check car elles nécessitent un runtime de conteneur, et une vérification qui nécessite Docker est une vérification que les gens arrêtent d'exécuter.
scripts/interop-up.sh démarre tous les conteneurs et imprime ce que chaque vérification débloque.
| Conteneur | Vérifications | Ce que l'on a trouvé |
|---|---|---|
| Keycloak 26 | web/e2e-saml/, et des fixtures internal/saml | Un défaut. La forme canonique d'une signature était calculée avec des préfixes d'espace de noms supprimés, donc aucun fournisseur d'identité réel n'aurait jamais pu connecter quelqu'un |
| Microsoft Entra | Vérifications et fixtures internal/saml en direct | Deux défauts, tous deux dans ce qui entoure le protocole. Un compte a été créé sous l'ID Entra opaque, car la logique de nom lisible voulait une revendication d'e-mail et Entra n'en envoie aucune. Et un compte SAML a été enregistré comme OIDC, car le magasin a dérivé le protocole d'un émetteur qui ressemble à l'identique pour les deux |
| HAPI FHIR | go test ./internal/engine/ -run HAPI | Un défaut. Une autorité d'affectation non mappée a produit un système d'identifiant qui annonçait un OID et portait un mot, que HAPI a accepté sans plainte |
| ActiveMQ | go test ./internal/engine/ -run RealBroker | Correct, y compris le cas de cadre de byte nul. Asserté via l'interface de gestion du courtier lui-même plutôt que via une fonction qui retourne nil |
| nginx, certificats client | go test ./internal/engine/ -run ClientCertificate | Correct |
| Orthanc (un PACS réel) | go test ./internal/engine/ -run RealPACS | Correct. Un C-STORE arrive et le nom du patient, l'identifiant, la date d'étude, la modalité et la classe SOP survivent tous |
| PostgreSQL | go test ./internal/engine/ -run RealPostgres | Correct, et cela a déclenché une meilleure erreur : une instruction dans les espaces réservés du dialecte incorrect est maintenant refusée lors de l'enregistrement plutôt que de devenir une erreur de syntaxe sur le serveur lorsqu'un message arrive |
| OpenSSH sftp-server | go test ./internal/engine/ -run OpenSSHServer | Correct. Les tests SFTP existants utilisent la même bibliothèque Go sur les deux extrémités ; OpenSSH est une implémentation différente et celle qui se trouve à l'extrémité lointaine de presque chaque flux réel |
| Mirth 4.5.2 | go test ./internal/mirth/ -run RealMirth | Correct maintenant. Le seul fixture utilisé était écrit à la main et Mirth ne l'a pas chargé ; scripts/mirth-author-channel.sh a Mirth créé un canal à la place, et Perfuse le lit |
Chacun saute plutôt que d'échouer lorsque son conteneur est absent, donc make check passe sur une machine sans Docker.
Pourquoi cela est séparé du reste de la suite. Chaque autre test de ces fonctionnalités avait les deux moitiés écrites ici : un document que ce codebase a signé, relu par le code qui l'a signé. C'est un accord avec soi-même, et cela vaut moins qu'il n'y paraît.
Le canoniseur SAML est le cas qui prouve le point. Il contenait mille lignes de tests, cinq d'entre eux spécifiquement sur la canonisation, et tous ont passé tandis que aucun fournisseur d'identité réel n'aurait jamais pu connecter quelqu'un — la forme canonique que la signature couvre était calculée avec des préfixes d'espace de noms supprimés, et la seule façon de le découvrir était de lui donner un document que Perfuse n'avait pas écrit.
Deux des huit vérifications ont trouvé des défauts ouverts, et une troisième a déclenché une amélioration réelle. Trois n'ont rien trouvé de mal. Ce ratio est l'argument pour conserver tous : une vérification qui passe a dit quelque chose que vous ne pouviez pas savoir autrement, et il n'y avait pas de moyen de savoir à l'avance lesquels ils seraient.
Un modèle qui vaut la peine d'être nommé, car il est apparu dans les deux défauts : l'acceptation n'est pas la vérification. HAPI a accepté le système d'identifiant malformé et l'a stocké ; le défaut n'est apparu que lors de la lecture de la ressource. Un récepteur qui tolère quelque chose n'est pas la preuve qu'il est correct, mais seulement que ce récepteur était indulgent.
Deux assertions capturées sont commitées, à internal/saml/testdata/keycloak-assertion.xml et entra-response.xml, avec des tests sur les deux — donc cette régression particulière est capturée sans conteneur.
Les deux sont nécessaires plutôt que l'un étant de trop. Keycloak préfixe son assertion et sa signature, Entra ne le fait pas, et ce sont les deux cas opposés dans la canonisation — qui est précisément où se trouvait le défaut. Un test asserte chaque document qui couvre toujours son propre cas, car une capture de remplacement qui se produit par hasard à préfixe silencieusement réduirait la couverture sans échouer quoi que ce soit. La leçon générale ne se généralise pas si facilement : pour tout autre cas, le conteneur est la vérification.
14.5 Diagnostiquer un test qui échoue une fois et jamais plus
Un test qui échoue dans une exécution complète et passe seize fois seul n'est pas un test instable. C'est un test qui partageait quelque chose avec l'exécution, et la façon de découvrir ce que c'est de mesurer la chose partagée plutôt que le test.
Deux instruments existent pour cela, et les deux sont destinés à être exécutés aux côtés d'une suite complète :
./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
Chacun découvre les ports de l'exécution à partir du fichier d'état de configuration et échantillonne tous les 500 millisecondes jusqu'à ce que le serveur se termine. Ils enregistrent chaque échantillon plutôt que seulement les échecs, ce qui les rend utiles : un pic apparaît dans une exécution où rien n'a échoué, donc une faute qui apparaît une fois sur trois exécutions devient mesurable sur chaque exécution.
Définissez PERFUSE_E2E_KEEP=1 pour conserver le répertoire temporaire, qui contient la base de données telle qu'elle a été laissée et le journal du serveur pour toute la durée de l'exécution. Le journal du serveur est généralement la réponse. Dans un cas examiné, il a enregistré l'arrêt d'un canal et la réaffectation de son écouteur 421 millisecondes plus tard, et la connexion refusée de la sonde est tombée dans cette fenêtre.
Lisez la trace plutôt que error-context.md, qui a été vide à plus d'une occasion où la trace contenait le message réel.
Copiez les artefacts avant de réexécuter quoi que ce soit. Une exécution réussie supprime test-results, donc la trace de l'échec que vous êtes en train d'examiner disparaît au moment où vous essayez de le reproduire. Une fois perdu, la question qu'il aurait répondu ne peut pas être répondu.
Arrêtez les conteneurs d'interopérabilité en premier. Arrêtez-les avant une exécution complète du navigateur, et démarrez-les avec ./scripts/interop-up.sh par la suite si vous en avez encore besoin.
Huit conteneurs occupent environ 9,8 Go de mémoire, et sur une machine sans beaucoup plus que cela, il reste trop peu de mémoire pour les processus de Chromium, node et la chaîne d'outils Go ensemble. Ce qu'il produit n'est pas une erreur de mémoire insuffisante, mais un rendu qui cesse d'être planifié : une trace enregistrée montre un écart de 60,2 secondes sans aucun cadre, pendant lequel Playwright attendait qu'un bouton devienne « visible, activé et stable » et ne pouvait pas obtenir deux trames d'animation consécutives à comparer. Le serveur était sain tout au long de l'exécution, la requête la plus lente de toute la durée de l'exécution étant de 154 millisecondes.
Cet échec ressemble à un défaut dans le test qui se trouvait à exécuter. Il vaut la peine de connaître sa forme : chaque requête rapide, la page visuellement gelée, la boucle de réessai ne parvenant jamais à une deuxième itération, et tout cela passant en isolement.
Une exécution à la fois. La suite partage un serveur, une session connectée dans web/e2e/.auth/admin.json, et un fichier d'état nommant le processus du serveur. Aucun de ces éléments n'est par exécution, donc une deuxième exécution qui démarre pendant que la première est en cours écrase le fichier d'état, et la déconnexion qui se termine en premier tue le serveur de l'autre exécution et supprime sa session.
Ce à quoi cela ressemble n'est pas du tout la cause. Il a produit une exécution de 279 échecs dont le premier message était ENOENT: no such file or directory, open './e2e/.auth/admin.json', une exécution qui s'est arrêtée tôt en signalant 217 passes, et deux tests échouant avec bind: address already in use — aucun de ces éléments ne suggère deux exécutions en conflit. La suite prend maintenant un verrou et refuse de démarrer, en nommant le processus qui le détient. Un verrou laissé par une exécution interrompue est repris plutôt que de bloquer pour toujours, car une mesure de sécurité qui bloque la suite est une mesure que quelqu'un supprime avec la sécurité.
Un piège connexe, maintenant corrigé : deux spécifications ont nommé leurs ports d'écoute directement, donc un serveur laissé derrière par une exécution interrompue les faisait échouer sur quelque chose avec lequel ils n'avaient rien à voir. Les ports sont maintenant demandés au système d'exploitation.
Ne répondez à aucun de ces éléments avec des réessais. Un test qui passe à la deuxième tentative a trouvé une course réelle et l'a cachée, et playwright.config.ts définit retries: 0 pour cette raison.
Une mise en garde : l'échantillonnage toutes les 100 millisecondes a fait apparaître vingt processus par seconde, a allongé une exécution de moitié, et a fait échouer deux tests sur des délais d'attente qui n'avaient rien de mal. Un instrument qui modifie ce qu'il mesure produit des résultats sur lui-même.
14.6 Ce qui nécessite encore une infrastructure réelle
Plusieurs parties de Perfuse sont implémentées et n'ont jamais été exercées contre la chose réelle. Elles sont énumérées ici plutôt que d'être découvertes :
- SMB contre un partage Windows réel — le code de protocole est complet et testé pour la sécurité des chemins et la gestion des arguments, mais aucun test n'ouvre un socket vers un serveur joint au domaine.
- Un port série réel.
- L'importateur Mirth contre du XML produit par un Mirth réel. Testé contre Mirth 4.5.2 dans un conteneur, et la découverte a porté sur ce référentiel : le seul fixture de migration ici a été écrit à la main et Mirth ne le chargera pas — il stocke le canal comme invalide et supprime chaque connecteur. Ce qui a été réglé, c'est que les attributs
versionque le Mirth réel écrit sur chaque élément analysent le même canal, donc ils ne sont pas un danger ; ce qui n'est pas réglé, c'est tout le reste que contient une exportation réelle. - SAML contre un fournisseur d'identité commercial hébergé. Keycloak est vérifié ; un fournisseur prouve qu'une implémentation correspond à un fournisseur.
- Une réclamation NCPDP via un commutateur de pharmacie réel.
- Un message SCRIPT via Surescripts, où la certification est un processus commercial plutôt que technique.
Les fonctionnalités de ce chapitre et du suivant existent pour que vous puissiez rassembler vos propres preuves plutôt que de prendre la parole de quelqu'un.
14.7 Mesuré contre des corpus de conformité publics
Une suite de tests dont les fixtures ont été écrites ici prouve l'accord avec soi-même. Ce sont les données de autres personnes.
14.7.1 FHIR R4, les exemples de la spécification
Tous les 2 912 fichiers d'exemple publiés avec la spécification FHIR R4 — chaque exemple que les auteurs de la norme ont écrit.
| Résultat | Compte |
|---|---|
| Ressources validées sans résultats | 13 723 |
| Ressources signalées comme invalides | 0 |
| Fichiers refusés en tant que type de ressource non implémenté | 753 |
| Entrées de bundle ignorées en tant que type non implémenté | 1 348 |
Aucune ressource n'a été validée incorrectement. Toute défaillance est un refus explicite nommant le type qu'il ne peut pas lire — 672 ValueSet, 80 ConceptMap et un Parameters. Un validateur qui passe silencieusement ce qu'il ne comprend pas est pire qu'un qui le dit.
Le corpus a trouvé un défaut, ce qui est la raison de l'exécution. La validation d'un bundle a imprimé « La validation d'un bundle à partir d'un fichier n'est pas encore prise en charge » et a continué. C'était faux dans les deux sens : les bundles dont les entrées se sont avérées être des types que l'analyseur pouvait contenir étaient déjà validés, et un bundle qui était vraiment invalide a produit la même ligne, n'a compté rien et est sorti zéro — y compris sous -strict, qui existe pour que cela puisse gêner une construction. Quarante-deux des bundles de la spécification elle-même ont été ignorés.
Les bundles sont maintenant validés entrée par entrée, avec trois résultats conservés séparément : une entrée qui est incorrecte échoue et nomme le champ, une entrée d'un type que cette version ne peut pas lire est comptée comme ignorée et signalée, et un bundle qui ne contient pas de corps de ressource n'est ni l'un ni l'autre. Le même corpus est passé de 2 100 ressources vérifiées à 13 723.
14.7.2 HL7 v2, le corpus de test HAPI
Les fixtures de message de HAPI, la mise en œuvre de référence Java HL7 v2 — matériau intentionnellement maladroit, y compris des charges utiles uuencodées, des délimiteurs échappés et des groupes répétitifs.
59 messages, 59 analysés, rien refusé. Sept types de messages dans un corpus que n'importe quel système unique décrirait comme une chose, ce qui est le point perfuse profile existe pour faire.
14.7.3 Ce qui n'a pas été exécuté
DICOM contre un ensemble de conformité public, et X12 contre un corpus publié. Rien de cela n'a été fait, et rien de cela ne devrait être déduit des deux précédents.
15 Migration de Mirth
Deux choses sont nécessaires pour remplacer un moteur de travail : les canaux doivent être transférés, et quelqu'un doit être capable de montrer que le remplacement produit la même sortie. Perfuse fait le premier en important les propres exports de Mirth, et le second en comparant les deux moteurs sur votre propre trafic.
Tout ce qui se trouve dans ce chapitre s'applique de la même manière à Open Integration Engine et BridgeLink. Mirth Connect a cessé d'être open source à la version 4.6 en mars 2025 ; OIE (hébergé par la Fondation Eclipse) et BridgeLink (Innovar Healthcare) sont les forks qui continuent la ligne open source, et les deux écrivent les mêmes formats d'export. L'importateur est testé contre les trois, ci-dessous.
15.1 Importation de canaux
Perfuse lit chaque export que ces moteurs écrivent :
| Export | Depuis l'administrateur | Ce qui est transféré |
|---|---|---|
| Un canal | Exporter le canal | Le canal |
| Un groupe de canaux | Exporter le groupe | Chaque canal qui le compose, en conservant le groupe |
| Modèles de code | Exporter les modèles de code | Chaque bibliothèque comme un fichier de script |
| Une sauvegarde de serveur | Sauvegarder la configuration, ou GET /api/server/configuration | Tout ce qui précède à la fois |
Pointez perfuse translate sur l'un d'eux, ou déposez-en un sur Administer → Migrate :
perfuse translate -o ./channels server-backup.xml
Une bibliothèque de modèles de code devient lib/<library>.js à côté des canaux, et chaque canal pour lequel Mirth avait activé la bibliothèque obtient scripts.include: [lib/<library>.js] — ainsi, un transformateur appelant une fonction de site telle que formatMRN() la trouve toujours. Un canal pour lequel la bibliothèque n'a pas été activée ne l'inclut pas, car ses scripts ne pouvaient pas la voir dans Mirth non plus. Les extraits de code glissés-déposés sont laissés de côté : Mirth ne les colle jamais que dans une étape manuellement, ils ne sont donc pas du code qui s'exécute de manière autonome. Dans le navigateur, l'importation d'un canal enregistre d'abord les bibliothèques qu'il inclut.
Un Channel Writer nomme le canal auquel il livre par id. Dans un groupe ou une sauvegarde, la cible se trouve dans le même document, elle devient donc une destination de channel nommant ce canal ; à partir d'une exportation à canal unique, elle est signalée pour que vous la remplissiez. Les scripts globaux serveur n'ont pas d'équivalent Perfuse et sont signalés plutôt que supprimés.
Le rapport indique, par canal, s'il a été traduit proprement, traduit avec des avertissements ou s'il n'a pas pu être lu.
Le titre est une fraction avec son dénominateur — "37 sur 40 prêts" — car "37 prêts" ne vous dit rien sur ce que vous devez encore faire.
Un canal qui n'a pas pu être lu est un problème différent de celui qui n'a pas pu être traduit. Le premier signifie que le XML lui-même n'a pas été analysé et est généralement une exportation tronquée ou partielle ; le second signifie que le contenu du canal comporte quelque chose sans équivalent dans Perfuse. L'importation les sépare.
15.2 Ce qui se traduit et ce qui nécessite une décision
Les sources, les destinations, les filtres et les étapes de transformation ordinaires se traduisent directement. Les connecteurs qui se traduisent : TCP/MLLP (et TCP brut avec son encadrement), HTTP, Fichier, Base de données, JavaScript, DICOM, Service Web (SOAP), SMTP et Lecteur/Écrivain de canal. JMS et l'Écrivain de document ne se traduisent pas, et sont signalés comme des bloqueurs.
Une étape de mapping qui définit une variable la place dans la carte dont la portée est nommée — channelMap par défaut — exactement comme Mirth le fait, de sorte que les étapes suivantes la lisant avec $('name') la trouvent.
Les transformateurs JavaScript ne le font pas, en général. Les canaux Mirth contiennent souvent du code important dans un transformateur, et il n'y a pas de conversion automatique d'un JavaScript arbitraire en étapes déclaratives. L'importateur les signale plutôt que de tenter une traduction qui pourrait être subtilement incorrecte : un transformateur mal traduit est pire qu'un transformateur signalé pour un humain, car il s'exécutera.
Lorsqu'un script doit vraiment rester un script, Perfuse peut l'exécuter — voir la clé scripts dans la référence de canal — au prix de la trace au niveau de l'étape décrite dans débogage
15.3 Ce que l'importateur a été testé
Cinq moteurs, chacun rédigeant ses propres documents : Mirth 4.5.2, OIE 4.5.2, 4.6.0 et 4.7.0, et BridgeLink 26.9.0. scripts/mirth-engine-corpus.sh compile un petit programme contre les jars de chaque moteur et a son propre sérialiseur qui écrit trois canaux ordinaires — un flux MLLP avec un mappage, un script appelant une bibliothèque de modèle de code et un filtre ; un flux HTTP dans une base de données ; un fichier de sonde sortant sur MLLP — plus la bibliothèque et un groupe de canaux. Il les charge dans le moteur en cours d'exécution et télécharge la sauvegarde du serveur propre au moteur. Les résultats sont validés sous internal/mirth/testdata/engines/, et la suite de tests tient l'importateur à chacun d'eux à chaque build : chaque sauvegarde est lue, traduite, chargée, et le canal ADT est exécuté avec deux messages pour vérifier que la bibliothèque remplit le numéro d'enregistrement et que le filtre supprime le résultat.
Les exportations propres de Perfuse vont dans l'autre sens — les canaux Perfuse importés dans chaque moteur en cours d'exécution et vérifiés pour que le moteur ne les stocke pas comme étant invalides. Les cinq acceptent chaque transport que Perfuse exporte. Open Integration Engine 4.7.0 a ajouté deux paramètres HTTP sans équivalent ici : un émetteur HTTP lié à une adresse locale choisie est signalé comme un avertissement, et une limite d'en-tête de requête d'écouteur HTTP uniquement lorsqu'elle est supérieure à 1 Mo que Perfuse accepte.
La première exécution contre ce corpus a trouvé quatre défauts, tous corrigés : le traducteur a refusé les sources HTTP et de fichiers en tant que « seul MLLP est pris en charge » longtemps après que Perfuse ait eu les deux ; il a lu l'adresse d'un expéditeur HTTP à partir d'un champ que aucun des moteurs n'a écrit ; il a traduit la taille du tampon de socket de Mirth comme une limite de message de 64 Ko ; et une variable de Mapper est devenue une variable globale JavaScript que $('mrn') n'a jamais vu, donc la bibliothèque a rempli une chaîne vide.
Le fixture à canal unique qui a démarré cela a également été exporté par Mirth 4.5.2, rédigé par Mirth lui-même plutôt que écrit ici. Cette distinction a valu sa place : le seul fixture de ce référentiel utilisé pour être écrit à la main, et un véritable Mirth ne chargera pas — l'API accepte le POST, puis stocke le canal en tant que This channel is invalid. Verify all required extensions are loaded correctly, avec chaque connecteur de destination supprimé.
La rédaction manuelle n'allait jamais fonctionner, et la raison vaut la peine d'être connue si vous produisez vos propres exportations. Le sérialiseur de Mirth ignore les éléments qu'il ne reconnaît pas, donc un nom d'élément incorrect ne produit aucune erreur - le connecteur n'est simplement pas là après.
scripts/mirth-author-channel.sh construit un canal en utilisant les classes de modèle de Mirth et son propre sérialiseur, puis le poste sur un serveur en cours d'exécution et échoue si le serveur le rejette. L'importateur de Perfuse lit le résultat : le nom, le transport source et les destinations survivent tous.
15.4 Prouver qu'il correspond
C'est la partie qui décide si une migration se produit, et elle a besoin de preuves plutôt que de confiance.
Perfuse compare sa propre sortie avec l'ancien moteur, message par message, sur votre trafic. Ce dont il a besoin, ce sont des paires : le message tel qu'il est arrivé, et le message que l'ancien moteur a produit à partir de celui-ci. Les deux se trouvent dans le magasin de messages de Mirth et peuvent être exportés à partir de son navigateur de messages.
15.4.1 Quatre nombres, et non un taux de réussite
| Résultat | Signification |
|---|---|
| Identique | Byte pour byte identique. |
| Différences cosmétiques | Diffère de manière qui ne porte aucune information - champs vides de fin, un terminateur final. |
| Différent | La valeur d'un champ est différente. |
| Ne peut pas s'exécuter | Perfuse ne peut pas traiter le message du tout. |
Ce sont quatre nombres car ils signifient quatre choses différentes et les combiner cache ceux qui nécessitent une décision.
Identique signifie byte pour byte, et non équivalent. Un test plus faible laisserait passer les différences dans l'ordre des segments ou les séparateurs de fin, et ce sont exactement ceux que les systèmes en aval rejetteraient.
Les différences cosmétiques sont comptées séparément plutôt que regroupées dans la colonne des réussites. Elles ne portent vraiment aucune information, donc les traiter comme des échecs les enterrerait sous des milliers de rien - mais elles ne sont pas identiques non plus, et un récepteur effectuant son propre parsing strict peut être en désaccord.
"Ne peut pas s'exécuter" est séparé de "différent" car il s'agit généralement d'un écart de configuration que l'importateur n'a pas pu combler, et non d'une décision de mappage. Si tout se trouve dans cette colonne, le verdict le dit et vous demande de regarder la configuration avant de lire quoi que ce soit d'autre.
15.4.2 Les différences sont regroupées par champ
Une exécution sur cinquante mille messages signalant quatre mille différences vous a dit rien que vous puissiez agir. La même exécution signalant que PID-8 diffère dans chaque message car l'ancien moteur a écrit Male où Perfuse écrit M vous a dit exactement une chose à décider.
Chaque constatation est donc un champ, avec un décompte, et il indique si la différence est systématique - la même paire de valeurs chaque fois - ou si le contenu du champ diffère.
Cette distinction est la chose la plus utile dans le rapport. Une paire de valeurs distinctes à travers quatre mille messages est une décision de mappage unique. Quatre mille paires distinctes est le contenu qui diffère, ce qui est un problème différent et bien pire, et les deux ne doivent pas se lire de la même manière.
Les constatations sont classées par ordre de nombre de messages qu'elles affectent, donc la plus grande cause unique est en premier.
15.4.3 Le verdict ne fait pas de ronde
Il fournit des décomptes exacts : 49 993 sur 50 000, et non "plus de 99 %". Les sept sont le but de l'exécution.
Il est rédigé pour être cité dans une demande de modification, car c'est là que le numéro aboutit.
15.5 Une séquence suggérée
- Importez les canaux et résolvez tout ce qui est signalé comme illisible.
- Pour chaque canal, examinez les avertissements. La plupart seront des scripts.
- Exportez quelques milliers de paires de messages de Mirth pour le canal le plus actif et exécutez la comparaison.
- Travaillez sur les résultats. Les problèmes systématiques ne nécessitent qu'une décision chacun.
- Réexécutez jusqu'à ce que les seules différences soient celles que vous avez décidées comme correctes.
- Exécutez Perfuse en mode fantôme aux côtés de Mirth sur le trafic en direct, en livrant nulle part, et comparez à nouveau sur une période qui inclut un week-end et une fin de mois.
- Basculer sur un canal, et non sur tous.
15.6 Ce qui ne fonctionne que sur le logiciel d'un seul fournisseur
L'écran de migration répond à une deuxième question, et il vaut la peine de la poser avant d'avoir une opinion sur Perfuse : combien de votre logique d'intégration ne peut fonctionner que sur le logiciel que vous avez.
Chaque canal reçoit un verdict de portabilité, à partir du même scan qui produit les notes de migration. Il s'exécute contre une exportation de canal, il n'a donc besoin de rien d'installé et ne modifie rien.
15.6.1 La distinction est l'objectif principal
La plupart du Java dans les scripts Mirth n'est pas de verrouillage. SimpleDateFormat, HashMap, Apache Commons — tout cela fonctionne autour d'un moteur JavaScript de 2009, tout cela est ordinaire, tout cela a des équivalents directs. Un canal avec trois cents de ces références est entièrement portable, et un outil qui rapporte « 300 références Java, vous êtes piégé » vous mentirait.
Le verrouillage est spécifiquement les appels qui nécessitent le serveur du fournisseur : com.mirth.connect.* et les jar du fournisseur. Cinq de ceux-ci et vous êtes bloqué. Cinq cents de l'autre type et vous êtes libre.
Le verdict commence donc par le nombre qui compte et dit dans la même phrase que le plus grand nombre n'est pas celui-là. Lorsqu'il y a des appels de fournisseur, ils sont répertoriés par nom — un décompte est une affirmation, et une liste est quelque chose que votre propre ingénieur peut aller vérifier.
Une troisième catégorie est conservée séparément : la capacité qui existe mais pas à partir d'un script. Lancer un canal à partir de JavaScript n'a pas d'équivalent ici, et il y a un point de terminaison API qui fait exactement la même chose. Appeler cela un verrouillage exagérerait les résultats.
15.6.2 Les appels Java qui s'exécutent sans modification
Les classes Java les plus courantes s'exécutent telles quelles. Perfuse n'a pas de runtime Java, donc ce sont des classes JavaScript avec les mêmes noms et méthodes, suffisamment pour la façon dont les scripts de canal les utilisent ; importPackage(java.util) et importClass(...) les rendent accessibles par leurs noms courts, comme dans Rhino (les Date, Map, Set, Math, String et Boolean propres à JavaScript ne sont jamais remplacés : les classes Java correspondantes sont toujours accessibles par leur nom complet). Le rapport de migration compte chaque appel à ces classes comme déjà pris en charge.
| Package | Classes |
|---|---|
java.util | ArrayList, LinkedList, Vector, List, Collection, HashMap, LinkedHashMap, Hashtable, TreeMap, Properties, HashSet, LinkedHashSet, TreeSet, Arrays, Collections, Date, Calendar, GregorianCalendar, UUID, Base64, regex.Pattern (avec Matcher), concurrent.ConcurrentHashMap |
java.lang | String, StringBuilder, StringBuffer, Integer, Long, Short, Byte, Double, Float, Boolean, Math, System (heure et séparateur de ligne uniquement) |
java.text, java.math, java.net, java.nio | SimpleDateFormat et DateFormat (lettres de modèle Mirth), BigDecimal (en tant que double), URLEncoder, URLDecoder, StandardCharsets |
| Apache Commons | lang3.StringUtils et lang.StringUtils (environ soixante méthodes), StringEscapeUtils, codec.binary.Base64 |
Elles se comportent comme Java le fait lorsque les scripts en dépendent : Integer.parseInt("x") lance une exception NumberFormatException, String.replaceAll et split prennent des expressions régulières tandis que replace est littéral, les cartes clés des chaînes de caractères par valeur, TreeMap et TreeSet itèrent dans l'ordre, et SimpleDateFormat.parse renvoie une date sur laquelle getTime() fonctionne. Une méthode qu'un script appelle et que l'équivalent ne possède pas échoue à cette ligne, en nommant la méthode ; toute autre classe Java échoue par nom, comme avant. BigDecimal est un double ici, il ne conserve donc pas l'arithmétique décimale exacte de Java : vérifiez les scripts qui l'utilisent pour l'argent.
15.6.3 Les scripts externes sont signalés comme inconnus
Une étape qui exécute un fichier de script externe fait référence à un chemin sur l'ancien serveur, et le fichier n'est pas dans l'exportation. Rien ne peut être dit sur ce qu'il contient, il est donc compté comme inconnu plutôt que supposé dans un sens ou dans l'autre. Récupérez ces fichiers avant de conclure quoi que ce soit — dans les deux sens.
15.6.4 Le verrouillage propre de Perfuse, déclaré dans le même souffle
Cette section serait malhonnête sans cela.
Perfuse est Apache 2.0, ce qui est irrévocable pour le code déjà publié. Vous pouvez créer une branche de ce qui existe aujourd'hui et personne ne peut retirer cela. Les canaux sont des fichiers YAML et les scripts sont des JavaScript ordinaires, il n'y a donc pas de surface propriétaire à appeler — la dépendance Java de Mirth est structurellement indisponible ici, ce qui est l'endroit où une limitation est réellement une fonctionnalité.
Ce que cela ne promet pas : qu'une version future reste ouverte, qu'un service hébergé existe à un prix que vous aimez, ou que la migration hors de Perfuse ne coûte rien. Déplacer une couche d'intégration signifie rétester chaque canal contre du trafic réel. Ce que vous choisissez, c'est si les artefacts que vous créez sont lisibles et portables, et si la sortie dépend d'une licence que quelqu'un d'autre contrôle.
15.6.5 Configuration de l'étape 6
La section Shadow commence une comparaison. Choisissez le canal qui s'exécute, choisissez le candidat à comparer à partir de la liste et commencez.
Trois choses à savoir à son sujet avant de vous fier aux chiffres.
Le candidat est choisi dans une liste, et non saisi. Un shadow nomme un fichier de canal, et un nom qui ne se résout pas rend le canal *actif* invalide — Perfuse refuse un canal dans son ensemble lorsque quelque chose qu'il référence est cassé. Ainsi, une faute de frappe ne produit pas d'avertissement, elle fait disparaître le canal en cours d'exécution.
La partage est un pourcentage. Réduisez-le uniquement sur un flux occupé, et connaissez son coût : l'échantillonnage réduit le travail et la confiance dans la même proportion, et le message qui aurait montré la différence est celui inhabituel.
Les champs à ignorer sont généralement nécessaires. Un canal qui tamponne un horodatage ou un numéro de séquence diffère à chaque message, ce qui signale un taux de différence de 100 % et ne vous indique rien. MSH-7 et MSH-10 sont la paire courante.
Une comparaison est écrite dans le fichier de canal dès que vous le démarrez, et commence à observer lorsque le canal se charge ensuite — l'écran le signale plutôt que de prétendre qu'il est déjà en cours d'exécution. L'arrêt d'une comparaison laisse le canal candidat en place, car le candidat est la chose destinée à être mise en ligne.
L'étape 6 est celle qui ne peut pas être raccourcie. Les différences qui comptent sont généralement dans le trafic qui n'apparaît qu'occasionnellement — un événement déclencheur rare, un lot de fin de mois, un expéditeur qui se comporte différemment à minuit — et un échantillon pris sur un après-midi ne les contiendra pas.
15.7 Revenir dans l'autre sens
Un canal peut être exporté sous forme de fichier de canal Mirth, à partir du navigateur : Canal, puis Vers Mirth sur le canal que vous souhaitez.
Ceci existe parce que l'objection à remplacer un moteur de fonctionnement est rarement de savoir si le remplacement est bon. C'est ce qui se passe si la décision s'avère être mauvaise, et une exportation qui revient à l'endroit où elle est allée est la réponse la moins coûteuse à cela.
Lisez ce que le dialogue vous indique avant de prendre le fichier. Le format Mirth n'a nulle part où mettre un filtre Perfuse, une chaîne de transformation, un contrat ou une comparaison de shadow, donc un canal exporté fait moins que celui dont il provient. Les transports et leurs adresses se convertissent ; la logique ne l'est pas. Chaque perte est répertoriée par nom avant que le fichier ne soit proposé, et la même liste est insérée dans la description du canal afin que celui qui l'importera la voie également.
Un canal que Mirth ne peut pas exprimer est refusé plutôt que d'être approximé. Une destination S3 n'a pas d'équivalent Mirth, et un canal qui a été importé proprement tout en livrant ailleurs que dans le seau serait pire que pas de fichier du tout. Le refus nomme la destination en défaut.
Les définitions de connecteur ne sont pas écrites à partir d'une lecture du format Mirth. scripts/mirth-dump-connector-templates.sh a le sérialiseur Mirth produire les valeurs par défaut pour chaque classe de connecteur, et Perfuse substitue des valeurs à ces documents — en refusant tout paramètre que le modèle ne contient pas déjà. Cela compte parce que de la façon dont Mirth répond à un canal qu'il ne peut pas analyser : il n'en refuse pas l'importation. Il stocke un canal dont la description a été remplacée par « Ce canal est invalide. Vérifiez que toutes les extensions requises sont chargées correctement » et dont les destinations ont été silencieusement supprimées. Un exportateur vérifié contre sa propre sortie plutôt que contre un serveur passe tous les tests tout en produisant des documents qui sont jetés, ce qui est exactement ce qui s'est passé ici avant que les exportations ne soient essayées contre un Mirth en cours d'exécution.
Ce qui traverse aujourd'hui : MLLP et TCP dans les deux sens, HTTP dans les deux sens, lecture et écriture de fichiers, lecture et écriture de bases de données, DICOM dans les deux sens, et destinations SMTP, SOAP et JavaScript. Chaque paire est vérifiée en important dans un Mirth 4.5.2 réel et en vérifiant que le serveur n'a pas remplacé silencieusement le canal.
16 CMS-0057 pour les payeurs
La règle finale d'interopérabilité et d'autorisation préalable du CMS (CMS-0057-F) exige que les payeurs touchés — les organisations Medicare Advantage, les programmes Medicaid et CHIP de l'État et leurs plans de soins gérés, ainsi que les émetteurs de QHP sur les marchés fédéraux — exécutent quatre API FHIR à compter du 1er janvier 2027, et publient des métriques d'autorisation préalable sur leur site Web public chaque année à compter de 2026.
Perfuse fournit les quatre API sur son point de terminaison FHIR et les conversions qui les remplissent : les réclamations liquidées en tant que CARIN Blue Button, les autorisations préalables en tant que Da Vinci PDex, et les métriques annuelles dans le format du modèle propre au CMS. La vue CMS-0057, sous Échange, indique lesquelles des quatre cette instance peut répondre et ce que chacune nécessite encore, et effectue les trois conversions dans le navigateur.
Les médicaments sont hors du champ d'application dans l'ensemble, car ils le sont dans les dispositions d'autorisation préalable de la règle : pas de réclamations pharmaceutiques, pas de formule, et une ligne de métriques portant le nom d'un médicament est refusée plutôt que comptabilisée.
16.1 Les quatre API
| API | Ce qu'il sert | Guides | Activé par |
|---|---|---|---|
| Accès patient | Les réclamations d'un membre, les données cliniques et les autorisations précédentes, à une application qu'il choisit | CARIN Blue Button 2.2.0, PDex 2.2.0, US Core, SMART App Launch | -fhir et un émetteur SMART (-smart-issuer) |
| Accès fournisseur | Le même pour les membres attribués d'un fournisseur, en bloc | PDex 2.2.0, Da Vinci ATR 2.1.0, Bulk Data | -fhir-payer-apis et -fhir-bulk-export |
| Payer-to-Payer | L'enregistrement d'un membre à un autre payeur, après les avoir appariés | HRex 1.2.0 $member-match, PDex 2.2.0 | -fhir-payer-apis |
| Autorisation préalable | Ce dont un ordre a besoin, la documentation, puis la demande et la décision | Da Vinci CRD, DTR et PAS 2.2.x (2.2.1, 2.2.0, 2.2.1) et 2.1.0, avec la traduction X12 278 | -fhir, modifiable, et -crd-rules |
L'API d'accès patient n'a pas besoin d'opération propre : il s'agit du point de terminaison FHIR ordinaire de lecture et de recherche, protégé par SMART, avec des ressources CARIN et PDex dans le magasin. La recherche ExplanationOfBenefit prend en charge les paramètres CARIN — patient, identifier, type, service-date, billable-period-start, provider, insurer, coverage — et Coverage prend en charge subscriber-id, identifier et payor.
16.1.1 Deux versions des guides : 2.1.0 et 2.2.x
La recommandation CMS-0057-F recommande CRD, DTR et PAS 2.0.1 et 2.1.0. Les versions 2.0.1 sont basées sur US Core 3.1.1, qui a expiré le 1er janvier 2026, donc 2.1.0 est la version que probablement un système d'enregistrement électronique de santé (EHR) construit pour la règle est susceptible de parler ; les plus récentes sont CRD 2.2.1, DTR 2.2.0 et PAS 2.2.1. Perfuse répond aux deux. Il détermine laquelle une appelant parle, en commençant par la plus spécifique :
- à partir de la demande : l'extension CDS Hooks de CRD
davinci-crd.requestedVersion("2.1"), ou la version d'un profil Da Vinci qu'une entrée DTR ou PAS revendique (profile-pas-request-bundle|2.1.0) ; - à partir de l'enregistrement de l'appelant :
davinci_version: "2.1"sur un client SMART (-smart-clients) ou un client CDS (-cds-clients) ; - à partir du serveur :
serve -davinci-version 2.1; la valeur par défaut est 2.2.
clients:
- issuer: https://ehr.example.org
jwks_url: https://ehr.example.org/.well-known/jwks.json
davinci_version: "2.1"
Chaque réponse est décidée et conservée sous la forme 2.2.x et réécrite pour un appelant 2.1.0 lorsqu'elle est envoyée, donc les règles, la file d'attente de révision, le lien X12 278 et les métriques sont les mêmes pour les deux. La réécriture couvre ce que les versions épèlent différemment : CRD 2.1.0 n'a pas de indeterminate (Perfuse dit conditionnel, avec la raison) et pas de catégorie sur un détail de couverture ; DTR 2.1.0 nomme le package PackageBundle et laisse la QuestionnaireResponse à l'application ; PAS 2.1.0 répond à $inquire avec un seul Bundle, et il manque les extensions de révision et de transmission. La liste complète, ainsi que la vérification contre chaque exemple propre à chaque guide 2.1.0, se trouve dans conformance/davinci21. Une notification PAS suit -davinci-version, puisqu'une abonnement ne spécifie pas quelle version son propriétaire lit.
16.2 Exigences de couverture et documentation : CRD et DTR
L'API de préautorisation est en pratique trois guides Da Vinci ensemble. CRD indique au clinicien, alors que la commande est encore un brouillon, si elle est couverte, si elle nécessite une autorisation préalable et quels documents sont souhaités. DTR remet au dossier médical électronique (EHR) le questionnaire qui recueille ces documents. PAS soumet la demande et renvoie la décision. Perfuse sert les trois en tant que payeur.
-crd-rules rules.yaml sert CRD via les crochets CDS à /cds-services : les six crochets de CRD, order-sign, order-select, order-dispatch, appointment-book, encounter-start et encounter-discharge, chacun avec une prélecture pour la couverture active du patient. Les deux crochets d'encounter prélectent également l'encounter et répondent à propos de l'encounter lui-même, correspondant à son type et son type de service, comme appointment-book répond à propos d'un rendez-vous. Les règles sont la politique de l'assureur, conservées dans un fichier parce qu'elles changent sans version logicielle :
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
Chaque commande reçoit une mise à jour systemActions contenant l'extension d'information de couverture de CRD - que le dossier médical électronique stocke sur la commande et envoie plus tard avec l'autorisation préalable - et une carte que le clinicien lit. Une commande dont le code n'a pas de règle est répondu conditional, et non supposée couverte ; une demande sans couverture du tout reçoit une carte indiquant cela. examples/crd/ contient un fichier de règles et un questionnaire correspondant.
Une règle peut également transporter le reste de ce que CRD permet à un payeur de dire :
billing_codes: les codes à facturer.details: les limites et les coûts, tels queallowed-periodouin-network-copay.contact: qui appeler.expiry_days: combien de temps la réponse est valable.depends_on: les codes d'autres commandes dont la réponse dépend, afin que le dossier médical électronique (EHR) demande à nouveau si elles changent.doc_purpose: à quoi sert la documentation (withclaim,withorder,retain-doc).withpaest refusé, car l'invariant crd-ci-q4 de CRD 2.2.1 le rejette.
Ce que le dossier médical électronique (EHR) n'a pas préchargé, Perfuse lit à partir du fhirServer de l'EHR avec le jeton qu'il a envoyé. Si cela échoue, la réponse est indeterminate avec la raison technical de CRD, jamais une supposition. Une Couverture qui a pris fin ou n'est pas active est répondu not-covered, no-active-coverage.
members: fhir dans le fichier de règles résout la couverture contre les propres dossiers de l'assureur dans le magasin FHIR de ce serveur (lancez-le avec -fhir), les mêmes dossiers que $member-match lit :
- un patient qui n'est pas un membre est répondu
no-member-found; - un membre dont la couverture ne correspond pas est répondu
coverage-not-found; - une autorisation préalable déjà approuvée pour le service (une ClaimResponse avec un
preAuthRef) fait que la réponse estsatisfied,
avec ce numéro.
Discovery déclare davinci-crd.version et une option de configuration coverage-info. Lorsqu'un client désactive l'option, la réponse est vide. Les JWT EHR sont vérifiés comme CDS Hooks les définit, avec iss, aud, exp, iat et jti et sans sub, et un jti répété est refusé.
Les appels s'authentifient avec le JWT qu'un dossier médical électronique (EHR) signe pour chaque appel, à partir d'un émetteur nommé dans -cds-clients avec son URL JWKS - qui est ainsi que CDS Hooks le décrit - ou avec un jeton d'API Perfuse. La découverte est ouverte, comme CDS Hooks l'exige.
DTR : chargez les questionnaires dans le point de terminaison FHIR, et POST /fhir/Questionnaire/$questionnaire-package les renvoie sous forme de packages DTR, avec les bibliothèques CQL qu'ils nomment. La demande peut nommer le questionnaire, ou envoyer la commande et laisser son information de couverture indiquer lequel.
Essayer : Payers → Claims & auth → Coverage requirements (CRD) envoie une commande à ces règles du serveur, ou à l'URL du service CDS d'un payeur, et affiche les cartes et les informations de couverture.
16.3 Réclamations en tant que CARIN Blue Button
perfuse cms0057 carinbb associe chaque réclamation dans un 837 à son paiement dans un 835, par le numéro de compte patient que le 835 est tenu de renvoyer, et écrit une transaction FHIR pour chacune : l'ExplanationOfBenefit avec le Patient, la Couverture, les Organisations et les Praticiens qu'il référence.
perfuse cms0057 carinbb -system https://fhir.your-plan.org/identifier -network innetwork \
claims.837 remittance.835
Le profil suit la réclamation : les réclamations professionnelles (837P) deviennent C4BB-ExplanationOfBenefit-Professional-NonClinician, et les réclamations institutionnelles (837I) en fonction du type de facture. Chaque entrée est un PUT avec un id pris à partir des identificateurs source, afin que le chargement de la même réclamation deux fois la mette à jour plutôt que d'en créer une deuxième copie.
Trois choses ne sont pas dans les deux fichiers X12, et chacune est traitée en disant qu'elles ne sont pas là plutôt que de deviner :
- Le système d'identifiant. CARIN exige que l'identifiant de membre nomme l'espace de noms du payeur.
-systemest requis ; il n'y a pas de valeur par défaut, car une valeur par défaut donnerait à chaque payeur utilisant Perfuse le même espace de noms. - Le statut du réseau. Aucune des deux transactions n'indique si le fournisseur de facturation est dans le réseau, et cela décide ce que le membre paie. Sans
-network, le statut de paiement des prestations estotheret la conversion note pourquoi. - Une réclamation que le 835 ne mentionne pas. Une ExplanationOfBenefit CARIN est une réclamation jugée. Sans le 835, il n'y a pas de numéro de réclamation du payeur, pas de paiement et pas de responsabilité du membre, donc la réclamation est signalée comme ignorée et non convertie.
Les diagnostics sont écrits avec leur point décimal (J02.9, et non J029), car c'est ainsi que le système de codage les publie et qu'un serveur de terminologie interrogé sur l'autre orthographe dit qu'il n'existe pas. L'identifiant de membre d'un dépendant est celui de l'abonné, qui est ce que le 837 transporte, et les notes le disent. Un NPI dont le chiffre de contrôle est incorrect est signalé avant que US Core le rejette.
16.4 Préautorisations en tant que PDex
perfuse cms0057 priorauth convertit une réponse de réclamation Da Vinci PAS — ou le paquet de réponse PAS qui la contient — en une explication de bénéfice de priorisation PDex, qui est ce que les trois API de données servent.
perfuse cms0057 priorauth pas-response.json pas-claim.json
La réclamation PAS est facultative et presque toujours nécessaire. Une explication de bénéfice doit indiquer quelle couverture la décision a été prise sous, et seul la demande la porte ; sans elle, la conversion s'arrête et le signale. L'action de révision — approuvée, refusée, différée, avec son numéro d'autorisation et sa raison — passe de l'extension PAS à PDex, et le type de service X12 conserve son code sous l'URI que PDex le lie.
16.5 Les API d'accès des prestataires et des payeurs
Avec -fhir-payer-apis le point de terminaison FHIR répond à trois opérations supplémentaires :
POST /fhir/Patient/$member-match— appariement des membres HRex. Les identificateurs de couverture se réduisent à quelques candidats, et le nom de famille et la date de naissance doivent alors être d'accord ; un prénom est comparé par initiale, et le sexe uniquement lorsque les deux côtés le déclarent. Plus d'un candidat survivant n'est pas un appariement, et la réponse est 422 plutôt qu'une supposition, car une supposition divulgue les réclamations d'un étranger. Un consentement actif permettant la divulgation est requis, puisque l'API Payer-to-Payer est opt-in pour le membre ;-fhir-member-match-without-consentle désactive pour les tests.GETouPOST /fhir/Group/{id}/$davinci-data-export— l'exportation en bloc de Da Vinci d'un groupe de membres actuels.exportTypechoisit le public :hl7.fhir.us.davinci-pdex#provider-downloadou#provider-deltapour l'accès des prestataires,#payertopayerpour Payer-to-Payer.GET /fhir/Group/{id}/$export— l'exportation standard de données de groupe en bloc, traitée comme un accès de prestataire.
Les exportations appliquent les exclusions de la règle sur le chemin de sortie. Les réclamations perdent le paiement et chaque montant de participation aux coûts et de remboursement, et conservent les services, les codes, les dates et les prestataires ; le profil CARIN est supprimé de meta.profile car la ressource ne répond plus à celui-ci. Payer-to-Payer omet également les autorisations de priorité refusées. Les membres détenant un consentement actif de refus d'accès PDex sont exclus d'une exportation de prestataire, et le journal enregistre combien. Le paramètre patient ne peut être réduit qu'aux membres du groupe ; nommer quelqu'un d'autre est refusé.
L'accès à l'exportation d'un groupe est décidé par l'authentification du point de terminaison. Les étendues SMART indiquent quels types de ressource un jeton peut lire, et non quel groupe, donc chaque fournisseur a besoin d'un jeton qui ne peut atteindre que sa propre liste d'attribution. Un jeton d'API peut être limité aux groupes lorsqu'il est créé — perfuse token create -label riverside-provider-access -fhir-groups riverside-attributed, ou le champ Limiter aux groupes FHIR sous Utilisateurs → Informations d'identification de machine — et sur le point de terminaison FHIR, il peut alors lire ces groupes, exécuter $davinci-data-export ou $export sur eux et récupérer ce que l'exportation a produit, et rien d'autre. Un groupe d'un autre fournisseur répond « non trouvé » plutôt que « interdit », donc un jeton n'apprend pas quels autres listes d'attribution existent ; toute autre demande, y compris la correspondance des membres et la recherche ordinaire, est refusée. La limite s'applique aux jetons d'API ; un jeton d'un émetteur SMART ne comporte pas de limite de groupe. Lorsque SMART est configuré, les jetons d'API sont refusés à moins que Paramètres → FHIR → Accepter les jetons d'API Perfuse à côté des jetons SMART ne soit activé (voir Sécurité, *Qui peut appeler le point de terminaison FHIR*); un jeton limité au groupe d'un fournisseur nécessite cela.
16.6 Un annuaire de prestataires : Plan-Net
CMS-0057 demande également aux payeurs un répertoire de fournisseurs, et le point de terminaison FHIR en sert un à Da Vinci Plan-Net 1.1.0 sans option pour l'activer : chargez les Practitioners, PractitionerRoles, Organizations, OrganizationAffiliations, Locations, HealthcareServices, InsurancePlans et Endpoints, et les applications des membres peuvent les rechercher. Chaque paramètre de recherche Plan-Net est indexé - le réseau et le service d'un rôle, la zone de couverture d'un plan, l'organisation participant à une affiliation, l'organisation partof - ainsi que les includes et les chaînes inverses (_has) que les requêtes du guide utilisent, et la CapabilityStatement liste les profils Plan-Net.
La suite Plan-Net d'Inferno passe 199 tests. Les 10 qu'il échoue sont des chaînes avant où le kit prend sa valeur de recherche à partir de la première Organisation qu'il a vue plutôt que d'une ressource recherchée ; cela est signalé au kit (son problème 34), et le serveur répond correctement à ces requêtes lorsqu'il reçoit une valeur que les données contiennent.
16.7 Métriques d'autorisation préalable
perfuse cms0057 metrics lit un fichier CSV de décisions exportées du système de gestion de l'utilisation et produit la page publique que CMS exige, dans le format de son *Rapport de métriques d'autorisation préalable — Aperçu et modèle*.
perfuse cms0057 metrics -year 2025 -org "Springfield Health Plan" -services services.csv \
decisions.csv > prior-authorization-metrics-2025.html
Les colonnes sont trouvées par en-tête : priority, received, decided et decision sont obligatoires, et request_id, line_of_business, extended, appealed, appeal_decision, service_code et service_description sont lus lorsqu'ils sont présents. Une demande appartient à l'année où elle a été décidée ; une demande encore en attente est répertoriée comme exclue, et ne compte jamais. Chaque ligne qui ne peut pas être lue est signalée avec son numéro de ligne.
L'arithmétique suit le modèle : pour les demandes standard et accélérées séparément, la part approuvée et refusée, approuvée et refusée dans le délai de décision, approuvée après que le temps d'examen ait été prolongé, et approuvée après appel — sur les appels, et non sur les demandes — avec la moyenne et la médiane du temps d'obtention de la décision. Une médiane inférieure à un jour est écrite en heures plutôt qu'arrondie à « 0 jours », ce que le modèle demande explicitement. Les demandes partiellement approuvées sont comptabilisées comme approuvées, puisque le modèle n'a pas de catégorie pour elles, et la page indique combien il y en a eu. Les métriques sont signalées par ligne d'activité, qui est le niveau que CMS exige.
La page est autonome — aucun script, aucune feuille de style externe ou police — car elle est publiée sur un site Web public par quiconque la maintient, et tout ce qu'elle charge d'ailleurs est quelque chose qui peut se briser ou suivre un visiteur. -format csv et -format json donnent les mêmes numéros pour d'autres utilisations. Sans -services, la page comporte un avis indiquant que la liste des éléments et des services nécessitant une autorisation préalable est manquante, car CMS l'exige sur la même page.
16.8 Médicaments : la formule, le bénéfice de prescription en temps réel et l'autorisation préalable électronique
La proposition CMS-0062-P (proposée le 14 avril 2026) intégrerait les médicaments dans l'autorisation préalable : les payeurs concernés prendraient en charge l'autorisation préalable électronique NCPDP SCRIPT, la norme de formule et de prestations NCPDP et les avantages en temps réel de prescription NCPDP à compter du 1er octobre 2027, décideraient des demandes de médicaments dans les 24 heures (accélérées) et 72 heures (standard), fourniraient une raison spécifique pour chaque refus et rapporteraient les métriques de médicaments à partir de 2028. Le Medicare Part D exige déjà une autorisation préalable électronique SCRIPT. Un seul fichier, la formule, répond à tout :
perfuse serve -fhir -pas -crd-rules payer-rules.yaml -formulary formulary.yaml
examples/formulary/formulary.yaml est un exemple dont les médicaments sont des concepts RxNorm réels avec des NDCs RxNorm pour eux (vérifiés contre RxNav). Un fichier nomme le payeur, ses plans (chacun avec la formule qu'il utilise, ses ID de groupe et ses parts de coûts par bénéfice de pharmacie et niveau) et ses formules. Chaque médicament est un SCD ou SBD RxNorm avec son groupe RxNorm (le SCDG ou SBDG que l'API de formule de médicament nécessite), ses NDCs, un niveau, et ses limites : prior_authorization, step_therapy, quantity_limit (une quantité sur un nombre de jours glissants, et une limite quotidienne maximale), not_covered, alternatives (codes RxNorm, le plus préféré en premier), notes, et questionnaire, l'URL canonique du questionnaire FHIR que demande une autorisation préalable. cost_30_day est le coût du plan pour une fourniture de 30 jours, qui est un pourcentage de la franchise ; sans cela, la franchise est indiquée en pourcentage, jamais en montant inventé. L'ensemble du fichier est vérifié lorsqu'il est chargé, chaque problème étant répertorié à la fois. Un membre est trouvé par la liste members du fichier, par groupe, ou par le biais du magasin FHIR : une Coverage dont subscriberId est l'ID du membre et dont class de type plan est l'ID du plan. Payers › Médicaments affiche la formule, fixe le prix d'un médicament et exécute une autorisation préalable de bout en bout.
16.8.1 L'API de formule de médicaments Da Vinci US
Publié à /formulary/fhir en tant que formule de médicament américain Da Vinci 2.1.0 : chaque plan est un PayerInsurancePlan, chaque formule est un Formulary (les deux InsurancePlan), chaque médicament est un FormularyDrug (MedicationKnowledge) et chaque entrée est un FormularyItem (Basic). Les recherches du guide sont servies (Basic?code=formulary-item&formulary=...&drug-tier=...&pharmacy-benefit-type=...&period=..., subject:MedicationKnowledge.code, InsurancePlan?formulary-coverage=..., coverage-type, MedicationKnowledge?code=...&doseform=...) avec _include=Basic:subject, Basic:formulary et InsurancePlan:formulary-coverage. Il est public, sans informations d'identification, comme le CMS l'exige pour la formule d'un payeur : il est servi à partir d'un magasin propre, en mémoire, qui contient la formule et rien d'autre, de sorte qu'être ouvert ne peut pas atteindre le dossier d'un patient. Il est en lecture seule. Un médicament exclu n'est pas publié, puisque l'API répertorie ce que couvre une formule ; RTPB et ePA répondent toujours qu'il n'est pas couvert. Vérifié avec le validateur HL7 FHIR contre le package 2.1.0 du guide avec la terminologie vérifiée : chaque ressource générée à partir de l'exemple ne contient aucune erreur.
16.8.2 Bénéfice de prescription en temps réel
POST /ncpdp/rtpb prend une demande RTPBRequest (NCPDP RTPB v13) avec un jeton d'API du rôle de l'opérateur et répond avec une réponse RTPBResponse à partir de la formule : le statut de couverture, le statut de la formule, la part estimée du membre et celle du régime, ainsi que les restrictions de couverture, avec jusqu'à cinq alternatives couvertes tarifiées de la même manière. Les codes de restriction et le statut auquel chacun est associé suivent les Recommandations publiques d'implémentation RTPB de NCPDP : 75 autorisation préalable requise, 608 thérapie par étapes, 76 limites du régime dépassées, 7X jours d'approvisionnement au-delà de la limite du régime (un médicament non disponible par la poste, par exemple), 70 non couvert, tous *couverts avec restrictions* (CR) sauf 70 (NC). Un membre ayant une autorisation préalable approuvée enregistrée reçoit CC et AB8, comme le demande le guide Surescripts, afin que le prescripteur ne soit pas invité à demander à nouveau. Une demande qui ne peut pas être tarifiée est NotProcessed avec un code de rejet NCPDP : 52 pour un membre non trouvé, E7 et 19 pour une quantité ou un approvisionnement manquant. Le bénéfice de la pharmacie est lu à partir de la demande : un remplissage supérieur à 34 jours est un approvisionnement de trois mois, et le type de pharmacie M est la commande par correspondance.
16.8.3 Autorisation préalable électronique (NCPDP SCRIPT)
POST /ncpdp/script prend PAInitiationRequest, PARequest, PAAppealRequest et PACancelRequest avec un jeton d'API du rôle d'opérateur, et répond à chacun avec sa réponse :
| Demande | Réponse |
|---|---|
PAInitiationRequest | Closed lorsqu'aucune n'est nécessaire : CC aucune autorisation préalable requise, FN dans la limite de quantité, FM non couvert ou non dans la formule, FQ une approbation dans le dossier, CD aucun membre de ce type, CG une déjà en cours. Sinon Open, avec un ID de dossier et l'ensemble de questions. |
PARequest | Décidé comme une demande PAS : Approved avec le numéro d'autorisation et la période, Denied avec la raison, ou Open en cours d'examen. |
PAAppealRequest | Un cas rejeté décidé à nouveau, sur la raison dans PANote (un appel sans celle-ci est invité à la fournir). |
PACancelRequest | Approved pendant que le cas est ouvert ou en cours d'examen, et la demande PAS est annulée ; Denied une fois qu'il est décidé. |
L'ensemble de questions est le questionnaire FHIR du médicament à partir du magasin FHIR, le même que DTR remplit : un booléen devient un choix oui/non, un choix un choix, un nombre un numérique, une date une date, et tout autre élément un texte libre ; les groupes sont aplatis dans l'ordre, et enableWhen n'est pas pris en charge, puisque SCRIPT branche par choix et non par condition. Un médicament sans questionnaire est invité à trois questions de texte libre : le diagnostic, ce qui a été essayé, et pourquoi ce médicament. Une PARequest devient une demande PAS de Da Vinci : une Claim pour le médicament (RxNorm et NDC), la MedicationRequest qu'elle demande, le patient, le prescripteur, le payeur et la couverture, ainsi que les réponses sous forme de QuestionnaireResponse, avec tout document joint sous forme de DocumentReference. Il est ensuite décidé comme chaque autorisation préalable sur ce serveur : le fichier de règles, un service de décision (-pas-decider-url), ou la file d'attente des réviseurs, où il est marqué Médicament et retenu aux délais du médicament. Un service de décision voit une demande de médicament exactement comme il voit une demande provenant d'un client PAS d'un dossier médical électronique. Nous recommandons Vaglio, le moteur de décision open source (PolyForm Shield) de BioDream, qui comporte des politiques de médicaments avec thérapie par étapes ; le moteur d'un payeur se branche via la même URL -pas-decider-url, et aucun n'est nécessaire pour que le fichier de règles et les réviseurs décident.
Une décision prise après que la demande a été répondu (celle d'un réviseur, d'un appel) est envoyée au prescripteur sous forme de réponse PAResponse ou PAAppealResponse non sollicitée, acheminée vers le canal nommé par -epa-reply-channel, qui la livre au réseau. Sans cela, ou en cas d'échec de la livraison, l'affaire indique que le prescripteur n'a pas été informé et l'écran l'envoie à nouveau.
Payeurs › Médicaments › Autorisation préalable envoie les messages qu'un système de prescripteur enverrait à la propre terminaison de ce serveur (démarrer, répondre aux questions, voir la décision), liste chaque cas avec ce que le prescripteur a été informé, et affiche les chiffres des médicaments que la proposition CMS-0062-P prévoit : demandes approuvées, refusées et en attente, appelées et approuvées ou refusées en appel, la moyenne et la médiane d'heures entre la demande et la décision, et combien ont été décidés en retard. Les médicaments à bénéfice médical demandés via PAS (un code HCPCS J avec une MedicationRequest, ou un article codé en RxNorm ou NDC) sont comptés comme des médicaments dans les chiffres de PAS également.
Ce sur quoi cela repose, énoncé clairement. Les schémas et les guides de mise en œuvre de NCPDP sont sous licence. Les noms d'éléments et l'ordre ici suivent les guides de mise en œuvre publics de Surescripts ePA et RTPB et leurs exemples, ainsi que les recommandations publiques de NCPDP pour RTPB. Deux éléments que le matériel public ne montre jamais sont écrits dans le modèle SCRIPT utilisé ailleurs et devraient être vérifiés contre une copie sous licence avant la certification : Closed/ReasonCode et Denied/DenialReason. Aucun message n'a été vérifié contre le XSD de NCPDP ou la certification d'un réseau. Le fichier de formule et de bénéfice de NCPDP n'est pas produit : sa disposition complète se trouve dans le guide sous licence de NCPDP, et un fichier partiel serait refusé par le réseau qui le charge.
16.9 Ce qui a été vérifié, et contre quoi
Les sorties CARIN et PDex ont été validées avec le validateur FHIR HL7 officiel, chargé des packages publiés (hl7.fhir.us.carin-bb#2.2.0, hl7.fhir.us.davinci-pdex#2.2.0) : les réclamations professionnelles, hospitalières et ambulatoires et deux décisions PAS, sans erreurs. Les entrées PDex étaient les exemples propres du guide PAS plutôt que les formes écrites ici pour convenir au convertisseur. Le validateur a trouvé cinq défauts lors de la première exécution — parmi lesquels CARIN exige la version du profil dans meta.profile et la version du système de code de type de réclamation sur les réclamations institutionnelles — et chacun est corrigé et couvert par un test.
La construction de cela a révélé un défaut plus ancien : le magasin FHIR supprimait chaque élément que son modèle interne ne déclarait pas, donc une ExplanationOfBenefit perdait ses éléments, ses diagnostics, son adjudication et son paiement en chemin. Le magasin conserve désormais tout ce qu'une ressource transporte, et un test charge une réclamation CARIN via le serveur et la lit à nouveau dans son intégralité.
La sortie de CRD - la commande mise à jour et la réponse CDS Hooks par rapport au modèle logique propre de CRD - et la sortie du package de DTR valident dans le validateur officiel HL7 contre CRD 2.2.1 et DTR 2.2.0 sans erreurs.
DTR ici est le côté payeur de 2.2.0. $questionnaire-package prend les questionnaires nommés, ceux que CRD a nommés sur une commande, ou l'identifiant d'assertion de couverture que CRD a retourné (context, tandis que le même processus sert CRD), et retourne chacun comme un package bundle avec une QuestionnaireResponse à remplir, les Bibliothèques dont son CQL a besoin et leurs dépendances. Les jeux de valeurs que ses réponses utilisent voyagent dans le package lorsqu'ils sont chargés (PUT /fhir/ValueSet/{id}), et $expand liste leurs codes. $log-questionnaire-errors écrit ce qu'une application DTR signale au journal du serveur.
Questionnaires adaptatifs : écrivez l'ensemble du questionnaire une seule fois, avec l'extension questionnaireAdaptive de SDC et enableWhen sur les questions qui n'appliquent que parfois. Le package remet à l'application un shell vide, et chaque appel $next-question ajoute la prochaine question qui s'applique aux réponses jusqu'à présent, jusqu'à ce qu'il n'y ait plus de questions à poser et que la réponse soit marquée comme complète. L'ordre et la division sont les règles propres du payeur ; les questions qui n'appliquent pas sont jamais affichées.
Se connecter en tant que client : les clients DTR et PAS atteignent le payeur avec les services SMART Backend - un JWT signé échangé pour un jeton sur le serveur d'autorisation du payeur. Pointez Perfuse sur ce serveur avec -smart-issuer (et -smart-jwks si son adresse ne se résout pas à partir de Perfuse), et passez -smart-backend-services afin que le document de découverte le dise. La suite DTR d'Inferno passe de cette façon avec Keycloak en tant que serveur d'autorisation.
Perfuse peut être ce serveur d'autorisation lui-même : serve -fhir -smart-clients clients.yaml émet des jetons de services Backend à /auth/token aux clients répertoriés, chacun avec les clés publiques qu'il signe avec ses assertions et les étendues de système qui peuvent lui être accordées, et le point de terminaison FHIR les accepte. Aucun serveur d'identité distinct n'est nécessaire pour les clients de machine à machine d'un payeur.
Avec -smart-users users.yaml également, les membres et les cliniciens se connectent pour autoriser les applications, dont l'API d'accès patient a besoin : l'application envoie la personne à /auth/authorize, ils se connectent, un clinicien choisit le patient, et les deux voient ce que l'application demande et peuvent décocher n'importe lequel. Un membre n'est jamais donné qu'à son propre dossier, quel que soit ce que l'application demande. Chaque personne dans le fichier nomme la ressource FHIR qu'elle est, Patient/… ou Practitioner/…, et un hachage de mot de passe à partir de perfuse smart hash ; le mot de passe lui-même n'est jamais écrit.
Les gens peuvent se connecter au fournisseur d'identité de l'organisation : -smart-oidc oidc.yaml le nomme (émetteur, id client et où le secret est), et la page de connexion offre « Se connecter avec » à côté du mot de passe. Chaque personne est liée par le sujet du fournisseur, oidc_subject dans le fichier des utilisateurs, afin que le fichier décide toujours qui peut autoriser des applications et quelle ressource FHIR elle est ; un compte lié à personne ne peut pas être refusé. Les codes, les jetons de rafraîchissement et les révocations sont conservés dans la base de données, afin qu'un redémarrage ne déconnecte personne.
Utilisateurs → Applications SMART dans la console répertorie les applications enregistrées et les personnes, et les ajoute, les modifie et les supprime. Chaque sauvegarde est vérifiée comme les fichiers le sont au démarrage, écrite dans ceux-ci, et utilisée immédiatement. Une application confidentielle enregistrée sans secret se voit attribuer un, montré une seule fois ; un mot de passe est défini ici et n'est jamais affiché à nouveau. La suppression d'une application, ou d'une personne, arrête les jetons d'accès déjà émis pour celle-ci ou accordés par eux immédiatement, et non lorsqu'ils expirent, ainsi que leurs jetons de rafraîchissement.
Les étendues peuvent être granulaires, comme SMART App Launch 2 et US Core les définissent : patient/Observation.rs?category=laboratory lit uniquement les Observations que cette recherche trouverait. Une concession qui est filtrée pour un type applique son filtre à chaque recherche et à chaque lecture de ce type ; une concession non filtrée pour le type, ou pour *, l'annule. Un filtre qui ne peut pas être lu ne concède rien plutôt que tout.
16.10 Décision des demandes d'autorisation préalable : PAS
serve -fhir -pas -crd-rules rules.yaml répond à Da Vinci PAS 2.2.1 à POST /fhir/Claim/$submit et POST /fhir/Claim/$inquire. Les décisions proviennent du même fichier de règles que les réponses de CRD, donc l'ordre dans lequel un clinicien est informé qu'une autorisation est nécessaire est décidé par la règle qui l'a indiqué :
- 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
Chaque élément reçoit une action de révision X12 : A1 certifié, A3 non certifié, A4 en attente, A6 modifié, C annulé (type de certification 3). Une ligne qui ne nomme aucun service n'est pas décidée mais répondue avec une erreur (X12 901 AG, corriger et ressoumettre). La réponse échoit ce que la réponse 278 échoit — les numéros de traçage des éléments, les dates de service demandées, les dates de rencontre, les identificateurs de transmission avec l'expéditeur et le destinataire échangés — et donne à chaque ligne le numéro de référence administratif propre à l'assureur. Un service dont aucune règle ne porte le nom est en attente, jamais approuvé : une décision que personne n'a consignée est une décision pour une personne.
Demandes en attente attendent un réviseur, qui répond avec 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 peut également être modify : certifié, mais pas comme demandé, avec quantity (valueDecimal, les unités certifiées) et/ou alternative (valueCoding, le service approuvé à la place). La réponse indique alors A6 Modifié, avec le détail certifié ou l'alternative comme élément ajouté, et un numéro d'autorisation. item (valueInteger, répétable) limite la décision à certaines lignes. La décision devient une nouvelle version de la réponse, marquée comme revue par une personne, et avec -fhir-subscriptions elle est livrée sur le sujet PAS (PASSubscriptionTopic, filtré par org-identifier, l'identifiant de l'organisation demanderesse) comme le paquet de réponse PAS complet, dans la même transaction qui l'enregistre. $inquire renvoie la réponse actuelle à chaque demande que le fournisseur a faite concernant ce membre ; une autre demande de fournisseur ne trouve rien. $decide nécessite une portée d'écriture ; $inquire est une lecture.
Les demandes et chaque version de leurs réponses sont conservées dans pas_requests et pas_responses dans la base de données du serveur.
16.10.1 La file d'attente du réviseur
Dans la console Web, Payers → CMS-0057 → File d'attente des réviseurs liste les demandes en attente les plus proches de l'échéance : une demande accélérée (Claim.priority stat) est due 72 heures après son arrivée, une demande standard 7 jours. La sélection d'une demande affiche le membre, le fournisseur, chaque service avec les unités demandées et son état, ce que la réponse a demandé, et chaque document reçu pour celui-ci, avec les documents texte brut affichés en ligne. Un éditeur enregistre la décision à cet endroit : approuver, refuser ou modifier (unités certifiées, ou un autre service approuvé à la place), avec une raison et le NPI du réviseur. Une modification doit certifier moins d'unités que celles demandées ; autant ou plus est un approbation, et est refusé comme modification. Un service approuvé à la place commence dans le système de codage de celui demandé. C'est la même décision que $decide prend, donc l'abonnement du fournisseur le livre. La lecture d'une demande et la décision sont toutes deux écrites dans le journal d'audit.
Surveillance → Tableaux de bord d'équipe → Autorisation préalable affiche, pour les 30 derniers jours, le nombre de demandes standard et accélérées qui ont été décidées dans les délais de CMS-0057, décidées en retard, toujours en attente dans les délais et en retard maintenant, avec la médiane du temps de décision, et comment les services demandés ont été répondu : approuvés, modifiés, refusés ou toujours en attente. Ces deux tuiles sont lues à partir des demandes elles-mêmes, donc elles ne sont pas dans l'exportation de tableau de bord de Grafana, qui le mentionne dans sa description.
16.10.2 Réception des documents demandés par une demande en attente
Une réponse différée demande des documents avec une tâche et une CommunicationRequest par document. Un questionnaire est demandé comme le décrit PAS : une CommunicationRequest avec le seul code LOINC 102089-0, sous le numéro de trace de la ligne pour laquelle il est destiné (itemTraceNumber, que la ClaimResponse répète ; une ligne envoyée sans numéro de trace en reçoit un). Ce numéro de trace est le contexte DTR : $questionnaire-package avec uniquement context défini sur celui-ci retourne le questionnaire. Le prestataire envoie ce qui a été demandé avec Da Vinci CDex $submit-attachment (POST /fhir/$submit-attachment) : le TrackingId est le numéro de trace de la demande (le premier identifiant de la ClaimResponse, qui est également celui de la tâche), ou un identifiant de CommunicationRequest, AttachTo est preauthorization, et MemberId doit être le membre de la demande. Chaque pièce jointe de DocumentReference ou QuestionnaireResponse est conservée avec la demande et affichée à son réviseur ; un document arrivant ne décide rien.
16.10.3 Décision dans un système de gestion des utilisations X12
La plupart des payeurs décident des autorisations préalables dans un système UM qui parle X12 278. Avec -pas-278-url, Perfuse est le front FHIR de ce système : chaque $submit est envoyé comme une demande 278 (005010X217), chaque élément étant un événement patient. Chacun porte ce que PAS nomme pour cela : le type d'examen (extension-serviceItemRequestType, UM01 : services de santé, admission ou soins spécialisés), le type de certification (extension-certificationType, UM02), le type de service, le lieu de prestation (UM04), le niveau de service (extension-levelOfServiceCode, UM06 : électif, urgent ou d'urgence ; une priorité stat remplace l'urgent), la date, les dates d'admission et de congé d'une revue d'admission, les diagnostics, le fournisseur de soins de l'équipe de soins qui effectuera le service, et la procédure et la quantité, en tant que service professionnel (SV1) ou, sur une réclamation institutionnelle, un service hospitalier (SV2) ligne de service. Le code d'action et le numéro d'autorisation de la réponse 278 deviennent l'action d'examen de l'élément : certifié, en partie ou modifié, refusé, différé, annulé ou non pris en compte (différé pour un réviseur, avec les raisons de rejet). Les règles locales ne sont pas consultées.
perfuse serve -fhir -pas -pas-278-url https://um.example/x12/278 -pas-278-receiver ACMEUM \
-pas-278-token-env UM_TOKEN
Un système UM qui met en attente d'abord et décide plus tard publie sa réponse 278 ultérieure sur POST /fhir/Claim/$decide-278 ; chaque événement est associé à sa demande par le numéro de traçage que Perfuse a envoyé, et est décidé comme $decide le déciderait. Si le système UM ne peut pas être joint, ou répond avec quelque chose qui n'est pas une réponse 278, chaque élément est en attente pour un réviseur et le fournisseur n'est informé que de cela ; la raison est dans le journal du serveur.
Les requêtes que le système UM répond
Un fournisseur doit trouver une autorisation dans son $inquire quelle que soit la façon dont elle a été demandée : par télécopie, via le portail de l'assureur, par téléphone ou dans une autre demande soumise. Perfuse ne conserve que les demandes qui sont passées par son intermédiaire ; le système de gestion des utilisations médicales (UM) les conserve toutes. Ainsi, avec un système UM qui répond en temps réel (tous les transports sauf sftp), chaque $inquire est également envoyé comme une demande d'information 278 (005010X215 : BHT02 28, le membre, le fournisseur, le numéro d'autorisation de la insurance.preAuthRef de la revendication lorsque celle-ci en a une, et les dates d'événement de billablePeriod ou les dates de service des éléments, sinon une année de chaque côté de la date actuelle). Chaque autorisation contenue dans la réponse que Perfuse ne possède pas (appariée par les numéros de trace qu'il a envoyés et les numéros d'autorisation qu'il a déjà fournis) est renvoyée comme un autre ensemble de réponses à la demande de revendication : la décision du système UM pour chaque ligne de service, le numéro et la période d'autorisation, ainsi qu'une note indiquant où elle a été trouvée. Aucune revendication n'est créée pour une autorisation que personne n'a soumise en FHIR : sa ClaimResponse.request contient une raison d'absence de données, comme le permet le profil PAS. Une demande d'information ne lit que les données ; rien dans les propres enregistrements de Perfuse ne change. Si le système UM est hors service ou répond avec un TA1 ou 999, le fournisseur reçoit ce que Perfuse possède, et le statut du lien indique pourquoi. La forme suit les guides d'accompagnement de la demande 278 que UnitedHealthcare, Cigna et Blue Cross Blue Shield du Massachusetts publient ; elle n'a pas été testée contre un système UM réel.
Comment les 278s atteignent le système UM
Le guide de connectivité du système UM indique comment il prend en charge les 278s, et -pas-278-transport (Paramètres, Payeurs, lien de gestion de l'utilisation) suit cela :
| Transport | Ce qui est envoyé | Authentification |
|---|---|---|
x12 (par défaut) | La 278 est envoyée sous forme de application/edi-x12 ; la réponse est le corps de la réponse | Un jeton porteur, OAuth, Authentification de base HTTP, un certificat client |
core-soap | L'enveloppe SOAP 1.2 CAQH CORE en temps réel (COREEnvelopeRealTimeRequest, type de charge utile X12_278_Request_005010X217E1_2, ou X12_278_Request_005010X215 pour une demande d'information) : Règle de connectivité vC2.2.0 avec la charge utile dans l'enveloppe, que la plupart des assureurs et des systèmes esMD de CMS exécutent, ou -pas-278-core-version C4.0.0 avec la charge utile en tant que pièce jointe MTOM | vC2.2.0 : un nom d'utilisateur et un mot de passe (jeton de sécurité WS-UsernameToken) ou un certificat client. vC4.0.0 : un certificat client et un jeton OAuth |
core-mime | L'enveloppe HTTP MIME multipart CAQH CORE vC2.2.0, la charge utile en tant que partie de fichier | Le nom d'utilisateur et le mot de passe de l'enveloppe, ou un certificat client |
sftp | Chaque 278 est placée dans un dossier sur le serveur SFTP du système UM (-pas-278-sftp, -pas-278-sftp-outbound) ; ses réponses sont collectées à partir d'un autre (-pas-278-sftp-inbound, chaque -pas-278-sftp-every) | Une clé SSH ou un mot de passe ; la clé du serveur doit être dans -pas-278-sftp-known-hosts |
Un certificat client est -pas-278-cert et -pas-278-key ; -pas-278-ca fait confiance à l'autorité de certification propre au payeur. OAuth est -pas-278-oauth-token-url, -pas-278-oauth-client-id et le secret, récupéré avec la subvention d'informations d'identification client et conservé jusqu'à une minute avant son expiration. Les mots de passe, les jetons et les secrets ne sont jamais des indicateurs : chacun est nommé par une variable d'environnement (-pas-278-password-env, -pas-278-token-env, -pas-278-oauth-secret-env, -pas-278-sftp-password-env), ou saisi dans l'écran de paramètres, où il est conservé dans le fichier de paramètres (lisible uniquement par le compte du serveur) et n'est plus jamais affiché.
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
Sur SFTP, chaque demande est mise en attente jusqu'à l'arrivée de sa réponse : la réponse 278 décide des éléments, et Perfuse place un 999 l'acceptant dans le dossier de sortie. Un fichier qu'il ne peut pas lire reste dans le dossier d'entrée pour une personne et est proposé à nouveau à la prochaine lecture.
Lorsque le système UM ne peut pas lire une demande
Un système UM qui ne peut pas lire un 278 répond avec un TA1 (l'enveloppe) ou un 999 (la transaction) au lieu d'une décision. Perfuse lit lequel et ce qu'il dit, met en attente chaque élément ("la gestion des ressources ne peut pas lire la demande"), et l'enregistre. Payeur, CMS-0057, File d'attente du vérificateur affiche le lien : ce qui a été envoyé au cours des sept derniers jours, chaque échange par son numéro de contrôle, et ce qui en est résulté (répondu ; reconnu, réponse à venir ; rejeté, avec le segment, l'élément et le code du 999 ; non atteint). Chaque échange a son propre numéro de contrôle, un de plus que le dernier, qui est ce qu'un TA1 ou un 999 nomme lorsqu'il répond.
16.10.4 Décision sur les preuves cliniques, avec un service de décision
Un fichier de règles décide par code de service : un code n'a pas besoin d'autorisation, n'est pas couvert, ou va à un réviseur. Que ce patient réponde aux critères pour celui-ci est une autre question, répondue à partir des conditions, des réponses au questionnaire et des documents que le fournisseur a envoyés avec la demande. Avec -pas-decider-url, chaque élément que les règles laissent à un réviseur est d'abord soumis à un service de décision, tel que Vaglio, qui lit le même dossier de demande PAS à travers le package pas publié de Perfuse. Un Vaglio public, sur des demandes inventées uniquement, s'exécute à côté de l'instance de test de Perfuse à l'adresse https://vaglio.perfuse.health:8443 (se connecter en tant que demo, mot de passe try-vaglio-demo ; il peut regarder tout et ne peut rien changer) : chaque décision a sa preuve, une lettre en langage clair et un reçu que n'importe qui peut vérifier.
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 doit être https, ou http simple vers cette machine (localhost, 127.0.0.1), car il transporte un dossier de patient et le jeton. Vaglio lui-même répond uniquement sur https ; lorsque vous utilisez un certificat de son propre autorité, passez cette autorité avec -pas-decider-ca DATA/tls/ca.crt (ou toute autorité interne d'un payeur dont le certificat de service provient). Le service reçoit la requête Bundle telle que le fournisseur l'a envoyée, POST <url>?item=<sequence> (application/fhir+json), et répond {"decision": "approve" | "deny" | "pend", "why": "...", "requested": ["..."]}, ou 404 lorsqu'il ne décide rien pour cet élément, ce qui laisse la réponse des règles en place. why est la note de processus de la réponse et est requise pour un refus, qui est sinon mis en attente ; requested est indiqué au fournisseur comme l'information dont une demande en attente a besoin. Une attente peut également transporter "questionnaire": "<canonical>" et "attachments": ["<LOINC>", ...], qui sont demandés dans la réponse CDex Task et CommunicationRequests à côté de tout questionnaire ou pièces jointes DTR demandés par la règle (le questionnaire de la règle l'emporte, puisqu'une tâche en demande une ; un code qui n'est pas de la forme LOINC est supprimé et consigné). Une règle qui approuve ou refuse est la politique de couverture du payeur et n'est pas envoyée au service. Une défaillance, un délai d'attente ou une réponse qui n'est pas l'une des trois décisions met l'élément en attente pour un réviseur, avec la raison dans le journal du serveur : rien ici ne transforme une défaillance en approbation. Il ne peut pas être combiné avec -pas-278-url, où le système UM répond à chaque élément.
Conseil avant de soumettre. Avec -crd-advisor-url à côté de -crd-rules, CRD demande également à un service de décision ce qu'une demande d'autorisation préalable pour chaque ordre en aurait besoin, et affiche la réponse comme une carte supplémentaire : « Avant de soumettre : une demande pour cela nécessiterait : ... », ou « serait approuvée », avec ce qui est encore nécessaire, le questionnaire qui le demande, et ce qui l'approuverait. Vaglio répond à /api/pas/advise, avec le même jeton et la même autorité qu'au-dessus :
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 envoie POST <url> avec {"service": {"system": "...", "code": "..."}, "resources": [ ... ]}, les ressources étant le préchargement de l'accroche (le patient en premier, la couverture laissée de côté), et lit {"decides": true, "answer": "approve" | "pend" | "deny", "summary": "...", "missing": [...], "questionnaire": "...", "toApprove": [[...]], "policyTitle": "..."}. Il s'agit d'un conseil et ne modifie rien : les informations de couverture, les autres cartes et la décision PAS sont ce que les règles disent. Il attend au maximum trois secondes, et aucune réponse, un échec ou "decides": false laisse la réponse exactement telle qu'elle est sans elle. Perfuse n'a jamais besoin d'un service de décision.
La requête transporte X-PAS-Request-Id, l'identifiant par lequel la réponse est connue. Un service avec ses propres réviseurs qui met un élément en attente peut envoyer leur décision plus tard comme celle de tout réviseur : Claim/$decide avec cet identifiant comme claimResponse, la séquence de l'élément et la décision et la raison. L'abonnement du fournisseur le livre comme s'il s'agissait d'un élément créé dans la file d'attente des réviseurs.
Un abonnement avec un contenu id-only indique au fournisseur quel élément de réponse a changé sans dire ce qu'il est : la notification se concentre sur Bundle/<id>. GET /fhir/Bundle/<id> renvoie le dernier bundle de réponse PAS, GET /fhir/Bundle/<id>/_history/<n> la version qu'une notification a envoyée, et GET /fhir/ClaimResponse/<id> la seule ClaimResponse. Un jeton lié à un patient est informé qu'il n'existe pas, comme pour tout dossier en dehors de son patient.
Vérifié avec la suite officielle du serveur PAS Inferno v2.2.1 (voir vérification). Non envoyé, bien que PAS marque les must-support : ClaimResponse.adjudication avec une action de vérification, ClaimResponse.extension:authorizedProvider et ClaimResponse.item.extension:communicatedDiagnosis, car les extensions dont ils ont besoin ne sont pas autorisées ici par leur propre contexte dans PAS 2.2.1 et le validateur rejette une réponse qui les transporte ; et request.extension:DataAbsentReason, car Perfuse sait toujours la demande. Les 278 envoyés à un système de gestion des ressources (ci-dessus) sont vérifiés contre les exemples de demande propres à PAS 2.2.1, les exemples d'esMD 278 publiés par CMS et un vérificateur 278 rédigé à partir de guides d'accompagnement publics, et chaque transport est vérifié contre un système UM factice rédigé à partir des règles de connectivité de CAQH (voir vérification) ; pas encore contre un système UM réel ou un clearinghouse, et pas certifié CORE. Non implémenté : les pièces jointes renvoyées avec CDex.
Un fichier de règles est vérifié contre les invariants propres à CRD lorsqu'il est chargé : un questionnaire nécessite une documentation, un service qui n'est pas couvert ne peut pas nécessiter d'autorisation, satisfied appartient à un cas et non à une règle, et tout ce qui est conditionnel doit donner une raison.
Non vérifié : les exports et la correspondance des membres contre la mise en œuvre d'un autre payeur, les métriques contre les chiffres publiés d'un payeur, et CRD contre un client CDS Hooks d'un véritable système d'enregistrement électronique de santé.
16.11 Envoi de demandes d'autorisation préalable à un payeur (pour les prestataires)
Tout ce qui précède répond aux demandes, en tant que payeur. Le côté d'un prestataire est l'inverse : un système de dossiers médicaux électroniques ou une application de dossier de soins construit un paquet de demande Da Vinci PAS, et quelque chose doit l'envoyer au payeur, conserver la réponse et la transmettre. Une destination pas fait cela.
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
Chaque message doit être un paquet de demande PAS complet sur un canal brut. Perfuse le publie inchangé sur {payer}/Claim/$submit : le payeur décide du Claim avec le patient, la couverture et les ressources de support dans le paquet, et un Claim reconstruit à partir d'un résumé perdrait ceux-ci. Hors de cette machine, l'adresse du payeur doit être https.
Une décision est une demande livrée, quelle que soit sa teneur. Un approbation, un refus et un pend sont tous enregistrés et aucun n'est réessayé, car réessayer un refus soumet la même demande deux fois. Ce qui échoue à la livraison, et est réessayé, est un payeur qui n'a pas décidé : un statut d'erreur, un OperationOutcome (son texte est l'erreur) ou un ClaimResponse dont le résultat est error. La décision est lue élément par élément à partir des codes d'action de revue PAS (X12 306 : A1 approuvé, A2 partiellement, A3 refusé, A4 différé, A6 modifié) ; une réponse sans code est répertoriée comme « pas de code de décision » plutôt que prise comme une approbation. Un refus sans raison nulle part est refusé car il ne répond pas à CMS-0057.
La réponse du payeur est la réponse de la destination, donc Inspecter la réponse peut la juger, et results_to la transmet à un autre canal. Chaque demande est répertoriée sur CMS-0057, Demandes envoyées aux payeurs : quand elle est partie, le patient, le service, la décision et la référence du payeur (preAuthRef), que nomme une enquête ultérieure. La liste est conservée dans prior-auth.json à côté de la base de données (au maximum 10 000 demandes ; les anciennes demandes décidées partent en premier, une demande en attente ne le fait jamais), et chaque locataire ne voit que la sienne.
Vérifié contre la référence d'implémentation du payeur Da Vinci PAS HL7 (image Docker hlseven/davinci-prior-auth) : une demande envoyée via un canal en cours d'exécution est différée par celui-ci avec sa référence, et la réponse s'affiche sur l'écran (voir vérification). Pas encore essayé contre un payeur de production. Pas construit : suivre une demande différée avec $inquire, ou recevoir la réponse ultérieure du payeur par abonnement ; un canal peut faire l'un ou l'autre aujourd'hui avec une destination http ou fhir.
16.12 Réseaux alignés sur le CMS
Le cadre d'interopérabilité de la CMS (écosystème technologique de la santé de la CMS) demande aux réseaux de données de santé de s'auto-attester à 26 critères et d'être répertoriés en tant que réseaux alignés CMS ; les dossiers médicaux électroniques, les fournisseurs, les payeurs et les applications se connectent à eux. Les critères 13 à 16 sont en vigueur depuis le 4 juillet 2026 : API FHIR sur US Core avec une déclaration de capacité complète et des données en bloc, des documents sous forme de pièces jointes FHIR lisibles par l'homme, des notifications de rendez-vous et de rencontre par abonnement FHIR, et un localisateur de dossiers.
Administrez › Réseau aligné CMS répertorie chaque critère avec ce que Perfuse fournit pour cela et où ce serveur se trouve, lu à partir de ce qui est activé ici :
| État | Signification |
|---|---|
| Prêt ici | Perfuse fournit cela et il est activé. |
| Prêt, avec un écart | Il est activé, et une partie du critère est en dehors de celui-ci (nommé sur l'écran). |
| Construit, non activé | Perfuse fournit cela ; l'écran nomme le paramètre ou le drapeau qui l'active. |
| À votre charge | La partie de l'organisation : un accord, une certification, une publication dans l'annuaire des fournisseurs nationaux. |
| Non construit | Le logiciel le ferait, et Perfuse ne le fait pas. |
Ce dont les quatre en vigueur ont besoin de ce serveur :
| Critère | Dans Perfuse | Activer |
|---|---|---|
| 13 API FHIR, US Core, données en bloc | Le point de terminaison FHIR avec sa déclaration de capacité, et $export | -fhir, -fhir-bulk-export |
| 14 Documents en tant que pièces jointes FHIR | DocumentReference avec Binary, et IHE MHD sur le registre XDS | -fhir (MHD également -xds) |
| 15 Notifications de rencontre et de rendez-vous | Abonnements basés sur des sujets (R5 Backport pour R4) à partir des flux ADT et SIU | -fhir-subscriptions |
| 16 Localisateur d'enregistrement | Le registre XDS.b, XCA pour d'autres communautés, PIXm | -xds, -xds-home-community |
L'écran est une feuille de travail pour l'attestation, et non une certification : la CMS examine les réseaux qu'elle soupçonne de ne pas répondre aux critères, et le texte du cadre lui-même est l'autorité. Non construit aujourd'hui : les requêtes de lacunes de qualité ouvertes (critère 8), une requête d'un payeur pour les données de rencontre d'une réclamation (9), la notification des métriques de requête au répertoire national des fournisseurs (19), la vérification des fournisseurs contre ce répertoire (6), la lecture des permis de conduire mobiles ou des cartes d'assurance numériques (3, 23), et l'application d'une politique de consentement général à chaque lecture (5). L'identification d'identité IAL2 est celle du service d'identité ; Perfuse accepte les jetons de celui que vous choisissez.
17 Sécurité
Perfuse gère des données cliniques. Ce chapitre décrit ce qu'il fait à ce sujet et ce qu'il laisse à votre charge.
17.1 Sécurité du transport
TLS sur l'interface web est configuré avec -tls-cert et -tls-key. Sans ceux-ci, l'interface est en HTTP non chiffré, ce qui est acceptable sur une adresse de bouclage pour un premier aperçu et nulle part ailleurs — il transporte des informations d'identification et des contenus de messages, tous deux lisibles sur le fil.
TLS sur les transports de canal est par source et par destination, sous un bloc tls. Les paramètres disponibles sont dans les références source et destination.
insecure_skip_verify accepte tout certificat. Il existe parce que les systèmes hospitaliers présentent régulièrement des certificats qui ne seront pas vérifiés, et refuser de se connecter signifierait refuser d'intégrer. Il est nommé pour être visible, et l'utiliser signifie que la connexion est chiffrée mais non authentifiée — vous avez une protection contre les interceptions passives et aucune contre un serveur interposé.
17.2 Authentification et rôles
Les utilisateurs sont stockés dans la base de données. Chacun a l'un des cinq rôles, et chaque rôle inclut tout ce qui est dans les rôles au-dessus de lui :
| Rôle | Peut |
|---|---|
| Superviseur | Voir si les choses fonctionnent : état du canal, comptes, carte de flux, alertes, tableaux de bord, métriques et profondeur de la file d'attente. Aucun contenu de message, fichiers de canal ou messages en file d'attente. |
| Lecteur | Lire également les messages, les fichiers de canal, les traces et le journal d'activité. |
| Opérateur | Réenvoyer également : retraiter un message, rejouer un canal et réessayer les livraisons en file d'attente. |
| Éditeur | Créer et modifier également les canaux, et exécuter des comparaisons. |
| Administrateur | Démarrer et arrêter également les canaux, vider les files d'attente, et gérer les personnes, les jetons et les paramètres du serveur. |
Un sixième rôle, Plateforme, appartient à quiconque exécute un serveur partagé : il crée des locataires et définit leurs limites, et ne détient aucun canal en propre.
Le moniteur est destiné à un bureau d'assistance ou à un écran d'opérations sur un mur : tout ce qui est nécessaire pour voir qu'un flux s'est arrêté, et rien qui nomme un patient. Le visualiseur peut lire le contenu des messages, qui constitue des données cliniques ; il s'agit d'un rôle à privilèges limités pour la *configuration*, et non pour la confidentialité. L'opérateur sépare la réparation d'une livraison échouée la nuit de la modification de ce que fait un flux : la personne qui renvoie n'a pas besoin d'être en mesure de réécrire le canal.
17.2.1 Mots de passe incorrects répétés
Les mots de passe incorrects et les connexions par clé de passe échouées sont comptabilisés par l'adresse à laquelle la connexion provient, et après quelques-uns à la suite, cette adresse attend avant de pouvoir réessayer (la réponse est 429, avec Retry-After). Les comptes ne sont pas verrouillés par nom, car cela permettrait à n'importe qui de verrouiller un administrateur intentionnellement.
L'adresse est propre à la connexion, et non celle qu'une demande revendique dans X-Forwarded-For, que l'expéditeur écrit. Derrière un proxy inversé sur la même machine, Perfuse utilise à la place la dernière entrée X-Forwarded-For, celle que le proxy a ajoutée, de sorte que chaque client est toujours comptabilisé séparément. Un proxy sur une autre machine atteint Perfuse à partir d'une seule adresse, et tous ses clients partagent un seul comptage : limitez les connexions à ce proxy également.
17.2.2 Groupes de canaux
Une personne (ou un jeton d'API) peut être limitée à certains groupes de canaux : elle voit et agit alors uniquement sur les canaux dont le group est l'un des siens. C'est l'arrangement d'un groupe hospitalier sur un serveur, chaque établissement ayant ses propres analystes qui s'occupent de leurs propres flux et une équipe centrale, sans limite, qui s'occupe de tous. Rhapsody l'appelle un casier.
La limite s'applique partout en même temps, car elle est appliquée à la demande plutôt qu'être mémorisée par chaque écran : la liste des canaux, le tableau de bord et la carte de flux, les messages et leur recherche, les comptes et les graphiques, la file d'attente, les alertes, les métriques, les certificats, les contrats et l'utilisation des jeux de codes. Un canal en dehors des groupes d'une personne n'existe pas pour elle ; demander son nom répond *non trouvé*, donc son nom n'est pas confirmé non plus. Un canal sans groupe n'est visible que pour les personnes sans limite.
Enregistrer un canal le conserve à l'intérieur des groupes d'une personne : ils ne peuvent pas créer un canal dans un autre groupe, ou déplacer un canal hors de leur propre groupe. Ce que chaque établissement partage - les tables de codes, les bibliothèques de scripts, les décisions de préautorisation - ils peuvent les lire mais pas les modifier. Les chiffres serveur (préautorisation, utilisation de jetons, tunnels) ne sont affichés qu'aux personnes sans limite, et il en va de même pour les métriques et les alertes sur l'ensemble du serveur plutôt que sur un canal.
Un administrateur limité à des groupes est l'administrateur propre d'un établissement. Ils gèrent les personnes et les jetons de leurs groupes, démarrent et arrêtent leurs canaux et nettoient leurs files d'attente. Un collègue qu'ils ajoutent reçoit leurs groupes, à moins qu'ils n'en nomment certains, ils ne peuvent pas donner un groupe qu'ils n'ont pas, et ils ne voient jamais ou ne modifient personne sans limite. Tout le reste qu'un administrateur peut faire modifie l'ensemble du serveur - les paramètres, la connexion, la réinitialisation, les règles d'alerte, la personnalisation, la flotte, le serveur SMART - et leur est refusé.
Les groupes sont définis dans Utilisateurs (et pour les jetons dans Jeton), sous forme de liste séparée par des virgules. Chaque modification est enregistrée dans le journal d'activité et prend effet à la prochaine demande de la personne.
Un rôle différent dans chaque groupe
Une personne peut avoir un rôle différent dans chacun de ses groupes : lab=editor, adt dans Users édite les canaux du laboratoire et a le rôle choisi à côté de celui-ci - disons le rôle de lecteur - dans les canaux d'admission. Elle voit les canaux des deux groupes sur chaque écran. Enregistrer, démarrer ou renvoyer un canal dans un groupe où son rôle est trop bas est refusé avec le rôle qu'elle détient là-bas ; il ne prétend pas que le canal est manquant, puisqu'elle peut le voir. Son rôle en haut de l'écran est le plus élevé qu'elle détient, ce qui ouvre les écrans que ce rôle utilise, et chaque action sur ces écrans est toujours limitée aux groupes où elle le détient.
Seules les personnes limitées à des groupes de canaux peuvent en avoir un. Quelqu'un qui voit tous les canaux n'a qu'un rôle, car « éditeur des canaux du laboratoire » pour une personne sans limite serait éditeur de tout ce qui n'appartient à aucun groupe, et des pages serveur. Un administrateur d'établissement peut donner un rôle par groupe uniquement dans les groupes qu'il administre, et jamais au-dessus de son propre rôle.
17.3 Qui peut appeler le point de terminaison FHIR
Le point de terminaison FHIR (serve -fhir) vérifie l'un des deux types de jetons :
- Jeton d'API Perfuse, créé sous Utilisateurs → Informations d'identification de la machine ou avec
perfuse token create. Chaque jeton porte un rôle et peut être limité aux groupes FHIR. Il s'agit du paramètre par défaut lorsque aucun serveur d'autorisation SMART n'est configuré. - Jeton d'accès SMART, du serveur d'autorisation propre de Perfuse (
-smart-clients) ou d'un serveur externe (-smart-issuer). Chaque jeton porte des étendues, et le point de terminaison tient chaque demande à eux.
Avec SMART configuré, seuls les jetons SMART sont acceptés, donc chaque appelant est tenu à ses étendues. Un jeton d'API a un rôle et pas d'étendues : un jeton de visualiseur peut lire l'enregistrement de chaque patient. Un payeur qui a activé SMART pour limiter chaque application à ce qui lui a été accordé ne devrait pas avoir un moyen d'accès qui ne soit pas limité.
Certains sites ont besoin des deux - un flux de réclamations interne qui détient un jeton d'API et n'a pas de client SMART, à côté d'applications de membre qui se connectent via SMART. Pour ceux-ci, Paramètres → FHIR → Accepter les jetons d'API Perfuse à côté des jetons SMART (-fhir-api-tokens au démarrage) permet aux jetons d'API d'entrer également. Il est désactivé par défaut, il prend effet à la prochaine demande dans les deux sens, et la modification est écrite dans le journal d'audit. Un jeton est distingué par sa forme : un jeton SMART est un JWT signé, et un jeton d'API ne l'est jamais, donc l'un n'est jamais vérifié comme l'autre. Lorsque vous le pouvez, donnez à un tel système un client de services de backend SMART, avec uniquement les étendues système dont il a besoin.
17.3.1 Un point de terminaison FHIR ouvert aux inconnus
Un serveur de test public distribue des informations d'identification qui peuvent écrire, car la tests de préautorisation ou d'abonnements nécessitent des écritures. Deux limites empêchent un client de gâcher les choses pour tout le monde, les deux sous Paramètres → FHIR et les deux désactivés par défaut :
- Écritures par minute d'un client (
-fhir-writes-per-minute): crée, met à jour et supprime à partir d'une adresse client. Au-delà, une écriture est répondue 429 avecRetry-After: 60. Les lectures et les recherches, y compris les recherches par POST, ne sont jamais comptabilisées. - Ressources maximales détenues (
-fhir-max-resources): au-delà, de nouvelles ressources sont refusées avec 507, tandis que les mises à jour et les suppressions fonctionnent toujours.
Le point de terminaison d'un hôpital n'a besoin de rien de tout cela.
17.4 Agents d'IA : le serveur MCP
Avec Paramètres › Sécurité › Agents IA (MCP) activé (ou serve -mcp), Perfuse sert le protocole de contexte de modèle à /mcp, afin qu'un agent IA tel que Claude, ChatGPT ou un assistant IDE puisse demander ce qui se passe. Il est désactivé par défaut, et la désactivation arrête tous les agents à leur prochaine appel.
Un agent se connecte avec un jeton d'API à partir de Administer › Utilisateurs › Informations d'identification de machine en tant que jeton porteur, et non avec une session de navigateur d'une personne (ce qui est refusé, donc un agent n'agit jamais avec l'accès complet d'une personne). Une configuration client ressemble à :
{ "mcpServers": { "perfuse": { "type": "http", "url": "https://perfuse.example/mcp",
"headers": { "Authorization": "Bearer <token>" } } } }
| Outil | Rôle | Fonction |
|---|---|---|
server_status, list_channels, queue, alerts | surveillant | Fonctionnement des éléments, sans contenu de message |
get_channel, search_messages, get_message, find_patient, fhir_search | visionneur | Canaux, messages (avec contenu), messages d'un patient à travers les formats, recherche FHIR |
retry_delivery, reprocess_message | opérateur, et mcp:write | Réessayer une livraison en file d'attente, renvoyer un message à travers son canal à nouveau |
start_channel, stop_channel | administrateur, et mcp:write | Démarrer ou arrêter un canal |
Chaque outil est répondu par la même route ou la recherche FHIR que l'écran d'une personne utilise, appelé avec le jeton propre de l'agent, donc le rôle du jeton, les groupes de canaux et le locataire décident de ce qu'il voit, exactement comme ils le font dans la console ; et fhir_search obtient son propre accès sur le point de terminaison FHIR (qui peut refuser les jetons d'API dans leur ensemble ; voir la section FHIR ci-dessus). Un agent n'est proposé que les outils qu'il peut utiliser. La lecture est la valeur par défaut : un outil qui modifie quelque chose nécessite également la portée mcp:write du jeton ("Laisser un agent IA agir avec lui" lors de la délivrance du jeton), donc un jeton délivré pour un agent de rapport ne peut pas être incité à agir par une invite. Les réponses d'un jeton de surveillance ont le contenu des messages supprimé, quel que soit ce que retourne une route.
Chaque appel est dans Activité en tant que mcp.tool avec le nom du jeton, l'outil, ses arguments et le résultat (ok, refused, invalid, rate-limited ou le statut HTTP) ; mcp.connect enregistre quel client s'est connecté. Chaque jeton peut effectuer 60 appels d'outil par minute (Appels d'outil par minute à partir d'un jeton) ; au-delà, un appel est répondu avec une erreur que l'agent peut lire, et rien n'est fait. Une demande à partir d'une page de navigateur sur une autre origine est refusée, ce que MCP demande à un serveur pour arrêter le rebinding DNS. Le transport est le Streamable HTTP de MCP, répondu sous forme de JSON sans flux d'événements ; les versions de protocole 2025-06-18, 2025-03-26 et 2024-11-05 sont acceptées. Les messages et les ressources FHIR contiennent des données de patient : les réponses d'un agent vont à tout modèle sur lequel il s'exécute, donc donnez un jeton à un agent uniquement là où ce modèle est autorisé à les voir, et donnez-lui le rôle le plus bas qui fait le travail.
17.5 Un compte de démonstration
serve -demo-account demo:PASSWORD crée un compte partagé pour un serveur de démonstration public, et la page de connexion affiche son nom d'utilisateur et son mot de passe avec un bouton qui se connecte avec eux. Le compte est un observateur, il peut donc regarder tout sans rien modifier. Contrairement à tout autre observateur, il peut également ouvrir les écrans des administrateurs (utilisateurs, jetons de machine, paramètres, protection des données, les pairs de la flotte), en lecture seule : une démonstration est jugée sur ses écrans. Il les lit comme un observateur lit les canaux, avec chaque information d'identification affichée comme définie ou non, jamais sa valeur, et chaque modification refusée. Il peut également appuyer sur les vérifications qui ne modifient rien et n'atteignent rien à l'extérieur du serveur : une vérification de script, et la validation et l'analyse de l'éditeur de canal. Il ne peut pas modifier son mot de passe ou ajouter une clé de passe, car le premier visiteur à le faire verrouillerait tout le monde après lui. Chaque démarrage le rétablit en tant qu'observateur avec le mot de passe publié. Le mot de passe doit comporter au moins 12 caractères, comme n'importe quel autre. N'utilisez-le que sur un serveur contenant des données de test : quiconque lit la page de connexion peut lire chaque message sur le serveur.
17.6 Audit
Les modifications de configuration, les connexions et l'accès au contenu des messages sont enregistrés avec qui, quoi et quand.
Le journal d'audit est dans la même base de données que les messages. C'est pratique et c'est une limitation : quelqu'un qui peut modifier la base de données peut modifier le journal d'audit. Si vos exigences incluent un journal d'audit à preuve de falsification, le journal doit être expédié vers un emplacement où seul l'ajout est autorisé, et la sortie de journal de Perfuse est la façon de le faire.
17.7 Secrets dans la configuration
Les mots de passe, les codes et les clés apparaissent dans la configuration du canal, ce qui signifie qu'ils sont dans les fichiers YAML.
Deux conséquences. Les fichiers nécessitent des autorisations de système de fichiers qui reflètent leur contenu, et s'ils sont sous contrôle de version — ce qui est autrement recommandé — le référentiel contient des informations d'identification et doit être traité en conséquence.
Lorsqu'une valeur est un secret, l'interface le rend comme un secret et l'API ne le renvoie pas une fois enregistré. Cela le protège contre la lecture par-dessus l'épaule de quelqu'un ou les fuites dans une capture d'écran. Cela ne protège pas le fichier.
17.8 Ce qui se trouve dans la base de données
Le magasin de messages stocke les messages tels qu'ils ont été reçus, ce qui signifie, pour un flux clinique, des données identifiables de patient. Il devrait être sur un stockage chiffré, sauvegardé comme des données cliniques avec la rétention que cela implique, et contrôlé d'accès au niveau du système de fichiers ainsi que via les rôles de Perfuse.
cleanup.periodDays limite la durée pendant laquelle il est conservé. Voir le magasin de messages pour la tension entre cela et avoir suffisamment d'historique pour l'alerte rythmique.
17.9 Protection des données (RGPD et RGPD-UK)
L'écran Protection des données (Administer, administrateurs uniquement) répond aux demandes d'une personne en vertu du RGPD et du RGPD du Royaume-Uni. Il ne décide rien au nom du contrôleur : si une demande doit être accordée, et si une exemption s'applique, est la décision du contrôleur, enregistrée avec la demande.
Trouver ce qui est détenu. Une personne est nommée par des identificateurs : system|value (un numéro NHS, un MRN avec son autorité d'attribution) ou un numéro à lui seul. Avec un index de patient, ceux-ci s'élargissent à chaque numéro de chaque enregistrement lié à la même personne, afin qu'une demande citant un numéro d'hôpital trouve les enregistrements classés sous les autres. Voir ce qui est détenu recherche alors chaque magasin qui conserve des données de patient :
| Magasin | Trouvé par |
|---|---|
| Messages | l'index d'identité (Paramètres → Données → Indexer les identifiants de patient) ; sans cela, les messages ne peuvent pas être trouvés par identifiant |
| La file d'attente de livraison | en lisant les identifiants de chaque message en attente |
| Le magasin FHIR | les ressources Patient portant un identifiant, et chaque ressource dont les références indexées pointent vers l'une |
| Les demandes d'autorisation préalable | les identifiants du patient de la demande |
| L'index de patient | l'identifiant, ou l'EUID |
Ce qu'il ne peut pas atteindre, il le dit : les traces envoyées à un collecteur (-trace-endpoint), le journal d'audit (conservé : c'est l'enregistrement de qui a fait quoi, y compris cette demande), et les sauvegardes.
Demandes. Une demande est enregistrée avec son type (accès, Article 15 ; portabilité, Article 20 ; effacement, Article 17 ; restriction, Article 18), l'identité de la personne qui la formule telle que référencée dans les enregistrements du contrôleur, les identifiants, ainsi qu'une note (modalités de confirmation de l'identité, prolongation et motif). Elle doit être traitée dans le mois suivant sa réception (Article 12(3)) ; une demande en retard est affichée en rouge.
- Accès et portabilité : Télécharger la copie fournit un fichier zip : chaque message reçu avec son enregistrement, chaque ressource FHIR avec toutes les versions stockées, les demandes d'autorisation précédentes et leurs réponses, ainsi que les enregistrements de l'index des patients, au format JSON, avec un fichier README expliquant chaque partie. Marquer comme traitée la clôture.
- Effacement : un deuxième administrateur l'approuve (celui qui l'a enregistrée ne le peut pas). Effacer maintenant supprime tout ce qui a été trouvé : messages entiers (enregistrement, corps, livraisons, identifiants, pièces jointes non utilisées par d'autres messages), livraisons en attente (elles ne sont pas envoyées), les ressources FHIR avec leur historique, les demandes d'autorisation précédentes avec leurs réponses, les pièces jointes et les numéros de suivi, ainsi que la personne dans l'index des patients avec tous les enregistrements liés et leur historique (un événement indique qu'un effacement a eu lieu et par qui).
- Restriction : enregistrée comme une rétention légale, de sorte que rien ne soit effacé ou n'expire pendant sa durée.
- Refuser clôture une demande avec son motif, que la personne doit être informée.
Une demande fermée ne conserve que les derniers caractères des numéros de la personne : elle reste comme enregistrement d'une réponse sans être une autre copie. Chaque étape est consignée dans le journal d'audit avec les numéros masqués.
Conservations légales. Une conservation nomme une personne par identifiants, avec sa raison et une date de fin optionnelle. Tant qu'elle est en vigueur, une suppression est refusée purement et simplement, et la fenêtre de rétention du magasin de messages épargne les messages de la personne (enregistrements et corps) jusqu'à ce que la conservation soit levée.
Sauvegardes et registre des suppressions. Une sauvegarde effectuée avant une suppression conserve toujours ce qui a été supprimé jusqu'à son expiration. Chaque suppression est consignée dans un registre : quand, par qui, approuvée par qui, combien a été supprimé de chaque magasin, et les identifiants de la personne sous forme de hachages SHA-256 salés plutôt qu'en clair. Après la restauration d'une sauvegarde, Réappliquer les suppressions hache les identifiants que les magasins restaurés contiennent avec chaque entrée de sel et supprime chaque personne que le registre nomme. Les petits numéros peuvent être trouvés à partir de leurs hachages en essayant toutes les valeurs, donc le registre est lui-même des données personnelles et est conservé avec la protection propre à la base de données.
Rétention. L'écran liste combien de temps chaque type d'enregistrement est conservé ici et ce qui le modifie : les enregistrements et les corps des messages par leurs fenêtres de rétention, la file d'attente jusqu'à la livraison ou la suppression, le magasin FHIR, les demandes d'autorisation précédentes et l'index des patients jusqu'à leur suppression (les dossiers médicaux ne sont pas supprimés selon un calendrier), le journal d'audit conservé.
Enregistrement du traitement (Article 30). Enregistrement du traitement télécharge, au format Markdown ou CSV, ce que ce serveur sait de celui-ci : le contrôleur, le délégué à la protection des données et où les données sont conservées (Paramètres → Données → Protection des données), la rétention de chaque type d'enregistrement, et une activité de traitement par canal avec ce qu'il reçoit, d'où il le reçoit, vers quels destinataires il l'envoie, et les hôtes auxquels il l'envoie. Les finalités, les bases légales et les catégories de sujet de données sont laissées à la charge du contrôleur pour les remplir, et le signalent. Une cellule CSV commençant par =, +, - ou @ est écrite avec une apostrophe de tête, afin qu'une feuille de calcul ne l'exécute pas.
Où les données sont conservées. Où les données sont conservées (Paramètres → Données → Protection des données) indique, en termes que peut vérifier un régulateur, où le serveur, sa base de données et ses sauvegardes s'exécutent ; l'écran de protection des données et l'enregistrement le montrent. Un projet d'accord de traitement des données pour les organisations que BioDream héberge se trouve dans docs/legal/dpa-template.md ; c'est un projet pour un avocat, et non un conseil juridique.
L'API est /api/privacy (résumé), /api/privacy/find, /api/privacy/requests (et /{id}/approve, /{id}/export, /{id}/erase, /{id}/close), /api/privacy/holds, /api/privacy/reapply et /api/privacy/register.
17.10 Locataires
Un locataire est une limite d'isolement : les canaux, les messages, les utilisateurs et les paramètres appartiennent à l'un d'eux, et rien ne les traverse.
Ceci existe pour un fournisseur de services qui exécute des flux pour plusieurs cabinets. N'utilisez pas cela pour séparer les départements au sein d'une même organisation qui doivent voir le trafic les uns des autres : l'isolement est réel et il n'y a pas de vue inter-locataires. Pour cela, utilisez les groupes de canaux (ci-dessus), qui divisent les personnes d'une même organisation tout en permettant à une équipe centrale de tout voir.
17.10.1 Limites
Un opérateur de plate-forme définit les limites de chaque locataire dans Tenants, afin qu'un client ne puisse pas supplanter le reste d'un serveur partagé. Laissez une limite vide pour aucune.
- Canaux : combien de canaux le locataire peut avoir. La création d'un canal supplémentaire est refusée, avec le décompte et la limite.
- Messages par minute : combien de messages ses canaux peuvent recevoir ensemble en une minute.
- Stockage : combien de contenu de message stocké il peut conserver, en mégaoctets.
Aucun d'entre eux ne perd de message. Au-delà du taux ou de la limite de stockage, un message reçu est refusé de la même manière qu'un récepteur occupé refuse un message, avant que quoi que ce soit soit stocké ou livré : MLLP n'obtient pas d'accusé de réception (ce n'est pas un rejet, que certains expéditeurs prennent comme « ne pas renvoyer »), HTTP obtient 429 avec Retry-After, SOAP obtient 503, DICOM obtient un statut répétible, et une file d'attente, un seau ou un fichier est laissé où il était. L'expéditeur renvoie, comme le font tous les moteurs d'intégration et les dossiers médicaux électroniques. Rien de ce qui est déjà stocké n'est supprimé pour faire de la place. Une limite relevée prend effet dans une minute, et chaque modification des limites est consignée dans le journal d'activité.
17.11 Données de test
Les messages générés décrits dans testing existent en partie comme un contrôle de confidentialité. La reproduction d'un problème ailleurs, l'envoi d'un exemple à un fournisseur ou la population d'un environnement de test sont autant de choses qui sont faites autrement avec des messages réels.
La sortie du générateur ne contient pas de données de patient par construction plutôt que par suppression. Préférez-la aux messages réels épurés à la main, ce qui est un processus qui peut être fait de manière incomplète et qui l'est généralement.
17.12 Authentification unique
Trois mécanismes, et des comptes locaux aux côtés de tous.
OpenID Connect (-oidc), un répertoire sur LDAP (-ldap), et SAML 2.0 (-saml). Chacun est configuré à partir de Administrar → Authentification et écrit dans le fichier que le drapeau nomme, afin que l'écran et le fichier soient deux vues d'une même chose plutôt que deux endroits à garder à jour.
Les comptes locaux sont toujours disponibles et ne peuvent pas être désactivés. C'est délibéré : un moteur d'intégration sur site dont la seule façon d'y accéder est un fournisseur d'identité devient inaccessible exactement lorsque le fournisseur d'identité est inaccessible, et une interface clinique n'est pas un bon endroit pour apprendre cela. L'écran d'authentification vous indique combien d'administrateurs locaux existent avant de vous encourager à dépendre de autre chose.
17.12.1 Ce que décide une correspondance de groupe
Les trois cartographient des groupes du répertoire aux rôles de Perfuse, et quelqu'un dans des groupes correspondant à plusieurs obtient le plus privilégié. C'est la seule direction sûre pour résoudre cela — l'alternative est une personne qui perd l'accès auquel elle a droit parce qu'elle est également dans un groupe inférieur.
L'un des six rôles peut être accordé : surveillant, visionneur, opérateur, éditeur, administrateur et plate-forme.
Un groupe peut également être limité à certains groupes de canaux, dans la deuxième case de sa ligne (channel_groups dans le fichier). Une fois que n'importe quel groupe en nomme un, chaque connexion définit les groupes de canaux d'une personne à partir des groupes qui ont accordé son rôle : quelqu'un dans un groupe qui édite les canaux du labo et dans un autre qui voit tous les canaux est un éditeur des canaux du labo et rien d'autre. Le rôle le plus fort n'est jamais joint à la portée la plus large, car aucun groupe ne l'accorde. Un groupe avec une case vide donne tous les canaux. Tant que aucun groupe n'en nomme, la connexion laisse les groupes de canaux tels qu'un administrateur les a définis dans Utilisateurs.
Lorsque chaque groupe qu'une personne correspond à des noms de groupes de canaux, chaque groupe de canaux reçoit le rôle le plus élevé parmi les groupes qui le nomment : avec Lab-Interfaces (éditeur, lab) et Clinical-IT (spectateur, lab et adt), la personne édite les canaux du lab et affiche les canaux d'admission, comme si cela avait été défini manuellement. Lorsqu'un de leurs groupes donne tous les canaux, il n'y a pas de liste pour conserver un rôle par groupe, et la règle ci-dessus s'applique.
roles:
editor: [Lab-Interfaces]
operator: [Night-Desk]
viewer: [Clinical-IT]
channel_groups:
Lab-Interfaces: [lab, pathology]
Night-Desk: [adt]
Ceci est le fichier OpenID Connect et SAML. Le fichier du répertoire mappe chaque groupe à un rôle (roles: {Lab-Interfaces: editor}), et channel_groups se trouve à côté de roles.
Un mappage qui n'accorde rien à personne est refusé plutôt que sauvegardé. Une configuration qui authentifie les personnes et les renvoie toutes ressemble à un produit défectueux de l'extérieur : le cycle complet se termine et tout le monde est refusé sans explication.
La création d'un compte lors de la première connexion est désactivée par défaut. Lorsqu'elle est désactivée, quelqu'un doit exister dans Perfuse avant de pouvoir se connecter, donc le répertoire décide qui ils sont et Perfuse décide qui est autorisé à entrer.
17.12.2 SAML, plus précisément
Les parties importantes à connaître avant de configurer :
- Seul le certificat que vous configurez est considéré comme fiable. Un certificat transmis à l'intérieur d'une réponse n'est jamais utilisé. Un attaquant qui peut envoyer un document peut également insérer son propre certificat, et un vérificateur qui le lit peut être authentifié par n'importe qui en tant que n'importe qui.
- Une réponse doit répondre à une demande d'authentification initiée par ce serveur. Perfuse mémorise la demande qu'il a envoyée et refuse une réponse qui nomme autre chose, ou qui nomme une demande à laquelle il a déjà répondu. Sans cette vérification, une réponse valide est un jeton porteur pour quiconque le détient : quelqu'un s'authentifie en tant que soi-même, conserve la réponse et la publie dans votre navigateur, et vous êtes alors à l'intérieur de son compte avec le journal d'audit enregistrant son nom.
- Les authentifications initiées par le fournisseur d'identité sont donc désactivées par défaut. Activez *Accepter les authentifications initiées par le fournisseur d'identité* uniquement si vous avez besoin d'une tuile de portail, et en sachant que c'est ce qui rend la possibilité ci-dessus possible.
- L'attribut de groupe n'a pas de valeur par défaut et est obligatoire. Entra envoie
groups, Okta envoie ce que l'application a été configurée pour envoyer, ADFS envoie un URI de revendication. Une supposition produirait une authentification qui fonctionne et qui n'accorde rien à personne. Si une authentification est refusée pour ne pas avoir de rôle, le journal du serveur nomme les attributs qui sont arrivés — ce qui est généralement la réponse complète. - L'URL de réponse doit correspondre exactement à ce qui est enregistré chez le fournisseur. Une réponse indique où elle était destinée et une réponse adressée ailleurs est refusée, car l'accepter signifierait accepter une réponse destinée à un autre service.
17.12.3 Ce que chaque fournisseur envoie
L'attribut de groupe est où les connexions tournent mal, et les trois fournisseurs courants le nomment différemment.
| Fournisseur | Envoie généralement | Notes |
|---|---|---|
| Keycloak | groups | Nécessite un mappage d'appartenance au groupe ajouté au client. |
| Entra ID | un URI de revendication se terminant par /claims/groups | Envoie des objets d'identifiant de groupe à moins que l'application ne soit configurée pour envoyer des noms. Mappez les identifiants ou modifiez le fournisseur. |
| Okta | ce que l'application a été configurée pour envoyer | Généralement groups, avec un filtre qui décide desquels sont envoyés. |
| ADFS | un URI de revendication | Signe la réponse plutôt que l'assertion, que Perfuse accepte. |
Un URI de revendication peut être saisi par son dernier segment : la saisie de groups trouve http://schemas.microsoft.com/ws/2008/06/identity/claims/groups. Un nom qui se termine simplement par le mot n'est pas une correspondance — excluded_groups n'est pas groups.
L'appartenance au groupe qui arrive comme une seule valeur séparée par des virgules est traitée comme un seul nom de groupe et ne correspond à rien. C'est la lecture correcte de la norme, et la division en fonction des virgules signifierait qu'un groupe contenant légitimement un est devenu silencieusement deux. Si c'est ce que votre fournisseur envoie, modifiez-le là-bas.
Test sur l'écran de connexion vérifie tout ce qui peut être vérifié sans personne : les paramètres, le certificat et si une demande de connexion peut être construite. Il indique clairement qu'il ne peut pas prouver que quelqu'un peut se connecter, car cela nécessite une assertion réelle sur une personne réelle et la seule façon d'en obtenir une est qu'ils essaient.
17.13 Comptes provisionnés par le fournisseur d'identité : SCIM
Avec -scim (Paramètres → Connexion → Comptes automatiques), un fournisseur d'identité tel qu'Okta, Microsoft Entra ID ou Google Workspace crée, met à jour et supprime les comptes Perfuse lui-même à /scim/v2/Users, de sorte qu'une personne qui quitte l'organisation perd l'accès lorsque son compte d'annuaire est désactivé, et non lorsque quelqu'un s'en souvient. Le fournisseur s'authentifie avec un jeton d'API possédant le rôle d'administrateur, créé sous Utilisateurs → Informations d'identification de machine, envoyé en tant que jeton porteur.
- La désactivation d'un compte met fin à ses sessions immédiatement, et le serveur vérifie qu'aucune n'a survécu avant de répondre. Un fournisseur n'est jamais informé qu'un compte a été désactivé lorsqu'il ne l'a pas été, car un fournisseur ne répète pas ce qui lui a été indiqué comme ayant réussi.
- Une suppression désactive d'abord, puis supprime, de sorte qu'une défaillance à mi-chemin laisse un compte avec lequel personne ne peut se connecter. L'historique d'audit d'un compte supprimé est conservé.
- Le rôle provient des groupes ou des rôles de la personne, appariés par nom : un groupe dont le nom contient *admin*, *editor*, *operator*, *viewer* (ou *read-only*) ou *monitor* attribue ce rôle, donc
APP-Perfuse-EditoretPerfuse Operatorsfonctionnent comme ils sont nommés. Tout autre élément obtient-scim-default-role, viewer sauf si défini autrement. La plate-forme ne peut jamais être accordée de cette façon. - Pas de mots de passe. Un compte créé par SCIM se connecte via le fournisseur d'identité ; un deuxième mot de passe que personne en amont ne connaît survivrait à une désactivation.
/scim/v2/ServiceProviderConfigindique ce qui est pris en charge : création, lecture, remplacement, correction et suppression des utilisateurs, ainsi que des filtres jusqu'à 200 résultats. Les opérations bulk, le tri et les ETags ne sont pas.
17.14 Ce que Perfuse ne fait pas
Il ne chiffre pas la base de données au repos. Utilisez le chiffrement de système de fichiers ou de volume.
Il ne gère pas ses propres certificats ou leur renouvellement. Pointez-le vers des fichiers et gérez ces fichiers avec ce que vous utilisez déjà.
SAML a été vérifié contre deux fournisseurs indépendants, chacun avec une connexion de navigateur réelle, une assertion réelle et une session réelle : Keycloak 26 et Microsoft Entra. Deux questions valent plus du double d'une, car les deux diffèrent d'une manière qui s'est avérée essentielle — Keycloak écrit son assertion avec des préfixes d'espace de noms et Entra écrit les mêmes éléments sans eux, et le seul défaut de cette zone a été dans le traitement des préfixes.
Commencez par lire les métadonnées de votre fournisseur. Paramètres, puis Connexion, puis l'onglet SAML : donnez l'URL des métadonnées ou collez le document, et l'adresse de connexion et le certificat de signature sont remplis automatiquement. Chaque fournisseur SAML publie l'un de ces éléments — Okta, Entra, AWS IAM Identity Center, Keycloak, ADFS — et c'est la différence entre la configuration d'un fournisseur et la transcription d'un fournisseur. Le faire manuellement signifie trouver le certificat à l'intérieur du XML, supprimer les sauts de ligne du base64 et l'entourer d'en-têtes PEM, où un seul espace errant produit une erreur de signature qui ne dit rien sur la mise en forme.
Ce qui est renvoyé est décrit plutôt que déchargé : le sujet de chaque certificat, son expiration et son empreinte SHA-256, afin que vous puissiez le vérifier contre ce que montre la console de votre fournisseur. Un certificat expiré est appelé expiré plutôt que laissé comme une date à comparer à l'œil. Rien n'est sauvegardé en lisant — appliquer à un formulaire est un clic séparé, car un document que quelqu'un a collé n'est pas encore une décision sur ce qui est fiable.
Une URL de métadonnées est récupérée via https uniquement, et l'adresse est vérifiée contre la même politique qui régit les destinations de canal, donc cela ne peut pas être utilisé pour faire lire au serveur les informations d'identification d'instances cloud. Les redirections ne sont pas suivies, car une adresse autorisée qui redirige vers une adresse bloquée passerait directement à côté de cette vérification.
Si vous configurez Entra, cinq choses ne correspondront pas à ce que montrent les exemples. Il n'envoie aucune revendication d'e-mail. Son NameID est un identifiant opaque plutôt qu'une adresse. Il n'envoie aucune revendication de groupe à moins que l'application ne soit explicitement configurée pour émettre une, donc une mise en correspondance de rôle écrite contre des groupes refuse chaque connexion. Lorsque des groupes sont émis, ils sont des GUID d'objet plutôt que des noms, à moins que votre locataire ne synchronise à partir d'Active Directory sur site. Et ses noms de revendication vivent sous schemas.microsoft.com/identity où la plupart de la documentation montre schemas.xmlsoap.org. Perfuse gère les cinq ; ils sont énumérés car les quatre premiers sembleraient sinon des défauts dans Perfuse alors qu'ils sont Entra étant Entra.
Cette distinction n'est pas théorique ici. La première assertion Keycloak réelle a échoué purement et simplement, car la forme canonique que la signature couvre était calculée avec des préfixes d'espace de noms supprimés. Aucun fournisseur d'identité réel n'aurait pu connecter quelqu'un, et les cinq tests de canonisation du package ont passé tout au long — chacun d'eux signé et vérifié avec le même code, donc ils prouvaient seulement qu'il était d'accord avec lui-même. Si vous êtes le premier à pointer un fournisseur différent vers cela, attendez-vous à trouver quelque chose, et le journal du serveur nommera l'étape qui a échoué.
18 Opérations
18.1 Déploiement
Un binaire et deux chemins : un répertoire de fichiers de canal et un fichier de base de données. Il n'y a pas de serveur d'applications, pas de couche web distincte et pas de courtier de messages requis.
perfuse serve -channels ./channels -db ./perfuse.db -addr 0.0.0.0:8443 \
-tls-cert ./cert.pem -tls-key ./key.pem
Exécutez-le sous ce qui supervise les services sur l'hôte — systemd, launchd, un runtime de conteneur. Il s'attend à être redémarré s'il sort.
18.2 Où les données peuvent aller (résidence des données)
serve -residency (Paramètres → Données → Où les données peuvent aller) nomme les régions cloud où les données de ce serveur peuvent être envoyées ou lues : des zones (eea, uk, ch) et des codes de région (eu-central-1, uksouth, europe-west2), séparés par des virgules. eea est les régions AWS, Azure et Google Cloud dans la zone économique européenne (Francfort, Irlande, Paris, Stockholm, Milan, Espagne ; Pays-Bas, Allemagne, France, Suède, Norvège, Italie, Espagne ; Belgique, Pays-Bas, Allemagne, Italie, France, Finlande, Espagne, Pologne), uk celles au Royaume-Uni, ch celles en Suisse.
Lorsqu'il est défini, un canal est refusé, lorsqu'il est enregistré et lorsqu'il est chargé, si un connecteur nomme une région en dehors de la liste : une source ou une destination S3, SQS ou SNS region (ou son endpoint, lorsque celui-ci est un nom d'hôte AWS), ou toute destination dont l'adresse est un nom d'hôte AWS portant une région (sqs.us-east-1.amazonaws.com, une URL de passerelle API). Le serveur refuse de démarrer avec un collecteur de traces ou un webhook d'alerte dans une autre région. Un connecteur pointant vers un hôte qui ne nomme pas de région (un système propre à l'hôpital, MinIO sur le réseau du site) n'est pas jugé : l'enregistrement du traitement sur l'écran de protection des données répertorie chaque hôte auquel chaque canal envoie, pour que le contrôleur vérifie. Le tableau de bord et l'écran de protection des données indiquent où les données peuvent aller.
Hébergement dans l'UE et le Royaume-Uni. deploy/hosted contient OpenTofu (ou Terraform) pour un serveur hébergé par organisation à Francfort, en Irlande ou à Londres : le serveur, sa base de données PostgreSQL et ses sauvegardes, un seau de sauvegarde, des journaux et des enregistrements de session de support, le tout chiffré avec une clé dans la Région, rien n'est répliqué dans une autre Région, le support est assuré uniquement via Session Manager, et Perfuse est exécuté avec -residency. Son fichier README indique ce qu'il construit, ce qu'il ne couvre pas, ce qui a été vérifié (validé et planifié par rapport à un compte réel ; pas encore appliqué) et combien cela coûte au prix de liste dans chaque Région.
18.3 Configuration sous forme de fichiers
Les canaux sont des fichiers, ce qui signifie qu'ils peuvent être dans un contrôle de version, examinés avant le déploiement et diffusés après un incident.
Les fichiers sont rélus sans redémarrage. Un fichier qui n'analyse pas est signalé et la version précédemment chargée continue à fonctionner, donc une erreur de syntaxe ne peut pas mettre un flux de travail en panne.
18.4 Sauvegarde
Deux choses à sauvegarder, et elles ont des caractéristiques différentes.
Le répertoire de canal est petit, change rarement et est ce dont vous avez besoin pour reconstruire le service. Sauvegardez-le en tant que configuration ; le contrôle de version est généralement suffisant.
La base de données contient des messages, des utilisateurs et des journaux d'audit. Elle est grande, change constamment et contient des données cliniques — elle doit donc être sauvegardée en tant que données cliniques, avec la rétention et le chiffrement que cela implique. La perdre n'arrête pas le service, mais elle perd la capacité d'enquêter sur tout ce qui s'est déjà produit et l'historique dont dépend l'apprenti rythme.
18.5 Comportement de redémarrage
Au redémarrage, les canaux sont chargés et les sources commencent à écouter. Les livraisons en file d'attente reprennent.
La chose à comprendre est ce qui se passe au travail en vol. Sous l'acquittement on_delivery par défaut, un message qui n'a pas encore été acquitté n'est pas acquitté, le expéditeur le renverra donc — ce qui est le résultat correct. Sous on_receipt, un message qui a été acquitté mais pas encore livré est en file d'attente et reprend ; si la file d'attente est désactivée, il est perdu. Voir flux de message.
18.6 Mise à niveau
Remplacez le binaire et redémarrez. Le schéma de base de données est migré automatiquement vers l'avant au démarrage.
Les migrations ne sont que vers l'avant. Il n'y a pas de rétrogradation, donc un retour à un binaire précédent après que le schéma a été déplacé nécessite la base de données précédente. Prenez une copie avant de mettre à niveau — c'est la seule précaution opérationnelle qui vaut la peine d'être disciplinée.
18.7 Supervision
L'alerte à l'intérieur de Perfuse est couverte dans alerte et est ce qui vous dira qu'un flux s'est arrêté.
Depuis l'extérieur, supervisez le processus, le disque sur lequel se trouve la base de données et si l'interface web répond. La base de données grandit et un disque plein arrête l'enregistrement des messages, ce qui est un mode de défaillance sans autre avertissement.
18.7.1 SNMP
Pour les outils de surveillance qui parlent SNMP (Nagios, Zabbix, PRTG, SolarWinds, LibreNMS), Perfuse exécute un agent SNMPv2c en lecture seule et envoie une trappe lorsqu'une alerte se déclenche ou se résout. Définissez-le sous Paramètres → Surveillance → SNMP, ou avec des indicateurs :
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'agent répond aux requêtes GET, GETNEXT et GETBULK, et uniquement à partir des réseaux dans
-snmp-allow: la communauté v2c est un mot de passe envoyé en clair, il n'est donc jamais ouvert à tous. Une communauté inférieure à 6 caractères, oupublic/private, arrête le serveur au démarrage. - Il sert le groupe système (sysDescr, sysUpTime, sysName à partir de l'étiquette de la flotte, sysContact, sysLocation), les totaux sous
BASE.1(canaux, en cours d'exécution, cassés, reçus, livrés, échoués, en attente) et un tableau de canaux sousBASE.2.1(nom, en cours d'exécution ou arrêté, reçu, livré, échoué, en attente, âge du message en attente le plus ancien). Les nombres sont ceux affichés par le tableau de bord et/metrics. - Les pièges sont envoyés à chaque gestionnaire dans
-snmp-traps:BASE.0.1une alerte s'est déclenchée,BASE.0.2elle s'est résolue, en portant le type d'alerte, la gravité, le canal, la destination et le résumé. Jamais de contenu de message. Une alerte reconnue n'envoie pas de piège. BASEest1.3.6.1.4.1.8072.9999.9999.16(espace expérimental Net-SNMP) à moins que-snmp-base-oidne le place sous votre propre numéro d'entreprise. Télécharger le MIB sur la page Paramètres (ouGET /api/snmp/mib) fournit un MIB pour la base en cours d'utilisation ; le même panneau indique si l'agent répond et combien de pièges ont été envoyés.
18.7.2 Un inventaire de chaque interface
-inventory interfaces.md (Paramètres → Surveillance → Inventaire) écrit un document Markdown répertoriant chaque canal - son format, si il s'exécute, ce qu'il reçoit de et ce qu'il envoie à - suivi de la description propre à chaque canal, et le réécrit toutes les -inventory-every (un jour par défaut). Il est destiné à être validé à côté des fichiers de canal, ou remis à un auditeur, et lu sans que l'application ne soit en cours d'exécution.
18.8 Capacité
Le plafond de débit de Perfuse n'a pas été mesuré sur du matériel réel sous un trafic réel, et ce manuel ne publiera pas un nombre qu'il ne peut pas soutenir.
Ce qui peut être dit : l'architecture est un goroutine par connexion avec des files d'attente par destination, donc le débit augmente avec les destinations plutôt que d'être sérialisé à travers un seul travailleur ; l'enregistrement de message est une écriture SQLite par message, ce qui rend le disque la contrainte la plus susceptible d'être la première ; et le magasin de messages grandit linéairement avec le trafic, donc la rétention est le paramètre qui régit l'utilisation du disque à long terme.
Si vous dimensionnez cela pour un grand flux, mesurez-le avec votre propre trafic en utilisant le corpus de test généré décrit dans testing. C'est la réponse honnête, et c'est également une meilleure réponse qu'un nombre provenant du matériel de quelqu'un d'autre.
18.9 L'endroit où cette installation est bloquée
L'activité comporte un panneau, visible pour les administrateurs, montrant ce que Perfuse a refusé de faire — regroupé par message, le plus fréquent en premier — et à quel point l'installation a progressé vers un canal de travail.
Il existe parce que chaque autre affirmation sur la facilité d'utilisation de ce logiciel provient des personnes qui l'ont écrit. Un refus ne l'est pas : quelqu'un voulait quelque chose, le serveur a dit non, et aucune des deux parties ne devinait. C'est la seule preuve dans le produit qui ne provient pas de BioDream LLC.
Le tunnel nomme l'étape qui n'a pas encore eu lieu plutôt que de laisser les horodatages à comparer. L'état à surveiller est les messages arrivent et aucun n'a été livré à une destination — un canal peut prendre du trafic pendant des semaines et ne livrer aucun d'entre eux, et à partir de chaque autre écran, cela ressemble à un fonctionnement.
Rien de ce que quelqu'un a tapé n'est enregistré. Le tableau contient l'itinéraire de la demande avec les identificateurs remplacés par {id}, le statut et la phrase propre du serveur. Un message de validation nomme un champ et une règle, qui est la partie utile ; la valeur qui a violé la règle est très souvent des données de patient, et un tableau de celles-ci serait une responsabilité plus grave que la friction qu'il mesure.
Deux exclusions délibérées. Un 5xx est une erreur dans ce logiciel et est déjà consigné comme tel — mélanger les deux enterrerait les cas où quelqu'un ne pouvait pas déterminer ce qu'il devait taper sous les cas où rien de ce qu'il a tapé n'aurait aidé. Et une session expirée produit une série de 401 qui ne disent rien sur la convivialité et noierait chaque constatation qui le fait.
La lecture du rapport élimine également le tableau à ses cinq mille lignes les plus récentes. Les refus sont des réponses 4xx, il grandit donc lentement, et la lecture est un moment naturel pour nettoyer : pas de minuteur et rien qui s'exécute lorsque personne ne regarde.
GET /api/friction renvoie la même chose pour quiconque préfère la lire au format JSON.
18.10 Journaux
Perfuse enregistre les journaux sur la sortie standard, qui est où un superviseur ou un runtime de conteneur les collectera.
Les détails au niveau du message vont au magasin de messages plutôt qu'au journal, délibérément. Une ligne de journal par message sur un flux occupé est un bruit qui cache les lignes qui comptent, et le magasin est recherchable de manière que ne l'est pas un fichier journal.
Le journal contient ce que le magasin ne peut pas : démarrage et arrêt, résultats du chargement de la configuration, changements d'état du canal et erreurs qui ne peuvent pas être attribuées à un message spécifique.
18.11 Exécution de deux instances
Deux serveurs ou plus peuvent fonctionner comme un cluster : lorsque celui qui exécute un flux s'arrête, un autre le reprend dans quelques secondes, et la prochaine tentative de l'expéditeur le rejoint. Ils partagent une base de données PostgreSQL unique au lieu de chacun conserver un fichier SQLite, et s'accordent entre eux, par son intermédiaire, pour savoir lequel exécute quoi.
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
Démarrez chaque serveur de la même manière avec son propre nom et adresse. Le compte de base de données doit créer des tables et, une fois, l'extension citext (ou un administrateur exécute CREATE EXTENSION citext au préalable). Chaque serveur conserve ses propres fichiers dans -data : son journal, son ID de nœud et ses copies de la configuration.
Deux façons de partager le travail.
active-passive: le leader exécute chaque canal et chaque tâche qui doit s'exécuter une seule fois (notifications d'abonnement FHIR). Les autres attendent. C'est le plus simple à comprendre, et c'est ce qu'un site avec un serveur occupé et un serveur de secours veut.active-active: les canaux sont répartis sur les serveurs actifs, à peu près de manière égale. Un serveur qui s'arrête transmet ses canaux aux autres ; un serveur qui rejoint prend sa part de canaux libres, un à la fois. Les canaux qui se routent les uns vers les autres (une destination de canal) s'exécutent sur un serveur et se déplacent ensemble, car le routage se produit à l'intérieur d'un serveur. Un administrateur peut déplacer un canal manuellement à partir de Monitor → Fleet ; il reste où il a été placé tant que le serveur est en vie.
Qui exécute quoi, et aucun moment avec deux. Chaque pièce de travail est un bail dans la base de données, renouvelé tous les cinquièmes de -cluster-lease (15 s par défaut). Un serveur qui ne peut pas le renouveler (il a crashé, son réseau a échoué, la base de données est inaccessible) arrête ce travail par lui-même une fois que sa propre horloge indique que le bail est presque terminé, avec un tiers du bail à épargner. Un autre serveur prend le bail uniquement après que sa propre horloge ait vu le compteur du bail rester immobile pendant un bail entier. Aucune horloge n'est comparée à une autre, donc les horloges des serveurs et de la base de données n'ont pas besoin d'être en accord ; elles n'ont besoin que de fonctionner à peu près au même rythme, ce que fait chaque horloge. Entre l'arrêt de l'ancien propriétaire et le démarrage du nouveau, il y a une courte pause avec personne qui écoute, que l'expéditeur voit comme une connexion refusée et retente ; il n'y a jamais de moment avec deux qui écoutent sur un flux ou deux travailleurs qui drainent une file d'attente.
Un serveur qui ferme correctement, ou un administrateur qui choisit Step down sur le leader, transmet immédiatement plutôt qu'après le bail.
Ce que chaque serveur partage. Les messages, la file d'attente de livraison, les comptes et les sessions, le journal d'audit, le magasin FHIR, les tables de terminologie et l'index des patients se trouvent dans la base de données, de sorte que quel que soit le serveur qui exécute un canal, il trouve la file d'attente que le dernier a laissée. Les fichiers de canal, le fichier de paramètres, les règles d'alerte, les fichiers d'authentification unique, le logo, les certificats Direct et les vues enregistrées sont conservés identiques sur chaque serveur via la base de données : chaque serveur conserve sa propre copie sur son propre disque, une modification sur n'importe quel serveur (dans la console, manuellement, par un git pull) atteint les autres dans les deux secondes, et un canal modifié sur un autre serveur redémarre avec son nouveau fichier. Le même fichier modifié sur deux serveurs en même temps conserve la version qui a atteint la base de données en premier, et l'autre à côté sous NAME.conflict-SERVER. Les paramètres qui ne s'appliquent qu'au redémarrage (la base de données de messages, les ports sur lesquels la console écoute) sont appliqués par chaque serveur à son prochain redémarrage, et le journal le signale. Ce qui identifie quelque chose sur une machine reste sur la ligne de commande du serveur et en dehors du fichier partagé : le certificat et la clé (-tls-cert, -tls-key), l'adresse d'écoute SNMP et le nom du serveur dans les traces. Les paramètres les affichent comme définis sur chaque serveur.
Démarrer et arrêter. Démarrer ou arrêter un canal sur n'importe quel serveur s'applique au cluster : le serveur qui l'exécute le démarre ou l'arrête dans une seconde, et la réponse indique quel serveur est concerné.
Le répartiteur de charge devant. L'adresse d'un flux doit atteindre le serveur qui l'exécute. Pointez l'expéditeur vers une adresse virtuelle (un répartiteur de charge, une adresse IP flottante, un nom DNS avec un TTL court) et faites en sorte que le répartiteur de charge vérifie /readyz?channel=NAME, qui répond 200 uniquement sur le serveur qui exécute ce canal, et 503 sur les autres. Pour la console, /readyz est 200 sur chaque serveur actif ; /readyz?role=leader uniquement sur le leader.
Sur un répartiteur de charge de réseau AWS, utilisez un groupe cible par flux avec une vérification de santé HTTPS sur /readyz?channel=NAME, un intervalle de 5 secondes et un seuil de 2, et activez le répartition de charge entre zones. Avec celle-ci désactivée, le nœud du répartiteur de charge dans une zone où aucun serveur n'exécute le flux ne voit que des cibles non saines, envoie à toutes de toute façon, et un expéditeur qui a résolu vers ce nœud attend jusqu'à ce que le flux revienne dans sa zone (95 secondes dans un test). Définissez le délai de désinscription sur 0, puisque le serveur qui arrête d'exécuter un flux n'a rien à éliminer.
Ce qui a été testé. Deux serveurs sur PostgreSQL 16, un expéditeur qui diffuse 300 messages, renvoyant jusqu'à ce qu'il obtienne une réponse, et le serveur qui exécute le flux tué avec SIGKILL deux fois (la première, puis la seconde après que la première soit revenue). Chaque message reconnu a atteint le destinataire, dans les deux formes essayées : livré avant l'accusé de réception, et en file d'attente dans le magasin partagé pendant que le destinataire refusait (185 messages reconnus attendaient dans la file d'attente au moment de la mort ; le survivant les a tous livrés). Le basculement a pris 3 à 4 secondes sur un bail de 3 secondes. Un doublon est possible et a été vu une fois sur 600 : un message que le serveur mourant a livré et n'a pas pu reconnaître, que l'expéditeur a renvoyé. Les tests propres du coordinateur couvrent une panne, un serveur coupé de la base de données pendant qu'il s'exécute, le retrait, la diffusion, les déplacements et la configuration partagée avec des conflits. Ils s'exécutent dans CI contre PostgreSQL avec le détecteur de course, avec la totalité de la suite.
La même chose a ensuite été faite sur AWS : deux serveurs Linux (ARM) et un serveur Windows Server 2022 dans trois zones de disponibilité, Amazon RDS PostgreSQL 16 sur TLS avec le certificat vérifié (sslmode=verify-full), un répartiteur de charge de réseau interne devant, et des expéditeurs renvoyant jusqu'à ce qu'ils obtiennent une réponse :
| Test | Messages | Reconnus mais perdus | Doublons | Temps d'attente le plus long pour un expéditeur |
|---|---|---|---|---|
| Actif-passif, le serveur qui exécute le flux tué deux fois (Linux, puis Windows), destinataire refusant entre-temps | 2 000 | 0 | 0 | 15 s |
| Un leader Linux coupé de la base de données (pare-feu), son processus laissé en cours d'exécution | 3 000 | 0 | 1 | 16 s |
| Un leader Windows coupé de la base de données | 3 000 | 0 | 0 | 20 s |
| Le leader tué pendant qu'une horloge de serveur fonctionnait 2 minutes trop vite et une autre 90 secondes trop lentement | 2 000 | 0 | 0 | 18 s |
| Actif-actif, quatre flux sur trois serveurs, un tué et ramené | 6 000 | 0 | 2 | 24 s |
Avec le bail par défaut de 15 secondes, un serveur coupé de la base de données a arrêté son flux 10 secondes après sa dernière actualisation, et le prochain serveur l'a démarré 6 à 8 secondes après cela : jamais les deux en même temps. Les horloges décalées n'ont rien changé, puisqu'aucune horloge n'est comparée à une autre.
Pas encore. Un cluster sert une organisation : -cluster avec -multi-tenant est refusé. Les écouteurs se déplacent avec leur canal, donc le répartiteur de charge est fourni par le site.
Un serveur seul continue de fonctionner comme il l'a toujours fait, sur SQLite, sans cluster du tout.
18.12 Plus d'un serveur
Un site avec deux instances a une question que aucune console unique ne peut répondre : tout fonctionne-t-il ? Mirth facture la réponse. C'est la vue de la flotte.
Une instance est nommée comme l'endroit où vous regardez. Il interroge les autres et affiche chaque canal sur chaque serveur dans une table, avec un regroupement sur tous.
18.12.1 Ajout d'un pair
Paramètres → Fleet, ou PUT /api/fleet/peers. Un pair nécessite un nom, une URL et un jeton émis par le pair lui-même.
Le nom est obligatoire et n'est pas l'URL, car une URL n'est pas quelque chose que quiconque reconnaît à trois heures du matin.
Le jeton doit être créé sur le pair, sous Utilisateurs, et doit avoir une portée de visualisation. L'ajout d'un pair sans jeton est refusé, avec ces instructions, plutôt que d'être accepté puis de échouer silencieusement à chaque interrogation. La lecture de l'état de santé d'une autre instance est le plus petit privilège qui existe, et c'est le seul dont a besoin la vue de flotte.
18.12.2 Contrôler un pair, qui est hors tension
allow_control permet de démarrer et d'arrêter les canaux de ce pair à partir d'ici. Il est désactivé par défaut et chaque utilisation est audité par nom.
Les deux privilèges sont délibérément séparés. La lecture de l'état d'un autre serveur est mineure ; arrêter ses canaux pendant une transfusion ne l'est pas, et le second ne devrait jamais arriver silencieusement attaché au premier.
18.12.3 Ce que dit le rapport
Chaque serveur signale le nombre total de canaux, combien sont en cours d'exécution, arrêtés ou en erreur, la profondeur de la file d'attente et l'âge du message en attente le plus ancien, combien d'alertes sont déclenchées, et s'il est en train de se vider pour l'arrêt.
Le regroupement compte les serveurs de trois manières : accessible, inaccessible et indéterminé. Le troisième couvre les pairs dont l'état de santé est inconnu — pas encore interrogé, refusant le jeton, ou exécutant une version que celui-ci ne peut pas lire. Il est conservé séparément de l'inaccessible car « nous ne pouvons pas le dire » n'est pas « il est hors service », et combiner les deux est la façon dont une page de fleet commence à mentir.
Pour la même raison, le regroupement comporte knownFrom : le nombre d'instances à partir desquelles les chiffres du canal et de la file d'attente ont été lus. Douze canaux en cours d'exécution sur une flotte signifient quelque chose de différent lorsque deux des cinq serveurs n'ont pas répondu, et le total seul ne peut pas le dire.
Un pair inaccessible indique pourquoi en termes que l'opérateur peut exploiter. Une connexion refusée est signalée comme l'hôte étant actif avec rien n'écoutant sur ce port, ce qui est un problème différent d'un hôte qui ne répond pas du tout.
18.12.4 Décalage d'horloge
Le regroupement signale la plus grande différence entre les horloges des serveurs qui le composent. Valeur d'un nombre à part : la corrélation d'un incident à travers deux instances dont les horloges ne sont pas synchronisées de quatre minutes produit une séquence d'événements qui n'a pas eu lieu.
18.12.5 Ce qu'un pair apprend sur vous
Nombres et taux. Le rapport que donne une instance à une autre ne contient aucun identifiant de message, aucun détail au niveau du canal et aucune donnée de patient de quelque nature que ce soit.
C'est ce qui empêche une vue de flotte d'être une centralisation de données cliniques : l'instance de regroupement apprend combien de canaux sont en cours d'exécution et rien du tout sur ce qui a transité à travers eux. Si vous voulez les messages, vous ouvrez la console propre du serveur, où le journal d'audit enregistre que vous l'avez fait.
18.12.6 Un pair pointé vers lui-même
Refusé. Une instance interrogeant sa propre adresse via sa propre pile HTTP apparaît deux fois dans sa propre vue de fleet et compte double chaque canal qu'elle possède.
18.12.7 TLS sur les réseaux internes
insecure_skip_verify accepte le certificat d'un pair sans le vérifier. Il existe parce que les infrastructures hospitalières fonctionnent sur des autorités de certification privées, et refuser de fonctionner du tout pousserait les gens vers le HTTP non sécurisé, ce qui est pire. Il est nommé ainsi pour qu'il ne puisse pas être confondu avec une bonne idée.
19 La ligne de commande
Tout ce que Perfuse fait à un système en cours d'exécution est accessible à partir de l'interface Web, et c'est délibéré : une fonctionnalité qui nécessite un terminal est traitée comme un défaut plutôt que comme un choix de conception. Les commandes ici sont pour le travail qui se déroule *autour* d'un système en cours d'exécution — avant qu'il n'existe, pendant que vous décidez si vous pouvez lui faire confiance, et lorsque vous devez transmettre quelque chose à quelqu'un d'autre.
Plusieurs d'entre elles ne touchent jamais un serveur. perfuse explain, perfuse profile, perfuse deident et perfuse translate lisent des fichiers et écrivent des fichiers, ils sont donc utiles sur un ordinateur portable contre un patrimoine qui fonctionne encore entièrement sur autre chose.
Exécutez n'importe quelle commande avec -h pour ses indicateurs. Ce chapitre indique à quoi sert chaque commande.
-h est généré à partir du code et ne peut pas être désuet ; une liste copiée dans la prose peut.19.1 Exécution des canaux
19.1.1 perfuse serve
Exécute l'interface web et l'API, et exécute les canaux par défaut. Il s'agit de la commande utilisée par une installation.
Chaque option qu'il prend est répertoriée dans Options du serveur, générée à partir du programme. Il refuse de servir le HTTP non sécurisé à tout autre que la boucle de retour, à moins que vous ne passiez -insecure. Il s'agit d'une politesse non configurable : le trafic clinique et un cookie de session sur une connexion LAN non chiffrée constituent un événement signalé, et le drapeau existe pour que dire oui soit une décision prise par quelqu'un plutôt qu'un paramètre par défaut hérité. Voir sécurité.
19.1.2 perfuse run
Exécute les canaux à partir de YAML sans interface web et sans base de données. Utile dans un conteneur qui doit faire exactement une chose, et utile lorsque vous souhaitez voir le comportement d'un canal sans rien d'autre en cours d'exécution.
19.1.3 perfuse check
Valide les définitions de canaux et imprime ce qu'ils font, sans les exécuter. La deuxième moitié est le but : un canal qui se charge n'est pas nécessairement le canal que vous vouliez, et la lecture d'un résumé en anglais clair de ce qu'un fichier fera permet de détecter une erreur que la validation ne peut pas voir.
Sortie non nulle en cas de défaillance, il appartient donc à toutes les vérifications de votre configuration avant qu'elle n'atteigne un serveur. -quiet n'imprime rien en cas de succès, pour cette utilisation.
-allow-metadata-egress permet aux destinations pointant vers les adresses de métadonnées d'instances cloud. Ces adresses contiennent les informations d'identification de la machine elle-même, donc un canal qui peut être convaincu d'envoyer là-bas est une fuite d'informations d'identification ; la vérification refuse celles-ci à moins que vous ne disiez autrement.
19.1.4 perfuse test
Exécute les tests écrits contre les définitions de canaux. Un test envoie un message à travers le filtre réel, les transformations réelles et les scripts réels du canal, dans l'ordre réel, avec uniquement le réseau remplacé — donc ce qui passe ici est ce que le canal fait.
Les tests se trouvent dans *_test.yaml ou *.test.yaml à côté des canaux. Voir testing.
19.2 Migration à partir d'un autre moteur
Ce sont les trois à exécuter en premier, avant de décider quoi que ce soit. Voir migration.
19.2.1 perfuse explain
Lit les exports Mirth, Open Integration Engine et BridgeLink — un canal, un groupe de canaux ou une sauvegarde complète du serveur — et décrit ce que chaque canal fait et ce qui bloquerait une migration. Il ne modifie rien et n'a pas besoin d'une installation Perfuse, ce qui en fait la première étape la moins coûteuse possible : pointez-le vers une exportation de votre domaine et lisez ce qui est retourné.
-strict sort non nulle si quelque chose est bloqué, il peut donc gérer un pipeline. -json émet les mêmes résultats pour une machine.
19.2.2 perfuse translate
Convertis les exports Mirth, Open Integration Engine et BridgeLink en fichiers de canaux Perfuse : un canal, un groupe de canaux, une exportation de bibliothèque de modèle de code ou une sauvegarde complète du serveur.
perfuse translate -o ./channels server-backup.xml
Les bibliothèques de modèles de code sont écrites dans lib/ à côté des canaux, et chaque canal Mirth avait une bibliothèque activée pour l'inclure. Voir migration.
Rien n'est silencieusement supprimé. Chaque partie d'un canal est soit traduite, soit transmise telle quelle en tant que script qui s'exécute inchangé, soit signalée comme nécessitant une intervention humaine. La troisième catégorie est la plus honnête — un traducteur qui produit un fichier propre pour chaque entrée cacherait les décisions que vous devez prendre.
19.2.3 perfuse compare
Exécute le même trafic à travers deux moteurs et signale où ils sont en désaccord, regroupés par champ.
Ceci est la commande qui répond à « pourquoi devrais-je faire confiance à cela avec des données de patients », et elle répond avec des preuves que vous avez recueillies plutôt qu'une affirmation faite ici. Il s'agit de l'étape recommandée avant de basculer et de la première étape dans toute discussion sur la préparation de Perfuse.
19.3 Comprendre un flux de données
19.3.1 profil Perfuse
Lit les messages et signale ce qui se trouve réellement à l'intérieur : quels champs sont toujours remplis, lesquels ne le sont jamais, les jeux de valeurs réels des champs codés, les comptes de répétition et quels Z-segments apparaissent.
Les valeurs ne sont signalées que pour les champs dont les valeurs forment un petit ensemble de codes, afin qu'un profil du trafic réel ne devienne pas un fichier rempli de données de patients.
Enregistrer un profil et le comparer plus tard permet de savoir si un expéditeur a modifié quelque chose :
perfuse profile -save last-month.json corpus/ perfuse profile -against last-month.json new/
19.3.2 contrat Perfuse
Transforme le résultat de cette réflexion en quelque chose d'exécutoire. Un contrat spécifie à quoi doit ressembler un flux de données, afin que le jour où il change, vous soyez informé, plutôt que de le découvrir des semaines plus tard à partir d'un récepteur qui a échoué - les messages sont toujours valides HL7 lorsque un champ disparaît, donc rien d'autre ne le remarque.
perfuse contract promote -o adt.contract.yaml corpus/ perfuse contract check adt.contract.yaml today/
promote génère un point de départ, pas une réponse. Lisez-le et supprimez la plupart des lignes : chaque ligne enregistre si elle a été mesurée ou décidée, ce qui vous indique quelles lignes conserver.
19.4 Production de messages
19.4.1 perfuse generate
Produit des messages HL7 v2 synthétiques. Tout est inventé - des noms évidemment fictifs, des identificateurs séquentiels, des adresses fictives - donc la sortie est sécurisée pour être envoyée, envoyée par courrier électronique et attachée à un ticket.
Il peut envoyer directement à un canal plutôt que d'écrire un fichier, ce qui est le moyen le plus rapide de prouver qu'un récepteur fonctionne :
perfuse generate -n 100 -send 127.0.0.1:6661
19.4.2 perfuse deident
Lit les messages réels et écrit un corpus qui conserve leur structure, leurs codes et leurs intervalles, et rien de ce qui identifie un patient. C'est la différence entre être capable d'envoyer à quelqu'un une reproduction et ne pas pouvoir le faire.
Ce n'est pas le même outil que perfuse generate et la distinction est importante. Les messages générés sont inventés et donc sécurisés mais irréalistes ; un corpus désidentifié est *dérivé du trafic réel*, il reproduit donc les particularités qui cassent réellement les interfaces.
Deux propriétés à comprendre avant de l'utiliser :
- Le même sel produit toujours le même corpus, donc un corpus partagé peut être régénéré plutôt que archivé.
- Conservez le sel secret. Les pseudonymes sont dérivés de valeurs réelles, donc toute personne détenant le sel peut confirmer une supposition sur qui un enregistrement fait référence.
-keep-local-segments transmet les Z-segments inchangés et est dangereux. Les Z-segments sont exactement où les sites placent les noms, les notes et le texte libre, donc les conserver détruit l'objectif de l'outil. Il existe parce qu'un problème structurel se trouve parfois *dans* un Z-segment, et alors vous avez besoin d'un corpus que vous ne devez pas partager.19.5 Déplacement de messages manuellement
19.5.1 perfuse listen
Accepte HL7 v2 sur MLLP et l'acknowledge. Un récepteur qui existe aussi longtemps que vous en avez besoin, pour prouver qu'un expéditeur peut atteindre cette machine.
19.5.2 envoyer Perfuse
Envoie des messages HL7 v2 sur MLLP à partir de fichiers.
19.6 FHIR
19.6.1 perfuse fhir
Convertis HL7 v2 en FHIR, valide FHIR ou le sert, selon la sous-commande.
La sous-commande de validation est utile en soi : elle vous indiquera si une ressource que quelqu'un vous a envoyée satisfait à US Core, qui est le profil contre lequel la réglementation américaine est écrite. Pouvoir répondre à cela sans adopter un moteur est le but.
19.6.2 perfuse x12
Converts X12 (or other delimited EDI) to the XML Mirth Connect and Open Integration Engine write for it, and back: perfuse x12 xml FILE and perfuse x12 from-xml FILE, standard input when no file is given. The output is what OIE 4.6 writes, byte for byte, so it can be compared with what a Mirth server produced or fed to a system built against it. A channel does the same with x12.arrives_as: xml and a destination's x12_as: xml; see X12.
19.6.3 perfuse sof
Exécute une requête SQL sur une définition de vue FHIR sur des fichiers FHIR (le NDJSON d'une exportation bulk, des bundles ou des tableaux JSON ; - pour l'entrée standard) et écrit le tableau : -view FILE (obligatoire), -format csv|ndjson|json|parquet (csv par défaut), -header=false, et -o FILE (obligatoire pour Parquet). Voir SQL sur les vues FHIR.
19.6.4 perfuse measure
Évalue une mesure de qualité avec des critères FHIRPath sur des fichiers FHIR (le NDJSON d'une exportation en bloc, des Bundles ou des tableaux JSON ; - pour l'entrée standard) et écrit le MeasureReport. Indicateurs :
-measure FILE, ou-measure example:IDpour un exemple fourni : obligatoire.-examplesliste les exemples.-period-startet-period-end: obligatoires.-type summary|subject|subject-list.-subject Patient/ID.-reporter NAME.-o FILE.
Voir mesures de qualité numériques.
19.6.5 Indicateurs FHIR sur perfuse serve
| Drapeau | Effet |
|---|---|
-fhir | Servez le point de terminaison FHIR à /fhir. Activé par défaut. |
-fhir-version | La version servie. R4 par défaut. |
-fhir-read-only | Refusez les écritures. |
-fhir-api-tokens | Avec SMART configuré, acceptez les jetons d'API Perfuse ainsi que les jetons SMART (désactivé par défaut ; également sous Paramètres → FHIR). |
-fhir-bulk-export | Activez $export. Désactivé par défaut. |
-fhir-subscriptions | Activez les abonnements aux sujets : notifications de rencontre et de rendez-vous aux points de terminaison choisis par les clients FHIR. Désactivé par défaut ; nécessite R4 et un point de terminaison modifiable. |
-fhir-subscriptions-allow-http | Laissez les abonnements livrer à http simple. Pour un récepteur de test, jamais pour les données de patient sur un réseau. |
-fhir-patient-directory-search | Laissez un jeton limité à un patient rechercher l'annuaire (praticiens, organisations, emplacements), dans ses étendues. Désactivé par défaut. |
-fhir-declares | Guides que ce serveur déclare dans sa déclaration de capacité, séparés par des virgules : l'adresse de la déclaration de capacité d'un guide, ou Type=profile adresse. Une déclaration pour les clients et les kits de test ; elle ne change rien que le magasin accepte. |
Le magasin conserve les documents ainsi que les ressources : un document, une collection ou un message Bundle mis à jour à /fhir/Bundle/{id} est conservé entier, relu avec chaque entrée dans la version servie, et trouvé par type, identifier, timestamp et composition. Une transaction mise à jour là est conservée comme un enregistrement et non appliquée ; un POST à /fhir applique une.
Les réponses sont au format JSON, sauf si le client demande du XML (Accept: application/fhir+xml, ou _format=xml). Perfuse ne lit que le JSON : un corps envoyé en XML obtient 415. Un document Bundle POSTé sur /fhir est conservé lorsque ce serveur détient, par identifiant, le patient et la rencontre que sa Composition nomme, et est refusé avec 422 sinon. Un binaire lu avec Accept défini sur son type de contenu répond avec le contenu lui-même.
19.7 Configuration et exploitation
19.7.1 perfuse init
Crée la disposition des répertoires, un canal d'exemple et une définition de service pour le système d'exploitation sur lequel il est exécuté. Rien de ce qui existe n'est remplacé à moins que vous ne passiez -force.
perfuse init -dir /opt/perfuse -service systemd
19.7.2 perfuse service
Enregistre Perfuse en tant que service Windows, le supprime ou signale s'il est installé et en cours d'exécution. Windows uniquement ; sur Linux, l'équivalent est le fichier d'unité que perfuse init peut écrire pour vous. Voir opérations.
19.7.3 perfuse token
Délivre des informations d'identification pour les machines plutôt que pour les personnes. Un jeton n'expire pas et n'est pas affecté par la déconnexion de quelqu'un, ce dont a besoin un serveur qui interroge son voisin et ce qu'une session de navigateur n'est pas censée être.
perfuse token create -db perfuse.db -label fleet-from-site-a -role viewer perfuse token list -db perfuse.db perfuse token revoke -db perfuse.db -label fleet-from-site-a
Seul le hachage est stocké, donc un jeton est affiché une seule fois lorsqu'il est créé et ne peut pas être récupéré par la suite. Un jeton volé ne donne donc aucun jeton utilisable. Donnez à un jeton le rôle le plus bas qui fait l'affaire : une flotte a besoin de viewer, et rien qui ne lit que ne doit détenir quoi que ce soit de plus.
-fhir-groups riverside-attributed,riverside-north limite un jeton à ces groupes FHIR, pour une exportation de fournisseur CMS-0057 Provider Access : sur l'endpoint FHIR, il peut lire ces groupes et les exporter, et rien d'autre. Voir CMS-0057 pour les payeurs.
19.7.4 perfuse athena
Affiche la commande Amazon Athena CREATE EXTERNAL TABLE pour un archive S3 écrit avec format: ndjson, en utilisant la projection de partition sur la partie dt=YYYY-MM-DD de la clé, de sorte qu'aucun crawleur n'a besoin de s'exécuter au fur et à mesure que les jours sont ajoutés.
perfuse athena -bucket hospital-archive -destination archive
Imprimé plutôt que exécuté, car la création d'une table nécessite des autorisations Athena et Glue que ce programme ne devrait pas détenir.
19.7.5 perfuse sbom
Liste tout ce qui est lié au binaire, lu à partir de la construction elle-même plutôt que de go.mod — il décrit donc le binaire devant vous et non ce que quelqu'un a demandé une fois.
-json émet CycloneDX et -spdx émet SPDX tag-value, ce qui est généralement ce que demande une revue d'approvisionnement ou de sécurité. Le code du navigateur intégré au binaire est inclus, car un réviseur qui fait correspondre un binaire avec des advisories a besoin de savoir qu'il contient une application React.
19.7.6 perfuse version
Affiche la version et le commit à partir duquel elle a été construite. Il vaut la peine de le mettre dans un ticket : « la version actuelle » n'est pas une version, et deux machines qui ont été installées à une semaine d'intervalle ne sont souvent pas exécutées avec la même version.
20 Options du serveur
Chaque option que perfuse serve prend, générée à partir du programme lui-même, de sorte que cette liste ne peut pas nommer une option qui n'existe pas ou en omettre une. La plupart sont également un paramètre dans l'interface web, nommé dans la dernière colonne : une valeur enregistrée là-bas l'emporte sur le flag au prochain démarrage, et le flag reste le moyen de le définir à partir d'une définition de service. L'adresse d'écoute, la base de données et le répertoire de canal restent des flags uniquement, car ils disent où le serveur trouve ce qu'il éditerait.
Les secrets ne sont jamais des flags. Une option qui nécessite un mot de passe ou un jeton nomme une variable d'environnement qui le contient.
20.1 Toutes les options
| 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 Référence de canal
Toute clé qui peut apparaître au niveau supérieur d'un fichier de canal. Ces clés sont extraites de la source, donc ce chapitre ne peut pas décrire une option qui n'existe pas ou omettre une qui existe.
21.1 Canal
Un canal est un flux de messages configuré : un endroit où les messages arrivent, un filtre facultatif et un ou plusieurs endroits où ils vont.
Défini comme Channel dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
name | texte | oui | — |
description | texte | non | — |
group | texte | non | — |
attachments | Attachments (un bloc, omis pour ne pas inclure) | non | — |
delimited | Delimited (un bloc, omis pour ne pas inclure) | non | — |
tables | liste de texte | non | — |
contract | ContractRef (un bloc, omis pour ne pas inclure) | non | — |
enabled | vrai ou faux (un bloc, omis pour ne pas inclure) | non | — |
dataType | DataType | non | hl7 |
hl7v3 | HL7v3Options (un bloc, omis pour ne pas inclure) | non | — |
x12 | X12Options (un bloc, omis pour ne pas inclure) | non | — |
ncpdp | NCPDPOptions (un bloc, omis pour ne pas inclure) | non | — |
edifact | EDIFACTOptions (un bloc, omis pour ne pas inclure) | non | — |
script | ScriptOptions (un bloc, omis pour ne pas inclure) | non | — |
dicom | DICOMOptions (un bloc, omis pour ne pas inclure) | non | — |
source | Source | oui | — |
filter | texte | non | — |
transformations | liste de transform.Step | non | — |
scripts | Scripts (un bloc, omis pour ne pas inclure) | non | — |
shadow | Shadow (un bloc, omis pour ne pas inclure) | non | — |
destinations | liste de Destination | oui | — |
21.1.1 nom
Le nom identifie le canal dans les journaux et les métriques.
Requis et unique.
21.1.2 groupe
Le groupe est ce dont fait partie ce canal, pour organiser une liste qui est devenue trop longue pour être lue.
Cosmétique pour cinq canaux et structurel pour deux cents : les canaux d'un site se divisent par le système avec lequel ils communiquent, ou par l'équipe qui les possède, et une liste plate de deux cents noms est inutilisable, quelle que soit la qualité du reste de l'interface.
Une chaîne simple plutôt qu'un objet de groupe avec son propre fichier, car un groupe n'a pas de comportement. Le moment où il a un fichier, il acquiert des paramètres, et les paramètres d'un groupe signifient que le comportement d'un canal dépend de quelque chose qui n'est pas écrit dans le canal - ce qui est la propriété qui rend la configuration de Mirth difficile à comprendre. Les groupes ici sont un libellé et rien de plus.
21.1.3 pièces jointes
Les pièces jointes déplacent les charges utiles importantes hors du message et les remettent en place avant la livraison.
Activation facultative par canal : un flux de messages ADT simples n'a rien à extraire et ne devrait pas payer pour le mécanisme.
21.1.4 délimité
Délimité configure un canal délimité.
Seulement significatif lorsque le type de données est délimité.
21.1.5 tableaux
Les tableaux nomment des fichiers de tableaux de mappage partagés que une transformation peut référencer par nom.
Partagés car la taxe de domaine est en grande partie une ré-édition d'une mappage que quelqu'un a déjà dérivé : les codes de sexe et les classes de patients d'un site sont traduits de manière identique dans chaque canal qui les touche, et un tableau à l'intérieur d'un canal est un tableau que seul ce canal peut utiliser.
21.1.6 activé
Activé est true par défaut.
Un canal désactivé est chargé et validé mais non démarré, donc un fichier qui est temporairement hors service est toujours vérifié par CI.
21.1.7 type de données
Le type de données est le format des messages que ce canal reçoit.
Par défaut, il est défini sur hl7, donc chaque canal créé avant son existence continue de fonctionner.
21.1.8 x12
X12 contient les paramètres qui n'ont de sens que sur un canal X12.
La définition de ce paramètre sur tout autre type de canal est refusée plutôt que d'être ignorée.
21.1.9 script
Le script configure un canal NCPDP SCRIPT.
Ses étapes sont définies ici plutôt que dans les transformations de niveau supérieur pour la même raison que les autres formats non v2 : les types d'étapes diffèrent selon le format, donc une clé aurait des significations différentes en fonction du type de données.
21.1.10 dicom
L'imagerie configure les étapes de transformation nommées d'un canal DICOM.
Imagerie est utilisé au lieu de DICOM car la source et la destination ont déjà un champ DICOM et trois champs avec le même nom à différents niveaux peuvent entraîner des erreurs. La clé yaml est dicom, ce à quoi s'attend une personne qui écrit le fichier, et le nom Go est celui qui empêche une erreur au moment de l'appel.
21.1.11 filtre
Le filtre est une expression qui doit être vraie pour qu'un message soit transmis.
Un message qui ne correspond pas est toujours accusé réception : l'expéditeur n'a rien fait de mal, nous sommes simplement pas intéressés.
21.1.12 transformations
Les transformations sont des modifications déclaratives appliquées aux messages acceptés, dans l'ordre, avant l'exécution de tout script.
Ceci est la couche destinée à effectuer le travail ordinaire : chaque étape est validée lors du chargement du fichier, apparaît dans une différence et peut être examinée par quelqu'un qui ne lit pas JavaScript.
21.1.13 scripts
Les scripts contiennent du code JavaScript pour les cas où les étapes déclaratives ne peuvent pas être exprimées, et c'est là que les scripts propres à un canal Mirth sont insérés sans changement.
Un canal avec un script est marqué comme tel dans l'interface, car son comportement ne peut pas être établi en lisant la configuration.
21.1.14 ombre
L'ombre exécute une version candidate de ce canal à côté de lui et signale les différences.
Rien de ce qu'il fait ne peut atteindre un récepteur.
22 Référence de la source
Toute façon dont un canal peut recevoir des messages, et chaque clé que chacun accepte. Un canal a exactement une source.
22.1 Source AMQP
AMQPSource reçoit d'une file d'attente ou d'un abonnement.
Un message n'est accepté qu'après que le canal l'a traité. Celui qui n'a pas pu être traité est rejeté comme une livraison échouée, de sorte que le courtier le redélivre et - sur Service Bus, au-delà du nombre maximum de livraisons de la file d'attente - le met dans les lettres mortes.
Défini comme AMQPSource dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
prefetch | nombre entier | non | 10 |
reconnect | durée, telle que 30s ou 5m | non | 5s |
22.1.1 prélecture
La prélecture est le nombre de messages que le courtier peut envoyer à l'avance.
Par défaut, 10. Ils sont toujours traités un à la fois, dans l'ordre.
22.1.2 reconnect
La reconnectivité est l'attente après une perte de connexion.
Defaults to 5s.
22.2 Source AS2
AS2Source reçoit AS2 (RFC 4130) : EDI publié sur HTTP, signé et chiffré avec S/MIME, répondu avec un reçu (un MDN) portant un résumé de ce qui est arrivé.
La charge utile est ce que le canal traite ; X12 et EDIFACT sont les plus courants.
Défini comme AS2Source dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
listen | texte | oui | — |
path | texte | non | — |
tls | tlsconf.Settings (un bloc, omis pour le supprimer) | non | — |
id | texte | oui | — |
cert_file | texte | oui | — |
key_file | texte | oui | — |
partners | liste de AS2Partner | oui | — |
max_message_size | nombre entier | non | — |
duplicate_window | durée, telle que 30s ou 5m | non | — |
22.2.1 chemin
Le chemin est le chemin d'URL que les partenaires publient.
Default /as2.
22.2.2 tls
TLS sert HTTPS.
La plupart des partenaires l'exigent dans leur accord, en plus de S/MIME.
22.2.3 id
L'ID est notre identifiant AS2, que les partenaires envoient dans AS2-To.
Un message à tout autre est refusé.
22.2.4 partenaires
Les partenaires sont ceux qui peuvent envoyer ici.
Un message de quiconque d'autre est refusé.
22.2.5 duplicate_window
DuplicateWindow est la durée pendant laquelle l'ID de message d'un partenaire est mémorisé, de sorte qu'un message envoyé à nouveau (le partenaire n'a pas reçu notre accusé de réception et a réessayé) est répondu avec un accusé de réception et non transmis deux fois (RFC 4130 section 7.5).
Default 30 days.
22.3 Azure Blob Source
AzureBlobSource récupère les blobs à partir d'un préfixe de conteneur.
Défini comme AzureBlobSource dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
prefix | texte | oui | — |
suffix | texte | non | — |
after_read | texte | non | — |
move_to | texte | non | processed/ |
error_prefix | texte | non | error/ |
poll_interval | durée, telle que 30s ou 5m | non | 30s |
max_object_size | nombre entier | non | 16 MiB |
framed | vrai ou faux | non | — |
22.3.1 move_to
MoveTo est l'emplacement où un blob traité est déplacé.
Par défaut, processed/.
22.3.2 error_prefix
ErrorPrefix est l'emplacement où un blob qui ne peut pas être traité est déplacé, de sorte qu'il ne bloque pas le reste.
Par défaut, error/.
22.3.3 poll_interval
PollInterval entre les listages.
Defaults to 30s.
22.3.4 max_object_size
MaxObjectSize refuse un blob plus grand, qui est laissé en place.
Par défaut, 16 MiB.
22.4 Broker Source
BrokerSource lit les messages à partir d'un courtier de messages.
Lecteur JMS de Mirth, accessible via STOMP car JMS est une API Java plutôt qu'un protocole. Voir internal/stomp pour savoir pourquoi STOMP et pas OpenWire.
Défini comme BrokerSource dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
addr | texte | oui | — |
destination | texte | oui | — |
login | texte | non | — |
passcode | texte | non | — |
host | texte | non | l'hôte de l'adresse |
selector | texte | non | — |
subscription_id | texte | non | le nom du canal |
heartbeat | durée, telle que 30s ou 5m | non | trente secondes |
reconnect | durée, telle que 30s ou 5m | non | cinq secondes |
timeout | durée, telle que 30s ou 5m | non | trente secondes |
tls | tlsconf.Settings (un bloc, omis pour ne pas le laisser) | non | — |
22.4.1 addr
Addr est l'hôte et le port du courtier.
Requis. 61613 est le port STOMP habituel.
22.4.2 destination
La destination est la file d'attente ou le sujet à lire.
Required.
Les courtiers épellent ces éléments différemment - /queue/name sur ActiveMQ, un nom nu sur RabbitMQ - il est donc transmis sans modification plutôt que d'être assemblé ici. Deviner signifierait travailler contre un courtier et lire discrètement rien sur un autre.
22.4.3 login
Le login et le code d'accès authentifient.
La plupart des courtiers refusent une connexion anonyme.
22.4.4 passcode
Le login et le code d'accès authentifient.
La plupart des courtiers refusent une connexion anonyme.
22.4.5 hôte
L'hôte est l'hôte virtuel.
Par défaut, il correspond à l'hôte de l'adresse.
22.4.6 sélecteur
Le sélecteur filtre les messages au niveau du courtier.
Un sélecteur JMS, transmis tel quel plutôt qu'interprété. Le filtrage au niveau du courtier plutôt qu'ici signifie que les messages que ce canal ne veut pas jamais traversent le réseau - ce qui, sur une file d'attente partagée, fait la différence entre la lecture de cent messages par jour et cent mille.
22.4.7 subscription_id
L'ID d'abonnement nomme l'abonnement.
Par défaut, il correspond au nom du canal.
Nommer plutôt que générer, car un abonnement durable est identifié par celui-ci : un abonnement généré créerait un nouvel abonnement à chaque redémarrage et laisserait les anciens s'accumuler des messages que personne ne lit.
22.4.8 rythme cardiaque
Le rythme cardiaque maintient la connexion active.
Par défaut, il est de trente secondes.
Activé par défaut ici, contrairement à la valeur par défaut du client, car une source maintient une connexion ouverte pendant des semaines. Sans rythme cardiaque, une connexion à travers un pare-feu qui a silencieusement supprimé la route semble parfaitement saine de ce côté et les messages cessent simplement d'arriver, sans rien dans les journaux.
22.4.9 reconnect
La reconnexion est le temps d'attente avant de se reconnecter après une défaillance.
Par défaut, il est de cinq secondes.
22.4.10 délai d'attente
Limites de délai d'attente de connexion.
Par défaut, il est de trente secondes.
22.5 Source de requête DICOM
DICOMQuerySource interroge un archive avec C-FIND et émet un message par nouvelle étude.
Mirth n'a pas d'équivalent de connecteur. Son support DICOM est un écouteur et un expéditeur - il peut recevoir des images poussées vers lui et les repousser, et c'est tout. Demander à un archive ce qu'il contient a été demandé sur leurs forums depuis 2015.
Ce qui le rend utile, ce n'est pas la requête, c'est l'automatisation : une prélecture qui s'exécute à trois heures du matin, une réconciliation qui remarque que l'archive manque une étude que le RIS dit exister, une liste de travail construite à partir de ce qui a été réellement scanné plutôt que de ce qui a été commandé. Ce sont des tâches que les sites effectuent actuellement avec un script planifié en dehors du moteur, ce qui signifie qu'ils sont invisibles pour lui - pas de nouvelles tentatives, pas d'alertes, pas d'historique de messages.
Défini comme DICOMQuerySource dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
address | texte | oui | — |
called_ae | texte | oui | — |
calling_ae | texte | non | — |
level | texte | non | STUDY |
patient_root | vrai ou faux | non | — |
match | mappage de texte à texte | non | — |
return | liste de texte | non | — |
interval | durée, telle que 30s ou 5m | oui | — |
window | durée, telle que 30s ou 5m | non | — |
overlap | durée, telle que 30s ou 5m | non | une heure |
limit | nombre entier | non | 500 |
timeout | durée, telle que 30s ou 5m | non | deux minutes |
tls | tlsconf.Settings (un bloc, omis pour le laisser de côté) | non | — |
emit_on_first_poll | vrai ou faux | non | faux |
22.5.1 adresse
L'adresse est l'hôte et le port de l'archive.
Required.
Nom pour correspondre à la destination DICOM plutôt que raccourci. Les deux étaient "adresse" et "addr" pour un après-midi, ce qui est le type d'incohérence que quelqu'un qui écrit un fichier de canal à la main se trompe une fois et puis se méfie ensuite de tout le format.
22.5.2 called_ae
CalledAE est le titre AE de l'archive.
Requis dans la pratique : la plupart des archives refusent une association adressée à autre chose, et ce refus se lit comme une panne plutôt que comme une erreur de configuration.
22.5.3 calling_ae
CallingAE est le titre AE que Perfuse présente.
Les archives utilisent couramment cela pour le contrôle d'accès.
22.5.4 niveau
Le niveau est le niveau de requête : PATIENT, STUDY, SERIES ou IMAGE.
Par défaut, STUDY.
STUDY est la valeur par défaut car c'est ce que presque toutes les requêtes utiles veulent et parce que les alternatives surprennent les gens : le niveau IMAGE contre un grand CT renvoie une réponse par tranche, ce qui fait des centaines par étude.
22.5.5 correspondance
Les correspondances sont les clés de requête.
Une valeur filtre ; une valeur vide demande que le champ soit renvoyé.
Les clés sont nommées plutôt que numérotées - "PatientID" et non "0010,0020" - car un fichier de canal est lu par des personnes, et un numéro de balise dans un fichier de configuration est une recherche que chaque lecteur doit effectuer.
22.5.6 retour
Les champs de retour sont des champs à renvoyer sans filtrage.
Séparé de la correspondance avec une valeur vide, même s’ils sont codés de manière identique, car l’intention diffère et qu’un lecteur peut voir quels clés restreignent la recherche et lesquels sont collectés.
22.5.7 intervalle
L’intervalle est la fréquence de sondage.
Required.
22.5.8 fenêtre
La fenêtre est la période de recherche pour chaque sondage, sous forme de plage de dates d’étude.
Zéro désactive entièrement le filtrage des dates.
Une fenêtre est ce qui maintient cela dans les limites. Sans elle, chaque sondage demande à l’archive tout ce qu’elle a jamais contenu, puis supprime ce qu’elle a vu auparavant - ce qui fonctionne sur une archive de test et est antisocial contre une archive réelle contenant des millions d’études.
22.5.9 chevauchement
Le chevauchement ré-interroge cette période déjà sondée.
La valeur par défaut est d’une heure.
Nécessaire plutôt que prudent. Une étude peut être enregistrée avec la date d’hier, notre horloge et celle de l’archive ne sont pas nécessairement en accord, et une limite de sondage qui correspond exactement à une arrivée la perd. Le chevauchement ré-interroge, et la vérification des études déjà vues arrête les doublons - donc le coût du chevauchement est une requête légèrement plus grande et le coût de l’absence de chevauchement est une étude silencieusement manquée.
22.5.10 limite
La limite plafonne les correspondances acceptées à partir d’un seul sondage.
Defaults to 500.
Un plafond plutôt que pas de plafond, car une clé de correspondance mal tapée transforme cela en « donnez-moi tout », et le premier symptôme de cela contre une archive réelle est que l’administrateur de l’archive demande qui la sollicite.
22.5.11 délai d'attente
Le délai d’attente limite un seul sondage.
La valeur par défaut est de deux minutes.
22.5.12 emit_on_first_poll
EmitOnFirstPoll envoie des messages pour tout ce que le premier sondage trouve.
La valeur par défaut est false.
False est important. Pointer cela sur une archive qui contient déjà un million d’études et lui faire émettre un message pour chacune n’est pas une première exécution utile, et c’est le type d’erreur qui est remarqué en aval plutôt qu’ici. Le premier sondage enregistre ce qui existe et n’émet rien ; le deuxième sondage et les suivants signalent ce qui est nouveau.
22.6 Source DICOM
DICOMSource reçoit des objets d’imagerie en tant que fournisseur de classe de service C-STORE.
Ce que l’on pointe un hôpital vers un appareil ou un PACS. Mirth appelle cela l’écouteur DICOM et il ne fait que C-STORE, donc c’est la parité plutôt qu’un sous-ensemble.
Défini comme DICOMSource dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
listen | texte | oui | — |
ae_title | texte | non | — |
allowed_calling_ae | liste de textes | non | — |
sop_classes | liste de textes | non | — |
transfer_syntaxes | liste de textes | non | — |
max_object_bytes | nombre entier | non | — |
idle_timeout | durée, telle que 30s ou 5m | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas l'inclure) | non | — |
22.6.1 écouter
Écouter est l'adresse sur laquelle servir.
Requis. 104 est le port DICOM enregistré ; 11112 est l'alternative courante lorsque le lien d'un port privilégié n'est pas possible.
22.6.2 ae_title
AETitle est le nom que cet endpoint se donne.
Fortement recommandé plutôt que requis, et averti en cas d'absence. Le contrôle d'accès d'un site sur un endpoint DICOM est souvent le titre AE, donc un endpoint qui accepte n'importe quel titre accepte tout ce qui peut le joindre.
22.6.3 allowed_calling_ae
AllowedCallingAE liste les titres AE autorisés à se connecter.
Vide accepte n'importe quel appelant.
Ceci est le contrôle d'accès que DICOM possède réellement. Un PACS est généralement configuré pour accepter un titre d'appel nommé et rejeter tout le reste, et cette fin n'avait pas d'équivalent : le titre appelé était vérifié - qui est le nom que l'appelant compose, donc n'importe qui peut l'envoyer correctement - tandis que celui qui appelait était enregistré dans le journal et ignoré par ailleurs.
Vide accepte toujours tout, car un appareil que personne n'a répertorié est l'état normal d'une première installation et refuser par défaut briserait chaque déploiement le premier jour. Il avertit à la place, et l'avertissement nomme les titres qui se sont connectés afin que quelqu'un puisse remplir ceci à partir de ce qui est réellement arrivé.
22.6.4 sop_classes
SOPClasses restreint les types d'objets à accepter.
Vide accepte n'importe lequel.
Vide est une valeur par défaut raisonnable ici, car ce moteur relaie des objets plutôt que de les interpréter, donc refuser une classe inconnue refuserait des images valides sans aucun bénéfice.
22.6.5 transfer_syntaxes
TransferSyntaxes restreint les codages à accepter, dans l'ordre de préférence.
Vide accepte les trois non compressés.
22.6.6 max_object_bytes
MaxObjectBytes limite un objet reçu.
Zéro applique une valeur par défaut.
22.6.7 idle_timeout
IdleTimeout ferme une association qui est devenue silencieuse.
Zéro signifie jamais, ce qui est généralement correct - une modalité maintient une association ouverte entre les études.
22.6.8 tls
TLS crypte les associations entrantes et peut exiger un certificat client.
Il vaut la peine de le dire clairement : Mirth nécessite son extension SSL Manager payante pour cela, et les forks communautaires ne peuvent pas la livrer du tout. Le DICOM transporte les noms de patients dans ses métadonnées, donc c'est l'un des endroits où être une réécriture plutôt qu'un fork est un avantage réel plutôt qu'un avantage stylistique.
22.7 Source Mweb DICO
DICOMwebSource accepte les requêtes STOW-RS.
Défini comme DICOMwebSource dans internal/config.
| Clé | Type | Requis | Défaut |
|---|---|---|---|
listen | texte | oui | — |
path | texte | non | /dicom-web |
token | texte | non | — |
username | texte | non | — |
password | texte | non | — |
max_object_bytes | nombre entier | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas inclure) | non | — |
22.7.1 écouter
Écouter est l'adresse sur laquelle servir.
Required.
22.7.2 chemin
Le chemin est la racine du service.
Les objets sont acceptés à Path/études et Path/études/{uid}. Par défaut, /dicom-web, qui est ce que Orthanc et dcm4chee utilisent, donc un expéditeur configuré pour l'un ou l'autre n'a besoin que de changer l'hôte.
22.7.3 jeton
Le jeton, lorsqu'il est défini, est requis en tant que jeton porteur.
Le nom d'utilisateur et le mot de passe nécessitent une authentification de base HTTP.
22.7.4 nom d'utilisateur
Le jeton, lorsqu'il est défini, est requis en tant que jeton porteur.
Le nom d'utilisateur et le mot de passe nécessitent une authentification de base HTTP.
22.7.5 mot de passe
Le jeton, lorsqu'il est défini, est requis en tant que jeton porteur.
Le nom d'utilisateur et le mot de passe nécessitent une authentification de base HTTP.
22.8 Source de base de données
DatabaseSource lit les lignes d'une base de données et les transforme en messages.
C'est ainsi que de nombreuses interfaces hospitalières commencent réellement. Un système de département n'a pas de capacité HL7, donc quelqu'un écrit des lignes dans une table de mise en page et le moteur d'interface interroge. C'est peu glamour et c'est partout.
C'est également la façon la plus courante pour une chaîne Mirth de stagner, et la raison est presque toujours la même : une ligne qui ne peut pas être traitée est lue, échoue et est lue à nouveau, pour toujours, car rien ne l'a marquée. La chaîne semble vivante. La file d'attente semble vide. Rien ne bouge, et chaque message derrière la mauvaise ligne attend une ligne qui ne réussira jamais.
La plupart de la conception ici est à ce sujet.
Défini comme DatabaseSource dans internal/config.
| Clé | Type | Requis | Défaut |
|---|---|---|---|
driver | texte | oui | — |
dsn | texte | oui | — |
query | texte | oui | — |
after_query | texte | non | — |
key_column | texte | non | — |
template | texte | non | — |
column | texte | non | — |
poll_interval | durée, telle que 30s ou 5m | non | — |
batch_size | nombre entier | non | 100 |
max_attempts | nombre entier | non | 3 |
query_timeout | durée, telle que 30s ou 5m | non | 30s |
22.8.1 pilote
Le pilote nomme la base de données.
See SupportedDrivers.
22.8.2 dsn
DSN est la chaîne de connexion.
Préférez une référence de variable d'environnement à une valeur littérale, car celle-ci contient généralement un mot de passe et les canaux sont destinés à être stockés dans git.
22.8.3 requête
La requête sélectionne les lignes en attente d'être envoyées.
Required.
Il doit s'agir d'une requête SELECT. Un sondage qui effectue discrètement des écritures s'exécuterait sur un calendrier sans aucun enregistrement de ce qu'il a modifié.
22.8.4 après_requête
AprèsRequête marque une ligne comme traitée et s'exécute avec la clé de ligne liée à celle-ci.
Strongly recommended.
Sans cela, chaque sondage relit toutes les lignes que la requête correspond toujours, donc la requête elle-même doit exclure les lignes traitées d'une autre manière. Si aucune de ces conditions n'est vraie, le canal renvoie les mêmes lignes indéfiniment, ce qui constitue une tempête de doublons plutôt qu'un blocage et est potentiellement pire.
22.8.5 colonne_clé
ColonneClé identifie une ligne pour AprèsRequête, la mise en quarantaine et la déduplication.
Requis lorsque AprèsRequête est défini.
22.8.6 modèle
Le modèle construit un message à partir d'une ligne.
Soit cela, soit Colonne est requis.
Les références de colonne utilisent ${nom_de_colonne}. Les colonnes manquantes sont une erreur lors du chargement plutôt qu'une chaîne vide dans un message clinique.
22.8.7 taille_de_lot
La taille de lot limite les lignes prises par sondage.
Defaults to 100.
Borné car un premier sondage non limité contre une table que quelqu'un a remplie pendant un an lirait tout dans la mémoire, puis l'enverrait tout, ce qui est la façon dont une migration inonde un récepteur actif.
22.8.8 nombre_de_tentatives
Le nombre de tentatives maximales est le nombre de fois qu'une ligne unique peut échouer avant d'être mise en quarantaine et que le sondage passe à la ligne suivante.
Defaults to 3.
Ceci est le paramètre qui empêche le blocage. Réessayer indéfiniment n'est pas de la résilience ; c'est une mauvaise ligne qui bloque un flux d'hôpital.
22.8.9 délai_d'attente_de_requête
Le délai d'attente de requête limite un seul sondage.
Defaults to 30s.
22.9 Source directe
La source directe reçoit le courrier Direct que le HISP livre : un écouteur SMTP pour cette adresse de messagerie.
Chaque message est déchiffré, sa signature vérifiée contre les ancres et son expéditeur contre l'expéditeur, et son contenu transmis : les documents d'un package XDM, sinon chaque pièce jointe, sinon le texte.
Défini comme DirectSource dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
listen | texte | non | — |
tls_cert | texte | non | — |
tls_key | texte | non | — |
max_bytes | nombre entier | non | — |
smtp_host | texte | non | — |
username | texte | non | — |
password | texte | non | — |
imap | DirectIMAP (un bloc, omis pour ne pas le configurer) | non | — |
xdr | DirectXDR (un bloc, omis pour ne pas le configurer) | non | — |
22.9.1 smtp_host
SMTPHost, Username et Password sont le serveur de soumission HISP, utilisé pour envoyer une notification de livraison « traitée » (MDN) à l'expéditeur une fois que le message a été pris en charge.
Sans cela, aucune notification n'est envoyée.
22.9.2 nom d'utilisateur
SMTPHost, Username et Password sont le serveur de soumission HISP, utilisé pour envoyer une notification de livraison « traitée » (MDN) à l'expéditeur une fois que le message a été pris en charge.
Sans cela, aucune notification n'est envoyée.
22.9.3 mot de passe
SMTPHost, Username et Password sont le serveur de soumission HISP, utilisé pour envoyer une notification de livraison « traitée » (MDN) à l'expéditeur une fois que le message a été pris en charge.
Sans cela, aucune notification n'est envoyée.
22.10 Source de messagerie électronique
EmailSource lit les courriels d'une boîte aux lettres et convertit les pièces jointes, les corps ou les messages entiers en messages.
Défini comme EmailSource dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
protocol | texte | non | — |
host | texte | oui | — |
port | nombre entier | non | — |
security | texte | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas inclure) | non | — |
username | texte | oui | — |
password | texte | non | — |
oauth | EmailOAuth (un bloc, omis pour ne pas inclure) | non | — |
mailbox | texte | non | — |
take | texte | non | — |
attachment_names | liste de textes | non | — |
allowed_senders | liste de textes | non | — |
after_read | texte | non | — |
move_to | texte | non | — |
error_folder | texte | non | — |
poll_interval | durée, telle que 30s ou 5m | non | — |
max_message_size | nombre entier | non | — |
22.10.1 mot de passe
Le mot de passe peut être ${ENV} ; pour Gmail, un mot de passe d'application.
Ignoré avec oauth.
22.10.2 attachment_names
AttachmentNames limite les pièces jointes prises, par modèle de nom de fichier (*.hl7).
Vide prend toutes les pièces jointes.
22.10.3 allowed_senders
AllowedSenders limite les courriels lus : adresses et domaines.
L'en-tête From peut être falsifié, donc cela empêche les accidents et les courriels occasionnels, mais pas un attaquant.
22.10.4 move_to
MoveTo est le dossier dans lequel les courriels traités sont déplacés ; « Traités » par défaut.
Créé lorsqu'il est manquant.
22.11 Source FTP
FTPSource collecte des fichiers à partir d'un serveur FTP ou FTPS.
Pourquoi FTP est toujours là
Il y a trente ans que sa substitution est recommandée et de nombreux systèmes hospitaliers exportent toujours vers celui-ci : des appareils dont le micrologiciel ne sera jamais mis à jour, des systèmes de facturation dont le fournisseur facture pour un changement. Refuser de parler ce langage ne fait pas disparaître ces systèmes, cela signifie que le moteur d'intégration ne peut pas être utilisé.
FTPS est la valeur par défaut. Il s'agit du même protocole avec TLS, la plupart des serveurs survivants le prennent en charge, et c'est une conversation beaucoup plus facile avec une équipe de sécurité qu'un FTP simple.
Défini comme FTPSource dans internal/config.
| Clé | Type | Requis | Défaut |
|---|---|---|---|
host | texte | oui | — |
user | texte | non | — |
password | texte | non | — |
security | ftpconn.Security | non | explicite |
insecure_skip_verify | vrai ou faux | non | — |
root | texte | non | — |
timeout | durée, telle que 30s ou 5m | non | trente secondes |
22.11.1 hôte
L'hôte est le serveur, avec un port facultatif.
Le port 21 est supposé.
22.11.2 utilisateur
L'utilisateur et le mot de passe authentifient.
Les deux peuvent être omis pour un serveur anonyme.
Le FTP anonyme est toujours utilisé pour publier certaines références publiques, donc un utilisateur vide est une configuration légitime plutôt qu'une omission et n'est pas refusé. Sur un serveur qui attend des informations d'identification, omettre celles-ci entraîne une erreur de connexion au moment de la connexion, qui est signalée contre le canal plutôt que de être réessayée silencieusement.
22.11.3 mot de passe
L'utilisateur et le mot de passe authentifient.
Les deux peuvent être omis pour un serveur anonyme.
Le FTP anonyme est toujours utilisé pour publier certaines références publiques, donc un utilisateur vide est une configuration légitime plutôt qu'une omission et n'est pas refusé. Sur un serveur qui attend des informations d'identification, omettre celles-ci entraîne une erreur de connexion au moment de la connexion, qui est signalée contre le canal plutôt que de être réessayée silencieusement.
22.11.4 sécurité
La sécurité est explicite, implicite ou aucune.
Par défaut, elle est explicite, ce qui est FTPS négocié avec AUTH TLS sur le port ordinaire. « none » est le FTP ordinaire et doit être demandé par son nom.
22.11.5 racine
La racine est le répertoire dont chaque chemin est relatif, et contre lequel la containment est appliquée.
Le serveur n'a pas de notion de cela : un serveur FTP acceptera volontiers ../.. comme chemin. Donc c'est ce qui empêche une opération move_to d'écrire n'importe où où le compte peut accéder.
22.11.6 délai d'attente
Le délai limite une opération, et non l'ensemble de l'interrogation.
Par défaut, il est de trente secondes.
Par opération, car une interrogation qui liste un répertoire et récupère vingt fichiers effectue vingt-et-une opérations, et un budget unique pour toutes elles interromprait une transfert parfaitement sain d'un fichier volumineux.
22.12 Source de fichiers
FileSource lit des fichiers à partir d'un répertoire que ce serveur peut voir.
Le connecteur que le site essaie en premier
Un analyseur écrit des résultats dans un dossier. Un système de facturation dépose un lot pendant la nuit. La radiologie exporte des rapports vers un répertoire que quelqu'un a monté il y a des années. Rien de tout cela implique un protocole, et un moteur d'intégration qui ne peut pas lire un dossier échoue à son évaluation le premier après-midi.
Défini comme FileSource dans internal/config.
| Clé | Type | Requis | Défaut |
|---|---|---|---|
root | texte | oui | — |
follow_symlinks | vrai ou faux | non | — |
22.12.1 racine
La racine limite chaque chemin que cette source touche.
Required.
Séparé de Dir afin que move_to et error_dir puissent être relatifs et toujours être contenus. Étant donné uniquement Dir, un error_dir de « ../failed » serait en dehors de tout ce que la source avait été autorisée, et le refuser serait arbitraire car il n'y aurait rien à refuser.
22.13 Source GCS
GCSSource récupère des objets à partir d'un préfixe de bucket, comme les sources s3 et azure_blob le font.
Défini comme GCSSource dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
prefix | texte | oui | — |
suffix | texte | non | — |
after_read | texte | non | — |
move_to | texte | non | processed/ |
error_prefix | texte | non | error/ |
poll_interval | durée, telle que 30s ou 5m | non | 30s |
max_object_size | nombre entier | non | 16 MiB |
framed | vrai ou faux | non | — |
22.13.1 move_to
MoveTo est l'endroit où un objet traité va après la lecture lorsque after_read est défini sur move.
Par défaut, processed/.
22.13.2 error_prefix
ErrorPrefix est l'endroit où un objet qui n'a pas pu être traité va.
Par défaut, error/.
22.13.3 poll_interval
PollInterval est la fréquence à laquelle le préfixe est listé.
Defaults to 30s.
22.13.4 max_object_size
MaxObjectSize laisse les objets plus grands où ils sont.
Par défaut, 16 MiB.
22.14 Source HTTP
HTTPSource accepte des messages via HTTP.
Un écouteur plutôt qu'un sondeur : quelque chose publie un message et reçoit un accusé de réception, ce qui est la façon dont la moitié moderne de l'hôpital s'intègre lorsque MLLP n'est pas disponible pour lui.
Défini comme HTTPSource dans internal/config.
| Clé | Type | Requis | Défaut |
|---|---|---|---|
listen | texte | oui | — |
path | texte | non | "/" |
tls | tlsconf.Settings (un bloc, omis pour ne pas inclure) | non | — |
token | texte | non | — |
max_message_size | nombre entier | non | — |
read_timeout | durée, telle que 30s ou 5m | non | — |
ack | Ack | non | — |
22.14.1 écouter
Écouter est l'adresse sur laquelle servir.
Required.
22.14.2 chemin
Path est le chemin d'URL pour accepter les messages.
Defaults to "/".
22.14.3 jeton
Token, lorsqu'il est défini, est requis dans un en-tête Authorization : Bearer.
Il n'y a pas de valeur par défaut et pas de commutateur de mode anonyme : un point de terminaison HTTP sur un réseau d'hôpital sans authentification du tout est une décision qui doit être visible dans le fichier, donc laisser cela vide est signalé comme un avertissement lors du chargement.
22.14.4 max_message_size
MaxMessageSize limite le corps d'un message entrant.
Zéro applique une valeur par défaut.
22.15 Source IBMMQ
IBMMQSource lit une file d'attente.
Défini comme IBMMQSource dans internal/config.
| Clé | Type | Requis | Défaut |
|---|---|---|---|
poll_interval | durée, telle que 30s ou 5m | non | 2s |
22.15.1 poll_interval
PollInterval est l'attente lorsque la file d'attente est vide, ou après un message qui n'a pas pu être traité.
Defaults to 2s.
22.16 Source JavaScript
JavaScriptSource configure une source qui exécute un script sur une minuterie et alimente les messages renvoyés dans le canal.
Ceci est l'équivalent du "JavaScript Reader" de Mirth.
Le script s'exécute dans une machine virtuelle goja avec le même bac à sable que les scripts de transformation : msg n'est pas disponible (il n'y a pas encore de message entrant), mais globalMap, configurationMap, logger et DateUtil sont présents. Le script doit renvoyer une chaîne (un message) ou un tableau de chaînes (plusieurs). Renvoyer rien ou un tableau vide signifie que la sonde n'a produit aucun message, ce qui est normal.
Défini comme JavaScriptSource dans internal/config.
| Clé | Type | Requis | Défaut |
|---|---|---|---|
script | texte | oui | — |
poll_interval | durée, telle que 30s ou 5m | non | — |
timeout | durée, telle que 30s ou 5m | non | — |
22.16.1 poll_interval
PollInterval définit la fréquence d'exécution du script.
Zéro signifie 5 secondes.
22.16.2 délai d'attente
Timeout définit la limite d'exécution d'un script.
Zéro signifie 30 secondes.
22.17 Source Kafka
KafkaSource lit les messages d'un sujet Kafka.
Défini comme KafkaSource dans internal/config.
| Clé | Type | Requis | Défaut |
|---|---|---|---|
brokers | liste de texte | oui | — |
topics | liste de texte | oui | — |
group | texte | oui | — |
from_beginning | vrai ou faux | non | — |
commit_after_delivery | vrai ou faux (un bloc, omis pour ne pas le spécifier) | non | — |
max_message_size | nombre entier | non | la limite du canal |
session_timeout | durée, telle que 30s ou 5m | non | quarante-cinq secondes |
timeout | durée, telle que 30s ou 5m | non | trente secondes |
sasl | KafkaSASL (un bloc, omis pour ne pas le spécifier) | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas le spécifier) | non | — |
22.17.1 courtiers
Les courtiers sont la liste des serveurs de démarrage.
Required.
Une liste plutôt qu'une seule adresse, car un seul courtier de démarrage est un point de défaillance unique pour le démarrage : le cluster survive à la perte de celui-ci et ce canal ne le ferait pas.
22.17.2 sujets
Les sujets sont les sujets à lire.
Au moins un est requis.
22.17.3 groupe
Le groupe est le groupe de consommateurs.
Required.
Nommez-le plutôt que de le générer, et requis plutôt que par défaut, car c'est ce qui se souvient de la façon dont ce canal a lu. Un groupe généré commencerait par le début - ou par la fin, en perdant tout - à chaque redémarrage, et il laisserait derrière lui l'ancien groupe en retenant les offsets validés que personne ne lit. L'exiger fait en sorte que la personne nomme la chose qui doit rester la même à travers les redémarrages.
22.17.4 from_beginning
FromBeginning lit le sujet à partir de son début lorsque le groupe n'a pas d'offset validé.
Désactivé par défaut, afin qu'un nouveau canal pointant vers un sujet avec deux ans d'historique ne rejoue pas deux ans d'événements de patient dans un système en direct le jour de son activation. La première personne à le faire le ferait en production, car c'est là que se trouve le sujet avec l'historique.
22.17.5 commit_after_delivery
CommitAfterDelivery valide l'offset uniquement une fois le message traité.
Activé par défaut, et la raison en est la différence entre perdre un message et le voir deux fois. Valider lors de la lecture signifie qu'une panne entre la validation et la livraison perd le message en silence, et rien nulle part n'enregistre son existence. Valider après signifie qu'une panne dans la même fenêtre le redélivre, ce qui est visible et que les récepteurs HL7 sont conçus pour tolérer - un A08 en double est une nuisance et un résultat de laboratoire manquant est un événement de sécurité des patients.
22.17.6 max_message_size
MaxMessageSize définit la limite d'un enregistrement.
Par défaut, il correspond à la limite du canal.
22.17.7 délai_d'expiration_de_session
SessionTimeout définit la durée pendant laquelle le coordinateur de groupe attend avant de considérer que ce consommateur est parti et de réattribuer ses partitions.
Par défaut, cela correspond à quarante-cinq secondes.
22.17.8 délai d'attente
Les limites de délai pour les connexions et les requêtes de métadonnées.
Par défaut, il est de trente secondes.
22.18 Source MQTT
MQTTSource s'abonne à un filtre de sujet.
Défini comme MQTTSource dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
topic | texte | oui | — |
reconnect | durée, telle que 30s ou 5m | non | 5s |
22.18.1 reconnect
Reconnect est le délai d'attente après une perte de connexion ou après un message qui n'a pas pu être traité.
Defaults to 5s.
22.19 Source Pub Sub
PubSubSource extrait des messages d'un abonnement Pub/Sub.
Défini comme PubSubSource dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
subscription | texte | oui | — |
max_messages | nombre entier | non | 10 |
reconnect | durée, telle que 30s ou 5m | non | 5s |
22.19.1 max_messages
MaxMessages définit le nombre de messages extraits à la fois.
Ils sont toujours traités un par un, dans l'ordre. Par défaut, cela correspond à 10.
22.19.2 reconnect
Reconnect est le délai d'attente après une erreur.
Defaults to 5s.
22.20 Source S3
S3Source récupère des objets à partir d'un seau.
Défini comme S3Source dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
bucket | texte | oui | — |
path_style | vrai ou faux | non | — |
prefix | texte | non | — |
suffix | texte | non | — |
after_read | texte | non | — |
move_to | texte | non | processed/ |
error_prefix | texte | non | error/ |
poll_interval | durée, telle que 30s ou 5m | non | 30s |
max_object_size | nombre entier | non | 16 MiB |
framed | vrai ou faux | non | — |
22.20.1 préfixe
Le préfixe limite les objets lus, par exemple inbound/.
Les lectures vides lisent tout le seau, ce qui est refusé avec after_read : move à moins que move_to ne soit en dehors - sinon les objets déplacés seraient lus à nouveau.
22.20.2 après_lecture
AfterRead est déplacer (par défaut) ou supprimer.
Il n'y a pas de départ : un seau n'a pas de fichier qu'un poller puisse se rappeler avoir vu à travers un redémarrage, donc laisser des objets signifie les lire à nouveau chaque fois que Perfuse démarre.
22.20.3 move_to
MoveTo est le préfixe vers lequel un objet traité se déplace.
Par défaut, processed/.
22.20.4 error_prefix
ErrorPrefix est où un objet qui n'a pas pu être traité se déplace, afin qu'un seul fichier erroné n'empêche pas le reste.
Par défaut, error/.
22.20.5 poll_interval
PollInterval entre les listages.
Defaults to 30s.
22.20.6 max_object_size
MaxObjectSize refuse tout ce qui est plus grand.
Par défaut, 16 MiB.
22.20.7 encadré
Framed lit plusieurs messages encadrés MLLP à partir d'un seul objet.
Autrement, un objet est un message.
22.21 Source SFTP
SFTPSource collecte des messages à partir d'un répertoire sur un serveur SFTP.
Extrêmement courant et rarement discuté. Un laboratoire ou un système de radiologie écrit un fichier toutes les quelques minutes, un serveur SFTP le contient, et quelque chose doit venir le récupérer. La moitié des flux décrits comme "nous vous envoyons HL7" sont cela.
La partie qui mérite attention n'est pas le transfert. C'est qu'un fichier en cours d'écriture et un fichier terminé ressemblent à l'identique via SFTP, donc une interrogation même légèrement trop impatiente collecte un demi-message. Cela produit un message HL7 tronqué mais souvent analysable, qui est le pire résultat disponible : il est accepté, reconnu, stocké et livré, et la moitié manquante n'est jamais mentionnée à nouveau.
Défini comme SFTPSource dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
host | texte | oui | 22 |
user | texte | oui | — |
password | texte | non | — |
key_file | texte | non | — |
key_passphrase | texte | non | — |
known_hosts_file | texte | non | — |
insecure_skip_host_key_check | vrai ou faux | non | — |
dir | texte | oui | — |
pattern | texte | non | tout |
poll_interval | durée, telle que 30s ou 5m | non | — |
after_read | texte | non | — |
move_to | texte | non | — |
error_dir | texte | non | — |
stable_for | durée, telle que 30s ou 5m | non | 5s |
framed | vrai ou faux | non | — |
max_file_size | nombre entier | non | 64MB |
timeout | durée, telle que 30s ou 5m | non | 60s |
22.21.1 hôte
L'hôte est le serveur, avec un port facultatif.
Defaults to 22.
22.21.2 mot de passe
Mot de passe authentifie avec un mot de passe.
Prefer KeyFile.
22.21.3 key_file
KeyFile est une clé privée.
Le meilleur choix, et celui que les équipes de sécurité des hôpitaux demandent.
22.21.4 known_hosts_file
KnownHostsFile vérifie l'identité du serveur.
Requis à moins que InsecureSkipHostKeyCheck ne soit défini. Sans cela, il n'y a rien pour distinguer le serveur réel de tout ce qui répond à cette adresse, et les informations d'identification sont transmises avant que quiconque ne s'en aperçoive.
22.21.5 insecure_skip_host_key_check
InsecureSkipHostKeyCheck accepte n'importe quelle clé hôte.
Existe parce que refuser purement et simplement envoie les gens à un script shell avec StrictHostKeyChecking=no, ce qui est pire à tous égards, y compris l'auditabilité. Il avertit bruyamment et il n'est jamais le paramètre par défaut.
22.21.6 modèle
Le modèle sélectionne les fichiers par glob.
Par défaut, tout est sélectionné.
22.21.7 move_to
MoveTo est le répertoire distant où les fichiers sont déplacés après lecture.
Requis lorsque AfterRead est « move ».
22.21.8 stable_pendant
StableFor est la durée pendant laquelle la taille et la date de modification d'un fichier doivent rester inchangées avant d'être lu.
Defaults to 5s.
Ceci est le paramètre qui empêche la collecte d'un message incomplet. Zéro signifie la lecture de tout ce qui est présent, ce qui fonctionne jusqu'à ce qu'un fichier soit suffisamment grand ou qu'un réseau soit suffisamment lent pour que l'écriture prenne plus de temps qu'une interrogation.
22.21.9 encadré
Framed indique que le fichier contient des messages encadrés MLLP.
Lorsqu'il est faux, le fichier est divisé sur les limites MSH.
22.21.10 taille_fichier_max
MaxFileSize refuse un fichier plus grand que ce nombre d'octets.
Par défaut, 64 Mo.
22.21.11 délai d'attente
Timeout définit les limites d'une connexion unique.
Defaults to 60s.
22.22 Source SMB
SMBSource collecte des fichiers à partir d'un partage de fichiers Windows.
Défini comme SMBSource dans internal/config.
| Clé | Type | Requis | Défaut |
|---|---|---|---|
host | texte | oui | — |
share | texte | oui | — |
user | texte | non | — |
password | texte | non | — |
domain | texte | non | — |
root | texte | non | — |
timeout | durée, telle que 30s ou 5m | non | trente secondes |
22.22.1 hôte
L'hôte est le serveur, avec un port facultatif.
Le port 445 est supposé.
22.22.2 partage
Partage est le nom du partage uniquement : le « données » dans \\\server\\data.
Un chemin ici est refusé plutôt que tronqué.
22.22.3 utilisateur
L'utilisateur et le mot de passe sont le compte Windows.
Requis dans la pratique.
Un partage accessible sans aucune authentification est suffisamment rare sur un domaine pour qu'un utilisateur vide ici soit beaucoup plus susceptible d'être une erreur qu'un partage invité - mais il est accepté, car le refuser bloquerait l'arrangement dans lequel il est correct. Lorsque le compte appartient à un domaine, définissez également le domaine : l'authentification d'un compte de domaine sans cela échoue de manière qui ressemble à un mot de passe incorrect.
22.22.4 mot de passe
L'utilisateur et le mot de passe sont le compte Windows.
Requis dans la pratique.
Un partage accessible sans aucune authentification est suffisamment rare sur un domaine pour qu'un utilisateur vide ici soit beaucoup plus susceptible d'être une erreur qu'un partage invité - mais il est accepté, car le refuser bloquerait l'arrangement dans lequel il est correct. Lorsque le compte appartient à un domaine, définissez également le domaine : l'authentification d'un compte de domaine sans cela échoue de manière qui ressemble à un mot de passe incorrect.
22.22.5 domaine
Le domaine est le domaine Windows ou le groupe de travail.
Vide est généralement approprié pour un compte local.
22.22.6 délai d'attente
Le délai d'attente limite une opération.
Par défaut, il est de trente secondes.
Vaut la peine d'être augmenté sur un partage atteint via un lien de site. Une opération SMB contre un serveur distant est plus lente que la même opération en local, ce qui fait que une valeur par défaut réglée pour un LAN produit des délais d'attente qui ressemblent à un partage indisponible.
22.23 Source SOAP
La source SOAP accepte les messages enveloppés dans une enveloppe SOAP.
Le contrepartie de la destination SOAP, et la direction la moins courante : la plupart des intégrations hospitalières ont Perfuse qui appelle un service plutôt que d'en être un. Elle existe parce que l'écouteur de service Web de Mirth le fait, et un site dont le système d'envoi ne parle que SOAP ne peut pas migrer sans cela.
Délibérément, ce n'est pas un framework de services Web général. Il accepte une enveloppe, extrait le message de celle-ci et répond avec une enveloppe. Il n'y a pas de WS-Security, pas de MTOM, pas de WS-Addressing et pas de liaisons générées - les mêmes omissions que la destination, pour la même raison : une demi-mise en œuvre de WS-Security est pire que rien.
Défini comme SOAPSource dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
listen | texte | oui | — |
profile | texte | non | — |
path | texte | non | "/" |
version | texte | non | 1 |
element | texte | non | — |
base64 | vrai ou faux | non | — |
response_element | texte | non | "AckResponse" |
response_namespace | texte | non | — |
wsdl | texte | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas inclure) | non | — |
token | texte | non | — |
username | texte | non | — |
password | texte | non | — |
max_message_size | nombre entier | non | — |
read_timeout | durée, telle que 30s ou 5m | non | — |
ack | Ack | non | — |
fault_on_nak | vrai ou faux | non | — |
22.23.1 écouter
Écouter est l'adresse sur laquelle servir.
Required.
22.23.2 profil
Le nom de profil désigne un service standard que ce point de terminaison met en œuvre.
Vide accepte n'importe quelle enveloppe telle que configurée ci-dessous.
"cdc-iis" répond comme un registre d'immunisation le ferait, sur l'interface CDC (urn:cdc:iisb:2011) : connectivityTest est écho, submitSingleMessage's hl7Message est le message et l'acknowledgement du canal est renvoyé en retour, le WSDL est servi à ?wsdl, et username et password, lorsqu'ils sont définis, sont vérifiés contre ceux du corps (où le WSDL les place) plutôt que contre l'authentification HTTP. Pour un double de test d'un registre, ou pour un site qui reçoit des soumissions de la manière dont les registres le font.
22.23.3 chemin
Le chemin est le chemin d'URL pour accepter les enveloppes.
Defaults to "/".
22.23.4 version
La version est la version SOAP à répondre, "1.1" ou "1.2".
Defaults to 1.1.
Les demandes sont acceptées dans les deux versions, car un expéditeur qui se trompe est courant et le rejeter n'apprend rien à personne. Le paramètre de configuration contrôle la réponse, où se tromper signifie que l'expéditeur ne peut pas lire la réponse.
22.23.5 élément
L'élément nomme l'élément à l'intérieur du corps SOAP qui contient le message.
Vide signifie que tout le texte du corps.
Nommer plutôt que deviner, car un corps peut transporter plusieurs éléments - un message aux côtés d'un identifiant d'expéditeur et d'une horodatage - et prendre tout le corps donnerait au moteur un fragment XML où il attendait HL7.
22.23.6 base64
La base64 décode le contenu de l'élément avant de le traiter comme un message.
Cela est courant dans les services réels, car HL7 transporte des retours à la ligne et les appelants qui n'ont pas pensé à cela se retrouvent avec un XML qui les déforme. Si le contenu se décode comme base64 mais n'était pas censé l'être, le résultat n'est pas un message et le moteur le dit - c'est pourquoi cela est explicite plutôt que détecté.
22.23.7 élément_de_reponse
ResponseElement nomme l'élément qui enveloppe l'accusé de réception dans la réponse.
Par défaut, il est défini sur « AckResponse ».
22.23.8 wsdl
WSDL est un fichier servi à l'adresse d'écoute avec ?wsdl.
Vide signifie qu'aucun n'est servi.
Un fichier plutôt que quelque chose de généré. Un WSDL généré décrirait ce que ce point de terminaison accepte, ce qui est presque jamais ce contre quoi le système d'envoi a été construit - et un WSDL qui est presque correct coûte plus de temps qu'aucun WSDL du tout, car il semble autoritaire.
22.23.9 nom d'utilisateur
Nom d'utilisateur et mot de passe, lorsqu'ils sont définis, nécessitent une authentification de base HTTP.
Proposé aux côtés d'un jeton, car les appelants SOAP s'attendent de manière écrasante à une authentification de base, et un site dont le système d'envoi ne peut pas être modifié a besoin de l'option qu'il possède déjà.
22.23.10 mot de passe
Nom d'utilisateur et mot de passe, lorsqu'ils sont définis, nécessitent une authentification de base HTTP.
Proposé aux côtés d'un jeton, car les appelants SOAP s'attendent de manière écrasante à une authentification de base, et un site dont le système d'envoi ne peut pas être modifié a besoin de l'option qu'il possède déjà.
22.23.11 max_message_size
MaxMessageSize limite le corps d'un message entrant.
Zéro applique une valeur par défaut.
22.23.12 erreur_lors_nak
FaultOnNak répond à un accusé de réception négatif avec une erreur SOAP au lieu d'une réponse normale contenant le NAK.
Désactivé par défaut, ce qui est la bonne valeur par défaut et vaut la peine d'être expliqué. HL7 a déjà un moyen de dire « J'ai reçu ceci et l'ai rejeté », et c'est un NAK - un échange réussi signalant un message rejeté. Transformer la même chose en une erreur de transport indique à l'expéditeur que sa demande était erronée, ce qui n'est pas le cas, et de nombreux clients répondent en réessayant indéfiniment.
Il existe parce que certains appelants ne regardent que le code d'état HTTP et traiteraient autrement un rejet comme un succès.
22.24 Source SQS
SQSSource lit à partir d'une file d'attente SQS.
Un message n'est supprimé qu'après que le canal l'a traité - livré, ou filtré, ou échoué d'une manière que le canal enregistre. Jusqu'alors, il reste dans la file d'attente, invisible pendant la durée de visibility_timeout, et revient si Perfuse s'arrête. Ainsi, un message n'est jamais perdu ; le prix à payer est qu'un message peut arriver deux fois, ce que SQS lui-même autorise déjà.
Défini comme SQSSource dans internal/config.
| Clé | Type | Obligatoire | Valeur par défaut |
|---|---|---|---|
queue_url | texte | oui | — |
wait_seconds | nombre entier | non | 20 : une file d'attente vide coûte une requête toutes les vingt secondes |
max_messages | nombre entier | non | 10 |
visibility_timeout | durée, telle que 30s ou 5m | non | la durée propre à la file d'attente |
22.24.1 delai_de_visibilite
DelaiDeVisibilite est la durée pendant laquelle un message reçu reste caché pendant qu'il est traité.
Par défaut, il est défini sur la durée propre à la file d'attente.
22.25 Source série
SerialSource lit les messages à partir d'un port série.
Pourquoi un connecteur série en 2026
Parce que l'équipement est toujours là. Un analyseur de gaz sanguin acheté en 2009 avec un capteur fonctionnel et une prise 25 broches, un moniteur de lit, une balance dans une unité de dialyse, une machine d'anesthésie plus ancienne. Aucun d'entre eux n'aura jamais de port Ethernet, plusieurs d'entre eux coûtent six chiffres, et l'alternative à la lecture est quelqu'un qui tape les résultats dans un formulaire.
Mirth dispose d'un connecteur série. Perfuse n'avait rien, et un site avec l'un de ces éléments n'avait aucune route d'entrée du tout.
Le encadré est partagé avec le connecteur TCP
Les encadrés sont les mêmes quelque soit l'origine des octets : un analyseur qui parle STX/ETX sur une socket parle STX/ETX sur un câble. Ainsi, cela réutilise le bloc d'encadré TCP plutôt que de définir le sien, ce qui signifie également qu'un appareil déplacé d'un câble série à un adaptateur série-Ethernet conserve sa configuration d'encadré.
Ce qui est différent pour une ligne série
Il n'y a pas de connexion. Une socket vous indique quand le pair a disparu ; un câble ne le fait pas. Un câble débranché, un appareil éteint et un appareil sans rien à dire sont indiscernables - tous les trois sont du silence. C'est pourquoi quiet_after existe : sans quelque chose pour dire « cette ligne a été silencieuse plus longtemps qu'elle ne devrait l'être », une alimentation morte ressemble exactement à une nuit calme.
Défini comme SerialSource dans internal/config.
| Clé | Type | Requis | Défaut |
|---|---|---|---|
port | texte | oui | — |
baud | nombre entier | oui | — |
data_bits | nombre entier | non | 8 |
parity | texte | non | aucun |
stop_bits | texte | non | 1 |
flow_control | texte | non | aucun |
max_message_size | nombre entier | non | — |
quiet_after | durée, telle que 30s ou 5m | non | — |
reply | texte | non | — |
reply_text | texte | non | — |
reopen_after | durée, telle que 30s ou 5m | non | — |
22.25.1 baud
Baud est la vitesse.
Requis, car deviner produit des octets plutôt qu'une erreur.
Un débit binaire incorrect ne provoque pas d'erreur. Il livre des déchets plausibles : les octets d'encadré apparaissent au hasard, des séries occasionnelles se décodent en caractères imprimables et un analyseur indulgent accepte certaines d'entre elles. Il n'y a délibérément pas de valeur par défaut.
22.25.2 parité
La parité est none, impaire, paire, marquage ou espace.
Par défaut, none.
22.25.3 bits d'arrêt
StopBits est 1, 1,5 ou 2, écrit sous la forme « 1 », « 1,5 » ou « 2 ».
Defaults to 1.
22.25.4 contrôle de flux
FlowControl est none, matériel ou logiciel.
Par défaut, none.
Vaut la peine d'être configuré correctement plutôt que laissé. Avec un contrôle de flux matériel attendu et non configuré, un appareil cesse d'envoyer à mi-chemin d'un message long et le résultat est un message tronqué plutôt qu'une erreur.
22.25.5 quiet_after
QuietAfter consigne un avertissement lorsqu'aucune chose n'a été reçue depuis cette durée.
Le seul moyen de remarquer une alimentation série morte. Un câble débranché et une nuit calme sont les mêmes silences, donc quelqu'un doit dire combien de temps est trop long pour cet appareil particulier.
22.25.6 reopen_after
ReopenAfter est la durée d'attente avant de rouvrir un port qui a échoué.
Un adaptateur série USB débranché et rebranché revient en tant que même chemin d'appareil mais avec une poignée de noyau différente, donc l'ancienne renvoie des erreurs à jamais. La réouverture est le seul moyen de récupération, et la faire dans une boucle serrée remplit le journal.
22.26 Source
Le source est l'endroit où un canal reçoit des messages.
Défini comme Source dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
type | SourceType | oui | — |
listen | texte | oui | — |
max_message_size | nombre entier | non | — |
idle_timeout | durée, telle que 30s ou 5m | non | — |
max_connections | nombre entier | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas être utilisé) | non | — |
http | HTTPSource (un bloc, omis pour ne pas être utilisé) | non | — |
soap | SOAPSource (un bloc, omis pour ne pas être utilisé) | non | — |
dicomweb | DICOMwebSource (un bloc, omis pour ne pas être utilisé) | non | — |
direct | DirectSource (un bloc, omis pour ne pas être utilisé) | non | — |
dicom | DICOMSource (un bloc, omis pour ne pas être utilisé) | non | — |
file | FileSource (un bloc, omis pour ne pas être utilisé) | non | — |
tcp | TCPSource (un bloc, omis pour ne pas être utilisé) | non | — |
ftp | FTPSource (un bloc, omis pour ne pas être utilisé) | non | — |
smb | SMBSource (un bloc, omis pour ne pas être utilisé) | non | — |
webdav | WebDAVSource (un bloc, omis pour ne pas être utilisé) | non | — |
serial | SerialSource (un bloc, omis pour ne pas être utilisé) | non | — |
dicom_query | DICOMQuerySource (un bloc, omis pour ne pas être utilisé) | non | — |
broker | BrokerSource (un bloc, omis pour ne pas être utilisé) | non | — |
kafka | KafkaSource (un bloc, omis pour ne pas être utilisé) | non | — |
sqs | SQSSource (un bloc, omis pour ne pas être utilisé) | non | — |
s3 | S3Source (un bloc, omis pour ne pas être utilisé) | non | — |
amqp | AMQPSource (un bloc, omis pour ne pas être utilisé) | non | — |
azure_blob | AzureBlobSource (un bloc, omis pour ne pas être utilisé) | non | — |
email | EmailSource (un bloc, omis pour ne pas être utilisé) | non | — |
as2 | AS2Source (un bloc, omis pour ne pas être utilisé) | non | — |
pgp | PGPReceive (un bloc, omis pour ne pas être utilisé) | non | — |
mqtt | MQTTSource (un bloc, omis pour ne pas être utilisé) | non | — |
ibm_mq | IBMMQSource (un bloc, omis pour ne pas être utilisé) | non | — |
pubsub | PubSubSource (un bloc, omis pour ne pas être utilisé) | non | — |
gcs | GCSSource (un bloc, omis pour ne pas être utilisé) | non | — |
database | DatabaseSource (un bloc, omis pour ne pas être utilisé) | non | — |
sftp | SFTPSource (un bloc, omis pour ne pas être utilisé) | non | — |
javascript | JavaScriptSource (un bloc, omis pour ne pas être utilisé) | non | — |
ack | Ack | non | — |
22.26.1 type
Le type est le transport.
Seul mllp est implémenté.
22.26.2 max_message_size
MaxMessageSize limite un message entrant.
Zéro utilise la valeur par défaut du transport.
22.26.3 idle_timeout
IdleTimeout ferme une connexion qui a été silencieuse pendant cette durée.
Zéro signifie jamais, ce qui est généralement correct : un flux d'hôpital maintient une connexion ouverte pendant des mois et se tait la nuit.
22.26.4 max_connections
MaxConnections limite les connexions concurrentes.
Zéro signifie illimité.
22.27 Source TCP
TCPSource écoute sur un socket pour des messages qui ne sont pas nécessairement HL7.
Pourquoi cela est séparé d'une source mllp
MLLP est un encadrement et Perfuse a toujours parlé. Un grand nombre d'équipements ne le font pas : un analyseur de laboratoire, une balance, un moniteur de lit, un système de facturation plus ancien. Chacun a tendance à avoir sa propre convention, et le connecteur TCP de Mirth les couvre tous, donc un site avec un flux de socket qui n'était pas HL7 ne pouvait pas utiliser Perfuse du tout.
Défini comme TCPSource dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
listen | texte | oui | — |
max_message_size | nombre entier | non | — |
idle_timeout | durée, telle que 30s ou 5m | non | — |
max_connections | nombre entier | non | — |
reply | texte | non | — |
reply_text | texte | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas être utilisé) | non | — |
22.27.1 idle_timeout
IdleTimeout ferme une connexion qui a été silencieuse pendant cette durée.
Zéro signifie jamais, ce qui est généralement correct : un flux de dispositif maintient une connexion ouverte pendant des mois et se tait la nuit.
22.27.2 max_connections
MaxConnections limite les connexions concurrentes.
Zéro signifie illimité.
22.27.3 reply
La réponse est ce qui est envoyé après chaque message : rien, ack ou une chaîne fixe.
La plupart des flux bruts n'attendent rien. Certains attendent un seul octet ACK. Un dispositif qui attend une réponse et ne l'obtient pas réessaie généralement le même message à l'infini, donc cela vaut la peine d'être explicite à ce sujet.
22.28 Source Web DAV
WebDAVSource collecte des fichiers à partir d'une collection WebDAV.
Où cela apparaît : systèmes de gestion de documents, SharePoint, Nextcloud et portails de fournisseurs qui exposent un dossier de dépôt sur HTTPS car c'est le seul port de sortie autorisé par les pare-feu de leurs clients.
Défini comme WebDAVSource dans internal/config.
| Clé | Type | Requis | Défaut |
|---|---|---|---|
url | texte | oui | — |
user | texte | non | — |
password | texte | non | — |
insecure_skip_verify | vrai ou faux | non | — |
timeout | durée, telle que 30s ou 5m | non | soixante secondes |
22.28.1 utilisateur
L'utilisateur et le mot de passe s'authentifient avec l'authentification de base HTTP.
L'authentification de base envoie le mot de passe dans un en-tête qui n'est protégé que par TLS, donc ceux-ci appartiennent à une URL HTTPS. Sur HTTP, ils sont lisibles par tout ce qui se trouve sur le chemin, et aucun avertissement du serveur ne vous le signalera.
22.28.2 mot de passe
L'utilisateur et le mot de passe s'authentifient avec l'authentification de base HTTP.
L'authentification de base envoie le mot de passe dans un en-tête qui n'est protégé que par TLS, donc ceux-ci appartiennent à une URL HTTPS. Sur HTTP, ils sont lisibles par tout ce qui se trouve sur le chemin, et aucun avertissement du serveur ne vous le signalera.
22.28.3 délai d'attente
Le délai d'attente limite une demande.
Par défaut, soixante secondes.
Plus long que les délais d'attente par défaut pour FTP et SMB, délibérément. La liste d'une collection WebDAV est une seule requête PROPFIND que le serveur peut mettre longtemps à assembler pour un grand répertoire, et il n'y a pas de résultat partiel pour revenir en arrière.
23 Référence de destination
Toute façon dont un canal peut envoyer des messages, et chaque clé que chacun accepte. Un canal peut avoir n'importe quel nombre de destinations, et elles sont indépendantes : une défaillance n'en empêche pas les autres.
23.1 Destination AMQP
AMQPDestination envoie à une file d'attente ou à un sujet, et signale la réussite uniquement une fois que le courtier a accepté le message.
Défini comme AMQPDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
content_type | texte | non | le type de données du canal |
23.1.1 content_type
ContentType est envoyé avec chaque message.
Par défaut, le type de données du canal.
23.2 Destination AS2
AS2Destination envoie chaque message sous forme AS2 : signé avec notre clé, chiffré avec le certificat du partenaire, publié à l'URL du partenaire, et, par défaut, livré uniquement une fois que le reçu signé du partenaire porte le même digest.
Défini comme AS2Destination dans internal/config.
| Clé | Type | Requis | Défaut |
|---|---|---|---|
url | texte | oui | — |
from | texte | oui | — |
to | texte | oui | — |
cert_file | texte | non | — |
key_file | texte | non | — |
partner_cert_file | texte | non | — |
unsigned | vrai ou faux | non | — |
unencrypted | vrai ou faux | non | — |
compress | vrai ou faux | non | — |
receipt | texte | non | — |
unsigned_receipt | vrai ou faux | non | — |
receipt_url | texte | non | — |
content_type | texte | non | — |
file_name | texte | non | — |
subject | texte | non | — |
username | texte | non | — |
password | texte | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas inclure) | non | — |
23.2.1 compress
Compresser compresse la charge utile (zlib, RFC 5402) avant de signer et de chiffrer.
Chaque récepteur AS2 qui annonce la version 1.1 ou ultérieure le lit ; demandez au partenaire avant de l'activer.
23.2.2 accusé de réception non signé
UnsignedReceipt demande un accusé de réception qui n'est pas signé.
Désactivé : un accusé de réception signé est demandé et un non signé est refusé.
23.2.3 content_type
ContentType est le type MIME de la charge utile.
Par défaut, en fonction du type de données du canal : application/edi-x12, application/edifact, application/hl7-v2, sinon application/octet-stream.
23.3 Destination Azure Blob
AzureBlobDestination écrit chaque message sous forme de blob de bloc.
Défini comme AzureBlobDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
blob | texte | non | ${date}/${channel}/${control_id} |
tier | texte | non | — |
content_type | texte | non | — |
23.3.1 blob
Blob nomme chaque blob, avec les placeholders de destination S3.
Par défaut, ${date}/${channel}/${control_id}.hl7.
23.3.2 tier
Tier est Hot, Cool, Cold ou Archive.
Archive est hors ligne : la lecture d'un blob nécessite une réhydratation, ce qui prend des heures.
23.4 Destination Broker
BrokerDestination publie des messages sur un courtier de messages.
L'écriture JMS de Mirth.
Défini comme BrokerDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
addr | texte | oui | — |
destination | texte | oui | — |
login | texte | non | — |
passcode | texte | non | — |
host | texte | non | l'hôte de l'adresse |
content_type | texte | non | text/plain pour HL7 |
headers | mappage de texte à texte | non | — |
persistent | vrai ou faux (un bloc, omis pour laisser de côté) | non | vrai |
timeout | durée, telle que 30s ou 5m | non | — |
tls | tlsconf.Settings (un bloc, omis pour laisser de côté) | non | — |
23.4.1 addr
Addr est l'hôte et le port du courtier.
Required.
23.4.2 destination
Destination est la file d'attente ou le sujet à publier.
Required.
23.4.3 login
Le login et le code d'accès authentifient.
La plupart des courtiers refusent une connexion anonyme.
23.4.4 passcode
Le login et le code d'accès authentifient.
La plupart des courtiers refusent une connexion anonyme.
23.4.5 hôte
L'hôte est l'hôte virtuel.
Par défaut, il correspond à l'hôte de l'adresse.
Il est utile de le définir explicitement sur un courtier qui héberge plusieurs hôtes virtuels, où la valeur par défaut atterrit la publication sur celui qui répond au nom du serveur lui-même - une file d'attente qui existe, accepte le message et est lue par personne.
23.4.6 content_type
ContentType est envoyé avec chaque message.
Par défaut, text/plain pour HL7.
23.4.7 headers
Les en-têtes sont envoyés avec chaque message.
Configuration uniquement, jamais de contenu de message. Un en-tête pris à partir d'un champ placerait un identifiant de patient dans les métadonnées du courtier qui sont consignées, indexées et visibles pour chaque autre application sur la file d'attente.
23.4.8 persistant
Persistant demande au courtier de survivre à un redémarrage.
Par défaut à true.
True car un message non persistant est perdu lorsque le courtier redémarre, et ce n'est pas une valeur par défaut raisonnable pour les données cliniques. False existe pour un flux vraiment transitoire - un battement de cœur de surveillance - et doit être choisi.
23.5 Destination CDA
CDADestination configure une destination cda : il prend le document clinique transporté à l'intérieur d'un message HL7 v2, le convertit et écrit ou publie le résultat.
Cela existe parce qu'un document arrive presque jamais seul. Il arrive codé en base64 à l'intérieur d'un MDM^T02, et chaque moteur qui traite ce message comme un blob opaque laisse le document non lu. Posséder les deux extrémités de cela est le but.
Défini comme CDADestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
url | texte | non | — |
dir | texte | non | — |
write | texte | non | — |
version | texte | non | R5 |
identifier_systems | mappage de texte à texte | non | — |
require_agreement | vrai ou faux | non | — |
on_no_document | texte | non | — |
headers | mappage de texte à texte | non | — |
bearer_token | texte | non | — |
23.5.1 url
L'URL est un serveur FHIR pour publier le bundle converti.
Laissez-le vide pour écrire dans Dir à la place. L'un des deux est requis.
23.5.2 dir
Dir écrit la sortie dans des fichiers au lieu de la publier.
Utile pour une zone d'atterrissage que另 un processus récupère, et pour voir ce que la conversion produit avant de le pointer vers un serveur en direct.
23.5.3 write
Write sélectionne ce qui est écrit ou publié :
fhir le bundle de transaction converti (par défaut) documenter le document d'origine en octets, inchangé les deux, avec le document aux côtés du bundle transférer un résumé de transition des soins PACIO : un document FHIR R4 pour l'endroit où le patient va ensuite (une maison de soins, une unité de réadaptation, des soins à domicile), publié à l'adresse url/Bundle ou écrit dans le répertoire dir
"document" vaut la peine d'être utilisé seul : un site qui veut ses CDAs sur disque pour une équipe d'enregistrement n'a pas besoin de la conversion FHIR du tout.
23.5.4 identifier_systems
IdentifierSystems mappe une racine OID du document à un URI, de sorte qu'un MRN devient espacé.
Un CDA identifie les personnes par OID et FHIR par URI, et rien ne peut en déduire un de l'autre.
23.5.5 require_agreement
RequireAgreement refuse un document dont les entrées narratives et codées se contredisent.
Désactivé par défaut, et délibérément. Le contrôle est précieux, mais il s'agit d'un jugement sur un document rédigé par quelqu'un d'autre, et un canal qui supprime silencieusement des documents cliniques réels parce que le générateur de C-CDA de l'expéditeur est peu soigneux est pire que celui qui les transmet avec un avertissement. Un site qui a examiné ses propres résultats et décidé qu'il souhaite la porte peut l'activer.
23.5.6 sur_aucun_document
OnNoDocument décide ce qui se passe lorsque le message ne contient pas de document clinique :
sauter, livrer rien et signaler la réussite (par défaut), échouer, traiter comme une défaillance de livraison
La valeur par défaut est sauter, car un canal transportant un flux ADT et MDM mixte échouerait autrement à chaque admission. Un canal dédié aux documents doit définir échouer, car un message de document sans document à l'intérieur est un véritable problème pour l'expéditeur.
23.5.7 jeton_porteur
BearerToken est envoyé comme en-tête d'autorisation.
Préférez une référence de variable d'environnement à une valeur littérale dans un fichier qui entre dans git.
23.6 Destination de canal
ChannelDestination achemine vers un autre canal sur le même serveur.
Défini comme ChannelDestination dans internal/config.
| Clé | Type | Obligatoire | Par défaut |
|---|---|---|---|
name | texte | oui | — |
23.7 Destination DICOM
DICOMDestination envoie des objets d'imagerie comme un utilisateur de la classe de service C-STORE.
Mirth appelle cela l'expéditeur DICOM.
Défini comme DICOMDestination dans internal/config.
| Clé | Type | Obligatoire | Par défaut |
|---|---|---|---|
address | texte | oui | — |
called_ae | texte | non | — |
calling_ae | texte | non | — |
transfer_syntaxes | liste de textes | non | — |
timeout | durée, telle que 30s ou 5m | non | — |
tls | tlsconf.Settings (un bloc, omis pour laisser de côté) | non | — |
23.7.1 adresse
L'adresse est l'hôte et le port distants.
Required.
23.7.2 called_ae
CalledAE est ce que l'hôte distant s'appelle lui-même, et CallingAE ce que cette extrémité s'appelle elle-même.
Les deux sont importants. Les sites configurent un PACS pour accepter un titre d'appel spécifique et rejeter tout le reste, donc une erreur de correspondance est la raison la plus courante pour laquelle une première connexion échoue - et l'échec ressemble à un problème de réseau.
23.7.3 calling_ae
CalledAE est ce que l'hôte distant s'appelle lui-même, et CallingAE ce que cette extrémité s'appelle elle-même.
Les deux sont importants. Les sites configurent un PACS pour accepter un titre d'appel spécifique et rejeter tout le reste, donc une erreur de correspondance est la raison la plus courante pour laquelle une première connexion échoue - et l'échec ressemble à un problème de réseau.
23.7.4 transfer_syntaxes
TransferSyntaxes restreint ce qui est proposé, dans l'ordre de préférence.
Vide propose le codage propre de l'objet, puis implicit VR little endian comme valeur par défaut.
23.7.5 délai d'attente
Timeout limite une opération de stockage.
Zéro applique une valeur par défaut.
23.8 Destination Mweb DICOM
DICOMwebDestination stocke chaque objet avec STOW-RS.
Défini comme DICOMwebDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
url | texte | oui | — |
token | texte | non | — |
username | texte | non | — |
password | texte | non | — |
headers | mappage de texte à texte | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas l'inclure) | non | — |
timeout | durée, telle que 30s ou 5m | non | — |
23.9 Destination de base de données
DatabaseDestination écrit chaque message dans une base de données.
Défini comme DatabaseDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
driver | texte | oui | — |
dsn | texte | oui | — |
statement | texte | oui | — |
params | liste de texte | non | — |
timeout | durée, telle que 30s ou 5m | non | 30s |
max_open_conns | nombre entier | non | 4 |
23.9.1 pilote
Le pilote nomme la base de données.
See SupportedDrivers.
23.9.2 instruction
L'instruction est exécutée une fois par message, avec les paramètres liés à celle-ci dans l'ordre.
Les espaces réservés sont propres au pilote : $1 pour postgres, ? pour mysql et sqlite, @p1 pour sqlserver. Perfuse ne les réécrit pas, car une couche de traduction qui se trompe sur un espace réservé lierait le nom d'un patient à la mauvaise colonne et le résultat ressemblerait à des données valides.
23.9.3 paramètres
Les paramètres sont des chemins HL7 ou des expressions ${...}, liés à l'instruction dans l'ordre.
Les valeurs sont toujours liées en tant que paramètres et jamais interpolées dans le SQL. Ce n'est pas seulement pour l'injection : O'Brien est un nom courant, et une requête concaténée se brise sur l'apostrophe.
23.9.4 délai d'attente
Le délai d'attente limite une instruction unique.
Defaults to 30s.
23.9.5 max_open_conns
MaxOpenConns limite le pool.
Defaults to 4.
23.10 Destination
La destination est un endroit où un canal envoie des messages.
Défini comme Destination dans internal/config.
| Clé | Type | Requis | Défaut |
|---|---|---|---|
name | texte | oui | — |
type | DestinationType | oui | — |
enabled | true ou false (un bloc, omis pour ne pas le laisser) | non | — |
filter | texte | non | — |
address | texte | non | — |
dir | texte | non | — |
file_name | texte | non | — |
temp_suffix | texte | non | " |
append | true ou false | non | — |
retain_hours | nombre entier | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas le laisser) | non | — |
fhir | FHIRDestination (un bloc, omis pour ne pas le laisser) | non | — |
cda | CDADestination (un bloc, omis pour ne pas le laisser) | non | — |
http | HTTPDestination (un bloc, omis pour ne pas le laisser) | non | — |
database | DatabaseDestination (un bloc, omis pour ne pas le laisser) | non | — |
sftp | SFTPDestination (un bloc, omis pour ne pas le laisser) | non | — |
tcp | TCPDest (un bloc, omis pour ne pas le laisser) | non | — |
smtp | SMTPDestination (un bloc, omis pour ne pas le laisser) | non | — |
channel | ChannelDestination (un bloc, omis pour ne pas le laisser) | non | — |
s3 | S3Destination (un bloc, omis pour ne pas le laisser) | non | — |
ftp | FTPDestination (un bloc, omis pour ne pas le laisser) | non | — |
document | DocumentDestination (un bloc, omis pour ne pas le laisser) | non | — |
soap | SOAPDestination (un bloc, omis pour ne pas le laisser) | non | — |
dicomweb | DICOMwebDestination (un bloc, omis pour ne pas le laisser) | non | — |
xds | XDSDestination (un bloc, omis pour ne pas le laisser) | non | — |
direct | DirectDestination (un bloc, omis pour ne pas le laisser) | non | — |
as2 | AS2Destination (un bloc, omis pour ne pas le laisser) | non | — |
mpi | MPIDestination (un bloc, omis pour ne pas le laisser) | non | — |
tefca | TEFCADestination (un bloc, omis pour ne pas le laisser) | non | — |
pas | PASDestination (un bloc, omis pour ne pas le laisser) | non | — |
x12_as | texte | non | — |
dicom | DICOMDestination (un bloc, omis pour ne pas le laisser) | non | — |
javascript | JavaScriptDestination (un bloc, omis pour ne pas le laisser) | non | — |
broker | BrokerDestination (un bloc, omis pour ne pas le laisser) | non | — |
kafka | KafkaDestination (un bloc, omis pour ne pas le laisser) | non | — |
sqs | SQSDestination (un bloc, omis pour ne pas le laisser) | non | — |
sns | SNSDestination (un bloc, omis pour ne pas le laisser) | non | — |
amqp | AMQPDestination (un bloc, omis pour ne pas le laisser) | non | — |
azure_blob | AzureBlobDestination (un bloc, omis pour ne pas le laisser) | non | — |
mqtt | MQTTDestination (un bloc, omis pour ne pas le laisser) | non | — |
ibm_mq | IBMMQDestination (un bloc, omis pour ne pas le laisser) | non | — |
pubsub | PubSubDestination (un bloc, omis pour ne pas le laisser) | non | — |
gcs | GCSDestination (un bloc, omis pour ne pas le laisser) | non | — |
elr | ELRDestination (un bloc, omis pour ne pas le laisser) | non | — |
pgp | PGPSend (un bloc, omis pour ne pas le laisser) | non | — |
response_transformer | texte | non | — |
timeout | durée, telle que 30s ou 5m | non | — |
retry | Retry | non | — |
queue | QueueConfig (un bloc, omis pour ne pas le laisser) | non | — |
23.10.1 nom
Le nom identifie la destination dans les journaux et les métriques.
Requis dans un canal.
23.10.2 file_name
FileName, pour une destination de fichier, modélise un fichier par message (${timestamp}, ${date}, ${control_id}, ${message_type}, ${destination}).
Vide conserve la valeur par défaut : un fichier par jour et type de message, ajouté à.
23.10.3 temp_suffix
TempSuffix est le nom qu'un fichier par message porte pendant qu'il est écrit, supprimé par une renommage une fois qu'il est complet, afin que ce qui collecte les fichiers ne lise jamais la moitié d'un fichier.
Par défaut, c'est ".part".
23.10.4 retain_hours
RetainHours supprime les fichiers dans Dir plus anciens que cela.
Zéro les conserve indéfiniment.
23.10.5 x12_as
X12As est un xml pour une destination sur un canal X12 qui reçoit l'échange sous la forme de XML que Mirth Connect et Open Integration Engine écrivent pour X12, pour un récepteur construit contre ce que Mirth lui a envoyé.
Vide ou x12 envoie X12.
23.10.6 elr
ELR rend cette destination un rapport de laboratoire de santé publique : chaque résultat de laboratoire (ORU^R01) est remodelé en un message ELR 2.5.1 ne contenant que les commandes avec un résultat pouvant être signalé, et c'est ce qui est livré ; un message sans rien de signalable n'est pas envoyé du tout.
S'applique aux destinations qui livrent un message HL7 v2 tel quel (mllp, http, fichier, sftp et le reste), sur un canal hl7.
23.10.7 response_transformer
ResponseTransformer inspecte ce que le destinataire a répondu et peut marquer la livraison comme ayant échoué.
Il existe parce que « est-ce que cela est arrivé » est souvent une question que le transport ne peut pas répondre : un récepteur MLLP renvoie un accusé de réception d'application dont le sens est dans son texte, et un récepteur HTTP renvoie 200 avec un document d'erreur. Dans les deux cas, le transport a réussi et le message n'est pas arrivé.
N'a de sens que sur une destination qui reçoit une réponse. Sur celle qui ne peut pas, elle est refusée au chargement plutôt que laissée inutilisée.
23.10.8 queue
La file d'attente rend la livraison durable : un message qui ne peut pas être livré maintenant est conservé sur disque et réessayé jusqu'à ce qu'il puisse l'être.
Désactivé par défaut.
23.11 Destination directe
DirectDestination envoie chaque message en tant que Direct : signé avec cette adresse, chiffré avec le certificat de chaque destinataire et soumis au HISP par SMTP.
Défini comme DirectDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
to | liste de textes | oui | — |
subject | texte | non | — |
text | texte | non | — |
attach_name | texte | non | — |
xdm | vrai ou faux | non | — |
xdm_source_id | texte | non | — |
recipient_certs_dir | texte | non | — |
dns | texte | non | — |
ldap | texte | non | — |
smtp_host | texte | oui | — |
username | texte | non | — |
password | texte | non | — |
request_mdn | vrai ou faux | non | — |
timeout | durée, telle que 30s ou 5m | non | — |
23.11.1 à
Les destinataires sont des adresses Direct.
Les références de champ sont substituées, donc un destinataire peut provenir du message.
23.11.2 recipient_certs_dir
RecipientCertsDir contient les certificats des destinataires (PEM, un fichier par adresse ou domaine, address.pem ou domain.pem) trouvés à l'avance ; vide lit le carnet d'adresses Direct du serveur (l'écran Direct).
Les destinataires qui n'y sont pas sont recherchés dans DNS (enregistrements CERT). Direct ne peut pas envoyer à un destinataire dont le certificat n'a pas été trouvé.
23.11.3 ldap
LDAP est l'annuaire dans lequel le certificat d'un destinataire est recherché lorsqu'il n'y en a pas dans le DNS (hôte:port, port 389) : la deuxième façon dont le guide de découverte de certificat Direct le permet.
Vide trouve l'annuaire du domaine du destinataire par son enregistrement SRV DNS (_ldap._tcp), comme le dit le guide ; « off » ne demande jamais à un annuaire.
23.12 Destination de document
DocumentDestination rend chaque message en un document.
Défini comme DocumentDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
dir | texte | oui | — |
format | DocumentFormat | non | |
template | texte | oui | — |
title | texte | non | — |
file_name | texte | non | — |
font_size | nombre | non | 10 |
landscape | vrai ou faux | non | — |
temp_suffix | texte | non | " |
timeout | durée, telle que 30s ou 5m | non | 30s |
23.12.1 format
Le format est pdf ou texte.
Par défaut, c'est pdf.
23.12.2 modèle
Le modèle est le corps du document, avec des références de style ${PID-5.1} aux chemins de message.
Requis. Il n'y a pas de valeur par défaut sensée : un document sans modèle serait soit le message brut, que personne ne veut imprimer, soit vide.
23.12.3 font_size
La taille de police en points.
Par défaut, c'est 10, ce qui correspond à 80 caractères sur A4.
23.12.4 temp_suffix
TempSuffix est ajouté pendant l'écriture et supprimé par un renommage.
Par défaut, c'est ".part".
La même courtoisie qu'avec toutes les autres destinations de fichiers, et cela compte encore plus ici : un surveillant d'impression qui récupère un PDF non terminé produit une page vide, et personne n'enquête sur une page blanche.
23.12.5 délai d'attente
La limite de timeout pour une écriture.
Defaults to 30s.
23.13 Destination ECR
ECRDestination configure les rapports de cas électroniques.
Défini comme ECRDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
rctc | texte | non | — |
source | texte | oui | — |
facility | ECRFacility | oui | — |
23.13.1 rctc
RCTC est un ensemble de valeurs FHIR, ou un paquet de ceux-ci, tels que l'eRSD, contenant les codes de déclenchement.
Sans cela, l'exemple intégré court de Perfuse est utilisé, qui est destiné aux tests : les agences attendent le RCTC.
23.14 Destination ELR
ELRDestination configure les rapports de laboratoire électroniques.
Défini comme ELRDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
config | texte | oui | — |
rctc | texte | non | — |
23.14.1 config
La configuration est le fichier ELR perfuse elr -config qui lit : les applications et les installations d'envoi et de réception par OID, le mode de traitement et ce qui remplit les lacunes laissées par un flux de laboratoire (installation de commande, laboratoire d'exécution, autorités d'attribution).
Un chemin relatif est lu à partir du répertoire du fichier de canal.
23.14.2 rctc
RCTC est un ensemble de valeurs FHIR, ou un paquet de ceux-ci, tels que l'eRSD, contenant les codes de déclenchement.
Sans cela, l'exemple intégré court de Perfuse est utilisé, qui est destiné aux tests : les agences attendent le RCTC. Relatif au fichier de canal, comme Config.
23.15 Destination FHIR
FHIRDestination configure la conversion en FHIR et la livraison à un serveur FHIR.
Défini comme FHIRDestination dans internal/config.
| Clé | Type | Requis | Défaut |
|---|---|---|---|
url | texte | oui | — |
version | texte | non | R5 |
timezone | texte | non | — |
default_identifier_system | texte | non | — |
identifier_systems | mappage de texte à texte | non | — |
claim_us_core | true ou false | non | — |
validate_before_send | true ou false (un bloc, omis pour ne pas le laisser) | non | true : l'envoi d'une ressource qu'un serveur va rejeter gaspille un budget de réessai et cache le problème réel derrière une erreur de transport |
reject_on_warning | true ou false | non | — |
headers | mappage de texte à texte | non | — |
bearer_token | texte | non | — |
auth | FHIRAuth (un bloc, omis pour ne pas le laisser) | non | — |
ecr | ECRDestination (un bloc, omis pour ne pas le laisser) | non | — |
bundle_script | texte | non | — |
23.15.1 url
L'URL est l'URL de base du serveur FHIR, par exemple "https://fhir.example.org/fhir".
Le paquet est publié directement dessus.
23.15.2 version
La version est la version FHIR à produire : R4, R4B ou R5. Par défaut, R5, la dernière version publiée.
Un déploiement qui communique avec un dossier électronique de santé (EHR) veut presque toujours R4 et devrait le spécifier, car la rétrogradation silencieuse cacherait une décision réelle d'interopérabilité.
23.15.3 fuseau horaire
Le fuseau horaire est appliqué aux horodatages HL7 v2 qui n'ont pas d'offset. La version 2 permet un temps local nu et FHIR ne le permet pas, donc quelque chose doit en fournir un.
Lorsqu'il n'est pas défini, le décalage que l'expéditeur a placé sur MSH-7 est utilisé, puisque v2 présume qu'un temps nu est l'heure locale de l'expéditeur ; un message dont MSH-7 n'a pas de décalage non plus revient à UTC.
23.15.4 système d'identifiant par défaut
DefaultIdentifierSystem fournit des noms d'espaces pour les autorités d'attribution qui n'ont pas d'URI configuré.
Sans système, un MRN est ambigu entre les établissements.
23.15.5 claim_us_core
ClaimUSCore ajoute le profil US Core 9.0.0 à chaque ressource produite qui a été vérifiée contre celui-ci et qui est conforme.
Une ressource qui ne répond pas aux exigences est envoyée sans la revendication, avec une note indiquant pourquoi.
23.15.6 valider_avant_envoi
ValidateBeforeSend refuse d'envoyer un paquet qui échoue à la validation.
Par défaut, la valeur est true : envoyer une ressource qu'un serveur va rejeter gaspille un budget de réessai et cache le problème réel derrière une erreur de transport.
23.15.7 rejeter_en_cas_d'avertissement
RejectOnWarning refuse également en cas d'avertissements, tels qu'un identifiant US Core manquant.
Désactivé par défaut, car un avertissement est un jugement sur la conformité du profil plutôt que sur la validité.
23.15.8 jeton_porteur
BearerToken est envoyé comme en-tête d'autorisation.
Préférez une référence de variable d'environnement, ${NAME}, à une valeur littérale dans un fichier qui entre dans git.
23.15.9 ecr
ECR fait de ce destinataire un cas de déclaration de santé publique.
Chaque message est vérifié pour les codes de déclenchement ; un message qui en contient est envoyé comme un eCR 2.1 eICR, enveloppé dans un message eCR, à l'URL $process-message, et un message sans code n'est pas envoyé du tout.
23.15.10 script_de_paquet
Le script_de_paquet est un JavaScript exécuté sur chaque Bundle converti avant qu'il soit validé et envoyé : bundle est le Bundle sous forme d'objet, édité sur place.
C'est ainsi qu'un site ajoute ce que ses propres systèmes connaissent et que le message v2 ne dit pas - le code IKNR ou ODS de son organisation, un niveau de contact de profil national - sans que le convertisseur devine. Un script qui lance une exception échoue le message, comme n'importe quel autre transformateur. Non exécuté pour les rapports de cas (ecr).
23.16 Destination FTP
FTPDestination télécharge un fichier par message.
Défini comme FTPDestination dans internal/config.
| Clé | Type | Requis | Défaut |
|---|---|---|---|
host | texte | oui | 21 |
user | texte | non | — |
password | texte | non | — |
security | FTPSecurity | non | explicite plutôt que none |
insecure_skip_verify | vrai ou faux | non | — |
allow_clear_password | vrai ou faux | non | — |
dir | texte | oui | — |
file_name | texte | non | — |
temp_suffix | texte | non | " |
framed | vrai ou faux | non | — |
timeout | durée, telle que 30s ou 5m | non | 60s |
23.16.1 hôte
L'hôte est le serveur, avec un port facultatif.
Par défaut, la valeur est 21, ou 990 pour le TLS implicite.
23.16.2 utilisateur
L'utilisateur et le mot de passe authentifient.
Un utilisateur vide signifie anonyme.
23.16.3 mot de passe
L'utilisateur et le mot de passe authentifient.
Un utilisateur vide signifie anonyme.
23.16.4 sécurité
Sécurité sélectionne TLS : explicite, implicite ou aucun.
Par défaut, il est explicitement sélectionné plutôt que rien, car la sélection par défaut du FTP non sécurisé rendrait le choix insécuré silencieux, et un site qui n'a vraiment pas de TLS devrait l'écrire.
23.16.5 insecure_skip_verify
InsecureSkipVerify accepte tout certificat.
Nécessaire plus souvent que quiconque le souhaiterait : ces serveurs ont souvent un certificat auto-signé généré il y a des années que personne ne peut rééditer. Nom séparé afin que le choix soit délibéré et visible dans le fichier plutôt que caché à l'intérieur d'un mode "sécurité : assouplie".
23.16.6 allow_clear_password
AllowClearPassword permet un mot de passe sur le FTP non sécurisé.
Refusé par défaut, car cela envoie une information d'identification sur le réseau en texte clair à chaque livraison. Certains analyseurs n'ont vraiment pas de TLS, il doit donc être possible - mais cela doit être écrit, afin que cela soit une décision que quelqu'un a prise plutôt qu'un paramètre par défaut qu'il a hérité. Le nom est délibérément inconfortable à taper.
23.16.7 temp_suffix
TempSuffix est ajouté pendant que le fichier est écrit et supprimé par une renommage une fois qu'il est complet.
Par défaut, c'est ".part".
Qui collecte ces fichiers est généralement un travail planifié qui prend ce qu'il trouve, et sans le renommage, il prend finalement la moitié d'un message.
23.16.8 délai d'attente
Timeout limite une seule transaction.
Defaults to 60s.
23.17 Destination GCS
GCSDestination écrit chaque message en tant qu'objet.
Défini comme GCSDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
object | texte | non | ${date}/${channel}/${control_id} |
storage_class | texte | non | — |
content_type | texte | non | — |
23.17.1 object
Object est le nom de l'objet, avec les mêmes espaces réservés qu'une clé s3.
Par défaut, ${date}/${channel}/${control_id}.hl7.
23.18 Destination HTTP
HTTPDestination publie les messages sur un point de terminaison HTTP.
La chose la plus courante qu'un canal Mirth fait que Perfuse ne pouvait pas, et le bloqueur le plus courant que le traducteur signale. La plupart des utilisations sont peu glamour : publier le message sur une API interne, publier sur un service Web qui encapsule un système hérité, publier sur quelque chose que quelqu'un a écrit dans un après-midi.
Défini comme HTTPDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
url | texte | oui | — |
method | texte | non | — |
content_type | texte | non | — |
headers | mappage de texte à texte | non | — |
bearer_token | texte | non | — |
username | texte | non | — |
password | texte | non | — |
tls | tlsconf.Settings (un bloc, omis pour laisser de côté) | non | — |
success_status | liste de nombres entiers | non | n'importe quel 2xx |
fail_on_body | liste de texte | non | — |
follow_redirects | vrai ou faux | non | — |
23.18.1 url
URL est l'endroit où publier.
Required.
23.18.2 méthode
La méthode par défaut est POST.
PUT est autorisé pour un point de terminaison qui le souhaite.
GET et DELETE sont refusés : cela envoie un corps de message, et un transport qui supprime silencieusement le message en raison d'un choix de méthode serait un moyen très silencieux de perdre des données.
23.18.3 content_type
ContentType par défaut est application/hl7-v2+er7, qui est le type enregistré pour un message HL7 v2 délimité par des pipes.
De nombreux points de terminaison préfèrent text/plain.
23.18.4 jeton_porteur
BearerToken est envoyé comme en-tête d'autorisation.
Préférez une référence de variable d'environnement à une valeur littérale dans un fichier qui entre dans git.
23.18.5 état_de_succès
SuccessStatus liste les codes d'état qui sont considérés comme livrés.
Par défaut, n'importe quel code 2xx.
Configurable car les points de terminaison ne sont pas d'accord sur ce que signifie le succès : certains répondent 200 avec une erreur dans le corps, et d'autres répondent 202 pour une file d'attente qu'ils ont acceptée.
23.18.6 échec_sur_corps
FailOnBody traite une réponse contenant l'une de ces chaînes comme une erreur, quel que soit le code d'état.
Ceci existe parce qu'un point de terminaison qui répond 200 avec « ERROR : patient non trouvé » dans le corps est courant, et le traiter comme livré signifie que le message est perdu et que personne ne le sait.
23.18.7 suivre_les_redirections
FollowRedirects permet à la demande d'être redirigée.
Désactivé par défaut : une redirection sur une écriture reprendrait les données cliniques quelque part que la configuration n'a jamais nommée.
23.19 Destination IBMMQ
IBMMQDestination place chaque message dans une file d'attente.
Défini comme IBMMQDestination dans internal/config.
| Clé | Type | Obligatoire | Par défaut |
|---|---|---|---|
non_persistent | true ou false | non | — |
23.19.1 non_persistent
NonPersistent envoie des messages qui ne survivent pas à un redémarrage du gestionnaire de files d'attente.
Désactivé par défaut.
23.20 Destination JavaScript
JavaScriptDestination exécute un script au lieu d'envoyer à un emplacement.
L'écriture JavaScript de Mirth, et elle est utilisée beaucoup plus que sa position dans une liste de fonctionnalités le suggère. C'est l'échappatoire : lorsque le site a besoin de parler à quelque chose que aucun connecteur ne couvre, ou d'appliquer une logique que aucune transformation n'exprime, ils écrivent un script JavaScript. Une migration qui ne peut pas exécuter ces scripts ne peut pas déplacer les canaux qui les utilisent, ce qui dans une installation Mirth mature est une grande partie.
Délibérément pas un hôte de script général. Le script reçoit le message et les mêmes aides qu'un transformateur reçoit ; ce qu'il n'obtient pas, c'est un moyen d'accéder au système de fichiers ou au réseau, car c'est ce que les autres destinations sont pour et un script qui ouvre sa propre socket est invisible à chaque réessai, file d'attente et métrique dans le moteur.
Défini comme JavaScriptDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
script | texte | oui | — |
timeout | durée, telle que 30s ou 5m | non | — |
success_on_undefined | true ou false (un bloc, omis pour le laisser vide) | non | true |
23.20.1 script
Le script est le code à exécuter.
Required.
23.20.2 délai d'attente
Le délai d'attente limite une exécution.
Zéro applique une valeur par défaut.
Limité car un script de destination est sur le chemin de livraison : une boucle infinie dans l'un ne fait pas seulement échouer un message, mais bloque également la file d'attente derrière lui.
23.20.3 success_on_undefined
SuccessOnUndefined traite un script qui ne retourne rien comme une réussite.
Par défaut à true.
True est la valeur par défaut correcte et vaut la peine d'être expliquée. Les writers JavaScript de Mirth effectuent leur travail et ne retournent rien, donc exiger un retour explicite les casserait tous lors de l'importation. La définition de cette valeur sur false est pour un site qui souhaite qu'un script soit explicite sur le fait qu'il a fonctionné.
23.21 Destination Kafka
KafkaDestination publie des messages sur un sujet Kafka.
Défini comme KafkaDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
brokers | liste de texte | oui | — |
topic | texte | oui | — |
key | texte | non | — |
acks | texte | non | all |
compression | texte | non | snappy |
headers | mappage de texte à texte | non | — |
timeout | durée, telle que 30s ou 5m | non | trente secondes |
sasl | KafkaSASL (un bloc, omis pour le laisser vide) | non | — |
tls | tlsconf.Settings (un bloc, omis pour le laisser vide) | non | — |
23.21.1 courtiers
Les courtiers sont la liste des serveurs de démarrage.
Required.
23.21.2 sujet
Le sujet est où publier.
Required.
23.21.3 clé
La clé est un modèle pour la clé d'enregistrement, qui décide de la partition.
Ceci est le champ qui rend Kafka sûr pour un flux clinique, et il vaut la peine d'être précis sur pourquoi. Kafka garantit l'ordre dans une partition et nulle part ailleurs. Les enregistrements avec la même clé atterrissent toujours dans la même partition, donc la clé sur l'identifiant du patient garde les événements de ce patient dans l'ordre tout en laissant les patients différents aller en parallèle.
Sans clé, il n'y a pas de garantie. Mesuré contre un courtier réel, trente enregistrements non clés sont allés à une partition plutôt que de se répartir : le client garde un lot ensemble et choisit une nouvelle partition entre les lots. L'ordre est donc maintenu par accident et se brise à une limite que personne ne peut voir, ce qui est pire que de se briser de manière cohérente - un A03 de sortie lu avant son A01 d'admission, de manière intermittente, sous charge.
Un chemin HL7, évalué contre le message sortant : PID-3.1 clé par patient.
23.21.4 acks
Acks est le nombre de courtiers qui doivent confirmer une écriture : "all", "leader" ou "none".
Par défaut, c'est all, qui est le seul paramètre qui survive à un courtier qui défaille entre l'écriture et la réplication. "none" est fire-and-forget et perdra des messages ; il existe car quelqu'un qui déplace une télémétrie non clinique peut légitimement le vouloir, et refuser de l'accepter purement et simplement signifierait qu'il a écrit son propre producteur à la place.
23.21.5 compression
La compression est "none", "gzip", "snappy", "lz4" ou "zstd".
Par défaut, c'est snappy.
Activé par défaut car HL7 est un texte hautement compressible et le fil est généralement la contrainte. Snappy plutôt que zstd comme valeur par défaut : il est le moins coûteux en CPU, et un connecteur sur le chemin de livraison ne devrait pas être la chose qui sature un noyau.
23.21.6 headers
Les en-têtes sont des en-têtes d'enregistrement à définir.
Les valeurs sont des modèles évalués par message.
23.21.7 délai d'attente
La limite de timeout définit une publication.
Par défaut, il est de trente secondes.
23.22 Destination MPI
MPIDestination enregistre chaque message du patient dans l'index de patients de ce serveur : un PID HL7 v2 (une fusion A40 fusionne), ou un patient FHIR sur un canal brut.
L'index décide des enregistrements qui sont la même personne ; voir l'écran Index de patient.
Défini comme MPIDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
authorities | mappage de texte à texte | non | — |
id_type | texte | non | — |
ssn_system | texte | non | — |
no_merge | vrai ou faux | non | — |
23.22.1 autorités
Les autorités cartographient un espace de nom d'autorité d'attribution (PID-3.4.1) à son système d'identifiant, pour les expéditeurs qui ne fournissent pas d'identifiant universel.
Celles qui ne sont pas mappées deviennent urn:perfuse:aa:<namespace>.
23.22.2 type d'ID
Le type d'ID est le type d'identifiant (PID-3.5) du numéro de l'enregistrement.
Default MR.
23.22.3 système de numéro de sécurité sociale
Le système de numéro de sécurité sociale nomme le PID-19 en tant qu'identifiant.
Default http://hl7.org/fhir/sid/us-ssn.
23.23 Destination MQTT
MQTTDestination publie sur un sujet.
Défini comme MQTTDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
topic | texte | oui | — |
retain | vrai ou faux | non | — |
23.23.1 sujet
Le sujet est publié.
Il ne peut pas contenir de caractères génériques.
23.24 Destination PAS
La destination PAS soumet chaque message, un bundle de demande Da Vinci PAS, à la réclamation d'un payeur / $submit, pour un fournisseur dont les systèmes construisent la demande (un dossier médical électronique, DTR) et ont besoin qu'elle soit envoyée, la décision enregistrée et la réponse transmise.
Défini comme PASDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
payer | texte | oui | — |
bearer_token | texte | non | — |
auth | FHIRAuth (un bloc, omis pour ne pas inclure) | non | — |
results_to | texte | non | — |
23.24.1 jeton_porteur
Le jeton porteur est un jeton statique, ${ENV} autorisé.
L'authentification est les informations d'identification du client OAuth au lieu de cela, ou Azure, comme une destination FHIR.
23.24.2 auth
Le jeton porteur est un jeton statique, ${ENV} autorisé.
L'authentification est les informations d'identification du client OAuth au lieu de cela, ou Azure, comme une destination FHIR.
23.25 Destination Pub Sub
PubSubDestination publie sur un sujet Pub/Sub.
Défini comme PubSubDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
topic | texte | oui | — |
order_by | texte | non | — |
23.26 Destination S3
S3Destination écrit chaque message en tant qu'objet.
Défini comme S3Destination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
bucket | texte | oui | — |
region | texte | oui | — |
key | texte | non | un chemin partitionné par date plus l'identifiant de contrôle |
access_key_id | texte | non | — |
secret_access_key | texte | non | — |
session_token | texte | non | — |
endpoint | texte | non | — |
path_style | vrai ou faux | non | — |
server_side_encryption | texte | non | — |
content_type | texte | non | application/hl7-v2 pour HL7 et text/plain sinon |
framed | vrai ou faux | non | — |
timeout | durée, telle que 30s ou 5m | non | 60s |
storage_class | texte | non | — |
format | texte | non | — |
23.26.1 clé
La clé modélise la clé de l'objet, en utilisant les mêmes espaces réservés ${date}, ${timestamp}, ${control_id}, ${message_type} et ${channel} que les destinations de fichiers et SFTP.
Par défaut, un chemin partitionné par date plus l'identifiant de contrôle.
Partitionnement par date par défaut car l'alternative - tous les objets dans un préfixe plat - rend le bucket lent à lister et impossible à gérer par âge, et personne ne le découvre jusqu'à ce qu'il y ait quatre millions d'objets à l'intérieur.
23.26.2 access_key_id
AccessKeyID et SecretAccessKey authentifient.
L'un ou l'autre peut nommer une variable d'environnement au lieu de contenir la valeur, en utilisant la forme ${NAME}.
23.26.3 secret_access_key
AccessKeyID et SecretAccessKey authentifient.
L'un ou l'autre peut nommer une variable d'environnement au lieu de contenir la valeur, en utilisant la forme ${NAME}.
23.26.4 path_style
PathStyle adresse le bucket comme un chemin plutôt qu'un sous-domaine.
La plupart des magasins compatibles S3 ont besoin de cela.
23.26.5 content_type
ContentType étiquette l'objet.
Par défaut, application/hl7-v2 pour HL7 et text/plain sinon.
23.26.6 délai d'attente
Timeout limite une mise en ligne.
Defaults to 60s.
23.26.7 storage_class
StorageClass est la classe de stockage S3 que chaque objet est écrit avec : STANDARD_IA, INTELLIGENT_TIERING, GLACIER_IR, GLACIER, DEEP_ARCHIVE, etc.
C'est ainsi qu'un archive va directement à Glacier - S3 n'a pas d'API Glacier séparée à appeler.
23.26.8 format
Le format est hl7 (par défaut : chaque objet est le message) ou ndjson : chaque objet est une ligne JSON avec le message et les champs à interroger, sous des clés partitionnées par date, de sorte qu'Amazon Athena puisse interroger l'archive.
Voir perfuse athena.
23.27 Destination SFTP
SFTPDestination écrit chaque message dans un fichier sur un serveur SFTP.
Défini comme SFTPDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
host | texte | oui | 22 |
user | texte | oui | — |
password | texte | non | — |
key_file | texte | non | — |
key_passphrase | texte | non | — |
known_hosts_file | texte | non | — |
insecure_skip_host_key_check | vrai ou faux | non | — |
dir | texte | oui | — |
file_name | texte | non | une horodatage plus l'ID de contrôle |
temp_suffix | texte | non | " |
framed | vrai ou faux | non | — |
append | vrai ou faux | non | — |
timeout | durée, telle que 30s ou 5m | non | 60s |
23.27.1 hôte
L'hôte est le serveur, avec un port facultatif.
Defaults to 22.
23.27.2 mot de passe
Mot de passe authentifie avec un mot de passe.
Prefer KeyFile.
23.27.3 file_name
Le modèle de nom de fichier nomme le fichier.
Par défaut, c'est une horodatage plus l'ID de contrôle.
23.27.4 temp_suffix
Le suffixe temporaire est ajouté pendant que le fichier est écrit, et supprimé par une renommage une fois que c'est terminé.
Par défaut, c'est ".part".
La même courtoisie est nécessaire pour ce connecteur sur le chemin du retour. Quiconque collecte ces fichiers a le même problème, et une renommage dans un répertoire est atomique sur chaque serveur digne d'être utilisé.
23.27.5 délai d'attente
Timeout définit les limites d'une connexion unique.
Defaults to 60s.
23.28 Destination SMTP
La destination SMTP configure la livraison par e-mail.
Défini comme SMTPDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
host | texte | oui | — |
from | texte | oui | — |
to | liste de textes | oui | — |
cc | liste de textes | non | — |
bcc | liste de textes | non | — |
subject | texte | non | — |
body | texte | non | — |
attach | vrai ou faux | non | — |
attach_name | texte | non | l'ID de contrôle avec un |
username | texte | non | — |
password | texte | non | — |
starttls | vrai ou faux (un bloc, omis pour laisser hors) | non | — |
insecure_skip_verify | vrai ou faux | non | — |
timeout | durée, telle que 30s ou 5m | non | — |
23.28.1 hôte
L'hôte est le serveur de messagerie, avec un port facultatif.
Le port 587 est supposé, ce qui est la soumission avec STARTTLS - le port qu'un serveur moderne attend d'un client. Le port 25 est serveur-à-serveur et est généralement soit bloqué, soit non authentifié.
23.28.2 de
De est l'expéditeur de l'enveloppe.
Requis, car un message sans expéditeur est discrètement supprimé par une grande partie de l'infrastructure de messagerie, ce qui en fait la défaillance la plus difficile à diagnostiquer.
23.28.3 à
À, CC et BCC sont les destinataires.
Au moins un À est requis.
23.28.4 cc
À, CC et BCC sont les destinataires.
Au moins un À est requis.
23.28.5 bcc
À, CC et BCC sont les destinataires.
Au moins un À est requis.
23.28.6 corps
Le corps est le texte du message.
Les références de champ sont substituées, comme dans le sujet. Lorsqu'il est vide, le message lui-même est le corps.
23.28.7 nom_d'attachement
Le nom d'attachement nomme l'attachement.
Par défaut, c'est l'ID de contrôle avec un suffixe .hl7.
23.28.8 nom d'utilisateur
Le nom d'utilisateur et le mot de passe authentifient sur le serveur.
L'un ou l'autre, ou aucun des deux.
23.28.9 mot de passe
Le nom d'utilisateur et le mot de passe authentifient sur le serveur.
L'un ou l'autre, ou aucun des deux.
23.28.10 starttls
StartTLS met à niveau la connexion avant l'authentification.
Il est activé par défaut et la désactivation avec un nom d'utilisateur défini est refusée plutôt que d'être autorisée : envoyer un mot de passe via une connexion non chiffrée n'est pas un compromis qui vaille la peine d'être proposé.
23.28.11 insecure_skip_verify
InsecureSkipVerify accepte tout certificat.
Nommé de manière non ambiguë car c'est ce qu'il fait.
23.29 Destination SNS
SNSDestination publie chaque message sur un sujet SNS.
Défini comme SNSDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
topic_arn | texte | oui | — |
subject | texte | non | — |
group_by | texte | non | — |
23.29.1 sujet
Le sujet est envoyé avec les abonnements par e-mail.
Facultatif ; ${message_type} et ${control_id} sont remplis.
23.30 Destination SOAP
SOAPDestination publie une requête SOAP par message.
Défini comme SOAPDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
url | texte | oui | — |
profile | texte | non | — |
facility_id | texte | non | — |
warnings_are_errors | vrai ou faux | non | — |
action | texte | non | — |
version | texte | non | 1 |
body | texte | oui | — |
header | texte | non | — |
headers | mappage de texte à texte | non | — |
username | texte | non | — |
password | texte | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas inclure) | non | — |
fault_is_success | liste de texte | non | — |
timeout | durée, telle que 30s ou 5m | non | 30s |
23.30.1 profil
Le nom du profil désigne un service standard dont l'enveloppe Perfuse construit elle-même.
Vide est un appel SOAP simple avec le corps écrit dans ce fichier.
"cdc-iis" est l'interface du registre d'immunisation du CDC (urn:cdc:iisb:2011), que chaque registre d'État utilise : le message est envoyé dans submitSingleMessage, le nom d'utilisateur et le mot de passe sont dans le corps comme le WSDL le dit (et non comme authentification HTTP), SOAP 1.2 par défaut, et l'acknowledgement HL7 du registre décide si le message a été livré. Un registre répond à un rejet de tir avec un code HTTP 200 et un AR à l'intérieur, donc sans cela, un rejet est lu comme un succès.
23.30.2 facility_id
FacilityID est l'identifiant cdc-iis de l'organisation soumise.
Facultatif dans le WSDL ; certains registres l'exigent.
23.30.3 warnings_are_errors
WarningsAreErrors, pour cdc-iis, traite un accusé de réception AE contenant uniquement des avertissements comme une défaillance.
Désactivé par défaut : les registres envoient AE pour "accepté avec avertissements" et la gravité ERR indique si quelque chose a été perdu.
23.30.4 action
L'Action est le SOAPAction.
Requis par la plupart des services 1.1.
23.30.5 corps
Le corps est le XML qui se trouve à l'intérieur de l'enveloppe, avec des références de style ${PID-5.1} aux chemins de message.
Requis, sauf si un profil le construit. Il n'y a pas de valeur par défaut utile : les noms d'éléments proviennent du schéma propre au service et aucun moteur ne peut les deviner.
23.30.6 en-tête
L'en-tête est le XML pour l'élément d'en-tête de l'enveloppe.
Omis entièrement lorsqu'il est vide, car certains services refusent un en-tête vide.
23.30.7 fault_is_success
FaultIsSuccess liste les codes de défaillance qui sont considérés comme livrés.
Nécessaire plus souvent qu'il ne devrait l'être. Un service qui répond à une renvoi avec « déjà soumis » vous indique que le message est arrivé, et sans cela, un site doit écrire un transformateur de réponse pour le dire - ou pire, regarde une file d'attente réessayer à l'infini contre un récepteur qui a déjà le message.
23.30.8 délai d'attente
Délai d'attente limite une appel.
Defaults to 30s.
23.31 Destination SQS
La destination SQS envoie chaque message à une file d'attente SQS.
Défini comme SQSDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
queue_url | texte | oui | — |
group_by | texte | non | — |
23.31.1 queue_url
QueueURL nomme la file d'attente.
Une fin .fifo est une file d'attente FIFO, et est regroupée et dédoublonnée.
23.32 Destination TCP
TCPDest envoie des messages à un socket avec un encadrement configurable.
Défini comme TCPDest dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
address | texte | oui | — |
max_message_size | nombre entier | non | — |
timeout | durée, par exemple 30s ou 5m | non | — |
expect_reply | vrai ou faux | non | — |
keep_alive | vrai ou faux | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas inclure) | non | — |
23.32.1 expect_reply
ExpectReply attend des octets en retour avant de signaler la réussite.
Désactivé par défaut, et cela vaut la peine d'y réfléchir. Avec cette option désactivée, « livré » signifie que les octets ont atteint le tampon d'envoi du système d'exploitation, que un pair qui a crashé un instant plus tard n'a jamais lu. Avec cette option activée, un pair qui ne répond jamais fait expirer chaque message.
23.32.2 keep_alive
KeepAlive maintient une connexion ouverte sur plusieurs messages plutôt que de composer un numéro par message.
La plupart des points de terminaison d'appareil s'attendent à cela ; certains refusent un deuxième message sur la même connexion. Désactivé par défaut car une connexion par message est le comportement qui fonctionne partout, au prix d'une poignée de main à chaque fois.
23.33 Destination TEFCA
La destination TEFCA demande au partenaire FHIR facilité par TEFCA les dossiers de chaque patient du message.
Qui est ce serveur sur le réseau, son certificat et le partenaire sont des paramètres de serveur (Paramètres, TEFCA), car ils appartiennent à l'organisation et à son accord avec un QHIN. Ce que décide un canal est quand demander et pourquoi : l'objectif d'utilisation fait partie du canal, et non de qui est connecté, donc chaque requête qu'un flux effectue indique la même raison et la traçabilité peut être lue contre elle.
Défini comme TEFCADestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
purpose | texte | oui | — |
results_to | texte | non | — |
23.33.1 objectif
L'objectif est l'objectif d'utilisation : traitement, paiement, opérations, santé_publique ou accès_individuel.
Il doit s'agir d'un objectif que le participant déclare.
23.33.2 résultats_à
RésultatsÀ nomme un canal dans ce serveur qui reçoit chaque bundle que le partenaire retourne, comme un message à lui.
Vide conserve le bundle comme réponse de cette destination uniquement, pour qu'un transformateur de réponse puisse le lire.
23.34 Destination XDS
XDSDestination publie chaque document clinique dans un référentiel de documents XDS.b IHE avec ITI-41 Fournir et Enregistrer.
Les métadonnées sont lues à partir du document CDA (patient, titre, type, heure, auteur, confidentialité, langue) et complétées à partir de ces paramètres, qui indiquent ce que le document ne peut pas : qui l'envoie, quel type de facility et de pratique il provient, et lequel des identifiants du patient est le domaine d'affinité.
Défini comme XDSDestination dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
url | texte | oui | — |
source_id | texte | oui | — |
patient_domain | texte | non | — |
facility_type | XDSCode | oui | — |
practice_setting | XDSCode | oui | — |
class | XDSCode (un bloc, omis pour ne pas le configurer) | non | — |
content_type | XDSCode (un bloc, omis pour ne pas le configurer) | non | — |
token | texte | non | — |
username | texte | non | — |
password | texte | non | — |
headers | mappage de texte à texte | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas le configurer) | non | — |
timeout | durée, telle que 30s ou 5m | non | — |
direct_from | texte | non | — |
direct_to | liste de textes | non | — |
23.34.1 patient_domain
PatientDomain est l'autorité d'attribution du domaine d'affinité OID : l'identifiant de patient avec cette racine est celui qui est enregistré.
Sans cela, un document dont le patient a un identifiant envoie cet identifiant, et un avec plusieurs est refusé.
23.34.2 jeton
Le jeton ou le nom d'utilisateur/mot de passe authentifient ; les en-têtes sont ajoutés à chaque demande.
La plupart des domaines d'affinité utilisent le TLS mutuel (tls) à la place.
23.34.3 nom d'utilisateur
Le jeton ou le nom d'utilisateur/mot de passe authentifient ; les en-têtes sont ajoutés à chaque demande.
La plupart des domaines d'affinité utilisent le TLS mutuel (tls) à la place.
23.34.4 mot de passe
Le jeton ou le nom d'utilisateur/mot de passe authentifient ; les en-têtes sont ajoutés à chaque demande.
La plupart des domaines d'affinité utilisent le TLS mutuel (tls) à la place.
23.34.5 headers
Le jeton ou le nom d'utilisateur/mot de passe authentifient ; les en-têtes sont ajoutés à chaque demande.
La plupart des domaines d'affinité utilisent le TLS mutuel (tls) à la place.
23.34.6 tls
Le jeton ou le nom d'utilisateur/mot de passe authentifient ; les en-têtes sont ajoutés à chaque demande.
La plupart des domaines d'affinité utilisent le TLS mutuel (tls) à la place.
23.34.7 direct_from
DirectFrom et DirectTo font de la soumission XDR le transport Direct : un bloc d'adressage Direct nommant l'adresse Direct de l'expéditeur et celle des destinataires, et les destinataires dans l'intendedRecipient de la soumission.
Un HISP qui prend XDR le livre comme courrier Direct, ou à la fin de l'endpoint XDR du destinataire.
23.34.8 direct_to
DirectFrom et DirectTo font de la soumission XDR le transport Direct : un bloc d'adressage Direct nommant l'adresse Direct de l'expéditeur et celle des destinataires, et les destinataires dans l'intendedRecipient de la soumission.
Un HISP qui prend XDR le livre comme courrier Direct, ou à la fin de l'endpoint XDR du destinataire.
24 Référence de format
Options qui régissent la façon dont les messages sont analysés et écrits, pour les formats qui nécessitent plus qu'un nom.
24.1 Pièces jointes
Pièces jointes configure le déplacement de grandes charges utiles hors d'un message.
Un message transportant un rapport scanné ou un PDF est ordinaire dans les flux de documents, et la charge utile est régulièrement des centaines de fois plus grande que le message qui l'entoure. Laisser en ligne signifie que le magasin grandit au rythme des documents plutôt que du trafic, un message mis en file d'attente pour cinq destinations est copié cinq fois, et l'interface diffuse des mégaoctets pour montrer à quelqu'un un nom de patient.
Mirth appelle cela des gestionnaires de pièces jointes. C'est l'équivalent, et c'est opt-in par canal car un flux de messages ADT simples n'a rien à extraire et ne devrait pas payer pour le mécanisme.
Défini comme Attachments dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
extract | liste de règles d'attachement | oui | — |
reassemble | vrai ou faux (un bloc, omis pour laisser de côté) | non | vrai |
24.1.1 reassemble
Reassemble remet les charges utiles en place avant la livraison.
Par défaut à true.
La valeur par défaut est activée car un destinataire qui s'attend à un document doit recevoir un document ; un message contenant un jeton littéral serait classé comme un rapport et personne ne le découvrirait jusqu'à ce que quelqu'un ouvre le dossier.
La désactivation est utile dans les cas où l'objectif du canal est de supprimer les documents - transférer des métadonnées vers un système qui n'a pas besoin de l'image, où l'envoi poserait une question de confidentialité plutôt que de bande passante.
24.2 Délimité
Délimité configure un canal délimité.
Le type de données délimitées de Mirth : CSV, tabulé, et la longue liste de formats qu'un analyseur de laboratoire ou un service de bureau émet.
Défini comme Delimited dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
delimiter | texte | non | — |
quote | texte | non | une guillemet double |
comment | texte | non | — |
has_header | vrai ou faux | non | — |
columns | liste de textes | non | — |
trim_space | vrai ou faux | non | — |
relaxed | vrai ou faux | non | — |
split | vrai ou faux (un bloc, omis pour ne pas inclure) | non | vrai |
keep_blank_lines | vrai ou faux | non | — |
filter | texte | non | — |
transformations | liste d'étapes.Étape | non | — |
24.2.1 délimiteur
Le délimiteur sépare les colonnes, sous forme de caractère ou de nom.
Un nom est accepté car un tab ne peut pas être écrit dans un fichier YAML de manière non ambiguë, et un fichier de configuration contenant un caractère invisible est illisible pour qui que ce soit qui l'ouvre ensuite.
24.2.2 guillemet
Le guillemet entoure les valeurs contenant le délimiteur.
Par défaut, il est défini sur un guillemet double ; « none » le désactive.
24.2.3 diviser
La division rend chaque ligne son propre message.
Par défaut à true.
C'est la décision qui façonne un canal délimité et qui mérite d'être exprimée clairement. Un fichier de cinq mille résultats est soit un message, soit cinq mille. Un message signifie une seule accusé de réception, une seule entrée dans le navigateur et une seule erreur qui prend tout le fichier avec elle. Cinq mille signifient que chaque ligne est filtrée, transformée, livrée et réessayée individuellement, et qu'une seule ligne incorrecte n'arrête pas les autres.
La division est la valeur par défaut car la gestion par ligne est ce que presque tous les sites veulent, et parce que l'alternative est découverte tard : un canal qui semblait correct lors des tests avec un fichier de trois lignes échoue toute une nuit de transfert en raison d'une seule ligne malformée.
24.2.4 conserver_lignes_vides
ConserverLesLignesVides empêche les lignes vides d'être ignorées.
L'ignorance est la valeur par défaut, car chaque fichier se termine par un saut de ligne et qu'un enregistrement de champs vides n'est pas un enregistrement. Cela existe pour le format rare où une ligne vide est significative.
24.2.5 filtre
Le filtre décide quels messages continuent, écrit contre les noms de colonnes.
Ici plutôt que sur le canal, car le filtre de niveau canal compile les chemins HL7. Deux paramètres nommés filtre seraient confus, mais un paramètre qui signifie des choses différentes en fonction du type de données est pire : un canal délimité qui compile silencieusement son filtre comme HL7 ne correspondrait à rien et supprimerait tout, ce qui est la défaillance que le refus de niveau supérieur existe pour prévenir.
24.2.6 transformations
Les transformations sont les étapes déclaratives, qui s'adressent aux colonnes plutôt qu'aux champs HL7.
Séparé des transformations du canal pour la même raison que le filtre, et c'est l'arrangement que X12 et NCPDP utilisent déjà.
24.3 Options HL7v3
Les options HL7v3 sont les paramètres qui ne s'appliquent qu'à un canal HL7 v3.
Défini comme HL7v3Options dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
filter | texte | non | — |
acknowledge | vrai ou faux (un bloc, omis pour ne pas inclure) | non | — |
sender_device | texte | non | — |
sender_oid | texte | non | — |
transformations | liste de hl7v3.Step | non | — |
24.3.1 filtre
Le filtre exclut les messages en utilisant des chemins v3.
C'est son propre champ plutôt que le filtre ordinaire du canal, car les deux sont des langages différents contre des modèles de message différents. Le partage du champ signifierait qu'un filtre v2 ne correspondrait jamais silencieusement à un canal v3, ou qu'un filtre v3 ne parviendrait pas à analyser en tant que v2 - et la deuxième option n'est meilleure que parce qu'elle échoue bruyamment.
Un canal qui définit les deux est refusé lors du chargement, puisque l'un d'eux devrait être ignoré et qu'il n'y a pas de moyen honnête de choisir.
24.3.2 accuser réception
Accuser réception envoie un accusé de réception MCCI_IN000002UV01.
Activé par défaut, contrairement à X12. Une interaction v3 sur un transport synchrone attend un accusé de réception - l'application d'envoi attend généralement une réponse - et un expéditeur qui ne reçoit rien réessayera généralement, ce qui est la façon dont un patient est enregistré trois fois.
Un pointeur pour que « non défini » et « défini sur false » soient différents : la valeur par défaut est activée, et quelqu'un qui la désactive devrait l'avoir dit.
24.3.3 expéditeur_appareil
L'expéditeur_appareil est l'identifiant d'appareil que nous plaçons dans un accusé de réception.
Requis lors de l'accusé de réception. Un accusé de réception v3 nomme l'appareil dont il provient, et un récepteur qui ne reconnaît pas le nôtre peut le rejeter - ce qui ressemble exactement à ne pas l'envoyer.
24.3.4 transformations
Les transformations modifient le contenu d'un document v3.
C'est son propre champ plutôt que les transformations ordinaires du canal, pour la même raison que le filtre : ils sont des vocabulaires différents contre des modèles de message différents. Les étapes v2 s'adressent aux segments et aux champs, que un document v3 n'a pas, donc le partage du champ signifierait une étape qui ne ferait rien silencieusement.
Les noms d'étape correspondent aux noms v2 partout où le sens correspond, afin qu'une personne qui a écrit un canal puisse en écrire un autre. Ce qui est différent, c'est ce dont v3 a besoin et que v2 ne peut pas exprimer - principalement que la suppression d'une valeur a trois significations distinctes, donc clear, nullflavor et remove sont trois étapes plutôt qu'une.
24.4 Encadrement TCP
L'encadrement TCP est la façon dont les limites de message sont trouvées sur une socket brute.
Partagé par la source TCP et la destination TCP, et par la source série, car les encadrements sont les mêmes quelle que soit l'origine des octets. Un analyseur de laboratoire qui parle STX/ETX sur une socket parle STX/ETX sur un câble série également.
Défini comme TCPFraming dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
framing | texte | oui | — |
delimiter | texte | non | — |
start_block | texte | non | — |
keep_delimiter | vrai ou faux | non | — |
record_length | nombre entier | non | — |
trim_padding | vrai ou faux (un bloc, omis pour laisser intact) | non | — |
length_bytes | nombre entier | non | — |
big_endian | vrai ou faux | non | — |
length_includes_header | vrai ou faux | non | — |
24.4.1 encadrement
L'encadrement est mllp, délimité, fixe, longueur ou entier.
Requis, sans valeur par défaut. La lecture d'un flux avec un encadrement incorrect produit des messages qui semblent plausibles plutôt qu'une erreur, donc deviner est pire que demander.
24.4.2 bloc_de_début
Le bloc_de_début peut commencer un message.
Les octets avant lui sont rejetés comme du bruit d'une connexion partielle.
24.4.3 conserver_délimiteur
KeepDelimiter inclut le délimiteur dans le message.
Désactivé par défaut : il s'agit d'un encadrement, et non de contenu.
24.4.4 trim_padding
TrimPadding supprime les espaces et les NULs de fin d'un enregistrement fixe.
Activé par défaut.
24.5 Options X12
Les options X12 sont les paramètres qui ne s'appliquent qu'à un canal X12.
Défini comme X12Options dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
envelope | EnvelopePolicy | non | exiger |
split | vrai ou faux | non | — |
acknowledge | texte | non | — |
ack_sender_id | texte | non | — |
ack_sender_qualifier | texte | non | — |
arrives_as | texte | non | — |
transformations | liste de x12.Step | non | — |
24.5.1 envelope
Envelope indique ce qu'il faut faire lorsque les comptes auto-déclarés ne correspondent pas à ce qui est présent.
Par défaut, il est défini sur exiger.
24.5.2 diviser
Split envoie un message par ensemble de transactions au lieu d'un par fichier.
Désactivé par défaut. Un seul 837 peut contenir des centaines de réclamations, donc l'activation de cette option multiplie tout en aval - les comptes de messages, les accusés de réception, les lignes, les seuils d'alerte - et cela devrait être une décision prise par quelqu'un plutôt que par défaut hérité.
24.5.3 accuser réception
Acknowledge indique quel accusé de réception renvoyer : 999, 997, ta1 ou aucun.
Celui-ci est une propriété de la relation de partenaire commercial plutôt que du message, il doit donc être configuré. Un 999 remplace un 997 pour les transactions HIPAA, mais de nombreux partenaires - en particulier les connexions de payeur plus anciennes - sont configurés pour attendre un 997 et traiteront un 999 comme un fichier non reconnu. L'envoi du mauvais accusé de réception est pire que l'envoi d'aucun, car il répond à une question que personne n'a posée et laisse la vraie question ouverte.
Vide signifie aucun, ce qui est le paramètre par défaut sécurisé : un partenaire qui n'attend pas d'accusé de réception et en reçoit un peut le traiter comme un échange non sollicité.
24.5.4 ack_sender_id
AckSenderID et AckSenderQualifier sont notre propre identifiant d'échange, devenant ISA06 et ISA05 de tout accusé de réception.
Requis chaque fois que Acknowledge est défini, et refusé lors du chargement dans le cas contraire. Ces valeurs doivent être celles que le partenaire commercial a configurées pour nous et il n'y a pas moyen de deviner : un échange dont ISA06 n'est pas reconnu par le partenaire est supprimé avant que quiconque ne le lise, donc une valeur incorrecte produit un silence qui ressemble exactement à ne rien envoyer - et quelqu'un passe une semaine à regarder au mauvais endroit.
24.5.5 ack_sender_qualifier
AckSenderID et AckSenderQualifier sont notre propre identifiant d'échange, devenant ISA06 et ISA05 de tout accusé de réception.
Requis chaque fois que Acknowledge est défini, et refusé lors du chargement dans le cas contraire. Ces valeurs doivent être celles que le partenaire commercial a configurées pour nous et il n'y a pas moyen de deviner : un échange dont ISA06 n'est pas reconnu par le partenaire est supprimé avant que quiconque ne le lise, donc une valeur incorrecte produit un silence qui ressemble exactement à ne rien envoyer - et quelqu'un passe une semaine à regarder au mauvais endroit.
24.5.6 arrive_en_tant_que
ArriveEnTantQue est xml lorsque la source livre l'échange sous la forme XML que Mirth Connect et Open Integration Engine écrivent pour X12 (une racine X12Transaction, des éléments nommés CLM.05.1), comme un moteur en cours de migration à partir d'un ou d'un système construit contre l'un, l'envoie.
Il est reconvertis en X12 avant que quoi que ce soit d'autre se produise. Vide ou x12 est X12.
24.5.7 transformations
Les transformations sont des modifications déclaratives appliquées aux échanges acceptés.
Séparé des transformations au niveau du canal pour la même raison que les v3 : celles-ci s'adressent aux champs HL7 à travers un analyseur qui lit segment-champ-composant-sous-composant, et X12 n'a pas de sous-composant, traite les segments répétés comme ordinaires plutôt que comme exceptionnels, et est écrit CLM01 par les personnes qui le configurent. Un analyseur partagé devrait accepter les deux notations et serait alors ambigu dans les deux.
Les noms d'étape sont les mêmes que ceux utilisés par les étapes HL7 et v3, donc ce que l'auteur a déjà appris est applicable.
25 Référence de comportement
Accusé de réception, file d'attente, nouvelle tentative, interrogation et paramètres de script et d'ombre. Ces paramètres s'appliquent quel que soit le transport utilisé par un canal.
25.1 Connexion AMQP
AMQPConnection définit où et en tant que qui se connecter.
Défini comme AMQPConnection dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
addr | texte | oui | — |
address | texte | oui | — |
username | texte | non | — |
password | texte | non | — |
hostname | texte | non | l'hôte de addr |
tls | tlsconf.Settings (un bloc, omis pour ne pas inclure) | non | — |
timeout | durée, telle que 30s ou 5m | non | 30s |
25.1.1 nom d'utilisateur
Le nom d'utilisateur et le mot de passe s'authentifient avec SASL PLAIN ; les deux vides signifient ANONYMOUS.
Pour Service Bus, le nom de la stratégie et la clé.
25.1.2 mot de passe
Le nom d'utilisateur et le mot de passe s'authentifient avec SASL PLAIN ; les deux vides signifient ANONYMOUS.
Pour Service Bus, le nom de la stratégie et la clé.
25.1.3 nom d'hôte
Le nom d'hôte est envoyé au courtier, qui route Service Bus.
Par défaut, l'hôte de addr.
25.1.4 tls
TLS chiffre la connexion.
Requis pour Service Bus et Event Hubs.
25.1.5 délai d'attente
Délai d'attente pour la connexion et chaque attente du courtier.
Defaults to 30s.
25.2 Partenaire AS2
AS2Partner est un partenaire commercial qu'une source AS2 accepte des messages de.
Défini comme AS2Partner dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
id | texte | oui | — |
cert_file | texte | oui | — |
allow_unsigned | vrai ou faux | non | — |
allow_unencrypted | vrai ou faux | non | — |
25.2.1 cert_file
CertFile est le certificat du partenaire (PEM), pour ses signatures.
Souvent auto-signé : les partenaires AS2 échangent des certificats directement plutôt que par l'intermédiaire d'une autorité.
25.2.2 allow_unsigned
AllowUnsigned et AllowUnencrypted acceptent un message de ce partenaire qui n'est pas signé ou non chiffré.
Désactivé : un tel message est refusé avec un reçu indiquant pourquoi.
25.2.3 allow_unencrypted
AllowUnsigned et AllowUnencrypted acceptent un message de ce partenaire qui n'est pas signé ou non chiffré.
Désactivé : un tel message est refusé avec un reçu indiquant pourquoi.
25.3 Accès AWS
L'accès AWS est la façon dont un connecteur atteint AWS : la région pour laquelle il signe, les clés et une substitution de point de terminaison facultative.
Les informations d'identification peuvent être littérales ou des références ${ENV_VAR}, c'est ainsi qu'elles devraient être fournies. Il n'y a pas de chaîne d'informations d'identification d'instance de métadonnées, délibérément : voir internal/awsv4.
Défini comme AWSAccess dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
region | texte | oui | — |
access_key_id | texte | non | — |
secret_access_key | texte | non | — |
session_token | texte | non | — |
endpoint | texte | non | — |
25.3.1 secret_access_key
SecretAccessKey est le secret, littéral ou ${AWS_SECRET_ACCESS_KEY}.
Préférez la référence : ce fichier est intégré au contrôle de version.
25.3.2 jeton de session
SessionToken est destiné aux informations d'identification temporaires uniquement.
Elles expirent et le connecteur cesse de fonctionner lorsqu'elles le font.
25.4 Accusé de réception
Ack configure la génération d'accusés de réception.
Défini comme Ack dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
when | AckWhen | non | — |
application | texte | non | — |
facility | texte | non | — |
include_trigger_event | vrai ou faux | non | — |
25.4.1 inclure_l'événement_déclencheur
IncludeTriggerEvent envoie ACK^A01 plutôt que ACK.
Certains récepteurs l'exigent et d'autres le rejettent, il est donc explicite.
25.5 Accès au blob Azure
AzureBlobAccess est le compte, le conteneur et l'information d'identification.
Défini comme AzureBlobAccess dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
account | texte | oui | — |
container | texte | oui | — |
key | texte | non | — |
sas | texte | non | — |
endpoint | texte | non | — |
25.5.1 clé
La clé est la clé du compte, ou ${AZURE_STORAGE_KEY}.
Définissez-le ou sas.
25.5.2 sas
SAS est une chaîne de requête de signature d'accès partagé, ou une référence ${...}.
Préféré : il peut être limité à ce conteneur.
25.6 Référence de contrat
ContractRef pointe un canal vers son contrat.
Défini comme ContractRef dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
file | texte | oui | — |
check_every | texte | non | 15 minutes |
over | nombre entier | non | 500 |
25.6.1 check_every
CheckEvery est la fréquence à laquelle réévaluer, sous forme de durée.
Par défaut, 15 minutes.
En pratique, cette valeur est limitée à l'intervalle d'évaluation des alertes, qui est de 30 secondes par défaut, car la vérification s'exécute à partir de cette boucle plutôt que d'un minuteur propre - donc un contrat demandant 3s obtient 30s. C'est délibéré : un minuteur est plus facile à comprendre qu'un autre, et cela maintient le résultat d'un contrat en phase avec la lecture à laquelle il est attaché. Il est utile de le savoir avant que quelqu'un ne définisse un intervalle court et ne conclue qu'il est défectueux.
Pas par message. La construction d'un profil signifie la lecture du trafic récent, et le faire sur chaque message rendrait le débit d'un canal dépendant de l'historique dont il dispose - ce qui est le type de caractéristique de performance qui n'apparaît que en production, six mois plus tard.
25.6.2 over
Over est le nombre de messages récents à profiler.
Defaults to 500.
Un comptage plutôt qu'une fenêtre de temps, car un flux calme et un flux occupé ont besoin de la même quantité de preuves pour justifier un taux, et une fenêtre de temps leur donne des quantités très différentes.
25.7 Options DICOM
DICOMOptions configure un canal d'imagerie.
Pourquoi les étapes sont nommées plutôt que des chemins
Tout autre format obtient un écrivain de chemin. DICOM ne l'a pas délibérément, et la raison est les données de pixels : un objet est binaire, un écrivain de balise général peut définir n'importe quelle balise sur n'importe quels octets, et une erreur là-bas ne produit pas un message rejeté - il produit une image qui s'ouvre et est incorrecte. Un radiologue lisant une étude n'a aucun moyen de le savoir.
Donc, les quatre choses dont les sites ont vraiment besoin sont des actions nommées avec des effets limités : désidentifier, réécrire un titre AE, supprimer des balises privées, définir l'institution. Chacun sait quels balises il touche, et aucun ne peut atteindre les données de pixels.
Pourquoi ce bloc existe maintenant
internal/dicom a transporté steps.go et transform.go depuis un certain temps - les quatre actions, dicom.Apply, et les tests. Rien ne les référençait. Cinq cents lignes sans appelant, que la section 7 de la file d'attente nomme : une implémentation sans appelant est indiscernable d'une fonctionnalité qui n'existe pas. Ce bloc et l'appel du moteur sont le câblage, et non la fonctionnalité.
Défini comme DICOMOptions dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
transformations | liste de dicom.Step | non | — |
25.8 Adresse directe
DirectAddress est une adresse Direct que ce serveur détient : son certificat et sa clé, et les ancres qu'il fait confiance.
Le même bloc est utilisé pour envoyer (signer en tant qu'adresse) et pour recevoir (déchiffrer pour elle).
Défini comme DirectAddress dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
address | texte | oui | — |
cert_file | texte | oui | — |
key_file | texte | oui | — |
anchors_file | texte | oui | — |
25.8.1 cert_file
CertFile et KeyFile sont le certificat de l'adresse (PEM, avec sa chaîne après) et la clé privée (PEM).
Le HISP ou son autorité d'enregistrement les émet ; ils constituent l'identité de l'adresse.
25.8.2 key_file
CertFile et KeyFile sont le certificat de l'adresse (PEM, avec sa chaîne après) et la clé privée (PEM).
Le HISP ou son autorité d'enregistrement les émet ; ils constituent l'identité de l'adresse.
25.8.3 anchors_file
AnchorsFile est les ancres de confiance (PEM) : les autorités de certification dont les expéditeurs et les destinataires de cette adresse font confiance, comme le bundle DirectTrust.
Un message signé par autre chose est refusé.
25.9 Direct IMAP
DirectIMAP est la boîte aux lettres HISP qu'une source Direct lit.
Défini comme DirectIMAP dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
host | texte | oui | — |
port | nombre entier | non | — |
security | texte | non | — |
username | texte | oui | — |
password | texte | non | — |
mailbox | texte | non | — |
after_read | texte | non | — |
move_to | texte | non | — |
error_folder | texte | non | — |
poll_interval | durée, telle que 30s ou 5m | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas inclure) | non | — |
25.9.1 move_to
MoveTo est le dossier dans lequel les messages déplacés sont déplacés ; Traités par défaut.
Créé lorsqu'il est manquant.
25.9.2 tls
TLS fait confiance à un fichier CA (ou au certificat propre du HISP) et nomme le serveur attendu dans celui-ci, pour un HISP dont le certificat IMAP n'est pas délivré par une autorité publique.
Le certificat est toujours vérifié.
25.10 Direct XDR
DirectXDR est l'endpoint qu'une source Direct prend XDR.
Défini comme DirectXDR dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
listen | texte | oui | — |
tls_cert | texte | non | — |
tls_key | texte | non | — |
client_ca_file | texte | non | — |
25.11 Établissement ECR
ECRFacility est l'organisation qui envoie des rapports de cas.
Défini comme ECRFacility dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
name | texte | oui | — |
npi | texte | non | — |
phone | texte | oui | — |
line | texte | non | — |
city | texte | oui | — |
state | texte | oui | — |
postal_code | texte | non | — |
25.12 Options EDIFACT
EDIFACTOptions sont les paramètres qui ne s'appliquent qu'à un canal EDIFACT.
Défini comme EDIFACTOptions dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
envelope | texte | non | — |
split | vrai ou faux | non | — |
acknowledge | texte | non | — |
25.12.1 accuser réception
Acknowledge répond à un expéditeur qui publie via HTTP avec un CONTRL dans la réponse : accepté (action 7) lorsque l'échange a été lu et livré, rejeté (4) sinon.
Default none.
25.13 OAuth de messagerie électronique
EmailOAuth se connecte avec OAuth 2.0 (SASL XOAUTH2), que Microsoft 365 et Gmail exigent à la place d'un mot de passe.
Défini comme EmailOAuth dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
provider | texte | oui | — |
tenant | texte | non | — |
token_url | texte | non | — |
client_id | texte | oui | — |
client_secret | texte | non | — |
refresh_token | texte | non | — |
scope | texte | non | — |
25.13.1 client_secret
ClientSecret peut être ${ENV}.
Sans refresh_token, il sélectionne l'octroi d'informations d'identification du client uniquement pour l'application Microsoft.
25.13.2 refresh_token
RefreshToken peut être ${ENV} : une boîte de messagerie à laquelle une personne a consenti.
Requis pour Gmail.
25.14 Authentification FHIR
FHIRAuth est la manière dont une destination FHIR s'authentifie auprès d'un service FHIR hébergé.
Trois présélections, car les services hébergés sont là où un jeton porteur collé dans un fichier cesse de fonctionner dans l'heure :
- aws : AWS HealthLake, qui prend des requêtes signées avec la version 4 de signature pour le service « healthlake » - aucun jeton du tout. - azure : Azure Health Data Services, qui prend un jeton d'ID Microsoft Entra pour le public de son propre service FHIR, obtenu avec l'octroi de client-credentials d'un enregistrement d'application qui détient le rôle de contributeur de données FHIR. - client_credentials : n'importe quel point de terminaison de jeton OAuth 2.0 - Keycloak, Okta, un service de backend SMART avec un secret client.
Les jetons sont récupérés lorsqu'ils sont nécessaires et réutilisés jusqu'à une minute avant leur expiration.
Défini comme FHIRAuth dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
type | texte | oui | — |
region | texte | non | — |
access_key_id | texte | non | — |
secret_access_key | texte | non | — |
session_token | texte | non | — |
tenant_id | texte | non | — |
token_url | texte | non | — |
client_id | texte | non | — |
client_secret | texte | non | — |
scope | texte | non | — |
25.14.1 région
La région est la région AWS.
Lue à partir d'une URL HealthLake lorsqu'elle n'est pas donnée.
25.14.2 token_url
TokenURL est le point de terminaison de jeton OAuth, pour client_credentials.
Pour azure, il est dérivé du locataire.
25.14.3 client_id
ClientID et ClientSecret identifient l'application.
Le secret peut être une référence ${ENV}, ce qui est la façon dont il devrait être donné.
25.14.4 client_secret
ClientID et ClientSecret identifient l'application.
Le secret peut être une référence ${ENV}, ce qui est la façon dont il devrait être donné.
25.14.5 scope
La portée est demandée avec le jeton.
Pour azure, elle est par défaut l'URL du service FHIR suivie de /.default, qui est son public.
25.15 Sondage de fichiers
FilePoll est la partie d'une source de collecte de fichiers qui n'a rien à voir avec le transport.
Partagé par les sources locales, FTP, SMB et WebDAV, et par SFTP. Chacune de ces paramètres existe en raison d'une façon dont les fichiers peuvent aller mal plutôt que d'une façon dont les transports diffèrent, ce qui explique pourquoi ils appartiennent ensemble : un site qui a trouvé les bons paramètres stable_for pour son analyseur ne devrait pas avoir à les retrouver à nouveau lorsque l'analyseur est déplacé vers un partage.
Défini comme FilePoll dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
dir | texte | oui | — |
pattern | texte | non | — |
poll_interval | durée, telle que 30s ou 5m | non | — |
after_read | texte | non | — |
move_to | texte | non | — |
error_dir | texte | non | — |
stable_for | durée, telle que 30s ou 5m | non | — |
max_file_size | nombre entier | non | — |
framed | vrai ou faux | non | — |
raw | vrai ou faux | non | — |
batch_size | nombre entier | non | — |
sort_by | texte | non | name |
25.15.1 modèle
Le modèle sélectionne les fichiers par glob.
Vide signifie chaque fichier.
25.15.2 répertoire_erreur
ErrorDir est l'endroit où un fichier qui n'a pas pu être traité est stocké.
Séparé de MoveTo intentionnellement. Un répertoire qui ne contient que des échecs est quelque chose que quelqu'un peut surveiller, et mélanger les échecs avec les archives signifie que la seule façon de les trouver est de lire chaque fichier.
25.15.3 brut
Raw traite l'ensemble du fichier comme un seul message, quel que soit le contenu.
Le paramètre qui rend ce connecteur utile pour autre chose que HL7. Sans cela, un lot CSV, un fichier de réclamation X12 ou un PDF est divisé en lignes commençant par MSH et ne produit rien, et l'erreur indique que le fichier n'est pas HL7 - vrai mais pas le point, puisque le fichier n'était jamais destiné à l'être.
25.15.4 taille_de_lot
BatchSize limite le nombre de fichiers lus lors d'une interrogation.
Zéro signifie pas de limite.
Existe pour la première interrogation après une panne. Un répertoire contenant quarante mille fichiers accumulés pendant la nuit sera lu en une seule passe, ce qui bloque la boucle d'interrogation pendant autant de temps qu'il le faut et fait que le canal semble bloqué. La lecture d'un nombre limité de fichiers par interrogation maintient le canal réactif et la file d'attente se vidant de manière visible.
25.15.5 sort_by
SortBy ordonne les fichiers au sein d'une interrogation : nom, modifié ou aucun.
Par défaut, c'est le nom. L'ordre est plus important qu'il n'y paraît : un flux ADT où les mises à jour A08 arrivent avant l'admission A01 produit des patients qui n'existent pas encore. L'ordre de la liste de répertoire est arbitraire sur la plupart des systèmes de fichiers, donc laisser sans tri signifie que l'ordre change entre les interrogations pour aucune raison visible.
25.16 Accès GCP
GCPAccess est la façon d'authentifier auprès de Google Cloud.
Défini comme GCPAccess dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
project | texte | non | — |
credentials_file | texte | non | — |
endpoint | texte | non | — |
25.16.1 fichier_de_credentials
CredentialsFile est une clé JSON d'un compte de service.
Vide utilise le compte de service attaché à la VM, au pod GKE ou au service Cloud Run sur lequel Perfuse s'exécute (le serveur de métadonnées), à moins que l'endpoint ne nomme un émulateur.
25.17 Accès GCS
GCSAccess est un bucket de stockage Cloud.
Défini comme GCSAccess dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
bucket | texte | oui | — |
25.18 Connexion IBMMQ
IBMMQConnection est une file d'attente accessible via l'API REST de messagerie du gestionnaire de files d'attente.
Défini comme IBMMQConnection dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
url | texte | oui | — |
queue_manager | texte | oui | — |
queue | texte | oui | — |
username | texte | non | — |
password | texte | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas le configurer) | non | — |
api_version | texte | non | — |
timeout | durée, telle que 30s ou 5m | non | 30s |
25.18.1 nom d'utilisateur
Le nom d'utilisateur et le mot de passe sont un utilisateur mqweb avec le rôle MQWebUser ; le mot de passe peut être ${ENV}.
Laissez les deux vides lorsque le certificat client (tls.cert_file) authentifie.
25.18.2 mot de passe
Le nom d'utilisateur et le mot de passe sont un utilisateur mqweb avec le rôle MQWebUser ; le mot de passe peut être ${ENV}.
Laissez les deux vides lorsque le certificat client (tls.cert_file) authentifie.
25.18.3 délai d'attente
Le délai d'attente limite chaque demande.
Defaults to 30s.
25.19 SASL Kafka
KafkaSASL authentifie à un cluster Kafka.
Défini comme KafkaSASL dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
mechanism | texte | oui | — |
username | texte | oui | — |
password | texte | oui | — |
25.19.1 mécanisme
Le mécanisme est « plain », « scram-sha-256 » ou « scram-sha-512 ».
PLAIN envoie le mot de passe lisible sur le fil, il appartient donc au TLS. SCRAM ne le fait pas, c'est pourquoi il vaut la peine de nommer la différence ici plutôt que de traiter les trois de manière interchangeable.
25.19.2 mot de passe
Le mot de passe est le mot de passe SASL.
Prend en charge les références ${ENV} comme tous les autres secrets ici, donc une référence de cluster n'a pas besoin d'être écrite dans le fichier de canal.
25.20 Connexion MQTT
MQTTConnection est la façon de rejoindre un courtier MQTT 3.1.1 : Mosquitto, EMQX, HiveMQ, AWS IoT Core, Azure Event Grid.
Défini comme MQTTConnection dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
addr | texte | oui | — |
client_id | texte | non | — |
username | texte | non | — |
password | texte | non | — |
tls | tlsconf.Settings (un bloc, omis pour ne pas inclure) | non | — |
qos | nombre entier (un bloc, omis pour ne pas inclure) | non | — |
timeout | durée, telle que 30s ou 5m | non | 30s |
25.20.1 client_id
L'ID client nomme la session.
Une source conserve ses messages à travers les reconnexions uniquement sous un ID client fixe ; il est par défaut perfuse-<channel>.
25.20.2 nom d'utilisateur
Le nom d'utilisateur et le mot de passe authentifient ; l'un ou l'autre peut être vide.
Le mot de passe peut être ${ENV}.
25.20.3 mot de passe
Le nom d'utilisateur et le mot de passe authentifient ; l'un ou l'autre peut être vide.
Le mot de passe peut être ${ENV}.
25.20.4 délai d'attente
Délai d'attente pour la connexion et chaque attente du courtier.
Defaults to 30s.
25.21 Options NCPDP
Les options NCPDP sont les paramètres qui ne s'appliquent qu'à un canal de réclamation de pharmacie.
Défini comme NCPDPOptions dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
transformations | liste de ncpdp.Step | non | — |
25.21.1 transformations
Les transformations sont des modifications déclaratives appliquées à chaque transmission avant la livraison.
Le même vocabulaire que tous les autres formats - définir, copier, effacer, mapper, remplacer, tronquer, cas, chacun avec une condition facultative - car le moteur d'étapes dans internal/steps est générique. Ce qui diffère est la notation : un chemin est écrit D1 ou 07-D7, en utilisant les identificateurs de champ à deux caractères propres à la norme.
25.22 Réception PGP
PGPReceive ouvre ce que une source reçoit avec OpenPGP : déchiffré avec notre clé secrète, et sa signature vérifiée contre les clés publiques des expéditeurs.
Défini comme PGPReceive dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
decrypt_with | texte | non | — |
passphrase | texte | non | — |
verify_with | liste de texte | non | — |
require_signature | vrai ou faux | non | — |
allow_unencrypted | vrai ou faux | non | — |
pass_plain | vrai ou faux | non | — |
25.22.1 decrypt_with
DecryptWith est notre fichier de clé secrète.
Requis à moins que allow_unencrypted ne soit activé et que les messages soient uniquement signés.
25.22.2 passphrase
La phrase de passe débloque DecryptWith lorsqu'il est protégé.
Préférez une référence de variable d'environnement, ${NAME}.
25.22.3 verify_with
VerifyWith sont les fichiers de clés publiques des expéditeurs.
Une signature de l'un d'eux est vérifiée et enregistrée.
25.22.4 pass_plain
PassPlain laisse un message qui n'est pas du tout PGP passer inchangé, pour un dossier qui reçoit les deux.
Désactivé : un tel message est refusé, donc un expéditeur qui a oublié de chiffrer est informé.
25.23 Envoi PGP
PGPSend protège ce qu'une destination livre avec OpenPGP : chiffré à la clé publique du destinataire, signé avec la nôtre, ou les deux.
Les payeurs, les organismes de compensation et les agences étatiques prennent souvent des fichiers via SFTP uniquement de cette façon.
Défini comme PGPSend dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
encrypt_to | liste de texte | non | — |
sign_with | texte | non | — |
passphrase | texte | non | — |
armor | vrai ou faux | non | — |
no_compress | vrai ou faux | non | — |
file_name | texte | non | — |
25.23.1 encrypt_to
EncryptTo sont les fichiers de clés publiques des destinataires (armure ou binaire).
Le message est lisible par n'importe lequel d'entre eux. Vide : le message n'est signé que.
25.23.2 sign_with
SignWith est notre fichier de clé secrète, pour signer chaque message.
Vide : chiffré uniquement.
25.23.3 passphrase
La phrase de passe déverrouille SignWith lorsqu'il est protégé.
Préférez une référence de variable d'environnement, ${NAME}.
25.24 Configuration de la file d'attente
QueueConfig active la file d'attente durable pour une destination.
Sans cela, une destination qui est hors service pendant deux minutes perd tout ce qui a été envoyé pendant ces deux minutes : les réessais se produisent en mémoire et lorsqu'ils sont épuisés, le message est enregistré comme ayant échoué et est perdu. Avec cela, le message est sur disque et conserve sa place jusqu'à ce que le destinataire revienne.
Il est désactivé par défaut, ce qui est un choix délibéré plutôt que de la prudence. Une file d'attente modifie ce qu'une acknowledgement signifie et modifie le comportement d'ordre pendant une panne, et les deux sont des choses que l'opérateur devrait opter pour sciemment plutôt que de les découvrir.
Défini comme QueueConfig dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
enabled | vrai ou faux | non | — |
max_attempts | nombre entier | non | — |
backoff | durée, telle que 30s ou 5m | non | — |
max_backoff | durée, telle que 30s ou 5m | non | — |
max_depth | nombre entier | non | — |
retain_hours | nombre entier | non | — |
25.24.1 nombre_de_tentatives
MaxAttempts est le nombre de fois que la file d'attente tente avant de marquer un message comme ayant échoué et de passer au suivant.
Zéro signifie continuer à essayer indéfiniment, ce qui est légitime pour un flux qui ne doit pas perdre quoi que ce soit, mais devrait être choisi plutôt qu'hérité.
25.24.2 max_backoff
MaxBackoff limite la durée de retard croissante.
La valeur par défaut est d'une minute plutôt que de quelque chose de plus grand, car un destinataire qui revient après une brève panne devrait être trouvé rapidement : un plafond d'une heure transforme un blip de deux minutes en une heure de retard.
25.24.3 max_depth
MaxDepth refuse les nouveaux messages une fois que ce nombre est en attente, afin qu'un destinataire qui a été hors service pendant une semaine ne puisse pas remplir le disque.
Zéro signifie pas de limite.
Lorsque la limite est atteinte, le message est considéré comme ayant échoué plutôt que d'être mis en file d'attente, et l'expéditeur est informé - ce qui est la réponse honnête, car nous ne promettons plus de le livrer.
25.24.4 retain_hours
RetainHours est la durée pendant laquelle les éléments livrés et abandonnés sont conservés avant d'être purgés.
Ils sont conservés afin que quelqu'un qui surveille le drainage d'une file d'attente puisse voir ce qui se passe, et afin qu'un message abandonné puisse être trouvé par la suite.
25.25 Réessai
Retry contrôle la réexpédition après une défaillance.
Défini comme Retry dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
attempts | nombre entier | non | — |
backoff | durée, telle que 30s ou 5m | non | — |
max_backoff | durée, telle que 30s ou 5m | non | — |
25.25.1 tentatives
Les tentatives représentent le nombre total de tentatives, y compris la première.
Zéro signifie la valeur par défaut.
25.25.2 backoff
Le backoff est le délai d'attente avant la deuxième tentative.
Il double à chaque fois, jusqu'à MaxBackoff.
25.26 Options de script
ScriptOptions configure un canal NCPDP SCRIPT.
Pourquoi SCRIPT obtient un bloc lorsque son filtre est de niveau supérieur
Le filtre de canal pour chaque type de données est la clé de filtre de niveau supérieur, car internal/expr est générique sur le type de message : une clé, compilée contre l'arbre ou la revendication que le canal transporte. Les étapes ne peuvent pas être organisées de cette manière. Une étape v2 s'adresse à un segment et à un champ, une étape X12 s'adresse à un élément à largeur fixe, et les types sont différents, donc une clé yaml devrait contenir celui que le type de données implique - ce qui est un champ qui signifie des choses différentes en fonction d'un autre champ, et le mode d'échec est une étape qui se fait silencieusement sans rien faire.
Donc cela suit hl7v3, x12, ncpdp et délimité : les étapes vivent dans le bloc de format propre, et la clé de transformations de niveau supérieur est refusée sur un canal SCRIPT plutôt que d'être acceptée et ignorée.
Défini comme ScriptOptions dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
transformations | liste de hl7v3.Step | non | — |
25.26.1 transformations
Les transformations sont les étapes déclaratives, qui s'adressent à la prescription comme un arbre XML.
hl7v3.Step plutôt qu'un type propre, et ce n'est pas de la paresse. Une prescription et un document v3 sont tous deux des XML, la grammaire de chemin est la même, et internal/eprescribe emprunte déjà hl7v3.Path pour son filtre avec un commentaire qui le dit - v3 et CDA l'utilisent déjà, et une troisième copie serait un troisième ensemble de réponses à ce que //a/b[2]@c signifie.
Les étapes qui portent un sens propre à v3 sont refusées lors du chargement plutôt que d'être silencieusement disponibles. nullflavor est le seul : il écrit l'attribut v3 indiquant pourquoi une valeur est absente, ce que une prescription n'a pas d'équivalent, et une étape qui l'écrirait produirait un document que le destinataire ne comprend pas.
25.27 Scripts
Scripts contient le JavaScript attaché à un canal.
Défini comme Scripts dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
filter | texte | non | — |
transformer | texte | non | — |
preprocessor | texte | non | — |
deploy | texte | non | — |
undeploy | texte | non | — |
postprocessor | texte | non | — |
language | texte | non | — |
timeout | durée, telle que 30s ou 5m | non | — |
include | liste de texte | non | — |
file_roots | liste de texte | non | — |
allow | liste de texte | non | — |
25.27.1 filtre
Le filtre s'exécute après le filtre d'expression, si disponible, et doit renvoyer un booléen.
Un script de filtre Mirth se glisse ici inchangé.
25.27.2 transformer
Le transformateur s'exécute après les étapes déclaratives et peut modifier le message.
Un script de transformateur Mirth se glisse ici inchangé.
25.27.3 préprocesseur
Le préprocesseur s'exécute avant que le message ne soit analysé, lit le texte en tant que « message » et retourne le texte à analyser.
Un préprocesseur Mirth est inséré ici sans modification.
C'est le seul endroit où un message qui ne peut pas être analysé peut être réparé. Les sites l'utilisent pour un caractère errant provenant d'une passerelle série, un terminateur de segment qui est arrivé sous forme de saut de ligne, ou un fournisseur qui remplit un champ avec quelque chose d'illégal pour sa position. Sans cela, Perfuse rejette le trafic que Mirth accepte aujourd'hui.
25.27.4 déployer
Le déploiement s'exécute une seule fois lorsque le canal démarre, avant qu'il n'accepte quoi que ce soit.
C'est ici que les sites réchauffent une cache de recherche ou vérifient que quelque chose sur quoi ils dépendent est accessible. Il s'exécute avant que la source ne soit liée, donc un script de déploiement qui échoue empêche le canal de démarrer plutôt que de laisser accepter des messages qu'il ne peut pas gérer.
25.27.5 annuler le déploiement
L'annulation du déploiement s'exécute une seule fois lorsque le canal s'arrête.
Après que la source a cessé d'accepter et après que les messages en cours ont terminé, donc il voit un canal qui est réellement inactif. Son échec ne peut pas arrêter une arrêt : un canal qui ne pouvait pas être arrêté parce qu'un script de nettoyage a généré une exception serait pire qu'un qui a enregistré et fermé.
25.27.6 postprocesseur
Le postprocesseur s'exécute après que le message a été traité et ne peut pas le modifier.
Le message et ce qui lui est arrivé sont visibles, il peut donc notifier, compter ou enregistrer. Il ne peut pas modifier ce qui a été envoyé : au moment où il s'exécute, l'envoi a déjà eu lieu, et un script qui semblait modifier un message livré mentirait à ce sujet.
25.27.7 langage
Le langage est celui dans lequel ces scripts sont écrits : javascript ou lua.
Pourquoi un paramètre pour l'ensemble du bloc plutôt qu'un par script
Les scripts d'un canal partagent la carte de canal et la carte de connecteur, et ils sont lus ensemble par celui qui les maintient. Un filtre en Lua à côté d'un transformateur en JavaScript signifierait deux langages dans une revue, partageant un état à travers une carte dont les valeurs devraient avoir le même sens dans les deux. Les sites qui veulent cela peuvent diviser le canal.
Pourquoi le paramètre par défaut est javascript
Chaque script écrit avant que ce paramètre n'existe est en JavaScript et ne dit rien sur son langage. Faire de lua le paramètre par défaut interpréterait silencieusement tous les scripts ; exiger le champ les refuserait. Ni l'un ni l'autre n'est acceptable pour un paramètre ajouté plus tard.
25.27.8 délai d'attente
La limite de temps encadre chaque script.
Zéro signifie cinq secondes.
Il n'y a délibérément pas de moyen de la désactiver. Mirth permet à un transformateur de boucler indéfiniment, ce qui arrête le canal, et une interface qui cesse d'accepter les admissions en raison d'une faute de frappe n'est pas quelque chose qu'on peut offrir en option.
25.27.9 inclus
Inclure nomme des fichiers de code source de script partagé mis à la disposition de chaque script sur ce canal, dans le langage que scripts.langage nomme.
Il s'agit des modèles de code Mirth. Un site avec quarante canaux a généralement une bibliothèque que chaque canal appelle, et sans cela, une migration signifie copier cette bibliothèque dans quarante fichiers - quarante endroits à corriger la prochaine fois qu'elle change.
Les chemins sont relatifs au fichier de canal, donc une bibliothèque à côté des canaux les accompagne. Il s’agit d’une liste car l’alternative est un seul fichier énorme, et les bibliothèques ont tendance à se diviser par sujet.
Les fichiers doivent être dans la langue du canal. C’était JavaScript uniquement pendant un certain temps, et ce n’était pas par refus : un canal Lua lisait les fichiers, refusait un fichier manquant, puis le runtime n’en installait aucun, donc chaque appel à la bibliothèque échouait sur le premier message avec une variable globale nil - l’erreur exacte que le refus ci-dessus est censé éviter. Les deux langages l’installent maintenant, et une bibliothèque qui ne peut pas être analysée est refusée lors du chargement en nommant le fichier.
25.27.10 file_roots
FileRoots sont les répertoires que FileUtil peut lire et écrire.
Requis chaque fois que « fichier » est autorisé. Autoriser l’accès aux fichiers sans nommer les répertoires utilisés signifiait autrefois l’ensemble du système de fichiers : un script pouvait lire la base de données de Perfuse, qui contient des hachages de mots de passe, le mot de passe du compte de service LDAP et le secret client OIDC. La création d’un canal nécessite uniquement le rôle d’éditeur, donc l’escalade s’est terminée dès que l’administrateur l’a démarré.
25.27.11 allow
Allow accorde des capacités qu’un script serait autrement refusé : « fichier », « base de données », « route ».
Mirth accorde tous ces éléments à chaque script ; exiger qu’ils soient nommés signifie qu’un transformateur ne peut pas commencer à lire discrètement le système de fichiers après une copie-collage.
25.28 Ombre
Shadow exécute une version candidate d’un canal à côté de la version live et signale où ils diffèrent.
C’est la réponse à la question qui rend le travail d’interface effrayant : comment savoir qu’une modification est sûre ? Pas en la lisant. Une transformation est un programme qui opère sur des messages dont la variété que personne n’a cataloguée, et le cas qui casse est toujours celui que personne n’a pensé - le patient avec deux identifiants, le résultat avec un champ d’unités vide, l’A08 qui arrive avant son A01.
Un test de canal prouve les cas que quelqu’un a pensés. Le mode Shadow prouve les cas qui arrivent réellement, contre un trafic réel, avant que le changement n’en transporte aucun.
Deux propriétés le rendent sûr, et les deux sont structurelles plutôt que configurables :
- L’ombre ne livre jamais. Ses destinations ne sont pas construites, donc il n’y a pas de chemin de code d’un canal d’ombre à un récepteur, et aucun paramètre ne peut en créer un par erreur. - L’ombre n’affecte jamais le canal live. Il s’exécute après que le message live a été livré et accusé réception, et une ombre qui panique, jette ou bloque est enregistrée comme une défaillance d’ombre et rien d’autre.
Défini comme Shadow dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
channel | texte | oui | — |
sample | nombre | non | 1 |
compare | liste de texte | non | — |
ignore | liste de texte | non | — |
max_differences | nombre entier | non | 100 |
timeout | durée, telle que 30s ou 5m | non | 5s |
25.28.1 channel
Channel est le chemin du fichier de canal candidat.
Un fichier distinct plutôt qu’un bloc en ligne, intentionnellement : le candidat est censé devenir le canal live, il devrait donc être l’artefact qui est examiné, validé et promu, et non un fragment qui doit être extrait.
25.28.2 sample
Sample est la fraction de messages à mettre en ombre, de 0 à 1. Par défaut, 1.
Vaut la peine de le réduire uniquement sur un flux occupé, et vaut la peine de le comprendre avant de le faire : l’échantillonnage réduit le coût et réduit la confiance dans la même proportion, et le message qui aurait montré la différence est le message inhabituel.
25.28.3 compare
Compare limite la comparaison à ces chemins de champ.
Vide compare tout.
25.28.4 ignore
Ignore exclut les chemins de comparaison.
Nécessaire dans la pratique, car un canal qui tamponne une horloge ou un numéro de séquence diffère à chaque message unique et rapporterait un taux de différence de 100 % sans vous apporter d'informations.
25.28.5 max_differences
MaxDifferences limite le nombre de messages différents conservés pour inspection.
Defaults to 100.
25.28.6 délai d'attente
Timeout limite une exécution d'ombre.
Defaults to 5s.
Séparé de la durée d'attente propre du canal, et plus court. Un candidat avec un script défaillant ne doit pas accumuler de goroutines derrière le trafic en direct.
25.29 Code XDS
XDSCode est une valeur codée dans les paramètres de destination : code, schéma de codage (un OID) et affichage.
Défini comme XDSCode dans internal/config.
| Clé | Type | Requis | Par défaut |
|---|---|---|---|
code | texte | oui | — |
scheme | texte | oui | — |
display | texte | non | — |
26 Fonctionnement de chaque composant
Perfuse est construit à partir de petits packages, chacun ayant une tâche. Ce chapitre est le compte rendu de chaque package sur ce qu'il fait et pourquoi il est construit de cette manière, tiré de la source. Lorsqu'une décision a une raison qui n'est pas évidente, la raison est ici plutôt que dans un message de validation que personne ne trouvera.
26.1 fhir
Le package fhir implémente les ressources FHIR, la sérialisation et la validation.
La gestion des versions est la première décision de conception, car « FHIR » seul ne permet pas d'identifier un format de fil. R5 est la dernière version publiée et est la valeur par défaut ici. R4 est ce que la base installée et la réglementation américaine consomment réellement, elle est donc entièrement prise en charge plutôt que traitée comme une version obsolète. R6 est en vote au moment de la rédaction et n'est pas délibérément implémentée : expédier une supposition sur une spécification non publiée serait pire que de ne pas la prendre en charge.
Le modèle de ressource est de forme R5. Lorsque R4 diffère, la différence est appliquée lors de la sérialisation plutôt que de conserver deux ensembles parallèles de structs, ce qui est la façon dont un codebase se retrouve avec deux définitions subtilement divergentes de Patient.
Source: github.com/biodream-llc/perfuse/fhir
26.2 principal
La commande xmlordergen écrit l'ordre des éléments XML FHIR nécessaires, à partir d'un package de base de StructureDefinitions.
go run ./fhir/xmlordergen hl7.fhir.r4.core-4.0.1.tgz | gzip -9 -n > fhir/xmlorder_r4.txt.gz
Les objets JSON peuvent contenir leurs membres dans n'importe quel ordre ; XML ne peut pas : chaque élément doit apparaître dans l'ordre où sa définition le liste. Chaque ligne de sortie est un chemin et ses enfants dans cet ordre, chaque enfant avec la façon de trouver ses propres enfants : "@Path" (un élément défini en ligne, une colonne vertébrale), "#Path" (le même qu'un autre élément), ou ses types.
Source: github.com/biodream-llc/perfuse/fhir/xmlordergen
26.3 hl7
Le package hl7 lit les messages HL7 version 2.
Il n'a pas de dépendances en dehors de la bibliothèque standard, et un test force cela. Il n'effectue pas d'entrées-sorties réseau, n'écrit pas de fichiers et ne démarre pas de goroutines, il est donc sécurisé pour une utilisation depuis n'importe où.
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"
Les chemins sont la notation que les gens utilisent déjà lorsqu'ils parlent d'HL7 : segment, champ, puis composant et sous-composant facultatif, comme dans PID-5.1 ou OBX-5.2.3. Les répétitions sont adressées avec des crochets, comme dans PID-3[2].1.
Get renvoie une erreur pour un chemin qu'il ne peut pas analyser ; MustGet renvoie une chaîne vide à la place. Les deux sont sécurisés pour les segments et les champs absents, car un flux réel est plein des deux et un analyseur qui panique sur les données manquantes est inutile pour le travail. L'absence n'est pas une erreur — un message qui ne transporte simplement pas PID-8 donne "" au lieu d'une défaillance.
Absent et vide
HL7 distingue un champ qui n'a pas été envoyé d'un champ envoyé délibérément vide, et cliniquement, ceux-ci peuvent signifier des choses différentes - « pas d'allergies enregistrées » n'est pas « pas d'allergies connues ». Value.Exists signale la différence lorsque les appelants en ont besoin, tandis que String aplatit les deux en "" pour le cas courant.
Copie, et la seule façon de se tromper
Parse copie sa saisie, donc le Message renvoyé reste valide quel que soit la façon dont l'appelant réutilise son tampon. Cela coûte environ 3 % et une allocation par message.
WithZeroCopy omet la copie et conserve une référence au slice de l'appelant à la place. Il est plus rapide, et il rend le Message non sécurisé à utiliser après que ce slice soit réécrit. La lecture dans un tampon réutilisé est la façon normale et efficace de lire à partir d'un réseau en Go, donc le piège attrape le code soigneux, et le symptôme est des valeurs de champ incorrectes plutôt qu'une erreur - les données d'un patient sous le nom d'un autre patient. L'utilisez pour les saisies qui sont immuables ou survivent au Message, et non autrement.
Acknowledgements
AckFor construit un ACK ou NAK pour un message, y compris pour un message qui n'a pas pu être analysé, ce qui est le cas qui compte le plus : un expéditeur a besoin d'une réponse même lorsque ce qu'il a envoyé n'était pas un message. Voir AckOptions.
Ce que ce package ne fait pas
Il n'écrit ni ne modifie les messages. Il n'a pas de notion de structure de message au-delà des segments, donc il ne vous dira pas qu'un PV1 appartient à un groupe de visite particulier. Il ne valide pas contre les tables d'une version. Ce sont des omissions délibérées plutôt que des oublis : ceci est un indexeur pour le trafic réel, qui est souvent non conforme aux normes et qui doit encore être acheminé.
Source: github.com/biodream-llc/perfuse/hl7
26.4 admettre
Le package admit limite la quantité de travail en cours à la fois.
Le moteur crée un goroutine par destination par message. Les goroutines sont bon marché ; ce qu'ils détiennent ne l'est pas. Chaque livraison sortante détient une socket à l'autre extrémité et un descripteur de fichier ici, et les détient pour tout le budget de réessai - avec les valeurs par défaut, cinq tentatives à une durée d'attente de trente secondes plus quinze secondes de temporisation, soit près de trois minutes. Quelques centaines d'expéditeurs contre un récepteur qui s'est tu est donc plusieurs centaines de descripteurs détenus pendant des minutes, et le processus se termine.
Se terminer est la défaillance qui vaut la peine d'être prévenue, car elle ne se manifeste pas à l'endroit où elle s'est produite. Elle se manifeste comme « trop de fichiers ouverts » à un endroit sans rapport : la base de données ne peut pas ouvrir son journal, l'interface cesse d'accepter, un journal ne peut pas être écrit. Le moteur semble défectueux en trois endroits à la fois et la cause est un système partenaire qui a cessé de répondre.
Deux limites, et la seconde compte plus que la première :
Un total, afin que le processus reste à l'intérieur de son budget de descripteurs.
Une limite par destination, afin qu'un récepteur ne puisse pas consommer le total. Sans cela, un partenaire unique bloqué fait tomber toutes les autres interfaces, ce qui est pire que de ne pas avoir de limite du tout : la zone touchée passe d'une interface à toutes les interfaces.
Source: github.com/biodream-llc/perfuse/internal/admit
26.5 alertes
Le package alertes surveille les métriques et indique quand quelque chose ne va pas.
Le but est que personne n'ait à regarder le tableau de bord. « Les transactions échouées restent en file d'attente sans enquête en temps opportun » est une défaillance opérationnelle documentée dans ce type de logiciel, et la raison est toujours la même : les informations étaient sur un écran que personne ne regardait à quatre heures du matin.
Trois décisions façonnent cela.
Une alerte doit se résoudre elle-même. Une notification qui se déclenche et ne se résout jamais entraîne les gens à ignorer les notifications. Chaque règle ici est évaluée par rapport à l'état actuel, donc un récepteur qui revient ferme l'alerte qu'il a ouverte.
Les alertes sont déclenchées par la durée, et non par le nombre. « Taux d'erreur supérieur à 5 % en ce moment » se déclenche sur un seul message malchanceux pendant une heure calme. « Supérieur à 5 % pendant deux minutes » ne se déclenche pas. Chaque règle comporte une durée For et rien ne se déclenche jusqu'à ce que la condition ait duré aussi longtemps.
Ce qui est envoyé ne contient aucune donnée de patient. Une alerte contient un nom de canal, un nom de destination, un numéro et un seuil. Ceux-ci proviennent de la configuration et du comptage. Un webhook va dans une salle de chat, une salle de chat a un défilement, et un défilement n'est pas un endroit où un identifiant de patient devrait se retrouver.
Source: github.com/biodream-llc/perfuse/internal/alerts
26.6 amqp
Le package amqp est un client AMQP 1.0 : une connexion, une session, des liens d'envoi et de réception, réglés après que le récepteur le dise.
AMQP 1.0 est ce que Azure Service Bus et Event Hubs parlent, ce que RabbitMQ 4 parle nativement, et ce que ActiveMQ et Artemis parlent à côté de STOMP. Écrit ici pour la même raison que le client STOMP et le signataire AWS : une bibliothèque cliente complète serait la majeure partie de la liste de dépendances du binaire pour quatre performatifs qui comptent.
Ce qu'il fait : SASL PLAIN ou ANONYMOUS (Service Bus prend un nom de clé d'accès partagé et une clé en tant que PLAIN), TLS, ouvrir/démarrer/attacher, flux basé sur les crédits, un transfert divisé en trames lorsqu'il dépasse la taille de trame maximale du pair, et dispositions - acceptées, libérées, rejetées. L'expéditeur attend la disposition du courtier avant de signaler la réussite, donc « envoyé » signifie que le courtier a pris possession. Les trames vides maintiennent la connexion active à l'intérieur de la durée d'inactivité du pair, que Service Bus impose.
Ce qu'il ne fait pas : transactions, plusieurs sessions, récupération de lien et annotations de message au-delà de la lecture.
Source: github.com/biodream-llc/perfuse/internal/amqp
26.7 analyser
Le package analyze transforme un canal Mirth analysé en quelque chose que l'homme peut exploiter : une description simple de ce que le canal fait, et une liste honnête de ce qui ne survivra pas à une migration.
La règle de conception ici est qu'une découverte doit être suffisamment spécifique pour être exploitée. "Ce canal utilise JavaScript" n'est pas une découverte. "La destination 1 appelle java.util.Date, qui n'a pas d'équivalent en dehors de la JVM" est.
Source: github.com/biodream-llc/perfuse/internal/analyze
26.8 api
Le package api sert l'interface HTTP utilisée par le frontend web.
La contrainte de conception importante : les canaux sont lus et écrits à partir de fichiers sur disque. L'API est un éditeur pour ces fichiers, et non un système de stockage différent qui se trouve exporter du YAML. Un canal créé dans le navigateur et un écrit à la main sont le même artefact, ce qui rend "exporter pour partager" trivial et conserve git comme l'historique des enregistrements.
Source: github.com/biodream-llc/perfuse/internal/api
26.9 as2
Le package as2 est Applicability Statement 2 (RFC 4130) : EDI sur HTTP, signé et chiffré avec S/MIME, avec un accusé de réception signé (un MDN) qui nomme un résumé de ce qui est arrivé.
Les payeurs et les partenaires commerciaux l'utilisent pour X12 et EDIFACT.
Le S/MIME est internal/cms, le même code que Direct messaging utilise. Ce qui se trouve ici est propre à AS2 : ses en-têtes, le contrôle d'intégrité des messages (MIC) et l'accusé de réception.
Source: github.com/biodream-llc/perfuse/internal/as2
26.10 attach
Le package attach déplace les grandes charges utiles hors d'un message et les remet en place.
Un message HL7 transportant un rapport scanné ou un PDF est ordinaire dans les flux de documents, et la charge utile est régulièrement des centaines de fois plus grande que le message qui l'entoure. Stocker cela en ligne signifie que le magasin de messages grandit au rythme des documents plutôt que du trafic, un message en file d'attente pour cinq destinations est copié cinq fois, et l'interface doit diffuser des mégaoctets pour montrer à quelqu'un un nom de patient.
La charge utile est donc extraite, stockée une fois par contenu et remplacée dans le message par un jeton. Mirth appelle cela des gestionnaires d'attachements et c'est une fonctionnalité de migration documentée, c'est pourquoi le format du jeton est conçu pour être reconnaissable plutôt que malin.
Ce que ce package ne décide pas
Il ne fait aucun stockage et aucune E/S. L'extraction produit le message réécrit et les charges utiles ; un magasin quelque part ailleurs décide où celles-ci vont. Cette séparation est ce qui rend l'extraction testable sans base de données, et c'est également ce qui permet à la même logique de s'exécuter dans le playground WASM où il n'y a pas de base de données du tout.
Source: github.com/biodream-llc/perfuse/internal/attach
26.11 authlimit
Le package authlimit limite les tentatives d'authentification échouées par adresse source.
Il existe parce que deux écouteurs avaient besoin de la même chose et que l'un d'eux n'avait rien. Le serveur FHIR a obtenu un limiteur lorsqu'il a obtenu l'authentification ; la connexion à la console n'en avait pas du tout, et une mesure a montré vingt devinettes de mot de passe par seconde soutenues contre le compte administrateur sans retard et sans verrouillage. À ce rythme, un mot de passe faible disparaît pendant la nuit et la seule trace est un journal plein d'avertissements identiques.
Délibérément pas un limiteur de taux général. Il limite les échecs, et non les demandes : un client légitime occupé n'est jamais affecté, et la seule chose qui s'accumule est l'erreur.
Source: github.com/biodream-llc/perfuse/internal/authlimit
26.12 awsmsg
Le package awsmsg parle à Amazon SQS et SNS avec la bibliothèque standard et le signateur partagé Signature Version 4.
Le même argument que s3put : le SDK AWS doublerait la taille de la liste des matériaux pour quatre appels d'API. SQS utilise son protocole JSON (AWS JSON 1.0, X-Amz-Target AmazonSQS.<Action>), que AWS documente comme le protocole actuel ; SNS utilise son protocole de requête, qui est le seul qu'il ait. Les deux fonctionnent contre LocalStack et les points de terminaison VPC via un remplacement de point de terminaison.
Source: github.com/biodream-llc/perfuse/internal/awsmsg
26.13 awsv4
Le package awsv4 signe les demandes à AWS avec Signature Version 4, en utilisant uniquement la bibliothèque standard.
Il a commencé à l'intérieur de s3put. SQS, SNS et la lecture à partir de S3 nécessitent la même signature avec un nom de service différent et avec une chaîne de requête, et une deuxième copie du code de signature serait un deuxième endroit pour le seul bogue qui compte - une erreur de signature ressemble exactement à des informations d'identification incorrectes. Il vit donc ici, vérifié contre les vecteurs de test publiés par AWS, et chaque connecteur AWS l'utilise.
Les informations d'identification sont des clés statiques ou des variables d'environnement standard. Il n'y a pas de chaîne d'informations d'identification d'instance par défaut : cela signifie des appels IMDS, un cache et un rafraîchissement, ce qui est où une petite implémentation cesse d'être petite, et Perfuse refuse les adresses de métadonnées comme destinations par défaut.
Source: github.com/biodream-llc/perfuse/internal/awsv4
26.14 azblob
Le package azblob lit et écrit le stockage d'objets Azure Blob avec la bibliothèque standard : autorisation Shared Key ou SAS sur des appels HTTP simples.
La même logique que s3put : le SDK Azure est volumineux et les opérations dont un moteur d'intégration a besoin sont cinq - mettre, obtenir, lister, supprimer et définir le niveau d'accès. La signature Shared Key est spécifiée exactement ("Autoriser avec Shared Key", Azure Storage REST), et Azurite, l'émulateur de Microsoft, la vérifie de la même manière que le service.
Source: github.com/biodream-llc/perfuse/internal/azblob
26.15 marque
Le package branding stocke le logo et le nom de produit d'un client afin qu'une installation puisse se présenter comme son propre produit plutôt que comme Perfuse.
Pourquoi le logo n'est pas un paramètre
Tout le reste qu'un opérateur peut modifier est un scalaire dans le fichier de paramètres. Un logo est constitué de quelques centaines de kilo-octets de données binaires, et le placer dans le fichier de paramètres signifierait utiliser une base64 dans un fichier YAML que une personne est censée pouvoir lire et modifier manuellement. Il est donc stocké à côté de ce fichier, et seule sa présence est visible à travers la surface des paramètres.
La partie qui compte : une image téléchargée est une entrée non fiable
Un logo est téléchargé par un administrateur, puis servi à chaque navigateur qui charge la console, y compris sur la page de connexion avant que quiconque se soit authentifié. Cela en fait le contenu fourni par l'attaquant le plus largement distribué dans le produit, il est donc traité en conséquence :
- Le type de contenu déclaré est ignoré. Les octets sont analysés, et le résultat doit figurer dans une liste autorisée. Un fichier appelé logo.png contenant du HTML est du HTML. - Le SVG est accepté, car c'est ce que les entreprises possèdent réellement, mais c'est un format de document exécutable : il peut contenir des éléments de script, des attributs de gestionnaire d'événements, des références externes et des objets étrangers intégrés. Il est réécrit pour supprimer tous ces éléments avant d'être stocké, et la réécriture est vérifiée en insérant chaque attaque dans un test. - Il est servi avec une stratégie de sécurité du contenu qui n'autorise rien, avec l'analyse désactivée, et en tant qu'image intégrée sans pièce jointe uniquement. Même un bogue de désinfectant ne devrait pas devenir une exécution de script sur l'origine de la console elle-même. - Le nom de fichier téléchargé n'est jamais utilisé pour construire un chemin. Le nom stocké est dérivé du type analysé, donc un nom comme ../../etc/perfuse ne peut pas s'échapper nulle part.
Source: github.com/biodream-llc/perfuse/internal/branding
26.16 cda
Le package cda lit les documents cliniques.
La conception commence par la façon dont ces documents voyagent réellement, ce qui n'est pas sous forme de fichiers. Un résumé de sortie quitte un dossier médical électronique à l'intérieur d'un message HL7 v2 MDM^T02, avec l'ensemble du document codé en base64 dans OBX-5 et décrit par un segment TXA. Cela représente des milliers de messages par jour dans un hôpital de taille moyenne, et c'est pourquoi ce package est situé à côté d'un analyseur HL7 v2 plutôt que dans un kit de documents : la moitié v2 est déjà ici, donc le pipeline de "un message est arrivé" à "une référence de document FHIR existe" est court.
Trois choses sont délibérément dans le cadre et une chose ne l'est pas.
Dans le cadre : lire un document et dire ce qu'il contient en termes simples ; vérifier que le récit lisible par l'homme et les entrées codées sont d'accord ; et convertir en FHIR. La vérification du récit est la plus inhabituelle. Chaque section C-CDA transporte les mêmes informations deux fois, une fois sous forme de texte pour un clinicien et une fois sous forme de codes pour une machine, et elles sont censées correspondre. Dans la pratique, elles ne correspondent souvent pas, et rien ne le vérifie - ni les outils de certification, ni les moteurs. Lorsque le texte indique qu'un patient est allergique à la pénicilline et que l'entrée codée indique autre chose, l'un des deux lecteurs agit sur les mauvaises informations. Il s'agit d'un défaut de sécurité des patients qui est mécaniquement détectable, il est donc détecté ici.
Hors du cadre : générer un C-CDA conforme. Écrire un tel document signifie satisfaire plusieurs centaines de règles de modèle et un Schematron, et produire des documents qui sont à 95 % corrects échoueraient à la certification de manière misérable à déboguer. La lecture, la vérification et la conversion représentent la majeure partie de la valeur pour une fraction du risque.
Source: github.com/biodream-llc/perfuse/internal/cda
26.17 channeltest
Le package channeltest exécute des tests contre une définition de canal.
Un canal est un programme. Il filtre, réécrit et achemine les messages cliniques, et il est édité sous pression par des personnes qui ne peuvent pas l'essayer contre la production. L'absence d'un moyen de tester un canal est la principale raison pour laquelle le travail d'interface est effrayant, et "j'ai modifié le transformateur et rien n'a l'air différent dans le navigateur de messages" n'est pas un test.
La décision centrale est qu'un test exécute le message à travers le chemin de transformation réel — le même filtre, les mêmes étapes déclaratives, le même moteur de script, dans le même ordre — avec uniquement le transport remplacé. Un test qui exerçait une réimplémentation passerait tandis que le canal échouerait, ce qui est pire que ne pas avoir de test du tout car il induit activement en erreur.
Source: github.com/biodream-llc/perfuse/internal/channeltest
26.18 chanscope
Le package chanscope restreint les lectures et les écritures sur un contexte à certains canaux.
Il dépend du contexte plutôt que d'être un paramètre de chaque requête, car il existe des dizaines de requêtes à travers le magasin de messages et la file d'attente de livraison, et la limite est une propriété de qui demande, et non de la question. L'API la définit une fois par demande pour une personne limitée à certains groupes de canaux ; chaque comptage, liste, graphique, recherche et action de file d'attente s'accorde alors avec les autres, de sorte que personne ne soit informé d'un total de quarante échecs et ne voit que quatre.
Source: github.com/biodream-llc/perfuse/internal/chanscope
26.19 cluster
Le package cluster permet à plusieurs serveurs Perfuse de partager un magasin PostgreSQL et de décider, entre eux, lequel exécute quoi.
Le problème qu'il résout
Un serveur est un point de défaillance unique : lorsqu'il s'arrête, chaque interface s'arrête. Deux serveurs sur une base de données résolvent cela uniquement si ils n'exécutent jamais le même canal, car deux écouteurs MLLP sur une alimentation se relaient avec l'expéditeur, deux travailleurs de file d'attente livrent le même message deux fois, et deux pollers DICOM signalent chacun la même étude.
How
Un bail est une ligne qui nomme qui détient quelque chose, avec un compteur que son détenteur déplace à chaque renouvellement, toutes les quelques secondes. Aucune horloge n'est comparée à une autre : un détenteur qui ne peut pas renouveler (planté, coupé de la base de données) arrête ce que le bail couvre une fois que sa propre horloge indique que le bail est presque terminé, et un autre serveur le prend uniquement après que sa propre horloge ait vu le compteur rester immobile pendant tout le bail. Chacun mesure un intervalle sur sa propre horloge, donc les horloges des serveurs et de la base de données n'ont pas besoin d'être en accord ; ils n'ont besoin que de fonctionner à peu près au même rythme. Une horloge qui saute (une machine virtuelle se resynchronisant, un administrateur réglant l'heure) ne change rien : la première version utilisait l'horloge de la base de données pour l'expiration, et un test a trouvé une base de données dont l'horloge sautait de treize secondes la main à chaque bail à un nouveau serveur tandis que les anciens les exécutaient encore.
Entre l'arrêt du détenteur et le démarrage du suivant, il y a une courte pause avec personne pour exécuter, ce qui coûte à l'expéditeur quelques secondes de connexions refusées, et jamais un moment avec deux.
Two modes:
- actif-passif : un bail, « leader ». Son détenteur exécute chaque canal et chaque tâche qui doit s'exécuter une fois (notifications d'abonnement, alertes). Les autres attendent, et le premier à voir son expiration prend le relais. - actif-actif : le leader exécute toujours les tâches, et chaque canal a un bail à lui, réparti uniformément sur les serveurs actifs. Un serveur qui part donne ses canaux aux autres ; un qui rejoint prend sa part à mesure qu'ils sont libérés.
Chaque bail comporte une époque, comptée à chaque fois que son détenteur change, qui nomme une détention dans l'historique.
Source: github.com/biodream-llc/perfuse/internal/cluster
26.20 cms
Le package cms est la syntaxe de message cryptographique (RFC 5652) telle que S/MIME et le messagerie sécurisée Direct l'utilisent : SignedData (signer un message, vérifier un message et indiquer qui l'a signé) et EnvelopedData (chiffrer un message pour les certificats des destinataires, déchiffrer un message avec notre clé).
Seulement ce que l'énoncé d'applicabilité directe et son guide d'implémentation exigent : RSA avec SHA-256 (SHA-1 accepté pour la lecture uniquement, puisque les anciens HISPs l'envoient toujours), transport de clé RSA avec PKCS#1 v1.5 ou OAEP, et AES-128 ou AES-256 en mode CBC. La cryptographie est celle de la bibliothèque standard ; ce package est l'ASN.1 qui l'entoure.
Source: github.com/biodream-llc/perfuse/internal/cms
26.21 cms0057
Le package cms0057 contient les pièces du côté payeur de la règle finale d'interopérabilité et d'autorisation préalable du CMS (CMS-0057-F) qui concernent les données plutôt que le transport : les réclamations adjudiquées en tant que ressources CARIN Blue Button ExplanationOfBenefit, les autorisations préalables en tant que ressources Da Vinci PDex ExplanationOfBenefit, la correspondance des membres HRex pour l'API Payer-to-Payer, la liste des membres derrière l'API d'accès des fournisseurs, et les métriques d'autorisation préalable que le payeur doit publier chaque année.
Les points de terminaison FHIR qui servent ceux-ci se trouvent dans fhirserver ; ce package décide ce qui va dans ceux-ci.
Les médicaments sont hors du champ d'application dans l'ensemble, car ils le sont dans les dispositions d'autorisation préalable de la règle : pas d'ExplanationOfBenefit de pharmacie, pas de formule, pas de NCPDP.
Source: github.com/biodream-llc/perfuse/internal/cms0057
26.22 codeset
Le package codeset contient des tables de mappage qui survivent au canal qui en avait besoin pour la première fois.
La taxe de domaine consiste en grande partie à rédériver un mappage que quelqu'un a déjà dérivé. Les codes de sexe d'un site, les classes de patients, les statuts de commande et les identificateurs d'installation sont traduits de la même manière dans chaque canal qui les touche, et aujourd'hui, chacune de ces traductions est une table distincte à l'intérieur d'un canal distinct. Quarante canaux signifient quarante copies et quarante endroits à corriger la prochaine fois que le système récepteur change.
Un tableau devient donc un objet nommé référencé par nom. Cela va de soi et c'est la moitié la plus petite de la valeur.
La moitié que personne ne construit
La plus grande moitié est la provenance. La plupart de ce qui rend une interface difficile à maintenir n'est pas le mappage - c'est que personne ne sait *pourquoi*. « Nous supprimons les zéros de tête parce que la colonne MRN du laboratoire est numérique » est une connaissance qui existe dans la tête d'une seule personne et quitte le bâtiment lorsqu'elle prend sa retraite, et le mappage qui reste devient quelque chose que personne n'ose modifier et que personne n'ose supprimer.
Chaque tableau enregistre donc qui a décidé et quand, chaque entrée peut enregistrer sa propre raison, et les deux survivent dans le fichier qui va dans le contrôle de version. Un mappage avec une raison peut être discuté. Un mappage sans raison devient une superstition.
Pourquoi le fichier est séparé du canal
Parce que c'est partagé. Une table à l'intérieur d'un canal est une table que seul ce canal peut utiliser, ce qui est le problème. Et une table partagée nécessite son propre historique : « qui a modifié la mise en correspondance du sexe, et quand » est une question sur la table, et non sur le canal qui a été édité ce jour-là.
Source: github.com/biodream-llc/perfuse/internal/codeset
26.23 conformité
Le package de conformité met en œuvre le flux de travail de notification d'événement ADT du CMS requis par le 42 CFR 482.24(d) depuis mai 2021.
Les hôpitaux doivent notifier électroniquement les fournisseurs établis d'un patient - soins primaires, spécialistes, établissements de soins post-aigus - lorsque le patient est admis, libéré ou transféré. La réglementation existe parce que les patients tombent entre les mailles du filet pendant les transitions : un médecin traitant qui ne sait pas qu'un patient a été libéré ne peut pas planifier le suivi qui empêche une réadmission.
Ce package fournit les mécanismes pour : - suivre quels fournisseurs sont établis pour chaque patient. - acheminer les événements ADT vers les fournisseurs appropriés à la priorité appropriée. - enregistrer chaque notification envoyée, avec le statut de livraison, pour les audits des enquêteurs du CMS. - générer des rapports de conformité montrant les taux de notification et les défaillances.
La sécurité des threads est requise dans l'ensemble, car les messages ADT arrivent de manière concurrente à partir de plusieurs canaux et le pipeline de notification s'exécute en parallèle.
Source: github.com/biodream-llc/perfuse/internal/compliance
26.24 config
Le package de configuration charge les définitions de canal à partir de fichiers.
La configuration vit dans des fichiers plutôt que dans une base de données, ce qui est la principale chose que Perfuse fait différemment de Mirth. Mirth conserve les canaux dans sa propre base de données, ce qui explique pourquoi le contrôle de version est un produit distinct, pourquoi la promotion d'un canal de test à production est difficile, et pourquoi personne ne peut répondre à « qu'est-ce qui a changé la semaine dernière » sans un appel de support. Les fichiers donnent git, des différences, une revue, une intégration continue et une promotion d'environnement sans machine supplémentaire.
La validation est délibérément stricte et se produit lors du chargement : les champs inconnus sont une erreur, les expressions de filtre sont compilées, les adresses sont vérifiées. Un canal qui ne peut pas être compris doit refuser de démarrer plutôt que de s'exécuter d'une manière que personne n'a l'intention de faire.
Source: github.com/biodream-llc/perfuse/internal/config
26.25 contrat
Le package de contrat transforme ce à quoi ressemble un flux en ce à quoi un flux doit ressembler.
Un profil répond à « ce que je reçois ». C'est utile une fois. Le problème coûteux est le jour où cela change : une mise à niveau du fournisseur supprime un champ, un nouveau code apparaît, un segment commence à se répéter. Aucun de ceux-ci n'est une erreur - les messages sont toujours des HL7 valides et chaque moteur du monde les accepte - donc rien ne remarque jusqu'à ce qu'un récepteur s'effondre, généralement des semaines plus tard, et l'enquête commence de la mauvaise extrémité.
Un contrat est le profil écrit comme une attente et vérifié. C'est un test de contrat, qui est une idée résolue dans les logiciels en général et presque entièrement absente de l'intégration de soins de santé.
Pourquoi l'unité est un taux et non un message
La conception évidente est de vérifier chaque message et de se plaindre lorsqu'un échoue. Cela produit un système que personne ne peut utiliser. Les flux réels contiennent une proportion de messages vraiment étranges - un message de test du fournisseur, un patient sans sexe enregistré, une saisie manuelle - et alerter sur chacun d'eux entraîne les gens à ignorer les alertes, auquel point la fonctionnalité est pire que rien, car elle a consommé l'attention dont elle avait besoin.
Donc, une attente concerne une proportion sur une fenêtre : « PID-3 est peuplé dans au moins 99 % des messages ». Un message étrange ne déclenche jamais. Cinq pour cent des messages perdant leur numéro de dossier médical le font.
Un contrat décrit ce qui arrive, et non ce qui part
C'est la distinction que les gens obtiennent d'abord, y compris moi pendant les tests d'intégration. Perfuse stocke le message tel qu'il est arrivé - c'est délibéré, car le message stocké est la preuve de ce qu'un expéditeur a envoyé - donc un contrat est vérifié contre le flux entrant et non contre la sortie des transformations du canal.
C'est la valeur par défaut correcte d'une grande marge : la chose qui change sans avertissement est le système d'envoi, et le but d'un contrat est de remarquer. Mais cela signifie qu'une attente écrite sur une valeur mappée (« après la mise en correspondance, seuls les codes du laboratoire doivent rester ») échouera immédiatement et de manière confuse, car les codes qu'il nomme n'apparaissent jamais dans le trafic profilé. Tout ce qui concerne ce qui part appartient à un test de canal, qui exécute les transformations réelles.
Pourquoi une violation nomme la tolérance qu'elle a violée
« PID-3 a échoué » ne dit rien à quelqu'un. « PID-3 a été peuplé dans 94,2 % des 500 derniers messages ; le contrat exige 99 % » dit combien c'est grave, à quel point on peut être confiant et si cela vaut la peine de réveiller quelqu'un. Les chiffres sont le message.
Source: github.com/biodream-llc/perfuse/internal/contract
26.26 crd
Le package crd est un service de découverte des exigences de couverture Da Vinci (CRD 2.2.1) : le côté payeur de la conversation CDS Hooks qui indique à un clinicien, alors que la commande est toujours un brouillon, si elle est couverte, si elle nécessite une autorisation préalable et quels documents le payeur exigera.
L'API de priorisation de l'autorisation CMS-0057 est en pratique trois guides Da Vinci ensemble : CRD pour dire ce qui est requis, DTR pour le rassembler, PAS pour le soumettre. Perfuse avait PAS. C'est le premier des deux autres ; le package $questionnaire de DTR est sur le point de terminaison FHIR.
Les décisions de couverture proviennent d'un fichier de règles, car il s'agit de la politique de l'assureur et changent sans mise à jour logicielle : un code (ou une liste de codes) et ce qui s'applique à celui-ci - couvert ou non, autorisation préalable nécessaire ou non, documentation, et le questionnaire DTR qui le collecte. Une commande qui ne correspond à aucune règle est répondu « conditionnel » et « indéterminé », ce qui est ce que CRD dit de retourner lorsque le service ne peut pas décider - jamais une supposition qu'il est couvert.
Les réponses suivent le guide : une action de système mettant à jour chaque commande avec l'extension d'informations de couverture, que le dossier médical stocke sur la commande et envoie plus tard avec l'autorisation préalable ; et une carte par commande, afin qu'un clinicien la voie.
Source: github.com/biodream-llc/perfuse/internal/crd
26.27 tableaux de bord
Le package tableaux de bord définit les tableaux de bord que Perfuse expédie pour chaque type de personne qui le surveille, et comment une personne se voit attribuer un : par son rôle, par un groupe d'annuaire que le fichier de tableaux de bord mappe, ou par la vue qu'il a sauvegardée.
Les tableaux de bord sont composés de tuiles, et les tuiles affichent uniquement des agrégats - des comptes, des taux, des temps, des états. Aucune n'affiche un message, un patient ou un identifiant, afin qu'un tableau de bord puisse être attribué à un responsable de service ou affiché sur un écran mural sans élargir l'accès aux données de patient. Une tuile qui nécessite des données que Perfuse n'enregistre pas encore n'est pas simulée : le tableau de bord la liste sous « Planifié ».
La flexibilité totale est le rôle de Grafana, et non de ce package. Chaque tuile qui a une métrique derrière elle est exportée sous forme de panneau Grafana sur /metrics de Perfuse, afin qu'un site qui souhaite plus que la configuration légère prenne le tableau de bord là-bas.
Source: github.com/biodream-llc/perfuse/internal/dashboards
26.28 davinci
Le package davinci indique quelle version des guides de pré-autorisation Da Vinci (CRD, DTR, PAS) un client parle.
Perfuse répond en deux : 2.2 (CRD 2.2.1, DTR 2.2.0, PAS 2.2.1), la plus récente, et 2.1 (CRD, DTR et PAS 2.1.0), la version recommandée par la liste CMS-0057-F une fois que la base US Core 3.1.1 des versions 2.0.1 a expiré. Les deux diffèrent dans les formes que le client lit par nom - les paramètres du package de questionnaire DTR (PackageBundle dans 2.1, packagebundle dans 2.2), la réponse $inquire de PAS (un Bundle dans 2.1, un Parameters dans 2.2), les extensions qui n'existent que dans l'un d'eux - donc une réponse ne peut pas servir les deux, et le serveur doit savoir à laquelle il parle.
Cela est indiqué, le plus spécifique en premier : par la demande elle-même (CRD's davinci-crd.requestedVersion ; la version d'un profil que l'entrée revendique, profil|2.1.0), puis par l'enregistrement du client (davinci_version sur un client SMART ou CDS), puis par la configuration propre du serveur (serve -davinci-version), qui par défaut est la plus récente.
Source: github.com/biodream-llc/perfuse/internal/davinci
26.29 dbtime
Le package dbtime formate les horodatages de telle sorte que les trier en tant que texte les trie en tant qu'heure.
Chaque magasin dans Perfuse conserve les horodatages sous forme de TEXT dans SQLite et repose sur la comparaison de chaîne pour l'ordre et les requêtes de plage : ORDER BY received_at DESC, WHERE expires_at < ?, WHERE at >= ?. C'est une conception raisonnable - cela permet à une base de données que quelqu'un peut lire avec l'interpréteur de commande sqlite3 - mais cela ne fonctionne que si la forme de texte est à largeur fixe.
time.RFC3339Nano ne l'est pas. Sa documentation indique qu'il supprime les zéros de fin du champ des secondes, de sorte que la même horloge produit des chaînes de longueurs différentes :
20:56:33.12345Z <- 123450 microsecondes, zéro de fin supprimé 20:56:33.123456Z <- 123456 microsecondes
Comparés en tant que texte, le premier est *plus grand*, car après le préfixe partagé « 12345 » il a 'Z' où le second a '6', et 'Z' se classe au-dessus de chaque chiffre. Ainsi, l'instant le plus précoce se classe plus tard. Environ un couple adjacent sur dix est affecté, ce qui explique pourquoi cela s'est présenté comme une défaillance de test intermittente plutôt que comme une fonctionnalité manifestement défectueuse.
Ce qui a réellement été cassé : le journal d'audit et le navigateur de messages sont tous deux classés par un horodatage et peuvent donc lister les entrées de la même seconde dans le mauvais ordre. Un journal d'audit est un artefact de conformité et un navigateur de messages est la façon dont quelqu'un reconstruit ce qui s'est passé, donc dans les deux cas, l'ordre est le point.
La disposition ci-dessous utilise .000000000 plutôt que .999999999. Les deux impriment des nanosecondes ; la différence est que les zéros sont significatifs dans le premier et supprimés dans le second.
Source: github.com/biodream-llc/perfuse/internal/dbtime
26.30 délimité
Le package délimité analyse les enregistrements séparés et divisés par des caractères configurés.
Il s'agit du type de données délimité de Mirth : CSV, fichiers séparés par des tabulations, fichiers séparés par des pipes, fichiers à colonnes fixes et la longue traîne de formats qu'un laboratoire d'analyse ou un service de bureau émet parce que quelqu'un l'a écrit en 1994 et qu'il fonctionne.
Délibérément pas une bibliothèque CSV générale. Ce qui compte ici, c'est ce qu'un flux de soins de santé fait que ne fait pas un CSV bien formé : une ligne d'en-tête qui peut ou non être présente, une ligne vide finale qui ne doit pas devenir un enregistrement vide, des colonnes référencées par nom afin qu'une transformation ne soit pas cassée lorsque le fournisseur insère une colonne, et la capacité de traiter l'ensemble du fichier comme un seul message ou chaque ligne comme son propre message.
Le dernier de ceux-ci est la décision qui façonne tout le reste. Un fichier de cinq mille résultats est soit un message, soit cinq mille messages, et les deux ne sont pas interchangeables : un message signifie une seule accusé de réception et une seule défaillance pour l'ensemble du fichier, et cinq mille signifient que chaque ligne peut être filtrée, transformée et réessayée à sa guise.
Source: github.com/biodream-llc/perfuse/internal/delimited
26.31 dicom
Le package dicom lit les ensembles de données DICOM.
DICOM est où vit la radiologie, et un moteur d'intégration hospitalier qui ne peut pas le parler est exclu de l'imagerie entièrement. Mirth a un écouteur et un expéditeur DICOM, donc c'est un bloqueur de migration pour tout site effectuant des travaux de modalité.
Portée, énoncée clairement
Ce package analyse les ensembles de données : les informations de métadonnées de fichier, les éléments, la syntaxe de transfert et les valeurs qui comptent pour l'acheminement et l'identification. Il ne décode pas les données de pixels et ne le fera jamais en ce qui concerne ce package - un moteur d'intégration déplace les images, il ne les affiche pas, et un décodeur est un grand corps de travail spécifique au format dont l'unique but ici serait d'augmenter la taille binaire.
La lecture des métadonnées sans toucher les pixels est également ce qui le rend rapide sur le trafic qui compte : une CT thoracique est composée de centaines de mégaoctets de pixels derrière deux kilo-octets d'informations sur lesquelles tout le monde se base pour l'acheminement.
Pourquoi les représentations de valeurs sont traitées explicitement
Un élément DICOM contient une représentation de valeur à deux lettres indiquant comment lire sa valeur, et les règles diffèrent par VR de manière qui ne peut pas être devinée : certaines ont une longueur de deux octets et d'autres de quatre, certaines sont remplies d'un espace et d'autres d'un caractère nul, et les chaînes numériques peuvent contenir plusieurs valeurs séparées par des barres obliques. Se tromper ne produit pas d'erreur, cela produit une valeur erronée ayant l'air plausible - un nom de patient lu à partir du milieu d'une date, ou un identifiant d'étude décalé d'un octet.
Source: github.com/biodream-llc/perfuse/internal/dicom
26.32 dicomweb
Le package dicomweb parle DICOMweb (DICOM PS3.18) : QIDO-RS pour la recherche, WADO-RS et WADO-URI pour la récupération, STOW-RS pour le stockage, sur HTTP.
C'est ainsi que les visualiseurs, les services d'intelligence artificielle et les archives cloud accèdent aux images maintenant : OHIF, Google Cloud Healthcare, Azure Health Data Services, AWS HealthImaging, les interfaces DICOMweb d'Orthanc et de dcm4chee. Un moteur d'intégration qui ne parle que le protocole réseau de 1993 (DIMSE : C-STORE, C-FIND) peut alimenter un PACS mais pas un navigateur.
Le package est divisé en quatre parties : un lecteur de jeu de données qui parcourt l'objet entier, y compris les séquences, et sait où se trouve les données de pixel sans les charger ; le modèle JSON DICOM (PS3.18 F.2) ; multipart/related, qui est la façon dont DICOMweb déplace plusieurs objets dans une seule requête ; et un archive avec un index, qui est ce que QIDO et WADO répondent.
Source: github.com/biodream-llc/perfuse/internal/dicomweb
26.33 direct
Le package direct est un système de messagerie sécurisée Direct en tant que système de bordure : un message à une adresse Direct est signé avec le certificat de cette adresse et chiffré pour le destinataire, comme S/MIME, et envoyé à un HISP par SMTP ; un message reçu du HISP (par SMTP ou collecté via IMAP) est déchiffré et sa signature vérifiée contre les ancres de confiance avant que quoi que ce soit ne le lise.
Il suit la Déclaration d'applicabilité du projet Direct pour le transport de santé sécurisé 1.2 et la spécification XDM (IHE ITI TF-1 Annexe 15) pour les documents avec des métadonnées. Il ne s'agit pas d'un HISP : l'accréditation du HISP, sa politique de certificat et son annuaire restent avec le HISP.
Source: github.com/biodream-llc/perfuse/internal/direct
26.34 médicament
Le package médicament gère les codes et les quantités qui identifient un médicament.
Séparé des normes de pharmacie qui les portent, car le même code de médicament apparaît dans une réclamation NCPDP, une ordonnance SCRIPT, un segment HL7 RXE et une demande de médicament FHIR, et une conversion qui vit dans l'un de ces endroits est une conversion que les trois autres n'ont pas.
Source: github.com/biodream-llc/perfuse/internal/drug
26.35 dsdr
Le package dsdr signe et vérifie les documents CDA comme le Guide de mise en œuvre HL7 pour CDA Release 2 : Signatures numériques et délégation de droits, Version 1 (octobre 2014) le décrit - la norme de signature électronique que HIPAA adopte pour les pièces jointes de réclamations dans CMS-0053-F, 45 CFR 162.2002(e), avec une conformité à partir du 26 mai 2028.
Ce que le guide demande, et où cela est fait ici :
- Le résumé est sur l'ensemble du document, en laissant de côté chaque élément legalAuthenticator et authenticator (section 3.1.2), de sorte que les signataires ultérieurs ne cassent pas les signatures antérieures. Exprimé dans la signature comme une transformation de filtre XPath 2.0, que toute implémentation XML-DSig peut évaluer. - La signature est XAdES-X-L (3.1.1, ESMD-1 à ESMD-6) : le certificat de signature, l'heure de signature UTC, un rôle de la taxonomie des fournisseurs NUCC, un but de signature de l'ASTM E1762, le chemin de certification dans CertificateValues et une réponse OCSP ou CRL dans RevocationValues, avec les horodatages X-L sur lesquels il est construit. - Il est transporté en base64 dans sdtc : signatureText sur le participant qui a signé, avec une vignette en texte brut (3.3, ESMD-7 à ESMD-16), à l'intérieur de digitalSignature/authorizedSigner.
Là où le guide est silencieux, les choix faits sont nommés : il ne donne pas d'espace de noms pour ses propres éléments (digitalSignature, authorizedSigner, SignaturePurpose), ils sont donc placés dans urn:hl7-org:sdtc ; et le but est également indiqué comme une indication de type d'engagement XAdES avec l'OID ASTM, que les outils XAdES lisent et l'élément propre du guide qu'ils ne lisent pas.
La délégation de droits (un signataire délégué avec une assertion SAML) n'est pas produite ; une signature qui en porte une est signalée comme telle.
Source: github.com/biodream-llc/perfuse/internal/dsdr
26.36 e4x
Le package e4x fait fonctionner JavaScript de Mirth Connect inchangé.
Les scripts Mirth sont écrits pour Rhino, qui implémente E4X : XML est un type natif avec sa propre syntaxe. Le moteur ici est goja, qui ne le fait pas, et le fossé n'est pas seulement un problème de runtime.
pour chaque (var seg dans msg..OBX) { } // pour chaque, et l'opérateur descendant var z = <ZZZ><ZZZ.1>value</ZZZ.1></ZZZ> ; // un littéral XML var id = node.@root; // une référence d'attribut
Ce fichier réécrit ceux-ci en ECMAScript ordinaire que goja analyse, en laissant la sémantique au modèle d'objet de runtime dans xml.go. Tout le reste d'E4X - l'accès aux propriétés par nom d'élément, l'indexation des répétitions, l'affectation, toString - est déjà une syntaxe JavaScript valide et n'a pas besoin d'être réécrit.
La réécriture est faite avec un analyseur lexical réel plutôt que des expressions régulières, car l'alternative corrompt les scripts fonctionnels. Un modèle pour l'opérateur descendant en trouve un à l'intérieur de "http://example.org", un modèle pour les littéraux XML en trouve un dans "a < b && c > d", et un script qui change silencieusement de sens est bien pire qu'un qui refuse de charger.
Source: github.com/biodream-llc/perfuse/internal/e4x
26.37 edifact
Le package edifact lit et écrit les échanges UN/EDIFACT (ISO 9735) : la chaîne de service UNA, l'enveloppe d'échange UNB/UNZ, les groupes fonctionnels UNG/UNE facultatifs, et les messages UNH/UNT, avec le caractère de sortie et, pour la version de syntaxe 4, le séparateur de répétition.
Il vérifie les comptes et les références de l'enveloppe, adresse les éléments de données pour les filtres, divise un échange en un par message et construit un accusé de réception CONTRL.
Il lit n'importe quel type de message (ORDERS, INVOIC, IFTSTA, MEDRPT...); il ne contient pas les répertoires qui indiquent quels segments un type de message peut contenir, il vérifie donc la structure, et non le contenu.
Source: github.com/biodream-llc/perfuse/internal/edifact
26.38 égress
Le package égress décide si ce moteur peut se connecter vers une adresse.
Il existe parce qu'une destination peut être pointée n'importe où, et qu'une combinaison transforme cela en un moyen de lire le réseau interne : une destination SOAP avec un transformateur de réponse retourne la réponse du récepteur à un script, de sorte qu'un éditeur peut créer un canal qui récupère une URL interne et écrit le corps dans un journal ou un message.
Démontré plutôt que théorisé : une destination SOAP visant un serveur HTTP local a placé le corps de la réponse du serveur dans une ligne de journal de canal.
La réponse proportionnée n'est pas d'interdire les connexions sortantes - la livraison de messages aux points de terminaison configurés est l'objectif principal du logiciel, et un éditeur est censé les configurer. C'est de refuser les adresses spécifiques qui ne sont jamais une destination de message et qui sont toujours un magasin de références.
Source: github.com/biodream-llc/perfuse/internal/egress
26.39 moteur
Le package moteur exécute les canaux configurés.
Un canal est une source, un filtre et un ensemble de destinations. Le travail du runtime est d'être honnête sur ce qui est arrivé à chaque message : un accusé de réception doit signifier ce que la configuration indique qu'il signifie, un message qui est filtré doit être distinguable d'un qui a été livré, et un message qui n'a pas pu être livré nulle part ne doit pas être signalé comme accepté.
Source: github.com/biodream-llc/perfuse/internal/engine
26.40 epa
Le package epa est l'autorisation électronique préalable de NCPDP SCRIPT, du côté de l'assureur : PAInitiationRequest, PARequest, PAAppealRequest et PACancelRequest en entrée, et leurs réponses en sortie.
La proposition CMS-0062-P suggère que les assureurs concernés doivent le prendre en charge à partir du 1er octobre 2027, et que Medicare Part D l'exige déjà. Une demande est décidée de la même manière que toute autorisation préalable sur ce serveur : elle devient une demande de PAS de Da Vinci (une réclamation, la MedicationRequest et les réponses du prescripteur en tant que QuestionnaireResponse) et va au même fichier de règles, service de décision et file d'attente d'examen. La formule indique quels médicaments nécessitent une autorisation et quelles questions poser, à partir du même questionnaire FHIR que Da Vinci DTR remplit.
Les schémas de NCPDP sont sous licence. Les noms et l'ordre des éléments ici suivent le guide d'accompagnement public de Surescripts ePA et ses exemples; deux éléments que le matériel public ne montre jamais (la raison à l'intérieur de Closed et à l'intérieur de Denied) suivent le modèle SCRIPT utilisé ailleurs et sont nommés dans le manuel afin qu'un assureur puisse les vérifier contre sa propre copie du schéma.
Source: github.com/biodream-llc/perfuse/internal/epa
26.41 eprescribe
Le package eprescribe lit et écrit NCPDP SCRIPT, la norme selon laquelle les ordonnances voyagent.
Nommé d'après ce qu'il fait plutôt que d'après la norme, car internal/script est déjà le moteur JavaScript et deux packages appelés script dans un arbre est une erreur qui attend d'être faite à une ligne d'importation.
SCRIPT est XML, contrairement à la norme de télécommunication qui transporte la réclamation résultante. Un prescripteur envoie un NEWRX à une pharmacie; la pharmacie envoie en retour RXFILL pour dire ce qui s'est passé, REFREQ pour demander un renouvellement, ou RXCHG pour demander un changement. Chacun de ceux-ci est un message ici.
Où est le danger
Deux champs dans une ordonnance sont dangereux lorsqu'ils sont mal lus plutôt que lorsqu'ils sont manquants.
Les substitutions sont le premier. Un zéro signifie que la substitution est autorisée et un signifie dispenser tel quel. Cela se lit à l'envers pour quiconque s'attend à un indicateur où un signifie oui, et se tromper dispense un générique où le prescripteur a exigé la marque - ou refuse une substitution qui était autorisée, ce qui est la même erreur coûtant de l'argent au patient au lieu. Ce package refuse donc de deviner : un élément Substitutions absent est une erreur plutôt qu'une valeur par défaut, car les deux valeurs par défaut sont incorrectes.
Le nombre de renouvellements est le deuxième. Une ordonnance de classe II ne peut pas être renouvelée du tout, et un système qui transporte un nombre de renouvellements à partir d'un modèle non contrôlé produit une ordonnance qui semble valide que une pharmacie doit refuser.
Ce qui n'a pas été vérifié
La structure du message suit les noms d'éléments SCRIPT publiés. Aucun message de ce package n'a été envoyé via un réseau de routage réel tel que Surescripts, et la certification par l'un d'eux est un processus commercial plutôt que technique. Cela analyse et construit le format; il ne prétend pas être certifié.
Source: github.com/biodream-llc/perfuse/internal/eprescribe
26.42 équiv
Package equiv prouve que deux moteurs d'intégration sont d'accord, ou indique exactement où ils ne le sont pas.
C'est la réponse à la seule question qui bloque réellement une migration. Une équipe d'interface ne refuse pas un nouveau moteur parce qu'il manque de fonctionnalités ; elle refuse parce qu'elle ne peut pas être certaine qu'il fera la même chose au trafic qu'elle a déjà, et se tromper signifie que les résultats d'analyse ne parviennent pas aux médecins. Aucune comparaison de fonctionnalités ne répond à cela. Les preuves, si.
L'utilisation prévue est une exécution parallèle. Les deux moteurs reçoivent les mêmes messages de production ; le moteur actuel continue de livrer et Perfuse livre à personne, ce qui est ce que les canaux d'ombre font déjà. Après deux semaines, les sorties sont comparées ici, et la conversation change de « faire confiance à ceci » à « voici les trois messages sur quatre cent mille où nous avons différé, et pourquoi ».
Le regroupement est la fonctionnalité entière
Une différence naive de 400 000 messages produit 400 000 résultats et est fermée sans être lue. Presque chaque différence réelle a une cause : un format de date, un code d'établissement, une étape de transformation que personne n'a portée. Les différences sont donc regroupées par cause - le chemin dans le message et le type de différence - et signalées une seule fois avec un comptage. Trois mille différences d'une cause sont un résultat, et non trois mille. Cette décision unique est ce qui rend le rapport lisible, et un rapport lisible fait la différence entre une migration qui progresse et une qui stagne.
Les valeurs sont retenues par défaut
Le trafic réel est des données de patient, donc un rapport de comparaison est un endroit où les informations sur la santé (PHI) pourraient fuiter dans un ticket, un e-mail ou une diapositive. Par défaut, ce rapport signale les chemins, les types et les comptages - jamais les valeurs. C'est suffisant pour trouver la cause : « MSH-7 diffère dans 3 000 des 3 000 messages » indique à un analyste que c'est le format de date sans afficher une date.
Les valeurs peuvent être activées délibérément, car finalement, quelqu'un a besoin de voir une, et prétendre le contraire ne ferait que les pousser vers un outil pire. C'est un opt-in explicite et le rapport indique clairement qu'il contient le contenu du message.
Source: github.com/biodream-llc/perfuse/internal/equiv
26.43 expr
Le lien HL7 v2.
C'est la logique qui vivait en ligne dans eval.go. Elle n'a pas changé de comportement - délibérément, car le filtre v2 est ce que chaque canal HL7 exécute et l'objectif de la grammaire générique était d'ajouter des formats, et non d'altérer celui-ci.
Source: github.com/biodream-llc/perfuse/internal/expr
26.44 fdlimit
Package fdlimit découvre combien de descripteurs de fichiers ce processus peut ouvrir, et augmente la limite s'il le peut.
Cela existe à cause de la forme de la défaillance qu'il empêche. Chaque connexion entrante est un descripteur, et chaque livraison sortante en cours de route l'est également. Un récepteur qui a cessé de répondre retient un descripteur pour tout le budget de réessai - avec les paramètres par défaut, cinq tentatives à une durée d'attente de trente secondes plus quinze secondes de temporisation, soit près de trois minutes. Quelques centaines de connexions contre un récepteur bloqué sont donc quelques centaines de descripteurs retenus pendant des minutes.
Ne pas disposer de suffisamment de descripteurs de fichiers ne produit pas une erreur propre au lieu où ils ont été utilisés. Cela produit « trop de fichiers ouverts » ailleurs entièrement : la base de données ne peut pas ouvrir son journal, l'interface Web cesse d'accepter, un fichier journal ne peut pas être écrit. Le moteur semble avoir été endommagé en trois endroits sans rapport les uns avec les autres, et la cause réelle est un système partenaire qui s'est tu. C'est l'appel de support que ce package existe pour éviter.
Deux choses se produisent au démarrage. La limite souple est augmentée à la limite dure, ce qui supprime généralement le problème - la limite souple par défaut est souvent de quelques centaines tandis que la limite dure est de dizaines de milliers. Ensuite, tout ce qui est disponible est signalé, afin que le moteur puisse limiter sa propre concurrence à l'intérieur de lui-même plutôt que de la découvrir en la heurtant.
Source: github.com/biodream-llc/perfuse/internal/fdlimit
26.45 fhirpath
Package fhirpath évalue FHIRPath (HL7 FHIRPath N1, 2.0.0) sur des ressources FHIR détenues sous forme de JSON décodé.
Il n'a pas de modèle FHIR : le type d'un élément est connu lorsque le JSON FHIR le dit (un suffixe d'élément de choix, tel que valueQuantity, un resourceType de ressource) ou déduit de la valeur JSON sinon. Cela couvre ce dont ont besoin les vues FHIR SQL et les mesures de qualité sans CQL ; la navigation qui dépend du modèle (le type propre d'un primitif lorsqu'il n'est pas un choix) est répondu à partir de la forme de la valeur.
Source: github.com/biodream-llc/perfuse/internal/fhirpath
26.46 fhirserver
Package fhirserver met en œuvre un serveur FHIR REST.
Cela existe parce que l'extrémité utile d'un mappage v2-FHIR est un endroit où mettre le résultat. Être capable de convertir un message est une démonstration ; être capable de le convertir, de le stocker, puis de retrouver le patient à nouveau par identifiant est un produit.
C'est un véritable serveur FHIR dans les parties qui comptent pour cela : une déclaration de capacité, créer, lire, mettre à jour, supprimer, rechercher sur les paramètres que les gens utilisent réellement, et des bundles de transactions appliquées de manière atomique. Ce n'est pas un serveur FHIR complet - pas d'historique, pas de recherche enchaînée, pas de _include - et il le dit dans sa propre déclaration de capacité plutôt que de laisser un client découvrir les lacunes.
Source: github.com/biodream-llc/perfuse/internal/fhirserver
26.47 formulary
Package formulary est un formulaire de médicaments d'un payeur : quels médicaments chaque plan couvre, sur quel niveau, et avec quels limites (autorisation préalable, thérapie par étapes, limites de quantité), et ce que le membre paie.
Un fichier est la seule source pour tout ce qui répond à une question sur un médicament : l'API Da Vinci US Drug Formulary (publiée à partir de celle-ci en tant que FHIR), les réponses NCPDP Real-Time Prescription Benefit et l'autorisation électronique préalable NCPDP SCRIPT (si un médicament en nécessite une, et quelles questions poser). Un formulaire qui vivait dans trois endroits répondrait à la même question de trois manières.
Source: github.com/biodream-llc/perfuse/internal/formulary
26.48 encadrement
Le cadenassage de package lit et écrit des messages sur un flux d'octets qui n'est pas MLLP.
Pourquoi cela existe séparément de mllp
MLLP est un cadenassage : 0x0B avant, 0x1C 0x0D après. C'est ce que HL7 v2 utilise sur TCP et Perfuse l'a toujours parlé.
Un grand nombre d'équipements ne le font pas. Un analyseur de laboratoire, une balance, un moniteur de lit, un système de facturation plus ancien - chacun tend à avoir sa propre convention, et les conventions sont toutes des variations simples sur les trois mêmes idées : un délimiteur quelque part, une longueur de registre fixe ou une longueur écrite avant la charge utile.
Le connecteur TCP de Mirth couvre cela et Perfuse n'avait rien, donc un site avec un flux de socket qui n'était pas HL7 ne pouvait pas l'utiliser du tout.
L'erreur que ce package est écrit pour éviter
La lecture d'un flux et la supposition de l'endroit où se termine un message est tout le problème. Deviner court et un message est coupé en deux ; deviner long et deux messages arrivent comme un. Les deux produisent une sortie qui ressemble souvent à une erreur, ce qui est pire qu'une erreur, donc chaque mode ici est explicite sur ce qui termine un message et aucun d'entre eux ne revient à un autre.
Un message sans cadenassage du tout est une configuration légitime - certains appareils ouvrent une connexion, envoient un message et ferment - mais il ne peut pas être combiné avec autre chose et ne peut pas être utilisé sur une connexion qui reste ouverte, il est donc nommé et validé plutôt que traité comme une valeur par défaut.
Source: github.com/biodream-llc/perfuse/internal/framing
26.49 ftpconn
Le package ftpconn télécharge des fichiers via FTP et FTPS en utilisant uniquement la bibliothèque standard.
FTP est ancien, bavard et n'est pas un bon protocole. Il est également toujours la façon dont un grand nombre de systèmes hospitaliers acceptent des fichiers, généralement parce que l'extrémité lointaine est un analyseur de laboratoire ou un service de bureau dont le logiciel n'a pas été touché depuis qu'il fonctionnait. Refuser de le prendre en charge ne rend pas ces systèmes modernes ; cela rend Perfuse inutilisable sur ces sites.
Implémenté ici plutôt que pris en tant que dépendance pour la même raison que S3 : la liste de huit dépendances est un argument réel avec quiconque examine le logiciel avant qu'un hôpital ne l'installe. Le canal de contrôle FTP est du texte orienté ligne sur TCP, donc ceci est quelques centaines de lignes de net et crypto/tls.
Ce qui est pris en charge et ce qui est refusé
Mode passif uniquement. Le mode actif nécessite que le serveur ouvre une connexion vers le client, ce que chaque pare-feu d'hôpital construit ce siècle bloque, et proposer cela signifierait que les gens le configurent puis déboguent un pare-feu.
FTPS explicite (AUTH TLS) est pris en charge et est la valeur par défaut lorsque TLS est demandé. Le FTPS implicite sur le port 990 est également pris en charge car certains analyseurs ne parlent que cela.
Le FTP simple est pris en charge et avertit. Il envoie le mot de passe en clair, et un site qui doit l'utiliser doit être informé une fois plutôt que de laisser découvrir à partir d'une capture de paquet.
Source: github.com/biodream-llc/perfuse/internal/ftpconn
26.50 gcp
Le package gcp parle à Google Cloud Pub/Sub et Cloud Storage via leurs API REST, avec l'authentification 2.0 d'OAuth de Google effectuée ici : une clé de compte de service signe un JWT (RS256, crypto/rsa) qui est échangé contre un jeton d'accès, ou, sur Google Cloud lui-même, le serveur de métadonnées en distribue un.
Aucun SDK Google.
Les émulateurs (l'émulateur Pub/Sub, fake-gcs-server) n'acceptent aucune information d'identification : définissez le point de terminaison et laissez les informations d'identification vides.
Source: github.com/biodream-llc/perfuse/internal/gcp
26.51 générer
Le package générer crée des messages HL7 v2 synthétiques.
Deux utilisations. Quelqu'un qui essaie Perfuse a besoin de trafic pour regarder, et un test de canal a besoin d'un élément de fixation qui est suffisamment réaliste pour exercer la chose testée. Un générateur est une extension payante dans Mirth, ce qui vous indique que les gens en veulent un.
Tout ici est inventé. Les noms proviennent d'une liste fixe de noms évidemment fictifs, les identificateurs sont séquentiels dans une exécution, et les adresses sont fabriquées. Ce n'est pas un disclaimer, c'est la conception : un générateur qui produirait des noms réels plausibles finirait par en mettre un dans un élément de fixation, un rapport de bogue et puis un référentiel.
Le réalisme est appliqué là où cela compte pour les tests et nulle part ailleurs. Les horodatages comportent des décalages, les champs répétitifs se répètent effectivement, un nom comporte parfois une initiale du deuxième prénom et parfois non, et environ un message sur douze est délibérément gênant : un champ facultatif manquant, un séparateur inhabituel mais légal, un composant vide. Alimenter un canal avec rien que des messages parfaitement formés vous apprend très peu de choses.
Source: github.com/biodream-llc/perfuse/internal/generate
26.52 hl7dict
Le package hl7dict nomme les champs des segments HL7 v2.
Ceci existe pour un seul écran : un visualiseur de messages qui peut vous indiquer que PID-5.1 est le nom de famille du patient au lieu de vous laisser compter les accents. Quiconque a débogué une interface a fait ce comptage manuel, et c'est la source la plus courante des erreurs de décalage d'un qui placent une valeur dans le mauvais champ.
Ce n'est pas la norme complète. HL7 v2 comporte des centaines de segments et des milliers de champs, et ceux-ci sont ceux qui apparaissent dans les trafics ADT, ORU, ORM et SIU. Un champ inconnu est signalé comme inconnu plutôt que deviné.
Source: github.com/biodream-llc/perfuse/internal/hl7dict
26.53 hl7v3
Le package hl7v3 lit les messages HL7 version 3.
La version 3 est une chose différente de la version 2 portant le même nom. La version 2 est un flux de segments délimités par des pipes dont la signification est positionnelle ; la version 3 est du XML généré à partir d'un modèle d'information de référence, où la signification est portée par les noms d'éléments et par un petit ensemble de types de données qui se répètent partout. Presque rien ne se transfère entre les deux au-delà du vocabulaire clinique.
Dans la pratique, v3 arrive sous l'une de deux formes. Soit c'est un document CDA, qui est dérivé de v3 et géré par le package cda, soit c'est une transaction IHE - PIX et PDQ v3 en particulier, qui est la façon dont de nombreux hôpitaux résolvent les identificateurs de patients entre les systèmes. Ce package cible le second.
Pourquoi les types de données viennent en premier
La chose la plus conséquente à propos de v3 est qu'un élément peut être présent et explicitement nul, avec une raison indiquée. Une date de naissance portant nullFlavor="ASKU" signifie que le patient a été demandé et a refusé de répondre. Une date de naissance portant nullFlavor="NAV" signifie que la valeur existe mais n'est pas disponible pour le moment, donc demander à nouveau plus tard peut fonctionner. Une date de naissance qui est simplement absente signifie que personne n'a enregistré quoi que ce soit.
Réduire ces éléments à une chaîne vide est l'erreur que ce package est conçu pour prévenir. Ce n'est pas une perte cosmétique : un système en aval qui reçoit une date de naissance vide où la source a indiqué "patient a refusé" traitera généralement cela comme des données manquantes à poursuivre, et une correspondance démographique qui aurait dû être laissée non résolue est résolue par une personne qui devine. Donc, chaque type de données ici distingue l'absence, le nul avec raison et le présent.
Source: github.com/biodream-llc/perfuse/internal/hl7v3
26.54 hl7xml
Le package hl7xml convertit les messages HL7 v2 en XML et vice versa, ainsi qu'en encodage ER7.
La forme n'est pas un choix de conception. Les scripts Mirth sont écrits contre la sortie de son propre sérialiseur ER7-XML, ils contiennent donc des expressions comme
msg['PID']['PID.5']['PID.5.1'].toString()
et la promesse qu'un script existant s'exécute sans changement n'est tenue que si l'arbre qu'il parcourt a exactement les mêmes noms d'éléments, un embranchement et un comportement de répétition. Chaque décision ci-dessous est donc "ce que fait Mirth", et non "ce qui serait plus ordonné".
Les deux qui comptent le plus :
Chaque champ est enveloppé dans des éléments de composant numérotés même lorsque le champ n'a qu'un seul composant, donc PID-5 avec la valeur "Doe" produit toujours <PID.5><PID.5.1>Doe</PID.5.1></PID.5>. Les scripts indexent directement sur .1 constamment et un arbre qui placerait le texte sur l'élément de champ briserait presque tous les scripts.
MSH conserve les numéros de champs HL7 standard, où MSH-1 est le séparateur de champ et MSH-9 est le type de message. L'analyseur dans internal/hl7 indexe MSH avec un décalage car le séparateur occupe une position que aucun délimiteur ne divise, et ce décalage s'arrête ici : un script disant MSH.9 signifie le type de message.
Source: github.com/biodream-llc/perfuse/internal/hl7xml
26.55 ibmmq
Le package ibmmq envoie et lit des files d'attente IBM MQ via l'API REST de messagerie du gestionnaire de files d'attente (mqweb), que IBM MQ 9.1.5 et les versions ultérieures expédient sur chaque plate-forme, y compris z/OS.
Il n'a pas besoin de bibliothèque de client MQ : le protocole MQI natif est d'IBM et non documenté, et l'API REST est la méthode prise en charge pour atteindre MQ sans client. (IBM MQ parle également AMQP 1.0 sur un canal AMQP ; le connecteur amqp de Perfuse couvre cette voie.)
La lecture est d'au moins une fois : le premier message est parcouru, remis à l'appelant et supprimé par son ID de message uniquement une fois que l'appelant l'a traité. Un message qui n'a pas pu être traité reste dans la file d'attente, en premier.
Source: github.com/biodream-llc/perfuse/internal/ibmmq
26.56 identité
Trouver un message par ce que vous savez à son sujet, quel que soit le format dans lequel il est arrivé.
Le contenu de recherche existant correspond aux métadonnées, propose une correspondance de sous-chaîne contre la charge utile et peut évaluer une expression de filtre - mais l'expression est évaluée contre HL7 v2 uniquement, et chaque expression nécessite de connaître le chemin. Ainsi, trouver le trafic d'un patient signifie connaître que l'identité se trouve à PID-3 dans une admission HL7 v2, à Patient.identifier dans une ressource FHIR, à (0010,0020) dans une instance DICOM et à NM109 d'une boucle NM1*IL dans une revendication 837. Quatre formats, quatre vocabulaires, et pendant un incident, le message recherché peut se trouver dans l'un d'entre eux.
Ce package mappe un petit ensemble de concepts - qui est le message, quelle visite, quelle étude, quelle revendication - sur l'endroit où chaque format les conserve, afin qu'une recherche puisse être effectuée pour « MRN 12345 » plutôt que pour un chemin. Les concepts sont délibérément peu nombreux : ce sont les choses que les gens ont réellement en main lorsqu'ils ont besoin de trouver un message, qui est un numéro sur un appel téléphonique ou un nom sur une plainte.
Pourquoi l'extraction se produit une fois, au moment de l'enregistrement
L'alternative consiste à analyser les charges utiles au moment de la requête, ce que fait la recherche d'expression. Cela fonctionne et est honnête en ce qui concerne une analyse limitée, mais ne peut pas répondre à « tous les messages concernant ce patient sur quatre flux et deux mois » sans lire chaque ligne. L'extraction une fois dans une table indexée transforme cela en une recherche d'index.
Il s'agit d'une escalation de confidentialité, et elle est facultative
Les noms et les identificateurs de patients se trouvent actuellement à l'intérieur d'une colonne de charge utile opaque. Les indexer les rend consultables, ce qui est l'objectif, et les rend également énumérables, ce qui constitue un changement réel d'exposition : une base de données qui ne pouvait être que parcourue peut désormais être interrogée « lister tous les patients ». C'est une décision pour le site, et non pour ce package, donc l'extraction est commutable et chaque recherche à travers elle est enregistrée dans le journal d'audit des informations sur la santé (PHI).
Source: github.com/biodream-llc/perfuse/internal/identity
26.57 iis
Le package iis parle du transport partagé par chaque registre d'immunisation américain : le service Web SOAP IIS du CDC.
En 2011, un panel d'experts convoqué par le CDC et l'American Immunization Registry Association a choisi une interface SOAP pour soumettre des messages HL7 v2 aux systèmes d'information sur l'immunisation, et les registres l'ont adoptée. Le WSDL est petit - deux opérations, connectivityTest et submitSingleMessage - et le message HL7 (un VXU pour signaler une injection, un QBP^Q11 pour demander l'historique d'un patient) voyage sous forme de texte échappé à l'intérieur du corps SOAP. La réponse revient de la même manière : un ACK, ou un RSP^K11 transportant l'historique et la prévision.
La destination SOAP générique pourrait être configurée pour effectuer cela, mais chaque site devrait taper la même enveloppe, obtenir l'espace de noms correct, placer les informations d'identification dans le corps plutôt que dans l'authentification HTTP, puis lire l'acknowledgement HL7 dans la réponse pour apprendre si le registre a conservé l'enregistrement. Un registre répond à une injection rejetée avec un HTTP 200 et un AR ; traiter le 200 comme une réussite est la façon dont les immunisations échouent silencieusement à être signalées. Ce package effectue donc l'enveloppe du CDC, et juge l'acknowledgement, une fois.
Ce qu'il ne fait pas : les nom d'utilisateur et mot de passe du WSDL sont les informations d'identification de l'application du registre et sont envoyés comme le WSDL le dit, dans le corps. Le TLS mutuel, lorsque le registre l'exige, est la configuration TLS de la destination comme pour tout appel HTTPS. Rien ici n'est spécifique à un État ; lorsque les États diffèrent (identifiant d'installation requis ou non, SOAP 1.1 accepté ou non, avertissements envoyés sous forme de AE) les paramètres de la destination le disent.
Source: github.com/biodream-llc/perfuse/internal/iis
26.58 kafka
Kafka, en tant que client plutôt que comme quelque chose à remplacer.
Un système de santé qui a une colonne vertébrale d'événements a une colonne vertébrale Kafka, et les systèmes construits au cours de la dernière décennie publient sur celle-ci plutôt que sur un courtier JMS. Ce connecteur existe donc pour faire de Perfuse le bord conscient de la santé de la plate-forme d'événements de quelqu'un d'autre : il lit les messages cliniques sur les sujets et les publie sur les sujets, et il ne tente pas délibérément d'être une plate-forme de traitement de flux. La fenêtrage, les joints, le traitement de flux et les registres de schémas sont l'écosystème Kafka et y restent.
Pourquoi une dépendance, lorsque STOMP et MLLP ont été écrits à la main
La règle énoncée dans ce référentiel est qu'une dépendance doit acheter une fonctionnalité plutôt que de la commodité, et doit être du Go pur afin qu'une binaire statique puisse toujours être compilée pour chaque cible. franz-go est du Go pur et ne contient pas de cgo, ce qui a été vérifié contre les six cibles.
Le protocole Kafka n'est pas celui de STOMP. STOMP est un protocole texte qui tient dans quelques centaines de lignes. Kafka est un protocole binaire versionné sur environ soixante-dix types de requêtes, et la partie qui compte le plus ici - les groupes de consommateurs - est un protocole de coordination distribué avec des phases de jointure, de synchronisation, de battement cardiaque et d'engagement d'offset et une danse de rééquilibrage entre eux. Se tromper subtilement ne produit pas une défaillance évidente : cela produit une partition que personne ne lit, ou deux consommateurs lisant la même partition. Dans un flux clinique, ce sont un résultat de laboratoire manquant et une commande dupliquée. C'est une fonctionnalité, et ce n'est pas la peine de le faire à la main pour économiser une dépendance.
Source: github.com/biodream-llc/perfuse/internal/kafka
26.59 ldap
Le package ldap parle suffisamment LDAP pour authentifier une personne et lire ses groupes.
Les hôpitaux utilisent presque universellement Active Directory, et AD parle LDAP. OpenID Connect est la meilleure réponse lorsque cela est possible - voir internal/oidc, et la note qui y est consacrée à propos de Mirth qui n'a pas de connexion unique à aucun prix - mais un moteur d'intégration est souvent situé sur un VLAN isolé où un navigateur ne peut pas atteindre un fournisseur d'identité. C'est pour cela que cela existe.
BER personnalisé plutôt qu'une dépendance, pour la même raison que DICOM et STOMP : l'encodage est petit, et ce qui arrive sur cette socket décide si quelqu'un peut accéder à un système qui manipule des données de patients.
encoding/asn1 dans la bibliothèque standard n'est pas utilisable ici. Il cible DER et rejette les balises spécifiques au contexte et les balises implicites que LDAP utilise partout, donc les parties qui comptent devraient être personnalisées de toute façon.
Source: github.com/biodream-llc/perfuse/internal/ldap
26.60 boîte aux lettres
Le package boîte aux lettres lit les courriels à partir de serveurs IMAP4rev1 (RFC 3501) et POP3 (RFC 1939), en se connectant avec un mot de passe ou avec OAuth 2.0 (SASL XOAUTH2, comme Microsoft 365 et Gmail l'exigent), et décompose les messages (RFC 5322 et MIME) afin qu'une pièce jointe ou le corps du texte puisse devenir un message sur un canal.
Seulement ce dont un flux entrant a besoin : sélectionner une boîte aux lettres, trouver les courriels non lus, les récupérer en entier, puis les déplacer, les marquer ou les supprimer. Bibliothèque standard uniquement ; TLS est crypto/tls.
Source: github.com/biodream-llc/perfuse/internal/mailbox
26.61 mappeur
Le package mappeur suggère des mappages de champs entre les systèmes avec des scores de confiance.
Il s'agit d'un moteur de mappage intelligent basé sur des règles. Aucun LLM, aucun appel réseau, aucune dépendance externe. Il s'exécute hors ligne dans le même binaire et n'envoie jamais de données de patients nulle part.
Le moteur combine plusieurs signaux - correspondance de chaînes floues sur les noms de champs, reconnaissance de modèles d'identificateurs de soins de santé, recherches de systèmes de codes, et données d'acceptation historiques - en un seul score de confiance par suggestion. Lorsque la confiance est en dessous d'un seuil configurable, le mappeur s'abstient plutôt que de deviner incorrectement, car un mappage incorrect dans les soins de santé peut acheminer les données vers le mauvais champ et cela constitue un défaut de sécurité des patients.
L'abstention est la décision de conception principale. Un système qui produit toujours une réponse entraîne les utilisateurs à cesser de vérifier, et la seule fois où il se trompe, personne ne le remarque jusqu'à ce qu'un résultat de laboratoire atterrisse dans un champ de notes. Un système qui dit « Je ne sais pas » force une décision humaine exactement lorsque l'humain est nécessaire.
Source: github.com/biodream-llc/perfuse/internal/mapper
26.62 mesure
Le package mesure évalue les Mesures FHIR (mesures de qualité numériques) dont les critères de population sont FHIRPath, et écrit le résultat sous la forme d'un rapport de mesure FHIR : résumé, individuel ou liste de sujets, avec des stratificateurs et un score de proportion.
Chaque critère est évalué une fois par patient, avec l'accent mis sur un Bundle du dossier du patient (leur compartiment) et ces variables : %sujet (le Patient), %periodStart et %periodEnd (la période de mesure, sous forme de DateTimes) et %« Période de mesure » (la même qu'une Période). Les critères en CQL sont refusés avec la raison : Perfuse n'a pas de moteur CQL.
Source: github.com/biodream-llc/perfuse/internal/measure
26.63 métriques
Le package métriques collecte ce que le moteur fait et conserve suffisamment d'historique pour le dessiner.
Un moteur d'interface est surveillé, et non simplement exécuté. Lorsqu'un service dit que les résultats ont cessé d'arriver il y a vingt minutes, la question est de savoir ce qui a changé il y a vingt minutes, et cela ne peut pas être répondu par les compteurs actuels seuls. Il conserve donc des séries plutôt que des totaux, en mémoire, à une résolution fixe.
Trois décisions façonnent cela.
La latence est conservée sous la forme d'un histogramme plutôt que d'une moyenne. Un temps de livraison moyen est presque inutile dans ce domaine : le nombre qui compte est de savoir si les quelques pour cent de messages les plus lents sont suffisamment lents pour enfreindre un engagement de délai, et une moyenne cache exactement cela. Les seaux sont exponentiels et fixés au moment de la construction, donc l'enregistrement d'une durée est une comparaison et un incrément sans allocation.
Les séries sont des tampons à anneau bornés, dimensionnés lorsque le collecteur est créé. Rien ici ne grandit sans limite, car un moteur d'interface s'exécute pendant des mois à la fois et un système de métriques qui nécessite un redémarrage est pire que rien.
La cardinalité est limitée. Une valeur d'étiquette prise à partir des données de message - une application d'envoi, par exemple - peut prendre des milliers de valeurs si quelqu'un déconfigure incorrectement un flux, et les étiquettes non limitées sont la façon standard dont la surveillance prend en charge la chose qu'elle surveille. Au-delà de la limite, les valeurs s'effondrent dans un seau « autre » et la limite est elle-même signalée.
Source: github.com/biodream-llc/perfuse/internal/metrics
26.64 mirth
Analyse Java pour les canaux Mirth importés.
Pourquoi cela existe
Mirth exécute Rhino sur la JVM, donc un script Mirth peut appeler n'importe quel Java sur le chemin de classe, y compris les classes de serveur Mirth. Perfuse exécute goja et n'a pas de runtime Java. Il refuse ces appels avec une erreur nommant la classe - mais ce refus se produit lorsque le script s'exécute, ce qui, pour un connecteur source, signifie lorsque le premier message réel arrive.
Un processus de migration utilisait donc à l'origine : l'importation réussit silencieusement, le canal est déployé, et le premier message provenant du fil échoue. Une migration qui semble propre et qui se brise sur le premier trafic est pire qu'une migration qui refuse à la porte, car la personne qui l'a fait a déjà dit à ses collègues que cela a fonctionné.
Ceci trouve ces appels au moment de l'importation et indique ce qu'il faut faire pour chacun d'eux.
Pourquoi quatre verdicts et non deux
« Utilise Java » est un élément d'information et le mauvais, car le Java qu'un canal Mirth réel utilise se divise en groupes avec des quantités de travail complètement différentes. Environ la moitié de ce que les sites écrivent réellement est SimpleDateFormat et HashMap, que JavaScript prend en charge de manière native. Une partie de cela est l'API de script documentée de Mirth, que Perfuse met déjà en œuvre sous les mêmes noms. Un peu de cela veut démarrer et arrêter des canaux, que Perfuse peut faire via son API REST mais n'expose pas aux scripts. Et une partie de cela est un fichier jar de fournisseur qui ne sera jamais exécuté ici.
Signaler ceux-ci comme un seul nombre n'indique rien à un migrateur sur le fait que son après-midi ou son trimestre est en jeu.
Source: github.com/biodream-llc/perfuse/internal/mirth
26.65 mirthlive
Le package mirthlive trouve les moteurs Mirth en cours d'exécution que les tests d'interopérabilité parlent.
Mirth Connect a cessé d'être open source à la version 4.6 (mars 2025). Les sites qui le quittent vont dans l'un des trois endroits suivants : Mirth 4.5.2, la dernière version open, qu'ils continuent à exécuter ; le Open Integration Engine, la fourche hébergée par Eclipse ; ou BridgeLink, la fourche d'Innovar, qui numérote ses versions par année (26.9.0). Un canal que Perfuse exporte doit être chargé dans tous ceux-ci, et un canal que l'un d'eux exporte doit être importé ici, donc chaque test en direct s'exécute une fois par moteur qui répond.
Les moteurs sont trouvés en demandant, et non configurés : ./scripts/interop-up.sh les démarre sur des ports fixes, et un moteur qui n'est pas en cours d'exécution est signalé comme ignoré plutôt que de passer silencieusement. PERFUSE_MIRTH_ENGINES remplace la liste, sous la forme de paires nom=url séparées par des virgules.
Seuls les tests importent ceci. Il vit à l'extérieur d'un fichier _test.go car deux packages le partagent.
Source: github.com/biodream-llc/perfuse/internal/mirth/mirthlive
26.66 mpi
Le package mpi est un index de patients maîtres : il prend des dossiers de patients de chaque système source (chacun identifié par son autorité d'attribution et son numéro), décide lesquels appartiennent à la même personne et attribue à chaque personne un identifiant d'entreprise (EUID).
Certaines correspondances se connectent d'elles-mêmes ; les incertaines attendent dans une file d'attente d'examen pour qu'une personne prenne une décision ; chaque lien, délien, fusion et décision est enregistré avec la personne qui l'a effectué.
La correspondance est déterministe en premier (un identifiant provenant d'un système que le site fait confiance pour être unique par personne, tel qu'un identifiant national ou un numéro d'entreprise) et probabiliste sinon : poids Fellegi-Sunter sur le nom, la date de naissance, le sexe, le code postal, le téléphone et l'adresse, avec Jaro-Winkler pour les noms. Il ne décide rien de clinique : il indique quels dossiers sont la même personne, avec ses raisons, pour qu'une personne confirme lorsqu'il n'est pas sûr.
Source: github.com/biodream-llc/perfuse/internal/mpi
26.67 mqtt
Le package mqtt est un client MQTT 3.1.1 : connecter (avec TLS, un nom d'utilisateur et un mot de passe, ou un certificat client), publier à QoS 0 ou 1, s'abonner et reconnaître chaque message QoS 1 reçu une seule fois lorsque l'appelant indique qu'il a été traité.
Écrit contre la norme OASIS MQTT 3.1.1 plutôt que d'être importé, comme les autres protocoles de fil Perfuse. 3.1.1 est la version que chaque courtier parle : Mosquitto, EMQX, HiveMQ, VerneMQ, le plugin MQTT de RabbitMQ, le canal de télémétrie d'IBM MQ, AWS IoT Core et Azure Event Grid.
Livraison : un message reçu à QoS 1 est confirmé (PUBACK) uniquement lorsque Ack est appelé. Un appelant qui ne peut pas traiter un message ferme la connexion à la place ; avec une session persistante (CleanSession false) le courtier envoie à nouveau le message, marqué comme un doublon, lorsque le client se reconnecte. MQTT 3.1.1 n'a pas d'accusé de réception négatif, donc c'est la seule façon de demander à nouveau un message.
Source: github.com/biodream-llc/perfuse/internal/mqtt
26.68 msgstore
Trouver un message stocké en fonction de ce que quelqu'un sait à son sujet.
La recherche qu'une personne a réellement besoin est « voici un numéro d'un appel téléphonique, montrez-moi chaque message à ce sujet ». Avant cela, cela signifiait soit une correspondance de sous-chaîne sur les charges utiles, ce qui est grep et lent, soit une expression de filtre, qui nécessite de savoir que l'identité vit à PID-3 dans HL7 v2 et ailleurs dans les trois autres formats sur le même serveur.
L'identité est extraite une fois lorsque le message est enregistré et indexé, donc c'est une recherche plutôt qu'un balayage. Le coût est payé sur le chemin d'enregistrement, une fois par message, au lieu de chaque recherche.
Source: github.com/biodream-llc/perfuse/internal/msgstore
26.69 natid
Le package natid connaît les identificateurs nationaux de patients et de personnes du Royaume-Uni et de l'Europe : leurs formats, leurs chiffres de contrôle, le système d'identifiant que les guides FHIR de chaque pays nomment, et combien de l'un peut être affiché.
Il existe pour l'index de patients. Un numéro national est la preuve la plus solide que deux dossiers sont une seule personne, et également la plus facile à mal interpréter : un chiffre tapé deux fois donne un numéro qui appartient à quelqu'un d'autre, et une source envoie le numéro NHS sous un OID tandis qu'une autre l'envoie sous son URL FHIR. Donc, chaque identifiant que l'index stocke passe par ici : son chiffre de contrôle est testé (un chiffre de contrôle incorrect n'est jamais utilisé pour relier), son espacement est supprimé et son système est écrit d'une seule manière.
Ce qui est vérifié et ce qui ne l'est pas est indiqué par schéma. Les algorithmes sont publics ; les URI des systèmes d'identifiant sont ceux du pays où un guide FHIR national en nomme un (SystemVerified), et une valeur par défaut documentée sinon, que le site modifie en sa valeur nationale sous Paramètres → Index de patients. Rien de tout cela ne décide rien de clinique.
Source: github.com/biodream-llc/perfuse/internal/natid
26.70 ncpdp
Écriture d'un champ dans une transmission NCPDP.
Pourquoi une écriture refuse un chemin ambigu
La lecture retourne toutes les valeurs qu'un chemin adresse, car un filtre demandant si un conflit DUR est une duplication thérapeutique doit voir tous les éléments. Une écriture ne peut pas fonctionner de cette façon. Si D7 adresse les codes de produit de deux demandes dans une transmission, définir D7 n'a pas de sens unique : écrire les deux modifierait un médicament que personne n'a demandé, et écrire le premier laisserait silencieusement le second.
Une écriture refuse donc un chemin qui adresse plus d'un champ, et l'erreur nomme la forme qualifiée qui serait non ambiguë. C'est la même logique qui donne aux étapes de transformation aucune action de suppression : là où la réponse honnête est que la configuration est ambiguë, le dire vaut mieux que de choisir un.
Source: github.com/biodream-llc/perfuse/internal/ncpdp
26.71 oidc
Le package oidc vérifie les identités OpenID Connect.
Écrit contre la bibliothèque standard plutôt que contre une dépendance JWT. L'authentification est l'endroit où une dépendance non auditée est le moins acceptable, la vérification de signature pour les algorithmes qui comptent est d'environ cent lignes de crypto/rsa et crypto/ecdsa, et Perfuse transporte déjà suffisamment de choses pour que l'ajout d'autres nécessite une raison plutôt qu'une habitude.
La portée est délibérément étroite : vérifier qu'un fournisseur d'identité a garanti une personne, et rapporter ce qu'il a dit à son sujet. Tout le reste - ce qu'ils peuvent faire, combien de temps la session dure - reste avec Perfuse, car un fournisseur d'identité sait qui est quelqu'un et non ce qu'il est autorisé à faire dans un moteur d'intégration.
Source: github.com/biodream-llc/perfuse/internal/oidc
26.72 parité
Le package parity compare ce que Perfuse produit à ce que le moteur remplacé a produit.
Pourquoi cela existe
Perfuse peut importer un canal Mirth et peut tracer ce qu'il ferait avec un message. Aucun de ces deux éléments ne répond à la question que quelqu'un se pose réellement avant de déplacer un flux en direct, qui est : est-ce que cela produira la même sortie que la chose qui a fonctionné pendant six ans ?
Aucune quantité de qualité de conception ne répond à cela. La seule réponse honnête est la preuve, et la preuve doit provenir de la sortie du vieux moteur sur le trafic du site.
Pourquoi les paires doivent être fournies
Cela ne peut pas atteindre Mirth, et prétendre le contraire serait le pire type de fonctionnalité. Ce dont il a besoin, ce sont des paires : un message tel qu'il est arrivé, et le message que le vieux moteur a produit à partir de celui-ci. Les deux se trouvent dans le magasin de messages de Mirth et peuvent être exportés à partir de son navigateur de messages, qui est une chose que l'administrateur sait déjà faire.
Cette contrainte est indiquée plutôt que cachée. Un outil qui prétendrait vérifier une migration sans jamais voir la sortie du vieux moteur ne vérifierait rien.
Pourquoi les différences sont regroupées plutôt que listées
Un parcours sur cinquante mille messages qui rapporte quatre mille différences n'a rien dit à quelqu'un qu'il puisse agir. Le même parcours rapportant que PID-8 diffère dans chaque message parce que le vieux moteur a mappé M à Male lui a dit exactement une chose à décider.
Les résultats sont donc regroupés par champ, avec un décompte, un exemple et les paires de valeurs distinctes vues. Une décision par résultat est l'unité que quelqu'un peut traiter.
Source: github.com/biodream-llc/perfuse/internal/parity
26.73 pas278
Le package pas278 mappe entre l'autorisation préalable Da Vinci et la transaction X12 278.
Pourquoi cela existe
CMS-0057-F exige que les payeurs exposent une API FHIR d'autorisation préalable d'ici le 1er janvier 2027. Elle ne remplace pas la transaction X12 278, et elle ne le ferait jamais : le système de gestion des utilisations d'un payeur décide des autorisations et parle 278. Un payeur qui respecte la règle traduit donc FHIR en 278 et vice versa, et un fournisseur qui envoie 278 aujourd'hui enverra FHIR demain aux mêmes payeurs qui acceptent toujours les deux.
Cette traduction est la chose la plus précieuse à posséder. Un moteur qui détient les deux modèles et ne peut pas les convertir laisse la partie la plus difficile du travail - et la partie où les erreurs sont coûteuses - à celui qui l'intègre.
Les règles que ce package suit, indiquées plutôt qu'impliquées
Écrit pour la même raison que v2fhir écrit ses propres règles : la mise en correspondance est où les projets d'interopérabilité échouent, et les échecs sont silencieux.
- Une décision n'est jamais mise à niveau. La certification partielle ne devient pas une approbation, et une demande que le payeur a refusé de considérer ne devient pas un refus. Les deux réductions sont disponibles dans la mise en correspondance évidente et les deux sont fausses dans la direction qui coûte à quelqu'un des semaines : un appel interjeté contre une décision que personne n'a prise, ou six sessions réservées contre trois approuvées. - Rien n'est inventé pour remplir un champ requis. Lorsque le format cible exige quelque chose que la source ne transporte pas, la mise en correspondance le signale comme une note plutôt que de fournir une valeur par défaut plausible. Un numéro d'autorisation fabriqué est pire qu'un absent. - Tout jugement est signalé. Les notes reviennent avec le résultat, afin qu'une personne puisse lire la poignée qui a nécessité une décision plutôt que toute la sortie. - Les aller-retour sont testés, et non supposés. Une mise en correspondance qui perd un champ dans une direction est trouvée en convertissant à nouveau et en comparant, ce qui est la seule façon de voir un champ que personne n'a pensé à affirmer.
Source: github.com/biodream-llc/perfuse/internal/pas278
26.74 pdf
Le package pdf écrit des documents texte simples, en utilisant uniquement la bibliothèque standard.
L'écriture de document Mirth rend l'HTML en PDF, ce qui nécessite un moteur de mise en page. Ce n'est pas ce que ceci est. Ceci produit un document texte simple, paginé, avec une police à espacement uniforme, et il existe parce que l'exigence réelle dans presque tous les sites qui utilisent ce connecteur est « mettre ce rapport sur un partage afin que quelqu'un puisse l'imprimer » - un résumé de sortie, un rapport de résultat, une réconciliation quotidienne. Ce sont des textes.
Refuser entièrement cette fonctionnalité laisserait un bloqueur de migration de niveau 2 en place. Intégrer un moteur de rendu HTML coûterait plus que le reste du binaire et apporterait un flux de vulnérabilités avec lui, ce qui annulerait l'argument de la liste des matériaux. Donc : du texte, décrit honnêtement comme du texte, et un site qui a réellement besoin d'une sortie composée est mieux servi par une destination de fichier et un outil conçu pour cela.
Pourquoi écrire un PDF plutôt qu'un fichier texte
Parce que le destinataire est généralement une personne avec une imprimante et un partage Windows, et un fichier .txt imprimé à partir d'un partage perd sa pagination, ses marges et souvent ses fins de ligne. Un PDF s'imprime de la même manière partout, ce qui est la seule raison pour laquelle quelqu'un a demandé un PDF.
Source: github.com/biodream-llc/perfuse/internal/pdf
26.75 pgp
Le package pgp chiffre, signe, déchiffre et vérifie les messages OpenPGP (RFC 9580, et RFC 4880 pour les anciens pairs), pour les payeurs, les organismes de compensation et les agences étatiques qui échangent des fichiers sur SFTP ou par courriel sous PGP.
La cryptographie est github.com/ProtonMail/go-crypto, la fourche maintenue de golang.org/x/crypto/openpgp ; rien ici n'implémente un primitif. Ce package ne charge que les clés et décide de ce qu'un message doit transporter.
Source: github.com/biodream-llc/perfuse/internal/pgp
26.76 pixv3
Le package pixv3 est la face HL7 version 3 de l'index des patients : les profils IHE Patient Identifier Cross-referencing et Patient Demographics Query, car la plupart des hôpitaux en dehors du monde FHIR les parlent encore.
- ITI-44, Patient Identity Feed HL7 V3 : une source ajoute un patient (PRPA_IN201301UV02), révise un (PRPA_IN201302UV02) ou dit que deux enregistrements sont la même personne (PRPA_IN201304UV02). Répondu avec MCCI_IN000002UV01. - ITI-45, PIXV3 Query : les autres identifiants de la personne détenant un (PRPA_IN201309UV02 -> PRPA_IN201310UV02). - ITI-47, PDQV3 Query : les personnes correspondant à certaines données démographiques (PRPA_IN201305UV02 -> PRPA_IN201306UV02), avec continuation (QUQI_IN000003UV01) et annulation (QUQI_IN000003UV01_Cancel).
Les réponses proviennent du même index de patient que PIXm, PDQm, Patient/$match et l'écran d'index, donc un enregistrement alimenté en v3 est trouvé sur FHIR et vice versa. Les messages sont écrits à la main, dans l'ordre du schéma, pour la raison hl7v3.Ack donne.
Source: github.com/biodream-llc/perfuse/internal/pixv3
26.77 priorauth
Le package priorauth implémente le flux de travail d'autorisation préalable du côté du fournisseur, requis par CMS-0057. Il soumet des demandes d'autorisation préalable aux API FHIR des payeurs, suit les réponses et convertit entre les types internes et les ressources FHIR.
Source: github.com/biodream-llc/perfuse/internal/priorauth
26.78 privacy
Le package privacy répond aux demandes d'un sujet de données en vertu du RGPD et du RGPD du Royaume-Uni : trouver tout ce que ce serveur détient sur une personne, le leur donner (articles 15 et 20), le supprimer (article 17) et conserver ce que couvre une rétention légale.
Il atteint tous les endroits où Perfuse conserve les données de patient : le magasin de messages (via son index d'identité), la file d'attente de livraison, le magasin FHIR (les ressources Patient de la personne et tout ce qui les référence, avec leur historique), les demandes d'autorisation préalable stockées, et l'index patient, dont les liens élargissent un identifiant en tous les numéros de la personne. Ce qu'il ne peut pas atteindre, il le nomme : les traces envoyées à un collecteur, le journal d'audit (conservé, car c'est l'enregistrement de qui a fait quoi), et les sauvegardes, qui conservent ce qui a été supprimé jusqu'à leur expiration - donc chaque suppression est écrite dans un registre, sous forme de hachages salés des identifiants plutôt que des identifiants, et peut être appliquée à nouveau à une copie restaurée.
Il ne décide rien au nom de qui que ce soit. Que une demande doit être accordée, et qu'une exemption s'applique, est la décision du contrôleur ; la suppression nécessite l'approbation d'un second administrateur, et une rétention légale la refuse catégoriquement.
Source: github.com/biodream-llc/perfuse/internal/privacy
26.79 publichealth
Le package publichealth implémente la déclaration de santé publique bidirectionnelle : déclaration électronique de cas (eCR), déclaration électronique de laboratoire (ELR) et requêtes de registre d'immunisation.
Chaque hôpital est légalement tenu de déclarer certaines conditions - tuberculose, rougeole, hépatite, COVID-19, infections sexuellement transmissibles, maladie d'origine alimentaire - aux agences de santé publique étatiques et locales. La déclaration se fait à travers trois interfaces distinctes :
- ELR : messages HL7 2.5.1 ORU^R01 transportant les résultats de laboratoire aux agences de santé publique (elr.go). - eCR : rapports électroniques initiaux de cas (eICR) basés sur FHIR lorsqu'une condition déclarable est diagnostiquée. - Registre d'immunisation : VXU^V04 pour déclarer les vaccinations administrées, et VXQ^V01 pour interroger l'historique d'immunisation d'un patient.
Le package est bidirectionnel : il déclare vers l'extérieur (ELR, eCR, VXU) et interroge en retour (VXQ/VXR). Toutes les opérations sont en temps réel plutôt qu'en batch nocturne.
Sécurité des threads : SubmissionLog est sécurisé pour une utilisation concurrente. Les fonctions de construction sont pures et sécurisées pour être appelées à partir de n'importe quel goroutine.
Source: github.com/biodream-llc/perfuse/internal/publichealth
26.80 published
Le package published contient les gardes pour les packages importables de Perfuse, en un seul endroit.
hl7 était le premier package publié et contient sa propre copie de ces vérifications. fhir et pas ont été publiés afin qu'un service de décision tel que Vaglio lise les demandes FHIR et PAS avec exactement le code que Perfuse utilise, plutôt qu'une copie qui dévie : quatre lecteurs des codes d'action X12 dans ce référentiel étaient en désaccord, et l'un lisait un refus comme une approbation. Les gardes sont conservées ici plutôt que copiées dans chaque package, pour la même raison.
Source: github.com/biodream-llc/perfuse/internal/published
26.81 queue
Le package queue est une file d'attente de livraison durable, par destination.
Sans cela, une destination qui est hors service pendant deux minutes perd tout ce qui lui est envoyé pendant ces deux minutes : les réessais se font en mémoire, et lorsqu'ils sont épuisés, le message est enregistré comme ayant échoué et est perdu. Avec cela, le message est sur disque et conserve sa place jusqu'à ce que la destination revienne.
Deux décisions de conception influencent tout le reste.
L'ordre est préservé par destination, et cela signifie qu'une destination en file d'attente cesse de prendre le chemin rapide. HL7 est un flux d'événements concernant les mêmes patients : un A01 admet, un A03 licencie. Si un A01 échoué va en file d'attente tandis que le prochain A03 est livré directement, le système récepteur voit une sortie pour un patient qu'il n'a jamais admis. Donc, une fois que quelque chose est en file d'attente pour une destination, tout pour cette destination est mis en file d'attente derrière lui jusqu'à ce que la file d'attente soit vidée. Cela coûte du débit pendant une panne et ce n'est pas optionnel, car l'alternative est un non-sens clinique silencieux. C'est également la chose spécifique qui va mal dans d'autres moteurs lorsque quelqu'un active les threads de file d'attente concurrents pour faire drainrer plus rapidement un retard.
Un message en file d'attente est un message accepté. L'expéditeur est informé AA, car les octets sont sur disque et fsynced avant que l'accusé de réception ne soit envoyé. Dire AE rendrait une file d'attente de stockage et de transfert fonctionnant correctement semblable à une erreur et inviterait l'expéditeur à renvoyer ce que nous détenons déjà.
Source: github.com/biodream-llc/perfuse/internal/queue
26.82 résidence
La résidence du package indique où les données de ce serveur peuvent aller : les régions cloud qu'un site autorise (l'EEE, le Royaume-Uni, la Suisse, ou des régions nommées une par une), et si la région d'un connecteur est l'une d'elles.
Perfuse vérifie ce qu'il peut savoir. Un connecteur AWS nomme sa région (S3, SQS, SNS), et un nom d'hôte AWS porte une région (sqs.eu-west-2.amazonaws.com) ; ceux-ci sont vérifiés lorsqu'un canal est enregistré et chargé, afin qu'un canal ne puisse pas envoyer des données de patient à un seau en Virginie à partir d'un serveur dont les données doivent rester à Francfort. Un nom d'hôte simple (le système d'un hôpital, le système d'un partenaire, un écouteur MLLP) ne dit rien sur son emplacement et n'est pas jugé ici : l'enregistrement du traitement répertorie chaque hôte auquel un canal envoie, pour que le contrôleur le vérifie.
Source: github.com/biodream-llc/perfuse/internal/residency
26.83 rtpb
Le package rtpb répond aux demandes de bénéfice de prescription en temps réel NCPDP à partir d'un formulaire : ce que coûtera un médicament pour ce membre dans cette pharmacie, s'il nécessite une autorisation préalable ou une étape première, et quels alternatives coûtent moins cher.
CMS-0062-P propose RTPB pour les payeurs touchés à partir du 1er octobre 2027. Le XML est NCPDP RTPB v13 (PBv13). Le schéma NCPDP est sous licence, les noms d'éléments et l'ordre suivent les exemples publics Surescripts RTPB et les recommandations publiques NCPDP pour la mise en œuvre de RTPB (codes de restriction de couverture et le statut de couverture auquel chacun est associé) ; une réponse n'est pas vérifiée contre le XSD ici, et une certification de réseau est où cela se produit.
Source: github.com/biodream-llc/perfuse/internal/rtpb
26.84 s3put
Le package s3put écrit des objets dans S3 en utilisant uniquement la bibliothèque standard.
La façon évidente de communiquer avec S3 est le SDK AWS, et le SDK est énorme. Ce projet vend un binaire statique avec huit dépendances directes et une liste des matériaux qui tient sur un écran - c'est un argument réel avec la personne qui examine le logiciel avant qu'un hôpital ne l'installe, et échanger cela contre un connecteur serait une mauvaise affaire.
Ce dont S3 a vraiment besoin est un PUT HTTP et une signature. La version 4 de la signature est entièrement spécifiée, elle est déterministe, et AWS publie des vecteurs de test pour elle. Elle est donc mise en œuvre ici : environ deux cents lignes contre crypto/hmac et net/http, sans nouvelle dépendance et rien à corriger lorsque le SDK a un avis.
Ce que cela fait délibérément ne pas faire
Pas de téléchargement multipart, pas de réessais, pas de chaîne de credenciaux au-delà des clés statiques et des variables d'environnement standard. Un message HL7 fait des kilo-octets, donc le téléchargement multipart résout un problème que cela n'a pas ; le moteur réessaie déjà ; et une chaîne de credenciaux d'instance de rôle signifierait des appels IMDS, une logique de mise en cache et de rafraîchissement, ce qui est où une petite mise en œuvre cesse d'être petite. Si quelqu'un en a besoin, la réponse honnête est une destination de fichier et un outil de synchronisation, et non un SDK à moitié construit.
Cela fonctionne avec tout ce qui parle de l'API S3 - MinIO, Ceph, Wasabi, Backblaze - car c'est juste un HTTP signé. C'est un effet secondaire qui vaut la peine, puisque le stockage d'objets d'un hôpital n'est souvent pas AWS.
Source: github.com/biodream-llc/perfuse/internal/s3put
26.85 saml
Canonicalisation XML exclusive (exc-c14n) conformément à https://www.w3.org/TR/xml-exc-c14n/
Ceci est la forme canonique exacte des octets qu'une signature XML signe. Se tromper signifie que des signatures valides apparaissent comme invalides et - pire - une mise en œuvre qui obtient presque tout juste passera les tests contre ses propres signatures tout en rejetant les réponses réelles de l'IdP.
Les règles qui comptent pour SAML : - Les déclarations d'espace de noms sont rendues uniquement si elles sont visiblement utilisées par l'élément ou ses attributs. - Les espaces de noms hérités que l'élément utilise mais n'a pas déclarés sont rendus comme s'ils étaient déclarés sur cet élément. - Les attributs sont triés : les déclarations d'espace de noms d'abord (triés par préfixe), puis les autres attributs (triés par nom étendu : URI de l'espace de noms puis nom local). - Les éléments vides utilisent le balise de début/balise de fin, jamais l'autoclosure. - Les nœuds de texte sont sortis tels quels ; les CDATA sont remplacés par leur contenu avec une échappement d'entité. - Les instructions de traitement et les commentaires en dehors de l'élément du document sont exclus.
Source: github.com/biodream-llc/perfuse/internal/saml
26.86 scim
Le package scim met en œuvre SCIM 2.0, le protocole que les fournisseurs d'identité utilisent pour provisionner des comptes.
Okta, Entra ID, Google Workspace et OneLogin parlent tous ce langage. Un administrateur ajoute quelqu'un à un groupe dans le fournisseur d'identité, et dans une minute, un compte apparaît ici avec le rôle approprié. Ils le suppriment, et le compte disparaît.
La désapprobation est le point
La provision est une commodité. La désapprobation est la raison pour laquelle cela vaut la peine d'être construit, et c'est la moitié qui ne fonctionne pas.
Lorsqu'une personne quitte une organisation, le fournisseur d'identité est le système qui le sait en premier - généralement parce que les RH mettent fin à son contrat et que le fournisseur est piloté par le dossier RH. Il informe ensuite chaque application connectée de désactiver le compte. Si cet appel échoue, ou réussit sans supprimer réellement l'accès, un ancien employé conserve l'accès à un moteur d'intégration clinique et personne ne le découvre, car rien ne surveille quelque chose qui n'est pas arrivé.
Les parties de ce package qui comptent le plus sont celles qui rendent la désapprobation réelle :
- Définir active sur false met fin à chaque session immédiatement, et non à la prochaine expiration. Un onglet de navigateur laissé ouvert sur un ordinateur portable qui est rentré chez un employé licencié doit cesser de fonctionner, et une session qui survive jusqu'à son expiration est une session qui survive au licenciement. - Une erreur est une erreur. SCIM n'a pas de sémantique de réessai sur laquelle une application peut compter, donc renvoyer 200 pour quelque chose qui n'est pas arrivé signifie que le fournisseur d'identité enregistre la désapprobation comme complète et n'essaie plus. - La suppression d'un utilisateur est traitée de la même manière que la désactivation : l'accès prend fin. L'historique d'audit est conservé quoi qu'il arrive, car un enregistrement portant le nom de quelqu'un qui n'existe plus est pire qu'un enregistrement marqué comme retiré.
Pourquoi c'est un package séparé
Les formes de SCIM ne sont pas celles de Perfuse. Il a son propre format d'erreur, son propre enveloppe de liste, son propre langage de correction, et ses propres opinions sur la casse des attributs. Conserver la traduction en un seul endroit signifie que les gestionnaires peuvent se concentrer sur ce qui arrive à un compte plutôt que sur JSON.
Source: github.com/biodream-llc/perfuse/internal/scim
26.87 script
Le script du package s'exécute avec Mirth Connect JavaScript.
L'objectif est que les scripts d'un canal passent sans être modifiés. C'est un exercice de compatibilité, et non un exercice de conception, donc la forme de tout ici est dictée par ce que Mirth expose : msg et tmp en tant qu'arbres E4X, six cartes avec des méthodes Java Map, la famille de fonctions de recherche $, logger, et un certain nombre d'objets utilitaires dont les noms de méthode et les chaînes de format de date sont Java.
Trois décisions sont les nôtres plutôt que celles de Mirth, et chacune est un écart délibéré :
Un script s'exécute avec une échéance et est interrompu lorsqu'il la dépasse. Mirth laissera un script boucler indéfiniment, ce qui prend le canal avec lui ; une interface qui cesse d'accepter des admissions en raison d'une faute de frappe dans un transformateur n'est pas acceptable, donc il y a toujours une temporisation.
L'interopérabilité Java est refusée avec une erreur nommant la classe, plutôt que de renvoyer undefined. Un script qui se connecte à Packages.java.sql ne peut pas être fait fonctionner ici, et le résultat utile est un message indiquant exactement cela à la ligne où cela se produit, et non une exception NullPointerException trois lignes plus tard.
L'accès aux fichiers et à la base de données est désactivé à moins qu'un canal ne l'active. Mirth accorde les deux à chaque script par défaut. Un transformateur qui peut lire n'importe quel fichier que le processus peut lire est une chose raisonnable à vouloir et un paramètre par défaut déraisonnable.
Source: github.com/biodream-llc/perfuse/internal/script
26.88 paramètres
Le package paramètres est la description unique de tout ce qui concerne un serveur Perfuse que l'opérateur peut modifier.
Pourquoi cela existe
Avant ce package, environ trente choses étaient des indicateurs de ligne de commande et rien d'autre. Changer la durée de conservation des messages signifiait modifier une définition de service et redémarrer, ce qui dans un hôpital signifie un ticket de modification - donc dans la pratique, personne ne les modifiait, et un paramètre par défaut choisi le premier après-midi est devenu le paramètre pour toujours.
Pourquoi un registre plutôt qu'un formulaire
La façon évidente de construire une page de paramètres est d'écrire le formulaire. Cela produit deux descriptions de chaque paramètre - une dans le serveur qui le valide et une dans l'interface qui le rend - et ils dérivent. La dérive est silencieuse : un champ que le serveur a cessé d'accepter a toujours un contrôle, donc quelqu'un le définit, le voit enregistré, et il ne fait rien.
Donc un paramètre est déclaré une fois, ici, avec tout ce qui est nécessaire pour le vérifier et le dessiner : le type de valeur qu'il est, le contrôle qui lui convient, le groupe auquel il appartient, ce qu'il signifie, et si le modifier prend effet maintenant. L'interface demande cette description et rend ce qui lui est dit. Ajouter un paramètre est une entrée dans ce package et aucun travail d'interface du tout.
TestEverySettingIsFullyDescribed force les parties qu'un humain doit fournir, car un paramètre sans texte d'aide est un paramètre que quelqu'un devine.
Pourquoi un fichier plutôt qu'une base de données
Les paramètres vivent dans un fichier YAML que l'interface édite sur place, correspondant à la façon dont les canaux et les règles d'alerte fonctionnent déjà. Trois raisons, par ordre de poids : le contrôle des modifications d'un hôpital veut une configuration qui peut être diffusée et placée sous contrôle de version ; un opérateur avec la machine mais pas l'application peut lire un fichier et ne peut pas lire une base de données ; et la restauration des paramètres d'hier ne doit pas nécessiter que l'application fonctionne.
Pourquoi les indicateurs ne le font que semer
Le fichier l'emporte une fois qu'il existe, et les indicateurs fournissent le contenu initial. L'alternative - les indicateurs gagnent toujours - rendrait l'interface menteuse, puisque tout ce qui est passé sur une ligne de commande pourrait être édité, enregistré et ignoré silencieusement.
Un indicateur qui est en désaccord avec le fichier est signalé au démarrage, en nommant les deux valeurs, car sinon l'indicateur reste dans la définition de service pendant des années et la prochaine personne qui le lit le croit.
Source: github.com/biodream-llc/perfuse/internal/settings
26.89 sftpconn
Le package sftpconn ouvre des connexions SFTP.
Séparé des connecteurs car la partie intéressante est l'authentification et la vérification de la clé hôte, et les deux sont identiques que le canal collecte des fichiers ou les écrit. Deux copies dériveraient, et la moitié qui dériverait serait la moitié qui cesserait de vérifier.
Source: github.com/biodream-llc/perfuse/internal/sftpconn
26.90 ombre
Le package shadow compare un canal candidat avec le canal en direct.
La comparaison elle-même est la partie facile. Toute la valeur réside dans deux garanties, et les deux sont appliquées par construction plutôt que par configuration :
- Une ombre ne peut pas livrer. Elle contient un pipeline de transformation et aucun expéditeur, il n'y a donc aucun chemin de code d'ici à un récepteur. Un paramètre ne peut pas en créer un et une erreur ne peut pas l'activer. - Une ombre ne peut pas affecter le canal en direct. Elle est appelée après que le message en direct a été livré et accusé réception, ses paniques sont récupérées, et ses délais d'attente sont les siens.
Tout ce qui est inférieur à cela et le mode ombre devient un moyen de casser la production en essayant d'éviter de casser la production.
Source: github.com/biodream-llc/perfuse/internal/shadow
26.91 shl
Le package shl implémente les liens de santé SMART et les cartes de santé SMART : les codes QR que le CMS demande aux prestataires d'accepter à l'enregistrement, et de remettre avec le dossier de visite.
Un lien de santé SMART (SMART Health Links STU 1) est shlink : / suivi de JSON base64url : une URL de manifeste, une clé de 256 bits, et facultativement une date d'expiration, un libellé et des indicateurs (P mot de passe, L long terme, U un seul fichier par GET). Le récepteur publie sur l'URL de manifeste et reçoit des fichiers, chacun chiffré JWE avec cette clé - alg dir, enc A256GCM, facultativement compressé DEFLATE - contenant du JSON FHIR, des cartes de santé SMART ou un jeton d'accès SMART. Le serveur qui héberge les fichiers ne voit jamais la clé : elle ne voyage que dans le lien, qui est celui du patient.
Une carte de santé SMART (SMART Health Cards Framework 1.4) est un paquet FHIR signé : un JWS compact, ES256, avec une charge utile compressée DEFLATE nommant son émetteur, dont la clé publique se trouve à <iss>/.well-known/jwks.json. Elle voyage sous la forme d'un code QR numérique shc : / ou d'un fichier .smart-health-card.
Seulement la bibliothèque standard : crypto/aes, crypto/cipher, crypto/ecdsa et compress/flate couvrent tout, et une bibliothèque JOSE apporterait une surface beaucoup plus grande pour deux algorithmes.
Source: github.com/biodream-llc/perfuse/internal/shl
26.92 smartauth
Le package smartauth est un serveur d'autorisation de lancement d'application SMART : il émet les jetons d'accès que le point de terminaison FHIR de Perfuse accepte.
Écrit avec la bibliothèque standard, comme internal/oidc, qui vérifie ce que cela signe. Les jetons sont des JWT signés RS256, l'algorithme sur lequel chaque client SMART et les règles de jeton d'ID de la spécification peuvent compter.
Source: github.com/biodream-llc/perfuse/internal/smartauth
26.93 snmp
Le package snmp est un agent SNMPv2c en lecture seule de petite taille : GET, GETNEXT et GETBULK sur UDP contre une table de valeurs que l'appelant remplit, et les pièges SNMPv2.
Les messages sont codés BER (X.690) ici ; rien dans cela n'est de la cryptographie (la chaîne de communauté v2c est un mot de passe en texte brut, c'est pourquoi l'agent ne répond qu'aux réseaux qu'il est informé).
Source: github.com/biodream-llc/perfuse/internal/snmp
26.94 soap
Le package soap envoie des requêtes SOAP et lit les erreurs SOAP, en utilisant uniquement la bibliothèque standard.
SOAP est une cérémonie considérable autour d'un POST HTTP, et c'est toujours la façon dont une grande partie du middleware hospitalier accepte les données - les systèmes d'administration des patients, les référentiels de documents, les services d'enregistrement régionaux, tout ce qui est spécifié dans la décennie où cela était la réponse. Mirth a un connecteur de service Web, donc ceci est un bloqueur de migration de niveau 2 plutôt qu'un élément agréable à avoir.
Pourquoi pas un client généré
L'approche habituelle consiste à prendre un WSDL et à générer des types Go à partir de celui-ci. C'est la bonne réponse pour une application qui parle à un service connu, et la mauvaise réponse ici : la destination d'un moteur d'intégration est configurée par quelqu'un qui édite un canal, et non recompilé, donc l'enveloppe doit être assemblée à l'exécution à partir d'un modèle qu'il peut voir et modifier. Cela signifie également qu'il n'y a pas d'étape de génération de code et rien à régénérer lorsque l'extrémité distante publie un nouveau WSDL.
Ce que cela fait délibérément ne pas faire
Pas d'analyse WSDL, pas de WS-Security, pas de MTOM, pas de WS-Addressing. Chacun de ceux-ci est une spécification en soi, et prétendre en supporter un tout en se trompant sur un détail est pire que de ne pas l'offrir - une signature qui vérifie presque est indiscernable d'une attaque à l'autre extrémité. WS-Security en particulier est où une mise en œuvre partielle ferait vraiment des dégâts.
Ce qui est présent : les enveloppes SOAP 1.1 et 1.2, un corps modélisé, l'en-tête SOAPAction et la détection de défauts qui lit la chaîne de défaut au lieu de signaler « 500 ».
Source: github.com/biodream-llc/perfuse/internal/soap
26.95 sof
Le package sof exécute SQL sur FHIR v2 ViewDefinitions : une vue transforme chaque ressource FHIR d'un type en lignes de colonnes nommées, par FHIRPath, de sorte que les données FHIR puissent être lues comme des tableaux par les moteurs SQL, les tableurs et les mesures de qualité.
Il suit l'algorithme de traitement de ViewDefinition (colonne, sélection, forEach, forEachOrNull, répéter, unionAll, où, constantes, %rowIndex, getResourceKey et getReferenceKey) et est vérifié contre les fixtures de test officielles sql-on-fhir.
Source: github.com/biodream-llc/perfuse/internal/sof
26.96 sqldb
Le package sqldb ouvre des connexions de base de données pour la source et la destination de base de données.
Les pilotes sont enregistrés ici et nulle part ailleurs, il n'y a donc qu'un seul endroit qui décide à quoi Perfuse peut se connecter.
Source: github.com/biodream-llc/perfuse/internal/sqldb
26.97 sqlitedb
Le package sqlitedb ouvre SQLite de la manière dont un serveur en a besoin : une connexion pour les écritures et plusieurs pour les lectures.
La raison est un mode de défaillance qui n'apparaît qu'une fois que le déploiement a fonctionné pendant un certain temps. SQLite en mode WAL permet aux lecteurs de fonctionner aux côtés d'un écrivain, mais le pool de connexions Go se situe au-dessus de SQLite, donc un pool d'un seul serialise tout, quel que soit ce que la base de données permettrait. Un navigateur de messages de recherche qui scanne la colonne de charge utile conserve alors la seule connexion, et chaque message arrivant attend derrière.
Mesuré sur cette machine, une écriture prend 104 µs lorsque le magasin est inactif et 2,6 ms alors qu'une recherche scanne quatre mille messages : vingt-cinq fois plus lent. Cela se scale avec le tableau, donc à quelques centaines de milliers de messages stockés, un rapport se transforme en secondes de latence de livraison, et une écriture se trouve sur le chemin d'accusé de réception. L'expéditeur voit une expiration, renvoie, et quelqu'un passe une matinée à rechercher un problème dans le réseau.
Diviser les pools ne coûte rien et supprime l'interaction : les rapports obtiennent leurs propres connexions, et l'écrivain garde une pour lui-même, car SQLite permet exactement un écrivain de toute façon.
Source: github.com/biodream-llc/perfuse/internal/sqlitedb
26.98 steps
Étapes de transformation déclaratives, pour n'importe quel format de message.
Pourquoi cela est partagé
Le vocabulaire des étapes - définir, copier, effacer, mapper, remplacer, tronquer, cas, chacun avec une description et une condition facultative - n'a rien à voir avec un format particulier. Seules trois choses diffèrent entre les formats : la façon dont un chemin est écrit, la façon dont une valeur est lue, et la façon dont elle est réécrite.
C'est la même conclusion que la grammaire de filtre a atteinte dans internal/expr, et pour la même raison. X12 avait un moteur d'étapes et NCPDP en avait besoin ; le copier aurait produit un deuxième moteur de quatre cents lignes à maintenir à la main, et puis un troisième pour les délimités. Le comportement qui vaut la peine d'avoir est suffisamment subtil pour qu'une copie ne le maintienne pas - la raison pour laquelle le résultat est relu après chaque écriture, par exemple, a pris un défaut réel pour le découvrir.
Ce qu'un format fournit
Un Accesseur : un compilateur de chemin, un compilateur de condition et un veto facultatif sur les étapes qu'il ne peut pas honorer. Rien d'autre.
Source: github.com/biodream-llc/perfuse/internal/steps
26.99 stomp
Le package stomp parle STOMP 1.2 à un courtier de messages.
C'est ce que le « support JMS » doit signifier dans un programme qui n'est pas Java. JMS est une API plutôt qu'un protocole, il n'y a donc rien à implémenter : ce dont un site a vraiment besoin, c'est que Perfuse parle au courtier qui se trouve derrière ses applications JMS.
STOMP plutôt qu'OpenWire, et la raison en est digne d'être enregistrée, car la réponse évidente est fausse. OpenWire est le protocole natif d'ActiveMQ et une sérialisation binaire des commandes JMS - des semaines de travail, spécifiques à une famille de courtiers, et non documentées sauf par leur implémentation. ActiveMQ détecte automatiquement STOMP, AMQP et MQTT sur le même port qu'il sert OpenWire, donc un protocole texte atteint les mêmes courtiers. STOMP couvre ActiveMQ Classic, Artemis et RabbitMQ ; AMQP 1.0 ajouterait Azure Service Bus et IBM MQ, et est le suivant sensé plutôt qu'OpenWire.
Écrit contre la bibliothèque standard. Un client de courtier n'est pas l'endroit pour une dépendance dont les modes de défaillance sont à expliquer par quelqu'un d'autre, et le encadrement ici est suffisamment petit pour que le posséder coûte moins que lire leur suivi de problème.
Source: github.com/biodream-llc/perfuse/internal/stomp
26.100 magasin
Le magasin de packages contient les données qui sont réellement étatiques : utilisateurs, sessions et une traçabilité des actions.
Les canaux sont délibérément exclus de celui-ci. Ils vivent dans des fichiers, car c'est ce qui donne git, des différences, une revue de code et une promotion d'environnement gratuitement. Mettre les canaux dans une base de données est la décision qui oblige à acheter chacun de ceux-ci séparément, et c'est la raison pour laquelle un produit tiers existe uniquement pour acheminer les canaux Mirth entre sa base de données et un référentiel git.
La division est donc : configuration dans des fichiers, identité et historique dans SQLite.
Source: github.com/biodream-llc/perfuse/internal/store
26.101 tefca
Le package tefca met en œuvre les parties de la participation à TEFCA qui n'exigent pas de connexion QHIN.
Qu'est-ce qui est réel
La validation de l'objectif d'utilisation, la validation de la configuration et la traçabilité des actions - y compris sa persistance, son interface de requête et son obligation d'enregistrer les tentatives échouées ainsi que les réussies. Cette dernière partie n'est pas une question de détail : une série de livraisons échouées à un destinataire est la façon dont un partenaire mal configuré se manifeste, et une série de requêtes échouées pour différents patients est la façon dont les explorations se manifestent.
Qu'est-ce qui ne l'est pas
Le réseau. Il n'y a pas de transport QHIN dans cette version, donc aucun échange n'a lieu, et chaque fonction d'échange refuse avec ErrExchangeNotImplemented au lieu de renvoyer un succès.
Cette distinction n'a pas toujours été établie, et la façon dont cela a mal tourné vaut la peine d'être conservée. Les quatre fonctions d'échange validaient auparavant leurs entrées, ne faisaient aucun appel réseau et renvoyaient un succès ; Deliver renvoyait une réponse Acceptée avec un identifiant de suivi construit à partir de l'horloge. La couche d'audit enregistrait ensuite chacun comme un échange terminé - dans le journal qui existe pour prouver ce qui a été échangé lorsque quelqu'un demande des mois plus tard. Quatre tests affirmaient ce comportement et passaient.
Ce qu'il faut pour le compléter
L'intégration à un réseau d'information sanitaire qualifié, une authentification mutuelle TLS à l'aide de certificats délivrés dans le cadre de ce processus, et soit les profils IHE que l'accord commun a commencé avec, soit Facilitated FHIR tel que défini par la procédure standard d'exploitation du projet Sequoia, en vigueur à compter du 8 mars 2026. Rien de tout cela ne peut être écrit de manière spéculative : il est testé contre un QHIN réel ou il n'est pas testé, et une implémentation d'échange non testée est le même défaut qu'une absence d'implémentation avec un meilleur déguisement.
Source: github.com/biodream-llc/perfuse/internal/tefca
26.102 locataire
Le package locataire fournit les règles d'identité et d'isolation pour une exploitation multi-locataires.
Un HIE, un clearinghouse ou un fournisseur de services géré exécute un moteur au nom de plusieurs organisations. Mirth ne peut pas le faire - une instance sert une organisation, et un MSP se retrouve à exécuter cinquante JVM et cinquante bases de données.
Ce que possède un locataire
Ses canaux, sous forme d'un répertoire de fichiers. Ses utilisateurs. Ses messages, sa file d'attente, sa traçabilité des actions et ses ressources FHIR. Ses étiquettes de métriques. Rien n'est partagé, sauf le processus, les ports d'écoute qui lui ont été attribués et les administrateurs de la plate-forme.
L'isolation est structurale, et non mémorisée
La défaillance dangereuse ici n'est pas un crash. C'est le locataire A qui voit les messages du locataire B, ce qui est une violation de la confidentialité plutôt qu'un bogue. Un design où chaque requête prend un paramètre locataire_id échoue la première fois que quelqu'un écrit une requête et oublie celui-ci, et cette requête semble parfaitement correcte lors de la revue.
Le locataire n'est donc pas un paramètre. L'accès aux données se fait via un handle qui le transporte déjà, et il n'y a pas de moyen d'accéder aux tables sans celui-ci. L'oubli n'est pas possible.
Source: github.com/biodream-llc/perfuse/internal/tenant
26.103 terminologie
Le package terminologie conserve les systèmes de code publiés (LOINC, SNOMED CT, RxNorm, ICD-10-CM, CPT et les locaux) pour rechercher des codes, et les tables de mappage des valeurs que les tables n'avaient pas, pour que quelqu'un puisse les mapper.
Les systèmes de code sont importés à partir des fichiers que leurs éditeurs distribuent. Plusieurs sont sous licence (LOINC nécessite un compte gratuit, SNOMED CT une licence d'affiliation, RxNorm une licence UMLS, CPT une licence AMA), donc aucun n'est livré avec Perfuse : un administrateur qui détient la licence télécharge le fichier, et Perfuse enregistre qui l'a importé et quand.
Source: github.com/biodream-llc/perfuse/internal/terminology
26.104 tlsconf
Le package tlsconf construit une configuration TLS à partir de fichiers et décrit les certificats.
Ceci est l'équivalent gratuit d'une extension Mirth qui est maintenant payante. La majeure partie de la valeur ne réside pas dans le cryptage, qui nécessite seulement quelques lignes, mais dans la partie qui empêche quelqu'un de déployer quelque chose qu'il pense être sécurisé mais qui ne l'est pas : refuser de contourner silencieusement la vérification, insister pour que le certificat client soit réellement vérifié lorsqu'il est demandé, et indiquer clairement lorsque le certificat est sur le point d'expirer.
Un certificat expiré sur une interface d'alimentation est une véritable panne d'hôpital, et cela se produit parce que personne n'a été informé. La partie descriptive de ce package existe pour cette raison.
Source: github.com/biodream-llc/perfuse/internal/tlsconf
26.105 tomirth
Le package tomirth écrit à nouveau un canal Perfuse sous forme de canal Mirth XML.
Pourquoi cela existe. L'objection à l'adoption d'un nouveau moteur d'intégration est rarement « est-ce qu'il est bon », mais plutôt « et si nous nous trompons et que nous sommes bloqués », et la réponse la moins coûteuse à cela est de pouvoir revenir en arrière. Perfuse lit les canaux Mirth depuis le début ; jusqu'à présent, il ne pouvait pas en écrire un, ce qui rendait la garantie unidirectionnelle et donc peu rassurante.
Comment il évite le piège qui a rendu la première tentative inutile. Le XML de Mirth est la sortie de XStream, et XStream lit les attributs de classe et de version comme des instructions : un élément qu'il ne reconnaît pas est supprimé sans un mot, et un canal qu'il ne peut pas assembler est stocké avec sa description remplacée par « Ce canal est invalide. Vérifiez que toutes les extensions requises sont chargées correctement » et ses destinations supprimées. Rien dans cette réponse ne nomme l'élément en défaut. Un exportateur qui compose des blocs de propriétés à partir d'une lecture du format échoue donc de la seule manière qui est coûteuse à diagnostiquer, ce qui est ce qui s'est passé : ce référentiel contenait un exportateur avec neuf tests passés dont la sortie Mirth a rejetée, car chaque test la comparait à notre propre analyseur au lieu d'un serveur.
Ainsi, aucun des blocs de propriétés n'est composé ici. scripts/mirth-dump-connector-templates.sh a l'ObjectXMLSerializer de Mirth sérialiser les valeurs par défaut de chaque classe de propriétés de connecteur, et ces documents sont commités sous templates/. Ce package substitue des valeurs à ceux-ci, et mirth.SetRawProperty refuse tout chemin que le modèle ne contient pas déjà - donc une erreur est une erreur de nom de chemin, au moment de l'exportation, plutôt qu'un canal qui disparaît lors de l'importation.
Ce qu'il ne fera pas. Un transport sans équivalent Mirth est refusé par nom plutôt que d'être approximé. Une exportation qui transformerait silencieusement une destination S3 en un écrivain de fichiers serait pire que pas d'exportation du tout, car le canal importerait proprement et livrerait à la mauvaise place.
Source: github.com/biodream-llc/perfuse/internal/tomirth
26.106 trace
Le package trace produit des traces distribuées pour les messages qui se déplacent à travers un canal, et les exporte sur OTLP/HTTP avec le codage JSON.
Pourquoi cela existe plutôt que le SDK OpenTelemetry : le SDK plus un exportateur OTLP tire environ soixante modules et ajoute autant à la binary que l'ensemble du reste de ce programme. Ce qui est réellement nécessaire ici est étroit - la propagation du contexte de trace W3C, un modèle d'étendue, l'échantillonnage de tête et un POST HTTP batché - et OTLP/JSON est un codage stable documenté qui peut être produit avec la bibliothèque standard seule. Même échange que choisir lib/pq sur pgx : prendre la petite chose lorsque seule une partie de la grande chose est souhaitée.
La conséquence qui vaut la peine d'être mentionnée : il n'y a pas d'instrumentation automatique et pas d'exportateur spécifique au fournisseur. Les étendues sont celles que ce programme crée délibérément, et elles vont vers n'importe quel point de terminaison OTLP - un collecteur, Jaeger, Grafana Tempo, Honeycomb, l'ingestion OTLP de Datadog.
La propriété qui compte plus que les étendues
Un message arrive fréquemment en portant un en-tête de traceparent du système qui l'a envoyé, et part vers un système qui enregistrera un de ses propres. Poursuivre cette trace plutôt que d'en commencer une nouvelle est ce qui rend possible une vue unique de « l'EHR a envoyé cela, le moteur l'a transformé, le registre l'a rejeté », et les problèmes d'interface sont presque toujours signalés comme « nous l'avons envoyé et rien ne s'est passé », et cette question est sans réponse sans un identifiant qui survive au saut.
La traçabilité ne doit jamais affecter la livraison
Chaque opération ici est à best-effort. Les étendues sont supprimées lorsque le tampon est plein, les échecs d'exportation sont comptés et jamais réessayés dans le chemin du message, et aucun appel ne bloque sur le réseau. Une étendue supprimée est une nuisance. Un message retardé ou perdu parce que le backend de traçage était lent est un incident clinique, donc l'échange n'est jamais en question.
Source: github.com/biodream-llc/perfuse/internal/trace
26.107 transform
Le package transform applique des changements déclaratifs à un message.
Ceci est la couche censée supporter le travail ordinaire, avec la conservation de l'écriture de script comme une échappatoire marquée. La distinction n'est pas stylistique. Une étape déclarée dans YAML peut être validée avant de s'exécuter, montrée dans une différence, revue par quelqu'un qui ne lit pas JavaScript, et signalée ; un script ne peut être exécuté et espéré. La plupart de ce que les transformateurs Mirth font réellement est ennuyeux - copier un champ, rembourrer un identifiant, mapper un code à travers une table, effacer quelque chose qui ne devrait pas quitter le bâtiment - et tout cela appartient ici.
Chaque étape nomme explicitement sa cible et chaque étape est réversible dans le sens où elle indique ce qu'elle a fait, car la défaillance la plus coûteuse dans une interface est une transformation dont personne ne savait qu'elle se produisait.
Source: github.com/biodream-llc/perfuse/internal/transform
26.108 translate
Le package translate convertit un canal Mirth en une définition de canal Perfuse.
perfuse explain rapporte ce qui bloque une migration. Cela fait la majeure partie de la migration, qui est une affirmation différente et beaucoup plus large, donc c'est délibérément conservateur sur ce qu'il peut affirmer.
Trois règles façonnent l'ensemble.
Rien n'est silencieusement supprimé. Chaque partie du canal source est soit traduite, soit transmise telle quelle sous forme de script, soit signalée comme nécessitant une intervention humaine. Un traducteur qui omettrait discrètement une étape produirait un canal qui démarre, s'exécute et perd des données — le pire résultat possible et la raison pour laquelle les gens se méfient des outils de migration.
Déclaratif lorsque c'est certain, script lorsque ce n'est pas le cas. Une étape Mapper qui copie un champ devient une étape déclarative, car cela est lisible et vérifiable. Une étape JavaScript devient un script, car Perfuse exécute le JavaScript de Mirth sans modification et réécrire cela dans quelque chose qui semble équivalent est exactement là où un traducteur introduirait une différence que personne ne remarque.
La sortie est censée être lue. Elle contient des commentaires expliquant d'où vient chaque chose et ce qui a été laissé pour une personne. Une migration est examinée par quelqu'un qui doit l'approuver, et un mur non annoté de YAML ne peut pas être examiné.
Source: github.com/biodream-llc/perfuse/internal/translate
26.109 udap
Le package udap implémente la moitié client de la sécurité HL7 pour l'enregistrement, l'authentification et l'autorisation à grande échelle — la spécification sur laquelle repose l'échange FHIR facilité par TEFCA.
UDAP est une infrastructure à clé publique greffée sur OAuth 2.0. Une communauté de confiance émet des certificats X.509 à ses membres ; un membre prouve qui il est en signant des JWT avec la clé privée et en attachant la chaîne de certificats dans l'en-tête JWT. Cela remplace le secret client partagé de l'OAuth ordinaire, qui ne convient pas à des milliers d'organisations qui ne se sont jamais rencontrées.
Pourquoi ce package existe. L'échange TEFCA ne peut pas être entièrement vérifié sans un véritable QHIN : rejoindre l'un nécessite une intégration et des certificats émis, et ne peut pas être simulé. Mais le profil de sécurité sous-jacent est un guide d'implémentation HL7 publié avec des serveurs de référence publics, et l'un d'eux répond sur Internet ouvert. Donc, la partie qui peut être vérifiée est vérifiée ici, et la partie qui ne peut pas l'être est refusée à la limite plutôt que de deviner.
La distinction est importante en raison de ce qui s'est passé avec SAML dans ce référentiel : mille lignes de tests ont été passées, cinq d'entre elles spécifiquement sur la canonisation de la signature, tandis qu'aucun fournisseur d'identité réel ne pouvait authentifier qui que ce soit. Les deux moitiés avaient été écrites ici et se sont mutuellement accordées. La leçon tirée de cela est qu'une implémentation de sécurité ne vaut rien jusqu'à ce que quelque chose écrit par quelqu'un d'autre l'ait accepté ou rejeté.
Références de spécification : - HL7 UDAP Security STU 1 : http://hl7.org/fhir/us/udap-security/STU1/ - TEFCA SOP Facilitated FHIR Implementation v2.0, en vigueur à compter du 8 mars 2026
Source: github.com/biodream-llc/perfuse/internal/udap
26.110 umlink
Le package umlink transporte les X12 278 vers un système de gestion de l'utilisation d'un payeur, ainsi que les réponses, les moyens par lesquels ces systèmes sont atteints dans la pratique : X12 dans le corps d'un POST HTTPS ; l'enveloppe SOAP de CAQH CORE (Connectivity Rule vC2.2.0, celle utilisée par la plupart des payeurs et des CMS pour esMD, et vC4.0.0) ; l'enveloppe MIME multipart HTTP de CAQH CORE (vC2.2.0) ; et des fichiers batch via SFTP.
Rédigé à partir des règles de connectivité publiées par CAQH (vC2.2.0 et vC4.0.0), de leur schéma XML et WSDL, ainsi que du guide de compagnon X12N 278 de CMS pour esMD. Il n'est pas certifié CORE : la certification est effectuée par les fournisseurs de tests autorisés par CAQH.
Les liens en temps réel retournent la réponse que le système UM a donnée, qui peut être une réponse 278 ou, lorsque la demande n'a pas pu être lue, un 999 ou un TA1 : l'appelant lit lequel. Le lien batch retourne ErrAnswerLater une fois que le fichier est livré, et Poll collecte ce qui revient.
Source: github.com/biodream-llc/perfuse/internal/umlink
26.111 v2fhir
Le package v2fhir mappe les messages HL7 v2 aux ressources FHIR.
Le mappage est là où les projets d'interopérabilité échouent réellement, donc les règles que ce package suit sont énoncées plutôt qu'impliquées :
- Une valeur qui ne peut pas être mappée est préservée sous forme de texte, jamais devinée. Un code local transformé en un code standard plausible est pire qu'une valeur non codée, car le destinataire le croit. - Chaque décision de mappage qui a nécessité un jugement est signalée comme une note, afin qu'un humain puisse vérifier celles qui comptent au lieu de lire toute la sortie. - Les horodatages sont convertis, pas copiés. Les horodatages HL7 v2 ne sont pas ISO 8601, et un dateTime portant une heure locale sans décalage est la raison la plus courante pour laquelle une ressource convertie est rejetée. - Les unités conservent leur texte d'origine et gagnent un code UCUM uniquement lorsque le mappage est certain. Un code d'unité incorrect est un défaut de sécurité des patients, et non un problème de formatage.
Source: github.com/biodream-llc/perfuse/internal/v2fhir
26.112 vcs
Le package vcs lit l'historique des fichiers de canal à partir de git.
L'historique du canal est une extension payante ailleurs, et c'est une extension payante car ces moteurs conservent les canaux dans une base de données, donc la traçabilité des modifications signifie construire un système de traçabilité des modifications. Perfuse conserve les canaux dans des fichiers, donc l'historique existe déjà et existe depuis le premier commit. Ce package n'a qu'à le lire.
Il utilise git au lieu d'intégrer une bibliothèque git. La bibliothèque ajouterait une grande dépendance à un binaire dont le point de vente est d'avoir quatre, et cela ne servirait à rien : un déploiement qui conserve ses canaux sous contrôle de version a git installé, et celui qui ne le fait pas obtient un « non un référentiel git » clair au lieu d'une implémentation légèrement différente de la même chose.
Source: github.com/biodream-llc/perfuse/internal/vcs
26.113 vfs
Le package vfs est l'ensemble restreint d'opérations de fichiers dont un connecteur de sondage a besoin.
Pourquoi une interface plutôt que quatre connecteurs
Perfuse collecte des fichiers à partir d'un disque local, d'un serveur SFTP, d'un serveur FTP, d'un partage Windows et d'un serveur WebDAV. Le transfert diffère dans chaque cas. Tout ce qui décide réellement si les messages survivent ne diffère pas :
- Un fichier en cours d'écriture et un fichier dont l'écriture est terminée sont indiscernables. Il n'y a pas de verrou, pas de drapeau et pas de notification pour l'un de ces transports - il y a une taille et un horodatage, et les deux sont vrais pour un fichier partiellement écrit. La lecture trop tôt collecte un message incomplet, et HL7 n'a pas de terminateur, donc un message incomplet est souvent toujours analysable. Le MSH est intact, les segments qui sont arrivés sont bien formés, ceux qui n'ont pas été sont simplement absents. Il est accepté, reconnu, stocké, livré, et rien ne le mentionnera jamais. - Un fichier ne doit pas être supprimé jusqu'à ce que chaque message qu'il contient ait été accepté, car le fichier est la seule copie. - Un fichier qui a échoué ne doit pas être repris à la prochaine interrogation pour toujours, et ne doit pas être silencieusement supprimé.
Écrit une fois par transport, ces règles seraient légèrement différentes cinq fois, et les différences n'apparaîtraient que sous la forme de messages qui disparaissent sur un site. Ils sont donc écrits une fois, ici, sur la plus petite interface qui les prend en charge.
Ce qui est délibérément absent
Aucune écriture, au-delà de ce dont dispose la suppression. L'envoi de fichiers est un problème différent avec des modes d'échec différents - un fichier partiellement écrit à l'autre extrémité, que les expéditeurs existants gèrent en écrivant sous un nom temporaire et en renommant. Le regroupement des deux sens dans une interface unique rendrait chaque sens plus difficile à comprendre.
Pas de récursion. Un poller qui descend dans les sous-répertoires collecte le répertoire d'archive qu'il vient de déplacer.
Source: github.com/biodream-llc/perfuse/internal/vfs
26.114 vpn
Le package vpn signale l'état des tunnels VPN de site à site sur lesquels le trafic des partenaires est exécuté - AWS Site-to-Site VPN, Azure VPN Gateway connections et strongSwan - et conserve la feuille de connexion de chaque partenaire : les paramètres de tunnel des deux côtés, et si elles sont d'accord.
Un tunnel qui est arrêté ressemble, du point de vue d'un moteur d'interface, exactement à un partenaire dont le moteur est arrêté : les connexions expirent. Dire « le tunnel est arrêté » au lieu de cela fait la différence entre appeler l'équipe réseau et appeler le partenaire.
Lecture seule. Rien ici ne modifie un tunnel, et aucune clé prépartagée n'est jamais lue, conservée ou affichée.
Source: github.com/biodream-llc/perfuse/internal/vpn
26.115 web
Le package web sert la partie frontale construite à l'intérieur du binaire.
Les ressources sont intégrées plutôt que d'être expédiées à côté, donc le déploiement reste en un seul fichier. C'est la même raison pour laquelle le moteur évite cgo : un opérateur devrait être en mesure de copier un binaire sur un serveur et de l'exécuter, sans JVM, sans installateur et sans répertoire de ressources qui sortent de phase avec l'exécutable.
La sortie construite est validée afin que go build fonctionne sur une copie sans Node installé. Reconstruisez-la avec make web.
Source: github.com/biodream-llc/perfuse/internal/web
26.116 webauthn
Le package webauthn vérifie les passkeys.
Un passkey est une paire de clés que l'authentificateur détient - Touch ID, Windows Hello, une YubiKey, un téléphone - où la moitié privée ne quitte jamais l'appareil. La connexion signifie que le serveur envoie un défi aléatoire, que l'authentificateur signe après avoir vérifié que l'utilisateur est présent, et que le serveur vérifie la signature par rapport à la clé publique qu'il a stockée lors de l'enregistrement.
La propriété qui compte n'est pas qu'il est pratique. C'est qu'il n'y a rien à phisher. Un mot de passe peut être tapé dans une copie convaincante d'une page de connexion ; une signature de passkey est liée à l'origine pour laquelle elle a été créée, donc la copie obtient une signature que son serveur ne peut pas utiliser. Pour un moteur d'intégration qui détient les interfaces d'un hôpital, c'est la différence qui vaut la peine d'avoir.
Ce que cette implémentation refuse de faire
La spécification est permissive à certains endroits où être permissive est comment les implémentations sont cassées. Celle-ci ne l'est pas :
- L'algorithme de signature est fixé lors de l'enregistrement et stocké avec la clé. Rien lors de la connexion ne lit un algorithme à partir du client, car c'est la confusion d'algorithme et il n'y a pas de fonction ici qui puisse le faire. - L'origine est comparée exactement, jamais par préfixe ou suffixe. Un contrôle qui accepte tout ce qui se termine par le domaine correct accepte un sous-domaine d'attaquant. - Un défi est à usage unique et expire. Il est supprimé lorsqu'il est consommé, donc une assertion capturée ne peut pas être rejouée. - L'attestation n'est pas faite confiance pour quoi que ce soit. La déclaration d'attestation est analysée pour extraire les informations d'identification, puis sa signature est ignorée, car la vérifier correctement nécessite un magasin de racines entretenu et prétendre la vérifier est pire que de ne pas prétendre le faire. - Le comptage de signature est vérifié lorsque l'authentificateur fournit un, et son absence n'est pas traitée comme suspecte. De nombreux authentificateurs laissent légitimement à zéro.
Source: github.com/biodream-llc/perfuse/internal/webauthn
26.117 winservice
Le package winservice exécute Perfuse en tant que service Windows.
Ce fichier est la moitié partout ailleurs. Il existe afin que cmd/perfuse puisse appeler ce package sans envelopper chaque site d'appel dans une balise de construction : la sous-commande est toujours compilée, et sur Linux ou macOS, elle explique que les services sont une idée Windows plutôt que de ne pas exister.
Refuser avec une phrase claire est mieux que cacher la sous-commande. Quelqu'un qui suit les instructions Windows sur la mauvaise machine est informé de ce qui se passe réellement, et l'équivalent pour sa plate-forme.
Source: github.com/biodream-llc/perfuse/internal/winservice
26.118 x12
Lecture et écriture de valeurs à un chemin.
Pourquoi cela est séparé de Path
path.go décide de ce que signifie une expression de chemin. Ce fichier résout un chemin contre un échange réel. Ils sont séparés car les règles d'analyse sont dignes d'être lues sans la gestion d'octets, et parce que l'analyseur est utilisé par le validateur de configuration, qui n'a pas de message à résoudre.
Pourquoi une écriture réanalyse au lieu de modifier les octets en place
Les éléments de Segment sont des sous-slices de Segment.raw, et Message.segs indexe dans Message.raw. La modification d'une valeur en place change la longueur de tout ce qui suit, donc toutes ces slices devraient être ajustées, et celles qui sont manquées liront correctement jusqu'au message où cela ne fonctionnera pas.
Une écriture reconstruit donc le segment, reconstruit l'échange, et l'analyse à nouveau. Cela coûte une analyse par message modifié et offre la garantie qu'un Message renvoyé d'ici est exactement ce que produit l'analyse de ses propres octets. Il n'y a pas d'état où les index et les octets sont en désaccord, car cet état est non représentable.
Source: github.com/biodream-llc/perfuse/internal/x12
26.119 x12xml
Le package x12xml convertit X12 (et d'autres EDI délimités) en XML et vice versa, que Mirth Connect et Open Integration Engine écrivent pour lui, et vice versa.
Pourquoi cet XML et pas l'un des nôtres
L'objectif d'une forme XML de X12 est les systèmes qui utilisent déjà l'un. Un site qui migre de Mirth a des récepteurs construits contre ce que le type de données EDI/X12 de Mirth émet, des scripts qui parcourent msg['CLM']['CLM.05']['CLM.05.1'], et des moteurs en amont qui envoient X12 sous la forme de cet XML. Une forme plus propre de notre propre création ne servirait aucun d'entre eux. Il écrit donc exactement ce que Open Integration Engine 4.6 écrit, et lit exactement ce que celui-ci lit, et les tests les comparent octet par octet contre le sérialiseur d'OIE.
Une version antérieure de ce package a inventé sa propre forme (une racine X12Interchange, des éléments nommés CLM05) et a affirmé qu'elle correspondait à celle de Mirth. Ce n'était pas le cas ; elle n'avait jamais été comparée à Mirth, et rien dans Perfuse n'utilisait cela.
The format
La racine est X12Transaction lorsque le message commence par un segment ISA et EDIMessage sinon, en transportant les trois délimiteurs en tant qu'attributs (segmentDelimiter, elementDelimiter, subelementDelimiter). Chaque segment est un élément nommé par son identifiant. Chaque élément de données est SEG.NN, numéroté à partir de 01 (ISA.01, CLM.05), et contient ses composants en tant que SEG.NN.1, SEG.NN.2, etc. : toujours au moins SEG.NN.1 pour un élément avec une valeur, aucun pour un élément vide.
Les délimiteurs sont lus à partir de l'ISA lorsqu'il en existe un : le séparateur d'éléments à la position 3, le séparateur de composants à la position 104 et le terminateur de segment à la position 105, avec un saut de ligne après celui-ci compté comme faisant partie de celui-ci. Sinon, ils sont ~ * et :. Le séparateur de répétition (ISA11) n'est pas interprété, ce qui est également le comportement d'OIE : un élément répété conserve son ^ à l'intérieur d'une valeur.
Il s'agit d'une réimplémentation du comportement, écrite à partir de l'observation de la sortie d'OIE et de son format documenté ; aucun code de Mirth n'est présent ici.
Source: github.com/biodream-llc/perfuse/internal/x12xml
26.120 xds
Le package xds est un partage de documents d'entreprise croisée IHE : un registre et référentiel de documents XDS.b (ITI-41 Fournir et enregistrer, ITI-18 Requête de stockage de registre, ITI-43 Récupérer l'ensemble de documents), une passerelle de réponse XCA sur le même magasin (ITI-38, ITI-39), et le côté client de chacun, donc un canal peut publier un document vers le référentiel d'une autre organisation et la console peut interroger un registre ou une communauté.
Les métadonnées sont ebXML Registry 3.0 (ebRIM), comme XDS.b le définit dans IHE ITI TF-3 chapitre 4. Elles sont modélisées ici sous la forme de structs Go dont les balises XML portent les espaces de noms, donc un message est lu de la même manière quelle que soit la préfixe choisie par l'expéditeur, et écrit avec des espaces de noms corrects.
Source: github.com/biodream-llc/perfuse/internal/xds
26.121 xmldsig
Le package xmldsig met en œuvre les signatures numériques XML et le profil XAdES.
Pourquoi cela est écrit plutôt que prêté
Un document clinique signé est un artefact juridique. Il affirme qu'une personne nommée, à un moment nommé, a pris la responsabilité d'un ensemble spécifique d'octets. Se tromper dans un sens ou dans l'autre est grave : une signature qui ne peut pas être vérifiée fait qu'un document valide semble falsifié, et un vérificateur qui est trop généreux accepte un document que quelqu'un a modifié.
La canonicalisation est tout le problème
XML a de nombreuses séquences d'octets qui signifient la même chose. L'ordre des attributs n'est pas significatif, les préfixes d'espace de noms peuvent être renommés, les éléments vides peuvent être écrits de deux manières, et les espaces blancs à l'intérieur d'une balise sont libres. Une signature est sur des octets, donc avant de hasher quoi que ce soit, les deux extrémités doivent convenir d'une seule séquence d'octets pour un document donné. Cette convention est la canonicalisation, et c'est là que les implémentations vont mal, car chaque erreur produit une signature qui vérifie contre votre propre sortie et échoue contre celle de tout le monde.
Ce fichier est donc la canonicalisation, seule, avec ses propres tests. Rien sur la signature n'apparaît ici.
Exclusive plutôt qu'inclusive, par défaut
La canonicalisation inclusive tire dans toutes les déclarations d'espace de noms qui sont dans la portée, y compris celles que l'élément signé n'utilise jamais. Cela fait que une signature se brise lorsque le document est plus tard intégré à l'intérieur de quelque chose qui déclare un espace de noms non lié sur un ancêtre, ce qui est précisément ce qui se passe lorsque un CDA est placé à l'intérieur d'une enveloppe SOAP ou d'un wrapper de métadonnées IHE. La canonicalisation exclusive n'inclut que les déclarations que l'élément utilise réellement, et c'est ce que les profils d'échange de documents spécifient pour cette raison.
Source: github.com/biodream-llc/perfuse/internal/xmldsig
26.122 xtree
Le package xtree est un arbre XML mutable.
Trois fonctionnalités très différentes doivent modifier le XML : les transformations HL7, que Mirth modèle comme du XML car c'est ce sur quoi ses scripts opèrent ; les documents cliniques, qui sont nativement du XML ; et les étapes de transformation déclaratives. Ils partagent cet arbre unique plutôt que chacun en faisant pousser un, car l'alternative est de trois modèles qui ne sont pas d'accord sur ce qu'un élément vide signifie.
L'objectif de conception est la fidélité aux sémantiques E4X, puisque les scripts Mirth sont E4X et que le but de les exécuter inchangés est qu'ils se comportent de la même manière. Cela détermine deux décisions qui auraient par ailleurs l'air étranges : un nœud conserve un pointeur vers son parent, car E4X expose parent(), et les enfants sont ordonnés avec des doublons autorisés, car une répétition de champ HL7 est littéralement un élément répété et les scripts indexent en fonction de la position.
Source: github.com/biodream-llc/perfuse/internal/xtree
26.123 pas
Le package pas lit les requêtes de prise en charge préalable de Da Vinci (PAS) sous forme de bundles.
C'est le lecteur que le serveur PAS de Perfuse utilise, publié afin que ce qui décide d'une autorisation préalable - les règles d'un payeur, un système de gestion des utilisations, un service de décision tel que Vaglio - lise une requête avec le même code, et ainsi les mêmes réponses sur ce que contient une requête. Deux lecteurs d'un format de message unique sont deux opinions à son sujet.
Il n'a pas de dépendances en dehors de la bibliothèque standard. Une requête est conservée sous forme de JSON décodé (map[string]any) plutôt que sous forme de ressources typées, car un bundle PAS transporte toutes les ressources de support que le fournisseur a choisi d'envoyer, et un lecteur qui supprime ce qu'il ne modélise pas cacherait des preuves à la décision.
req, problems := pas.Read(bundle, false) if len(problems) > 0 { // refuser : la requête ne peut pas être répondue correctement } for _, svc := range req.Services() { // svc.Codes, svc.Item, et req.Resolve pour tout ce que l'élément référence }
Source: github.com/biodream-llc/perfuse/pas
27 Index des clés de configuration
Chaque clé dans l'ordre alphabétique, avec les blocs dans lesquels elle peut apparaître. Une clé qui apparaît dans plusieurs blocs signifie la même chose dans chacun d'eux ; là où elle ne l'est pas, les blocs sont documentés séparément et la différence est indiquée là.
27.1 Toutes les clés
| Clé | Apparaît dans |
|---|---|
access_key_id | Accès AWS, Authentification FHIR, Destination S3 |
account | Accès Azure Blob |
ack | Source HTTP, Source SOAP, Source |
ack_sender_id | Options X12 |
ack_sender_qualifier | Options X12 |
acknowledge | Options EDIFACT, Options HL7v3, Options X12 |
acks | Destination Kafka |
action | Destination SOAP |
addr | Connexion AMQP, Destination Broker, Source Broker, Connexion MQTT |
address | Connexion AMQP, Destination DICOM, Source de requête DICOM, Destination, Adresse directe, Destination TCP |
ae_title | Source DICOM |
after_query | Source de base de données |
after_read | Source Azure Blob, IMAP direct, Source e-mail, Sonde de fichiers, Source GCS, Source S3, Source SFTP |
allow | Scripts |
allow_clear_password | Destination FTP |
allow_unencrypted | Partenaire AS2, Réception PGP |
allow_unsigned | Partenaire AS2 |
allowed_calling_ae | Source DICOM |
allowed_senders | Source e-mail |
amqp | Destination, Source |
anchors_file | Adresse directe |
api_version | Connexion IBMMQ |
append | Destination, Destination SFTP |
application | Accusé de réception |
armor | Envoi PGP |
arrives_as | Options X12 |
as2 | Destination, Source |
attach | Destination SMTP |
attach_name | Destination directe, Destination SMTP |
attachment_names | Source e-mail |
attachments | Canal |
attempts | Réessai |
auth | Destination FHIR, Destination PAS |
authorities | Destination MPI |
azure_blob | Destination, Source |
backoff | Configuration de file d'attente, Réessai |
base64 | Source SOAP |
batch_size | Source de base de données, Sonde de fichiers |
baud | Source série |
bcc | Destination SMTP |
bearer_token | Destination CDA, Destination FHIR, Destination HTTP, Destination PAS |
big_endian | Encadrement TCP |
blob | Destination Azure Blob |
body | Destination SMTP, Destination SOAP |
broker | Destination, Source |
brokers | Destination Kafka, Source Kafka |
bucket | Accès GCS, Destination S3, Source S3 |
bundle_script | Destination FHIR |
called_ae | Destination DICOM, Source de requête DICOM |
calling_ae | Destination DICOM, Source de requête DICOM |
cc | Destination SMTP |
cda | Destination |
cert_file | Destination AS2, Partenaire AS2, Source AS2, Adresse directe |
channel | Destination, Ombre |
check_every | Référence de contrat |
city | Établissement ECR |
claim_us_core | Destination FHIR |
class | Destination XDS |
client_ca_file | XDR direct |
client_id | Authentification e-mail, Authentification FHIR, Connexion MQTT |
client_secret | Authentification e-mail, Authentification FHIR |
code | Code XDS |
column | Source de base de données |
columns | Délimité |
comment | Délimité |
commit_after_delivery | Source Kafka |
compare | Ombre |
compress | Destination AS2 |
compression | Destination Kafka |
config | Destination ELR |
container | Accès Azure Blob |
content_type | Destination AMQP, Destination AS2, Destination Azure Blob, Destination Broker, Destination GCS, Destination HTTP, Destination S3, Destination XDS |
contract | Canal |
credentials_file | Accès GCP |
dataType | Canal |
data_bits | Source série |
database | Destination, Source |
decrypt_with | Réception PGP |
default_identifier_system | Destination FHIR |
delimited | Canal |
delimiter | Délimité, Encadrement TCP |
deploy | Scripts |
description | Canal |
destination | Destination Broker, Source Broker |
destinations | Canal |
dicom | Canal, Destination, Source |
dicom_query | Source |
dicomweb | Destination, Source |
dir | Destination CDA, Destination, Destination de document, Destination FTP, Sonde de fichiers, Destination SFTP, Source SFTP |
direct | Destination, Source |
direct_from | Destination XDS |
direct_to | Destination XDS |
display | Code XDS |
dns | Destination directe |
document | Destination |
domain | Source SMB |
driver | Destination de base de données, Source de base de données |
dsn | Destination de base de données, Source de base de données |
duplicate_window | Source AS2 |
ecr | Destination FHIR |
edifact | Canal |
element | Source SOAP |
elr | Destination |
email | Source |
emit_on_first_poll | Source de requête DICOM |
enabled | Canal, Destination, Configuration de file d'attente |
encrypt_to | Envoi PGP |
endpoint | Accès AWS, Accès Azure Blob, Accès GCP, Destination S3 |
envelope | Options EDIFACT, Options X12 |
error_dir | Sonde de fichiers, Source SFTP |
error_folder | IMAP direct, Source e-mail |
error_prefix | Source Azure Blob, Source GCS, Source S3 |
expect_reply | Destination TCP |
extract | Pièces jointes |
facility | Accusé de réception, Destination ECR |
facility_id | Destination SOAP |
facility_type | Destination XDS |
fail_on_body | Destination HTTP |
fault_is_success | Destination SOAP |
fault_on_nak | Source SOAP |
fhir | Destination |
file | Référence de contrat, Source |
file_name | Destination AS2, Destination, Destination de document, Destination FTP, Envoi PGP, Destination SFTP |
file_roots | Scripts |
filter | Canal, Délimité, Destination, Options HL7v3, Scripts |
flow_control | Source série |
follow_redirects | Destination HTTP |
follow_symlinks | Source de fichiers |
font_size | Destination de document |
format | Destination de document, Destination S3 |
framed | Source Azure Blob, Destination FTP, Sonde de fichiers, Source GCS, Destination S3, Source S3, Destination SFTP, Source SFTP |
framing | Encadrement TCP |
from | Destination AS2, Destination SMTP |
from_beginning | Source Kafka |
ftp | Destination, Source |
gcs | Destination, Source |
group | Canal, Source Kafka |
group_by | Destination SNS, Destination SQS |
has_header | Délimité |
header | Destination SOAP |
headers | Destination Broker, Destination CDA, Destination DICO Mweb, Destination FHIR, Destination HTTP, Destination Kafka, Destination SOAP, Destination XDS |
heartbeat | Source Broker |
hl7v3 | Canal |
host | Destination Broker, Source Broker, IMAP direct, Source e-mail, Destination FTP, Source FTP, Destination SFTP, Source SFTP, Source SMB, Destination SMTP |
hostname | Connexion AMQP |
http | Destination, Source |
ibm_mq | Destination, Source |
id | Partenaire AS2, Source AS2 |
id_type | Destination MPI |
identifier_systems | Destination CDA, Destination FHIR |
idle_timeout | Source DICOM, Source, Source TCP |
ignore | Ombre |
imap | Source directe |
include | Scripts |
include_trigger_event | Accusé de réception |
insecure_skip_host_key_check | Destination SFTP, Source SFTP |
insecure_skip_verify | Destination FTP, Source FTP, Destination SMTP, Source Web DAV |
interval | Source de requête DICOM |
javascript | Destination, Source |
kafka | Destination, Source |
keep_alive | Destination TCP |
keep_blank_lines | Délimité |
keep_delimiter | Encadrement TCP |
key | Accès Azure Blob, Destination Kafka, Destination S3 |
key_column | Source de base de données |
key_file | Destination AS2, Source AS2, Adresse directe, Destination SFTP, Source SFTP |
key_passphrase | Destination SFTP, Source SFTP |
known_hosts_file | Destination SFTP, Source SFTP |
landscape | Destination de document |
language | Scripts |
ldap | Destination directe |
length_bytes | Encadrement TCP |
length_includes_header | Encadrement TCP |
level | Source de requête DICOM |
limit | Source de requête DICOM |
line | Établissement ECR |
listen | Source AS2, Source DICO Mweb, Source DICOM, Source directe, XDR direct, Source HTTP, Source SOAP, Source, Source TCP |
login | Destination Broker, Source Broker |
mailbox | IMAP direct, Source e-mail |
match | Source de requête DICOM |
max_attempts | Source de base de données, Configuration de file d'attente |
max_backoff | Configuration de file d'attente, Réessai |
max_bytes | Source directe |
max_connections | Source, Source TCP |
max_depth | Configuration de file d'attente |
max_differences | Ombre |
max_file_size | Sonde de fichiers, Source SFTP |
max_message_size | Source AS2, Source e-mail, Source HTTP, Source Kafka, Source SOAP, Source série, Source, Destination TCP, Source TCP |
max_messages | Source Pub Sub, Source SQS |
max_object_bytes | Source DICO Mweb, Source DICOM |
max_object_size | Source Azure Blob, Source GCS, Source S3 |
max_open_conns | Destination de base de données |
mechanism | Authentification SASL Kafka |
method | Destination HTTP |
move_to | Source Azure Blob, IMAP direct, Source e-mail, Sonde de fichiers, Source GCS, Source S3, Source SFTP |
mpi | Destination |
mqtt | Destination, Source |
name | Canal, Destination de canal, Destination, Établissement ECR |
ncpdp | Canal |
no_compress | Envoi PGP |
no_merge | Destination MPI |
non_persistent | Destination IBMMQ |
npi | Établissement ECR |
oauth | Source e-mail |
object | Destination GCS |
on_no_document | Destination CDA |
order_by | Destination Pub Sub |
over | Référence de contrat |
overlap | Source de requête DICOM |
params | Destination de base de données |
parity | Source série |
partner_cert_file | Destination AS2 |
partners | Source AS2 |
pas | Destination |
pass_plain | Réception PGP |
passcode | Destination Broker, Source Broker |
passphrase | Réception PGP, Envoi PGP |
password | Connexion AMQP, Destination AS2, Destination DICO Mweb, Source DICO Mweb, Destination directe, IMAP direct, Source directe, Source e-mail, Destination FTP, Source FTP, Destination HTTP, Connexion IBMMQ, Authentification SASL Kafka, Connexion MQTT, Destination SFTP, Source SFTP, Source SMB, Destination SMTP, Destination SOAP, Source SOAP, Source Web DAV, Destination XDS |
path | Source AS2, Source DICO Mweb, Source HTTP, Source SOAP |
path_style | Destination S3, Source S3 |
patient_domain | Destination XDS |
patient_root | Source de requête DICOM |
pattern | Sonde de fichiers, Source SFTP |
payer | Destination PAS |
persistent | Destination Broker |
pgp | Destination, Source |
phone | Établissement ECR |
poll_interval | Source Azure Blob, Source de base de données, IMAP direct, Source e-mail, Sonde de fichiers, Source GCS, Source IBMMQ, Source Java Script, Source S3, Source SFTP |
port | IMAP direct, Source e-mail, Source série |
postal_code | Établissement ECR |
postprocessor | Scripts |
practice_setting | Destination XDS |
prefetch | Source AMQP |
prefix | Source Azure Blob, Source GCS, Source S3 |
preprocessor | Scripts |
profile | Destination SOAP, Source SOAP |
project | Accès GCP |
protocol | Source e-mail |
provider | Authentification e-mail |
pubsub | Destination, Source |
purpose | Destination TEFCA |
qos | Connexion MQTT |
query | Source de base de données |
query_timeout | Source de base de données |
queue | Destination, Connexion IBMMQ |
queue_manager | Connexion IBMMQ |
queue_url | Destination SQS, Source SQS |
quiet_after | Source série |
quote | Délimité |
raw | Sonde de fichiers |
rctc | Destination ECR, Destination ELR |
read_timeout | Source HTTP, Source SOAP |
reassemble | Pièces jointes |
receipt | Destination AS2 |
receipt_url | Destination AS2 |
recipient_certs_dir | Destination directe |
reconnect | Source AMQP, Source Broker, Source MQTT, Source Pub Sub |
record_length | Encadrement TCP |
refresh_token | Authentification e-mail |
region | Accès AWS, Authentification FHIR, Destination S3 |
reject_on_warning | Destination FHIR |
relaxed | Délimité |
reopen_after | Source série |
reply | Source série, Source TCP |
reply_text | Source série, Source TCP |
request_mdn | Destination directe |
require_agreement | Destination CDA |
require_signature | Réception PGP |
response_element | Source SOAP |
response_namespace | Source SOAP |
response_transformer | Destination |
results_to | Destination PAS, Destination TEFCA |
retain | Destination MQTT |
retain_hours | Destination, Configuration de file d'attente |
retry | Destination |
return | Source de requête DICOM |
root | Source FTP, Source de fichiers, Source SMB |
s3 | Destination, Source |
sample | Ombre |
sas | Accès Azure Blob |
sasl | Destination Kafka, Source Kafka |
scheme | Code XDS |
scope | Authentification e-mail, Authentification FHIR |
script | Canal, Destination Java Script, Source Java Script |
scripts | Canal |
secret_access_key | Accès AWS, Authentification FHIR, Destination S3 |
security | IMAP direct, Source e-mail, Destination FTP, Source FTP |
selector | Source Broker |
sender_device | Options HL7v3 |
sender_oid | Options HL7v3 |
serial | Source |
server_side_encryption | Destination S3 |
session_timeout | Source Kafka |
session_token | Accès AWS, Authentification FHIR, Destination S3 |
sftp | Destination, Source |
shadow | Canal |
share | Source SMB |
sign_with | Envoi PGP |
smb | Source |
smtp | Destination |
smtp_host | Destination directe, Source directe |
sns | Destination |
soap | Destination, Source |
sop_classes | Destination DICOM, Source DICOM |
sort_by | Sonde de fichiers |
source | Canal, Destination ECR |
source_id | Destination XDS |
split | Délimité, Options EDIFACT, Options X12 |
sqs | Destination, Source |
ssn_system | Destination MPI |
stable_for | Sonde de fichiers, Source SFTP |
start_block | Encadrement TCP |
starttls | Destination SMTP |
state | Établissement ECR |
statement | Destination de base de données |
stop_bits | Source série |
storage_class | Destination GCS, Destination S3 |
subject | Destination AS2, Destination directe, Destination SMTP, Destination SNS |
subscription | Source Pub Sub |
subscription_id | Source Broker |
success_on_undefined | Destination Java Script |
success_status | Destination HTTP |
suffix | Source Azure Blob, Source GCS, Source S3 |
tables | Canal |
take | Source e-mail |
tcp | Destination, Source |
tefca | Destination |
temp_suffix | Destination, Destination de document, Destination FTP, Destination SFTP |
template | Source de base de données, Destination de document |
tenant | Authentification e-mail |
tenant_id | Authentification FHIR |
text | Destination directe |
tier | Destination Azure Blob |
timeout | Connexion AMQP, Destination Broker, Source Broker, Destination DICO Mweb, Destination DICOM, Source de requête DICOM, Destination de base de données, Destination, Destination directe, Destination de document, Destination FTP, Source FTP, Connexion IBMMQ, Destination Java Script, Source Java Script, Destination Kafka, Source Kafka, Connexion MQTT, Destination S3, Destination SFTP, Source SFTP, Source SMB, Destination SMTP, Destination SOAP, Scripts, Ombre, Destination TCP, Source Web DAV, Destination XDS |
timezone | Destination FHIR |
title | Destination de document |
tls | Connexion AMQP, Destination AS2, Source AS2, Destination Broker, Source Broker, Destination DICO Mweb, Source DICO Mweb, Destination DICOM, Source de requête DICOM, Source DICOM, Destination, IMAP direct, Source e-mail, Destination HTTP, Source HTTP, Connexion IBMMQ, Destination Kafka, Source Kafka, Connexion MQTT, Destination SOAP, Source SOAP, Source, Destination TCP, Source TCP, Destination XDS |
tls_cert | Source directe, XDR direct |
tls_key | Source directe, XDR direct |
to | Destination AS2, Destination directe, Destination SMTP |
token | Destination DICO Mweb, Source DICO Mweb, Source HTTP, Source SOAP, Destination XDS |
token_url | Authentification e-mail, Authentification FHIR |
topic | Destination Kafka, Destination MQTT, Source MQTT, Destination Pub Sub |
topic_arn | Destination SNS |
topics | Source Kafka |
transfer_syntaxes | Destination DICOM, Source DICOM |
transformations | Canal, Options DICOM, Délimité, Options HL7v3, Options NCPDP, Options de script, Options X12 |
transformer | Scripts |
trim_padding | Encadrement TCP |
trim_space | Délimité |
type | Destination, Authentification FHIR, Source |
undeploy | Scripts |
unencrypted | Destination AS2 |
unsigned | Destination AS2 |
unsigned_receipt | Destination AS2 |
url | Destination AS2, Destination CDA, Destination DICO Mweb, Destination FHIR, Destination HTTP, Connexion IBMMQ, Destination SOAP, Source Web DAV, Destination XDS |
user | Destination FTP, Source FTP, Destination SFTP, Source SFTP, Source SMB, Source Web DAV |
username | Connexion AMQP, Destination AS2, Destination DICO Mweb, Source DICO Mweb, Destination directe, IMAP direct, Source directe, Source e-mail, Destination HTTP, Connexion IBMMQ, Authentification SASL Kafka, Connexion MQTT, Destination SMTP, Destination SOAP, Source SOAP, Destination XDS |
validate_before_send | Destination FHIR |
verify_with | Réception PGP |
version | Destination CDA, Destination FHIR, Destination SOAP, Source SOAP |
visibility_timeout | Source SQS |
wait_seconds | Source SQS |
warnings_are_errors | Destination SOAP |
webdav | Source |
when | Accusé de réception |
window | Source de requête DICOM |
write | Destination CDA |
wsdl | Source SOAP |
x12 | Canal |
x12_as | Destination |
xdm | Destination directe |
xdm_source_id | Destination directe |
xdr | Source directe |
xds | Destination |