Modèles d'attributs
Maarch Digital Flow permet d'ajouter des attributs personnalisés aux entités gérées dans l'application, qu'il s'agisse des métadonnées pour les documents numériques, des données de formulaires pour les dossiers métier ou encore des informations personnelles des utilisateurs.
Bien que cela ne soit pas systématique, le plus souvent ces données doivent répondre à des contraintes en lien avec les règles du métier ou le besoin d'interopérabilité avec d'autres systèmes d'information. On peut par exemple souhaiter que les métadonnées des documents numériques de facture d'achat comportent obligatoirement l'identification du fournisseur, un numéro, une date et un montant total, ou que la structure des données d'un dossier correspondent à celle reçue depuis un formulaire de l'extranet.
Dans Maarch Digital Flow, la description de la structure des attributs des objets et les contraintes applicables sont décrites par des modèles d'attributs gérés par l'administrateur. Ces définitions sont ensuite utilisées dans les différentes sections d'administrations des entités.
Accès aux modèles
La section Modèle d'attributs de l'administration permet de créer et gérer les modèles. L'administrateur habilité l'utilise pour lister les modèles existants, les gérer et en ajouter de nouveaux.
Propriétés des modèles d'attributs
| Champ | Type | Description |
|---|---|---|
| Identifiant métier | texte |
Le nom utilisé par le système pour identifier le modèle. Il ne peut être changé quand le modèle est en cours d'utilisation |
| Libellé | texte |
Le nom affiché aux utilisateurs lorsqu'ils utilisent le modèle |
| Description | texte |
Description du modèle |

