# Prise de rendez-vous médical : ne pas exposer de données de santé en métadonnées

> Un module de rendez-vous pour un cabinet médical ne peut pas stocker le motif de consultation dans wp_postmeta comme n'importe quel champ. Voici comment isoler ces données.

- Auteur : WordPress Développement
- Publié le : 2021-12-24
- Mis à jour le : 2021-12-24
- Catégorie : Extensions
- URL : https://www.wpmoderne.fr/extensions/prise-rendez-vous-medical-donnees-sante-metadonnees/

## L’essentiel

- Les données de santé sont une catégorie particulière au RGPD
- wp_postmeta n'est jamais le bon endroit pour ce type de donnée
- Chiffrement, capacités dédiées et journal d'accès sont nécessaires

Une donnée de santé n'est pas une donnée personnelle comme les autres. Le RGPD la classe parmi les catégories dites « particulières » (article 9), avec un régime de traitement plus strict qu'un simple nom ou une adresse e-mail. Or un module de prise de rendez-vous médical construit à la va-vite, sur la base d'un CPT « rendez-vous » et de quelques champs ACF, finit presque toujours par stocker le motif de consultation, parfois un antécédent, directement dans `wp_postmeta`.

Le problème n'est pas seulement réglementaire, il est structurel. La table `wp_postmeta` est interrogeable par n'importe quel code qui dispose d'un accès à la base, y compris une extension tierce mal isolée, un export SQL de sauvegarde envoyé sans précaution à un prestataire, ou une requête `WP_Query` avec `meta_query` écrite par un développeur qui ignore la sensibilité du champ. Concevoir l'architecture en amont pour isoler ces données change radicalement le niveau de risque.

## Sortir la donnée sensible du modèle de contenu WordPress

Le premier principe consiste à ne jamais faire transiter une donnée de santé par les tables standards de WordPress. Un rendez-vous, en tant qu'événement (date, praticien, statut), peut rester un post ou une entrée dans une table personnalisée légère. Le motif de consultation, en revanche, doit vivre dans une table séparée, avec ses propres règles d'accès :

```
CREATE TABLE {$wpdb->prefix}rdv_donnees_sante (
  id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  rdv_id BIGINT UNSIGNED NOT NULL,
  motif_chiffre VARBINARY(1024) NOT NULL,
  cree_le DATETIME NOT NULL,
  KEY rdv_id (rdv_id)
) {$charset_collate};
```

Cette table n'est jamais interrogée par une `WP_Query` classique et n'apparaît dans aucun export standard de contenu. Elle est accessible uniquement via une classe d'accès dédiée, qui centralise le chiffrement, le déchiffrement et la vérification des permissions avant toute lecture.

## Chiffrer au niveau applicatif, pas seulement au niveau disque

Le chiffrement du disque (souvent proposé par l'hébergeur) protège contre le vol physique du serveur, pas contre un accès non autorisé via l'application elle-même. La donnée doit donc être chiffrée avant son insertion en base, avec une clé stockée hors du dépôt de code et hors de la base de données — typiquement une variable d'environnement injectée au niveau du serveur :

> L'essentiel à retenir : Les données de santé sont une catégorie particulière au RGPD ; wp_postmeta n'est jamais le bon endroit pour ce type de donnée ; Chiffrement, capacités dédiées et journal d'accès sont nécessaires

- Chiffrement symétrique (libsodium, disponible nativement depuis PHP 7.2) plutôt qu'un simple encodage réversible.
- Clé stockée dans une variable d'environnement, jamais dans `wp-config.php` versionné.
- Rotation de clé documentée, même si elle n'est pas mise en œuvre dès le premier déploiement.

## Restreindre l'accès avec des capacités dédiées

Un rôle « administrateur » WordPress standard ne devrait pas avoir automatiquement accès au motif de consultation. Il faut créer une capacité spécifique, attribuée uniquement au rôle « praticien » ou « secrétariat médical », et vérifier cette capacité à chaque point d'entrée qui touche à la donnée sensible :

```
add_action( 'init', function () {
    $role = get_role( 'praticien' );
    if ( $role ) {
        $role->add_cap( 'lire_motif_consultation' );
    }
} );

function rdv_get_motif( int $rdv_id ) {
    if ( ! current_user_can( 'lire_motif_consultation' ) ) {
        return new WP_Error( 'acces_refuse', 'Accès non autorisé à cette donnée.' );
    }
    // Déchiffrement et retour de la donnée.
}
```

## Journaliser chaque accès à la donnée sensible

Au-delà du contrôle d'accès, une exigence souvent oubliée est la traçabilité : qui a consulté quel motif, à quel moment. Un journal d'accès minimal, dans une table distincte, permet de répondre à une demande d'audit ou à une suspicion de fuite sans avoir à fouiller dans les logs serveur bruts :

| Colonne | Rôle |
| --- | --- |
| utilisateur_id | Qui a consulté la donnée |
| rdv_id | Quel rendez-vous concerné |
| horodatage | Quand l'accès a eu lieu |

## Ce que l'extension ne doit pas gérer elle-même

Il est tentant, une fois cette architecture posée, de vouloir aussi gérer l'hébergement conforme HDS (hébergement de données de santé) directement depuis l'extension. Ce n'est pas son rôle : l'hébergement HDS est une certification qui concerne l'infrastructure entière, pas un module applicatif. L'extension doit être conçue pour fonctionner correctement sur un hébergement HDS, sans jamais prétendre en tenir lieu.

> Un module qui manipule une donnée de santé sans que son architecture ait été pensée pour l'isolement dès le départ n'est pas un module qu'on corrige à la marge : c'est un module qu'on reconstruit.

## Notre verdict

Un module de prise de rendez-vous médical n'est jamais un simple CPT avec des champs ACF. La donnée sensible — le motif de consultation, un antécédent, une pièce jointe médicale — doit être isolée dans une table dédiée, chiffrée au niveau applicatif, protégée par des capacités spécifiques et journalisée à chaque accès. Cette rigueur architecturale coûte plus cher en développement initial, mais elle est la condition sine qua non pour livrer un module réellement adapté au secteur santé.
