Données et sauvegarde¶
Kauze n'utilise pas de base de données. Chaque entité est un fichier JSON dans ~/.cause/,
chargé au démarrage du backend et réécrit à chaque modification. Le dossier est monté dans
chaque conteneur sous /root/.cause.
Arborescence¶
Données métier, à sauvegarder¶
| Chemin | Contenu | Édition manuelle |
|---|---|---|
users/ |
Un fichier par compte, mot de passe haché. | Déconseillée. |
patients/ |
Un fichier par patient. | Déconseillée. |
consultations/ |
Un fichier par consultation : pistes, segments, rapports, verrou. | Déconseillée. Un fichier illisible est ignoré au démarrage et nommé dans les logs. |
act-types/ |
Référentiel des actes et sous-types. Peuplé au premier démarrage, puis le dossier fait foi. | Possible, relu au redémarrage. Préférez l'onglet Actes. |
prompts/ |
Surcharges des prompts par acte, dossier plat. | Possible, lu à chaque génération. Préférez l'onglet Templates et prompts. |
templates/ |
Surcharges des templates de rapport vide, préfixés report-. |
Idem. |
pdf-templates/ |
Modèles d'export PDF : un XHTML et son fichier .compose.json de paramètres. |
Un HTML déposé sans fichier de paramètres est utilisable mais pas rééditable dans le compositeur. |
asr-harvest.json |
Corrections en cours de comptage pour l'apprentissage. | Non. |
asr-variants-learned.json |
Variantes de transcription apprises, injectées au glossaire. | Risquée. |
dictionary-versions/ |
Copies horodatées du glossaire à chaque apprentissage. | Non, ce sont des archives. |
licence.lic |
Licence signée de cette machine. Lisible, jamais modifiable : toute retouche invalide sa signature. Voir La licence machine. | Non. Une nouvelle licence s'obtient auprès de l'éditeur. |
licence-grace.txt |
Compte des heures de la fenêtre de grâce qui suit un refus de licence, scellé. Voir La licence machine. | Jamais. Toute retouche, et l'effacement sur un serveur en service, provoquent un arrêt immédiat. |
docker-compose.yml, .env |
Sur un serveur livré : le compose du client et les versions épinglées, posés par le script d'installation depuis le disque de livraison. | OLLAMA_MODEL, CAUSE_VERSION et CAUSE_MOTEURS se modifient, le reste non. |
.env.backend.overrides |
Vos réglages de l'application, une ligne par réglage. Voir Votre fichier de réglages. | Oui, c'est le seul fichier de configuration qui vous appartienne. Aucune installation ne l'écrase. |
letsencrypt/desec.ini |
Jeton DNS pour le certificat. | C'est vous qui le créez. |
certs/ |
Certificat, clé privée et bloc nginx HTTPS. | Réécrit par le script. |
Caches, retéléchargeables¶
| Chemin | Contenu |
|---|---|
ollama/models/ |
Poids du modèle de langue, plusieurs Go. |
whisper/ |
Modèle de transcription. |
qwen-asr/ |
Second modèle de transcription, 4,4 Go sous hub/, posés par l'installation depuis le disque de livraison même tant que le profil qwen dort. Le sous-dossier triton/ est un cache compilé pour la carte de cette machine. |
spring-ai-cache/, djl-cache/ |
Modèle d'embedding du backend. |
vllm-cache/ |
Uniquement si le profil vLLM est activé. |
Conservé mais hors sauvegarde¶
| Chemin | Contenu |
|---|---|
audio/ |
Les segments audio de toutes les consultations. Conservés sans limite de temps : seuls les fichiers qu'aucun segment ne réclame sont purgés, après 168 heures. Ce dossier grossit donc sans borne et n'entre pas dans la sauvegarde par défaut, car il pèse des dizaines de Go pour une donnée déjà transcrite. Mesuré le 11/10/2026 : 431 Ko par portion de 30 s, soit environ 50 Mo par heure de dictée. Voir Exploitation. |
corpus-entrainement/ |
Le couple audio et transcription figé à la validation d'un rapport, rangé par mois, consultation, piste, puis instant de validation, avec un manifeste par unité. Cette dernière clé rend chaque unité autonome : un médecin qui recommence sa dictée puis revalide produit une seconde unité, et aucun audio ne reste sans description. Destiné à l'entraînement et au fine-tuning. Les audios y sont des liens durs vers audio/ : un seul contenu sur le disque sous deux noms, donc le corpus ne coûte rien tant que l'original existe, et en devient propriétaire quand le balayage retire l'autre nom. Conséquence à connaître : du sous-estime sa taille réelle. Part par l'envoi mensuel vers S3, jamais par la sauvegarde quotidienne. |
Transitoires¶
| Chemin | Contenu |
|---|---|
logs/ |
Un fichier par jour et par service. Jamais purgés automatiquement. |
qrcodes/ |
QR codes du hotspot et page d'impression. Supprimer un PNG force sa régénération. |
sessions/ |
Créé par le script, inutilisé. |
vector-store.json |
N'existe que si l'ancien enrichissement lexical est activé. |
remontee/ |
File d'attente de la remontée des évaluations et son registre envoyes.json. Son contenu est déjà dé-identifié : voir ci-dessous. |
La remontée des évaluations¶
Active par défaut. Elle envoie une fois par mois, vers le stockage compatible S3 de l'éditeur, un
seau commun où votre installation a son propre préfixe, ce que la machine produit d'évaluations et
qui ne part dans aucun dépôt : relevés de baseline (baseline-diagnostic/), mesures de charge
(mesure-charge/), corpus dé-identifié et ses
audios (corpus-entrainement/). Sans elle, une campagne menée chez un client reste sur son disque
et se perd. Les variables sont dans Configuration.
Sans ses clés, rien ne part. La file se remplit quand même, un seul avertissement est inscrit au journal du backend, et c'est ce qui rappelle de les poser ; le script d'installation vous les demande, puis redit à la fin de son passage ce qui manque encore. Sur une machine où le corpus d'entraînement existe, la construction du 1er du mois inscrit donc ce corpus en file : ses audios y entrent par lien dur, ce qui ne coûte aucun octet, et le seul coût réel est la copie des JSON et des textes dé-identifiés.
Deux passages, à deux rythmes. Le 1er du mois, la file est construite : chaque fichier nouveau
des dossiers sources est dé-identifié puis inscrit dans remontee/, le fichier d'origine n'étant
jamais touché. Toutes les cinq minutes, la file est reprise jusqu'au succès, parce qu'un lien
d'établissement à 1 ou 2 Mb/s coupe au milieu d'un envoi. Un envoi est inscrit sur le disque avant
la première tentative : un redémarrage ou une coupure ne perd rien, et une clé déjà posée ne repart
pas le mois suivant.
La dé-identification a lieu à la construction, pas à l'envoi. C'est ce qui garantit qu'un envoi avorté ne laisse jamais de donnée nominative dormir dans la file. Ce qui est retiré de chaque JSON et de chaque texte qui part :
- les champs dont le nom annonce une identité : nom, prénom, nom complet, identifiant de connexion,
date de naissance, téléphone, courriel, adresse, numéro de sécurité sociale, et les champs qui
désignent une personne comme
validatedBy,createdByoupatient; - les identifiants techniques, remplacés par une empreinte stable : deux fichiers restent reliables entre eux, sans porter l'identifiant d'origine, y compris dans les clés d'objet ;
- dans tout texte restant : courriel, téléphone, numéro de sécurité sociale, date au format jour/mois/année, et les noms que l'installation connaît, ceux de ses patients et de ses comptes, quelles que soient la casse et les accents.
Ce qui n'est pas retiré, et qu'il faut savoir : l'audio part tel quel, c'est sa raison d'être, donc une voix et les noms qu'elle prononce partent avec lui. Et un nom de personne inconnue de l'installation, cité dans une dictée, n'est pas reconnu. Un fichier que la remontée ne sait pas relire ne part pas : un JSON illisible, un binaire d'un type qu'elle n'inspecte pas, un fichier plus gros que la limite sont écartés et nommés dans le journal.
Sauvegarder¶
Un outil est fourni : scripts/sauvegarde/sauvegarde.py, qui n'a besoin que de Python 3.
python3 scripts/sauvegarde/sauvegarde.py sauvegarder --destination /mnt/sauvegardes
Il écrit cause-<horodatage>.tgz et sa somme de contrôle .sha256 à côté, puis relit l'archive
qu'il vient de produire : chaque JSON doit s'y analyser et porter un enregistrement. Une
sauvegarde qu'on n'a pas relue n'est pas une sauvegarde.
Un fichier déjà perdu n'arrête pas la sauvegarde. Il est écarté, nommé dans le compte rendu,
et listé dans un PROBLEMES.txt joint à l'archive pour que le défaut voyage avec elle. Deux cas
comptent comme perdus : un JSON illisible, et un JSON réduit à null, qui est du JSON
parfaitement valide mais que le backend ignore au démarrage. Seule une source sans aucune donnée
métier sauvegardable est un refus franc.
Les codes de sortie servent à une tâche planifiée : 0 tout est propre, 2 archive produite mais avec des réserves, à regarder, 1 rien n'a été produit.
Il affiche ce qu'il a archivé, et surtout ce qu'il a laissé :
/mnt/sauvegardes/cause-20261010-141559.tgz (246,6 Ko)
21 consultations, 22 patients, 8 users, 6 act-types, 1 pdf-templates
somme de contrôle : cause-20261010-141559.tgz.sha256
non sauvegardé, inconnu de l'outil : consultations.bak-20260514-155515
ÉCARTÉS, donnée déjà perdue (1), détaillés dans PROBLEMES.txt au sein de l'archive :
users/00000000-0000-0000-0000-000000000000.json : JSON valide mais aucun enregistrement
Ce qui entre : les dossiers métier du tableau ci-dessus, plus licence.lic,
licence-grace.txt, asr-harvest.json et asr-variants-learned.json. Ce qui n'entre pas :
les caches, les transitoires, ce qui part par la remontée mensuelle, les artefacts de mesure locaux
du banc d'essai (bench-output/, bench-reports/), l'audio (des dizaines de Go pour une donnée
déjà transcrite ; --avec-audio le force), et aucune clé privée : ni certs/, ni ssl/, ni
letsencrypt/, ni aucun fichier .pem ou .key. Une archive de sauvegarde voyage et se
duplique ; une clé privée, non. Ces éléments se régénèrent avec le script de certificat.
licence-grace.txt entre dans l'archive, de sorte qu'un serveur reconstruit sur une machine neuve
arrive avec son compteur et obtienne ses soixante-douze heures le temps que l'éditeur émette la
licence de cette machine ; sans lui, une installation restaurée refuserait le métier dès le
premier démarrage. Vous n'avez rien à en faire : il se réécrit seul à chaque démarrage où la
licence est acceptée.
Le compose du client et son .env n'entrent pas non plus : ils viennent du disque de livraison et
de l'éditeur, donc une réinstallation les repose à l'identique.
Votre fichier de réglages .env.backend.overrides reste dehors pour une autre raison : il peut
porter des clés si vous en écrivez, et un secret n'a rien à faire dans une archive qui voyage. Il
tient en quelques lignes : recopiez-les dans le cahier d'exploitation du service. Les deux clés du
stockage, elles, vivent dans le fichier généré : sur une machine reconstruite, relancer le script
les redemande.
L'outil n'archive que ce qu'il connaît, et nomme le reste dans la ligne « non sauvegardé ». Relisez cette ligne : si un dossier que vous avez créé vous-même y figure, c'est à vous de le sauvegarder à part.
Le backend peut tourner pendant la sauvegarde. Chaque fichier est écrit par un remplacement atomique, un temporaire voisin puis un déplacement d'un seul geste, donc une copie prise au mauvais moment voit l'ancienne version ou la nouvelle, jamais un fichier tronqué.
Vérifier une sauvegarde¶
python3 scripts/sauvegarde/sauvegarde.py verifier /mnt/sauvegardes/cause-20261010-141559.tgz
À faire périodiquement sur les archives anciennes : un disque se dégrade en silence. La commande compare la somme de contrôle, décompresse et analyse chaque JSON.
Restaurer¶
docker compose stop backend
python3 scripts/sauvegarde/sauvegarde.py restaurer /mnt/sauvegardes/cause-20261010-141559.tgz
docker compose start backend
La restauration vérifie la somme de contrôle avant d'écrire quoi que ce soit, et refuse toute
archive dont un chemin sortirait de la destination ou contiendrait un lien symbolique. La
destination par défaut est votre dossier personnel, donc les fichiers reprennent leur place dans
~/.cause/. Les fichiers existants sont écrasés par ceux de l'archive ; ceux qui n'y figurent pas
sont laissés en place.
Répétez cette restauration une fois, vers un dossier d'essai, avant d'en avoir besoin :
mkdir -p /tmp/essai && python3 scripts/sauvegarde/sauvegarde.py restaurer <archive> --destination /tmp/essai
Les fichiers de consultation d'une version antérieure sont migrés à la lecture.