Contenu du modèle
Les modèles d'attributs sont basés sur le formalisme de déclaration des schémas de données JSON Schema (cf https://json-schema.org). Ils en reprennent toute la syntaxe, les éléments de base tels que les types de données, les structures complexes de tableaux et d'objets, les contraintes sur les formats, propriétés obligatoires, etc, à laquelle ils ajoutent des éléments de description étendus pour répondre à de nouveaux besoins.
La présente documentation n'a pas pour objectif de redécrire les spécifications ou la documentation complète du standards JSON Schema. On fournit ici quelques bases mais on ne reprend dans le détail la documentation disponible sur le site du projets. Pour plus d'informations, consulter la page https://json-schema.org/understanding-json-schema.
La version de spécifications utilisée à ce jour est
Draft 2020-12.
Un modèle d'attributs est un schéma JSON décrivant une structure de type object qui contient les attributs souhaités. La base de tout schéma est donc la suivante :
Schéma de base pour les objets
Le schéma décrit les attributs grâce au mot-clé properties. Ce bloc contient une liste qui associe les noms des propriétés à leur définition. La définition d'une propriété elle-même un schéma qui répond aux spécifications du formalisme JSON Schema. Chaque propriété doit a minima déclarer un type de données avec le mot-clé type qui peut prendre les valeurs suivantes :
string: chaîne de caractères (texte)integer: nombre entiernumber: nombre réel (ou décimal ou à virgule flottante)boolean: indicateur booléen pouvant prendre les valeurs 'vrai' ou 'faux'object: structure composite objet (ou clés-valeurs)array: structure composite tableau (ou liste de valeurs non ordonnée)
Les propriétés obligatoires peuvent être déclarées par le mot-clé required sous la forme de la liste des noms des propriétés concernées.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type" : "object",
"properties": {
"firstmane" : { "type": "string" },
"lastname" : { "type": "string" },
"age" : { "type": "integer" }
},
"required": [
"lastname",
"firstname"
]
}
L'application autorise aussi les définitions de propriétés complémentaires avec les mots-clés additionalProperties, patternProperties ainsi que les compositions avec les mots-clés allOf, oneOfet anyOf.
Affichage du formulaire
En plus de la définition des données, le modèle d'attributs utilise des mots-clés spécifiques liés à la présentation des attributs par l'application dans des formulaires dynamiques.
| Mot-clé | Type | Description |
|---|---|---|
position |
entier |
Permet de définir l'ordre d'affichage des propriétés dans le formulaire |
collapsable |
indicateur |
Pour les propriétés de type object uniquement, permet de définir si le bloc d'affichage contenant le jeu de propriétés peut être refermé. Quelle que soit la valeur indiquée, le bloc est ouvert par défaut si les données ne sont pas valides au regard du schéma de la propriété. |
view |
définition de champ |
Ce bloc fournit les paramètres d'affichage du champ dans le formulaire (voir ci-après) |
Le bloc view contient des mots-clés pour adapter les paramètres d'affichage du champ dans le formulaire :
| Mot-clé | Type | Description |
|---|---|---|
type |
texte |
Mode de saisie de l'attribut, par exemple input-string, input-checkbox, textarea, etc. |
size |
texte |
Largeur du champ de saisie small-blockoularge-block |
L'application propose un mode de saisie par défaut pour les attributs en fonction de leur type de base, mais ce mode peut-être adapté grâce au mot-clé type :
| Type de champ | Description | Type d'attribut applicables |
|---|---|---|
input-text |
Champ de saisie de texte simple | string |
input-text-multiple |
Champ de saisie de texte multi-valeurs | minItems, maxItems, copySeparatoret uniqueItems |
input-textarea |
Zone de texte multilignes | string, nbLineToShow (2, 3, 10, 15, 20) |
input-number |
Champ numérique | number, integer(minimumet maximum) |
input-autocomplete |
Champs de saisie assistée | string avec enum ou externalReference |
input-checkbox |
Cases à cocher | Type simple avec enum, boolean |
input-radio |
Boutons radio | Type simple avec enum |
input-toggle |
Interrupteur à bascule | boolean |
input-date |
Champs de saisie avec sélecteur de date | string avec format: date-time, minDate, maxDate, today |
input-img |
Champs image | string |
input-array |
Tableau | items, uniqueItems |
Ci-dessous un exemple de définition d'attributs comportant des mots-clés de présentation :
"civilite": {
"enum": [
"Mme",
"M"
],
"gdpr": true,
"type": "string",
"view": {
"size": "small-block",
"type": "input-select"
},
"title": "Civilité",
"pattern": "^(Mme|M)$",
"position": 3,
"filterNode": "exact",
"description": "Civilité"
},
"date_naissance": {
"gdpr": true,
"type": "string",
"view": {
"mask": {
"mask": "d0/M0/0000",
"showMaskTyped": true
},
"size": "small-block",
"type": "input-date"
},
"title": "Date de naissance",
"format": "date",
"position": 6,
"filterNode": "date",
"description": "Date de naissance"
}
Protection des données personnelles et sensibles
Le mot-clé gdpr permet d'indiquer qu'un attribut contient des données à caractère personnel ou sensible.
De telles données pourront ainsi être facilement identifiées dans l'application pour des opérations ultérieures d'anonymisation ou de pseudonymisation par exemple.
Liaison à un référentiel interne ou externe
Le modèle d'attribut peut définir des contraintes sur les valeurs possibles d'un ou plusieurs attributs, en lien avec un référentiel de données externe accessible à l'application. Par exemple, il est possible de lier le matricule d'un employé au registre du service des ressources humaines fourni par le SIRH, de sorte que l'attribut devra obligatoirement contenir un matricule existant. Il est aussi possible de lier un groupe d'attributs dont les valeurs sont présentes dans une même entrée de référentiel, afin par exemple de renseigner et valider d'une seul coup le numéro, le nom et l'adresse d'un compte client présent dans un logiciel CRM.
Référentiel interne
Le bloc qui est chargé de la validation d'un référentiel interne dans un modèle d'attributs est le bloc internal ou internals comme le montre l'exemple:
{
"identifier": "PurchaseOrder",
"displayName": "Modèle Demande Achat",
"internals" : [
{
"service": "user",
"url": "users",
"bindings": [
{
"attribute": "commande.user_fullname",
"initOnField": true,
"serviceAttribute": "displayName",
"searchProperty": "displayName",
"searchType": "partial",
"limit": 15,
"sortField": "displayName",
"sort": "asc",
"viewFormat": "{displayName}"
},
{
"attribute": "commande.user_identifier",
"serviceAttribute": "identifier"
"searchProperty": "identifier",
"isValidationKey": true
}
]
}
],
"content": {
"properties": {
"commande": {
"type": "object",
"title": "Commande",
...
}
}
}
}
| Nom du champ | Type | Obligatoire | Valeur par défaut | Description | Exemple |
|---|---|---|---|---|---|
| attributes | string | Oui | Nom du champ dans le modèle. | "user_fullname" |
|
| initOnField | boolean | Non | Permet de cibler le champ cible utilisé pour le référentiel (uniquement front) | true |
|
| serviceAttribute | string | Oui | Nom de l'attribut dans la réponse du service | "displayName" |
|
| isValidationKey | boolean | Non | false |
Si true, champ utilisé comme clé lors de la validation des données. |
true |
| searchProperty | string | Non | null |
Nom de l'attribut dans le service à utiliser lors de la recherche (front) ou de la validation (back). | "displayName" |
| sort | string | Non | null |
Direction de tri pour l'attribut sortField |
"order[...]=desc" |
| sortField | string | Non | null |
Nom de l'attribut dans le service à utiliser pour trier les résultats de la recherche. dans les paramètres de l'endpoint c'est order |
"order[displayName]=..." |
| limit | integer | Non | 10 |
Nombre résultats de la recherche | "_limit=20" |
| queryParams | string | Non | null |
Défini un filtre prédéfini | "groupType.identifier=default_group_type_identifier" |
- La validation effectue une recherche dans le service (entité) correspondant avec le filtre sur le champs qui a une
searchPropertyici dans notre cas c'est ledisplayName - La recherche s'effectue sur le premier model de binding qui n'a pas de champs
isValidationKeyici dans notre exemple c'estidentifier - L'attribut
userqui a la propriétéisValidationKeyest l'attribut que l'on va utiliser pour la validation du referentiel
Exemple
POST /entries
{
"attributes": {
"PurchaseOrder": {
"commande": {
"user_fullname": "jenny JANE",
"user_identifier": "jenny.jane",
}
}
}
}
Dans notre exemple on fait une recherche sur le user_fullname qui a l'identifier jenny.jane
La validation est appelée lors du contrôle de validité de l'entité, par le service CompletenessManager si l'utilisateur qui a l'identifier jenny.jane n'est pas retrouvé alors des erreurs sont remontée au niveau du Completeness
NB: Tous les champs présents dans la configuration internals doivent etre renseignés au moment de la création d'une Entry sinon un Problem sera remonté indiquant qu'il manque des paramètres.
Référentiel externe
Les entités
CsvServiceetDatabaseServiceétendentAbstractSystemEntity, et possèdent donc les champsid,owner,createdAt,createdBy,updatedAt,updatedBy, non mentionnés ici
CsvService
| Nom du champ | Type | Obligatoire | Valeur par défaut | Description | Exemple |
|---|---|---|---|---|---|
| identifier | string | oui | Identifiant métier unique du service | "service-fournisseur" |
|
| agent | AgentInterface | oui | L'agent qui va lire le CSV | ||
| responseFormat | array | oui | Mapping de la réponse du service | {"nom": "fournisseur"} |
|
| filePath | string | oui | Chemin du fichier CSV | "/opt/service.csv" |
|
| separator | string | oui | Caractère séparateur dans le fichier CSV | ";" |
|
| searchableFields | string[] | non | [] |
Liste des colonnes du csv utilisable lors de la recherche | ["fournisseur"] |
| sortableFields | string[] | non | [] |
Liste des colonnes de la table utilisable pour trier les résultats de la recherche | ["fournisseur", "tva"] |
Pour ce type de service, agent n'a pas configuration particulière requise
Si le fichier CSV est placé dans un sous-dossier du dossier source de l'application, il est possible de commencer filePath par ./.
Exemple :
L'application est installé dans /var/www/mdf-api, le fichier CSV est dans /var/www/mdf-api/referential/csv/fichier.csv.
On peut mettre dans filePath le chemin ./referential/csv/fichier.csv.
DatabaseService
Le service base de données ne peut se connecter qu'à des bases de données PostgreSQL. Il est possible d'utiliser une base différente de la base de l'application MDF.
| Nom du champ | Type | Obligatoire | Valeur par défaut | Description | Exemple |
|---|---|---|---|---|---|
| identifier | string | oui | Identifiant métier unique du service | "service-db-agent" |
|
| agent | AgentInterface | oui | L'agent contenant les informations de connection à la base de données | ||
| responseFormat | array | oui | Mapping de la réponse du service | {"nom": "display_name"} |
|
| tableName | string | oui | Nom de la table SQL | "agent" |
|
| searchableFields | string[] | non | [] |
Liste des colonnes de la table utilisable lors de la recherche | ["display_name"] |
| sortableFields | string[] | non | [] |
Liste des colonnes de la table utilisable pour trier les résultats de la recherche | ["display_name"] |
Agent
Pour ce type de service, agent doit avoir dans ses attributs :
| Nom du champ | Type | Description | Exemple |
|---|---|---|---|
| dbName | string | Le nom de la base de données | "mdf" |
| host | string | L'adresse du serveur de base de données | "postgres.mdf.com" ou "10.0.0.42" |
| port | string | Le port du serveur de base de données | "5432" |
| user | string | Le nom de l'utilisateur à utiliser pour se connecter à la base de données | "maarch" |
| password | string | Le mot de passe l'utilisateur à utiliser pour se connecter à la base de données | "maarch" |
Exemple :
{
"attributes": {
"dbName": "mdf",
"host": "localhost",
"port": "5432",
"user": "maarch",
"password": "maarch"
}
}
Il est également possible d'utiliser un seul champ url, qui contient tous ces paramètres dans le même champ.
Exemple :
postgresql:// est obligatoire et ne peut pas être changé
Ces champs sont dans les attributs d'un agent, mais ne sont pas dans un modèle d'attributs, et le mot de passe n'est pas chiffré. Ce format sera revu lors d'une refonte de la gestion des agents délégués
Fonctionnement de responseFormat
L'objet responseFormat contient un ensemble de clé-valeur où la clé est le nom du champ utilisé par le système MDF (retourné dans la recherche, utilisé pour la validation),
et la valeur est le nom du champ dans le service externe.
Exemple
Avec un service CSV qui contient comme valeurs :
On peut utiliser le mapping suivant :
Lors d'une recherche sur ce service, l'API MDF retournera un tableau d'objets de la forme :
[
{
"fournisseur": "A Soft Software",
"ville": "PARIS"
},
{
"fournisseur": "Adirrp",
"ville": "NANTERRE"
}
]
Il n'est pas nécessaire de mapper tous les champs du service, ici le champ country n'est pas mappé
Modèle d'attributs - config external
Cette configuration permet de relier des attributs d'un modèle à des champs d'un service externe.
| Nom du champ | Type | Obligatoire | Description | Exemple |
|---|---|---|---|---|
| service | string | Oui | identifier du service à utiliser |
"service-fournisseur" |
| bindings | ExternalConfig[] | Oui | Liste des bindings des champs |
Modèle d'attributs - ExternalBinding
| Nom du champ | Type | Obligatoire | Valeur par défaut | Description | Exemple |
|---|---|---|---|---|---|
| attributes | string | Oui | Nom de l'attribut dans le modèle. | "nomFournisseur", "fournisseur.nom" |
|
| serviceAttribute | string | Oui | Nom du champ dans la réponse du service, selon le mapping de responseFormat du service |
"fournisseur" |
|
| isValidationKey | boolean | Non | false |
Si true, champ utilisé comme clé lors de la validation des données. |
true |
| conflictStrategy | ConflictStrategy | Non | "keep" |
Stratégie à appliquer si la valeur dans l'attribut ne correspond pas à la valeur du service lors de la validation | "replace" |
| searchProperty | string | Non | null |
Nom du champ dans le service à utiliser lors de la recherche. Doit être dans la liste searchableFields du service |
"provider" |
| sort | string | Non | null |
Nom du champ dans le service à utiliser pour trier les résultats de la recherche. Doit être dans la liste sortableFields du service |
"provider" |
| limit | integer | Non | 10 |
Nombre résultats de la recherche | 50 |
L'objet external doit avoir un ExternalBinding avec isValidationKey à true.
S'il n'y en a pas, la validation ne fonctionnera pas.
S'il y en a plus d'un, le premier trouvé dans la liste sera utilisé. Les autres seront ignorés.
ConflictStrategy
| Valeur | Description |
|---|---|
| keep | Si les valeurs sont différentes, garde la valeur de l'attribut. Un Problem sera remonté |
| replace | Si les valeurs sont différentes, remplace la valeur de l'attribut par la valeur du service. Les attributs seront considérés valides |
| replaceIfEmpty | Si les valeurs sont différentes, et que l'attribut est vide, remplace la valeur de l'attribut par la valeur du service. Les attributs seront considérés valides. Si l'attribut n'est pas vide, garde la valeur de l'attribut.Un Problem sera remonté |
Exemple
{
"external": {
"service": "fournisseur-service",
"bindings": [
{
"attribute": "fournisseur",
"serviceAttribute": "fournisseur",
"isValidationKey": true,
"searchProperty": "fournisseur",
"viewFormat": "{matricule} - {nom} {prenom}",
"sort": "fournisseur",
"limit": 50
},
{
"attribute": "intraco",
"serviceAttribute": "intracoTVA",
"conflictStrategy": "replace"
}
]
}
}