Passer au contenu principal

Schéma de base de données

Ce document décrit le schéma de base de données SQLite utilisé par duplistatus pour stocker les données des opérations de sauvegarde.

Emplacement de la base de données​

La base de données est stockée dans le répertoire des données d'application :

  • Emplacement par défaut : /app/data/backups.db
  • Volume Docker : duplistatus_data:/app/data
  • Nom du fichier : backups.db

Système de migration de base de données​

duplistatus utilise un système de migration automatisé pour gérer les modifications du schéma de base de données entre les versions.

Historique des versions de migration​

Voici les versions de migration historiques qui ont amené la base de données à son état actuel :

  • Schéma v1.0 (Application v0.6.x et antérieures) : Schéma de base de données initial avec tables machines et sauvegardes
  • Schéma v2.0 (Application v0.7.x) : Ajout de colonnes manquantes et table de configurations
  • Schéma v3.0 (Application v0.7.x) : Renommage de la table machines en serveurs, ajout de la colonne server_url
  • Schéma v3.1 (Application v0.8.x) : Amélioration des champs de données de sauvegarde, ajout de la colonne server_password
  • Schéma v4.0 (Application v0.9.x / v1.0.x) : Ajout du contrôle d'accès utilisateur (tables utilisateurs, sessions, journal d'audit)
  • Schéma v4.1 (Application v1.5.x) : Ajout de api_keys et clés de configuration par défaut pour l'authentification par clé API optionnelle, listes blanches IP et limites de téléchargement
  • Schéma v4.2 (Application v1.5.x) : Ajout du registre daily_summary_deliveries et configuration daily_summary par défaut pour les notifications de résumé quotidien optionnelles

La version actuelle de l'application (v1.5.x) utilise Schéma v4.2 comme dernière version du schéma de base de données.

Processus de migration​

  1. Sauvegarde automatique : Crée une sauvegarde avant la migration
  2. Mise à jour du schéma : Met à jour la structure de la base de données
  3. Migration des données : Préserve les données existantes
  4. Vérification : Confirme la migration réussie

Tables​

Table Serveurs​

Stocke les informations sur les serveurs Duplicati en cours de surveillance.

Champs​

ChampTypeDescription
idTEXT PRIMARY KEYIdentifiant unique du serveur
nameTEXT NOT NULLNom du serveur depuis Duplicati
server_urlTEXTURL du serveur Duplicati
aliasTEXTNom convivial défini par l'utilisateur
noteTEXTNotes/description définies par l'utilisateur
server_passwordTEXTMot de passe du serveur pour l'authentification
created_atDATETIMEHorodatage de création du serveur

Tableau des Sauvegardes​

Stocke les données d'opération de sauvegarde reçues des serveurs duplicati.

Champs clés​

ChampTypeDescription
idTEXT PRIMARY KEYIdentifiant de sauvegarde unique
server_idTEXT NOT NULLRéférence au tableau des serveurs
backup_nameTEXT NOT NULLNom du travail de sauvegarde
backup_idTEXT NOT NULLID de sauvegarde de duplicati
dateDATETIME NOT NULLHeure d'exécution de la sauvegarde
statusTEXT NOT NULLÉtat de la sauvegarde (Succès, Avertissement, Erreur, Fatal)
duration_secondsINTEGER NOT NULLDurée en secondes
sizeINTEGERTaille des fichiers source
uploaded_sizeINTEGERTaille des données téléchargées
examined_filesINTEGERNombre de fichiers examinés
warningsINTEGERNombre d'avertissements
errorsINTEGERNombre d'erreurs
created_atDATETIMEHorodatage de création de l'enregistrement

Tableaux de messages (Stockage JSON)​

ChampTypeDescription
messages_arrayTEXTTableau JSON des messages de journal
warnings_arrayTEXTTableau JSON des messages d'avertissement
errors_arrayTEXTTableau JSON des messages d'erreur
available_backupsTEXTTableau JSON des versions de sauvegarde disponibles

Champs d'opération sur les fichiers​

ChampTypeDescription
examined_filesINTEGERFichiers examinés lors de la sauvegarde
opened_filesINTEGERFichiers ouverts pour la sauvegarde
added_filesINTEGERNouveaux fichiers ajoutés à la sauvegarde
modified_filesINTEGERFichiers modifiés dans la sauvegarde
deleted_filesINTEGERFichiers supprimés de la sauvegarde
deleted_foldersINTEGERDossiers supprimés de la sauvegarde
added_foldersINTEGERDossiers ajoutés à la sauvegarde
modified_foldersINTEGERDossiers modifiés dans la sauvegarde
not_processed_filesINTEGERFichiers non traités
too_large_filesINTEGERFichiers trop volumineux pour être traités
files_with_errorINTEGERFichiers avec erreurs
added_symlinksINTEGERLiens symboliques ajoutés
modified_symlinksINTEGERLiens symboliques modifiés
deleted_symlinksINTEGERLiens symboliques supprimés

Champs Taille de fichier​

ChampTypeDescription
size_of_examined_filesINTEGERTaille des fichiers examinés lors de la sauvegarde
size_of_opened_filesINTEGERTaille des fichiers ouverts pour la sauvegarde
size_of_added_filesINTEGERTaille des nouveaux fichiers ajoutés à la sauvegarde
size_of_modified_filesINTEGERTaille des fichiers modifiés dans la sauvegarde

Champs État de l'opération​

ChampTypeDescription
parsed_resultTEXT NOT NULLRésultat de l'opération analysé
main_operationTEXT NOT NULLType d'opération principal
interruptedBOOLEANIndique si la sauvegarde a été interrompue
partial_backupBOOLEANIndique si la sauvegarde a été partielle
dryrunBOOLEANIndique si la sauvegarde a été un essai
versionTEXTVersion de duplicati utilisée
begin_timeDATETIME NOT NULLHeure de début de la sauvegarde
end_timeDATETIME NOT NULLHeure de fin de la sauvegarde
warnings_actual_lengthINTEGERNombre réel d'avertissements
errors_actual_lengthINTEGERNombre réel d'erreurs
messages_actual_lengthINTEGERNombre réel de messages

Champs Statistiques du serveur​

ChampTypeDescription
bytes_downloadedINTEGEROctets téléchargés depuis la destination
known_file_sizeINTEGERTaille de fichier connue sur la destination
last_backup_dateDATETIMEDate de dernière sauvegarde sur la destination
backup_list_countINTEGERNombre de versions de sauvegarde
reported_quota_errorBOOLEANErreur de quota signalée
reported_quota_warningBOOLEANAvertissement de quota signalé
backend_main_operationTEXTOpération principale du backend
backend_parsed_resultTEXTRésultat analysé du backend
backend_interruptedBOOLEANOpération du backend interrompue
backend_versionTEXTVersion du backend
backend_begin_timeDATETIMEHeure de début de l'opération du backend
backend_durationTEXTDurée de l'opération du backend
backend_warnings_actual_lengthINTEGERNombre d'avertissements du backend
backend_errors_actual_lengthINTEGERNombre d'erreurs du backend

Tableau Configurations​

Stocke les paramètres de configuration de l'application.

Champs​

ChampTypeDescription
keyTEXT PRIMARY KEY NOT NULLClé de configuration
valueTEXTValeur de configuration (JSON)

Clés de configuration courantes​

  • email_config: Paramètres de notification par e-mail
  • ntfy_config: Paramètres de notification NTFY
  • overdue_tolerance: Paramètres de tolérance de sauvegarde en retard
  • notification_templates: Modèles de messages de notification
  • daily_summary: Mode Résumé quotidien, calendrier, fuseau horaire, URL du tableau de bord public optionnelle et remplacement du destinataire SMTP optionnel (smtpRecipient; vide utilise les Paramètres de messagerie)
  • cron_service: Calendriers des tâches cron, y compris daily-summary-dispatch (minute hour * * * de daily_summary.utcTime)
  • audit_retention_days: Période de Conservation des journaux d'audit (par défaut : 90 jours)

Tableau Version de la base de données​

Suit la version du schéma de la base de données à des fins de migration.

Champs​

ChampTypeDescription
versionTEXT PRIMARY KEYVersion de la base de données
applied_atDATETIMEQuand la migration a été appliquée

Tableau Utilisateurs​

Stocke les informations de compte utilisateur pour l'authentification et le contrôle d'accès.

Champs​

ChampTypeDescription
idTEXT PRIMARY KEYIdentifiant utilisateur unique
usernameTEXT UNIQUE NOT NULLNom d'utilisateur pour la connexion
password_hashTEXT NOT NULLMot de passe haché avec Bcrypt
is_adminBOOLEAN NOT NULLSi l'utilisateur dispose de privilèges admin
must_change_passwordBOOLEANSi le changement de mot de passe est requis
created_atDATETIMEHorodatage de création du compte
updated_atDATETIMEHorodatage de dernière mise à jour
last_login_atDATETIMEHorodatage de dernière connexion réussie
last_login_ipTEXTAdresse IP de la dernière connexion
failed_login_attemptsINTEGERNombre de tentatives de connexion échouées
locked_untilDATETIMEExpiration du verrouillage du compte (si verrouillé)

Tableau Sessions​

Stocke les données de session utilisateur pour l'authentification et la sécurité.

Champs​

ChampTypeDescription
idTEXT PRIMARY KEYIdentifiant de session
user_idTEXTRéférence à la table Utilisateurs (nullable pour les sessions non authentifiées)
created_atDATETIMEHorodatage de création de session
last_accessedDATETIMEHorodatage du dernier accès
expires_atDATETIME NOT NULLHorodatage d'expiration de session
ip_addressTEXTAdresse IP d'origine de la session
user_agentTEXTChaîne d'agent utilisateur
csrf_tokenTEXTJeton CSRF pour la session
csrf_expires_atDATETIMEExpiration du jeton CSRF

Tableau Journal d'audit​

Stocke la piste d'audit des actions utilisateur et des événements système.

Champs​

ChampTypeDescription
idINTEGER PRIMARY KEY AUTOINCREMENTIdentifiant unique d'entrée du journal d'audit
timestampDATETIMEHorodatage de l'événement
user_idTEXTRéférence à la table Utilisateurs (nullable)
usernameTEXTNom d'utilisateur au moment de l'action
actionTEXT NOT NULLAction effectuée
categoryTEXT NOT NULLCatégorie d'action (par exemple, « authentification », « paramètres », « sauvegarde »)
target_typeTEXTType de cible (par exemple, « serveur », « sauvegarde », « utilisateur »)
target_idTEXTIdentifiant de la cible
detailsTEXTDétails supplémentaires (JSON)
ip_addressTEXTAdresse IP du demandeur
user_agentTEXTChaîne d'agent utilisateur
statusTEXT NOT NULLStatut de l'action (« succès », « échec », « erreur »)
error_messageTEXTMessage d'erreur si l'action a échoué

Tableau Clés API​

Stocke les clés API hachées pour les API HTTP externes. Le secret en texte clair est affiché une seule fois à la création et n'est jamais stocké.

Champs​

ChampTypeDescription
idTEXT PRIMARY KEYIdentifiant de clé unique
nameTEXT NOT NULLNom d'affichage
key_hashTEXT UNIQUEHash SHA-256 du secret
key_prefixTEXTQuatre premiers caractères du secret (pour les empreintes)
key_suffixTEXTQuatre derniers caractères du secret (pour les empreintes)
scopeTEXT NOT NULLupload ou read
descriptionTEXTDescription optionnelle
enabledINTEGER1 quand la clé est active
created_atDATETIMEHorodatage de création
created_byTEXTIdentifiant utilisateur de l'administrateur qui a créé la clé
expires_atDATETIMEExpiration facultative
last_used_atDATETIMEDernier utilisation réussie
usage_countINTEGERNombre d'utilisations réussies

Clés de configuration associées dans la table configurations : external_api_require_api_key, ip_trusted_proxies, admin_ip_allowlist, external_api_ip_allowlist, upload_limits.

Table des livraisons du Résumé quotidien​

Registre par chaîne pour la livraison d'e-mail du Résumé quotidien. Les lignes héritées peuvent inclure une chaîne ntfy des versions antérieures. Chaque occurrence planifiée (ou envoi manuel unique) a au maximum une ligne par chaîne. Les charges utiles rendues sont stockées avant l'envoi afin que les tentatives conservent le même instantané. Les lignes antérieures à 30 jours sont supprimées.

Si le processus s'arrête après qu'un fournisseur accepte un message mais avant que le succès soit enregistré, cette chaîne peut être relancée (au moins une fois).

Champs​

ChampTypeDescription
idTEXT PRIMARY KEYIdentifiant de livraison unique
occurrence_keyTEXT NOT NULLClé planifiée scheduled:UTC:{date}:{HH:mm} ou manual:{uuid}
channelTEXT NOT NULLemail ou ntfy
triggerTEXT NOT NULLscheduled, manual, ou retry
summary_dateTEXT NOT NULLDate du calendrier local pour l'instantané
time_zoneTEXT NOT NULLFuseau horaire IANA enregistré
payload_jsonTEXTChamps Sujet, HTML, texte et NTFY rendus
stateTEXT NOT NULLpending, sending, sent, ou failed
attempt_countINTEGERTentatives de livraison
next_retry_atDATETIMEQuand une chaîne défaillante peut être réclamée à nouveau
lease_expires_atDATETIMEBail de réclamation ; un bail obsolète peut être récupéré
errorTEXTDernier erreur, le cas échéant
created_atDATETIMEHorodatage de création de ligne
updated_atDATETIMEHorodatage de dernière mise à jour
sent_atDATETIMEHorodatage de succès

Un index unique sur (occurrence_key, channel) empêche les envois en doublon de la même occurrence sur la même chaîne.

Gestion des sessions​

Stockage des sessions sauvegardé en base de données​

Les sessions sont stockées dans la base de données avec secours en mémoire :

  • Stockage principal : Table des sessions sauvegardée en base de données
  • Secours : Stockage en mémoire (support hérité ou cas d'erreur)
  • ID de session : Chaîne aléatoire cryptographiquement sécurisée
  • Expiration : Délai d'expiration de session configurable
  • Protection CSRF : Protection contre les attaques par falsification de requête intersite
  • Nettoyage automatique : Les sessions expirées sont automatiquement supprimées

Points de terminaison de l'API de session​

  • POST /api/session : Créer une nouvelle session
  • GET /api/session : Valider une session existante
  • DELETE /api/session : Détruire une session
  • GET /api/csrf : Obtenir un jeton CSRF

Index​

La base de données inclut plusieurs index pour des performances de requête optimales :

  • Clés primaires : Tous les tableaux ont des index de clé primaire
  • Clés étrangères : Références de serveur dans la table des sauvegardes, références d'utilisateur dans les sessions et le journal d'audit
  • Optimisation des requêtes : Index sur les champs fréquemment interrogés
  • Index de date : Index sur les champs de date pour les requêtes basées sur le temps
  • Index d'utilisateur : Index de nom d'utilisateur pour les recherches d'utilisateur rapides
  • Index de session : Index d'expiration et user_id pour la gestion des sessions
  • Index d'audit : Index d'horodatage, user_id, action, catégorie et statut pour les requêtes d'audit
  • Index de clé API : Hash unique, plus recherches activées/portée pour l'authentification

Relations​

  • Serveurs → Sauvegardes : Relation un-à-plusieurs
  • Utilisateurs → Sessions : Relation un-à-plusieurs (les sessions peuvent exister sans utilisateurs)
  • Utilisateurs → Journal d'audit : Relation un-à-plusieurs (les entrées d'audit peuvent exister sans utilisateurs)
  • Utilisateurs → Clés API : Relation un-à-plusieurs via created_by (les clés persistent après la suppression de l'utilisateur)
  • Sauvegardes → Messages : Tableaux JSON intégrés
  • Configurations : Stockage clé-valeur

Types de données​

  • TEXT : Données de chaîne, tableaux JSON
  • INTEGER : Données numériques, nombre de fichiers, tailles
  • REAL : Nombres à virgule flottante, durées
  • DATETIME : Données d'horodatage
  • BOOLEAN : Valeurs vrai/faux

États de Sauvegarde​

  • Succès: Sauvegarde terminée avec succès
  • Avertissement: Sauvegarde terminée avec avertissements
  • Erreur: Sauvegarde terminée avec erreurs
  • Fatal: Sauvegarde échouée de manière fatale

Requêtes Courantes​

Obtenir la Dernière Sauvegarde pour un Serveur​

SELECT * FROM backups
WHERE server_id = ?
ORDER BY date DESC
LIMIT 1;

Obtenir Toutes les Sauvegardes pour un Serveur​

SELECT * FROM backups
WHERE server_id = ?
ORDER BY date DESC;

Obtenir le Résumé du Serveur​

SELECT
s.name,
s.alias,
COUNT(b.id) as backup_count,
MAX(b.date) as last_backup,
b.status as last_status
FROM servers s
LEFT JOIN backups b ON s.id = b.server_id
GROUP BY s.id;

Obtenir le Résumé Global​

SELECT
COUNT(DISTINCT s.id) as total_servers,
COUNT(b.id) as total_backups_runs,
COUNT(DISTINCT s.id || ':' || b.backup_name) as total_backups,
COALESCE(SUM(b.uploaded_size), 0) as total_uploaded_size,
(
SELECT COALESCE(SUM(b2.known_file_size), 0)
FROM backups b2
INNER JOIN (
SELECT server_id, MAX(date) as max_date
FROM backups
GROUP BY server_id
) latest ON b2.server_id = latest.server_id AND b2.date = latest.max_date
) as total_storage_used,
(
SELECT COALESCE(SUM(b2.size_of_examined_files), 0)
FROM backups b2
INNER JOIN (
SELECT server_id, MAX(date) as max_date
FROM backups
GROUP BY server_id
) latest ON b2.server_id = latest.server_id AND b2.date = latest.max_date
) as total_backuped_size
FROM servers s
LEFT JOIN backups b ON b.server_id = s.id;

Nettoyage de la Base de Données​

-- Delete old backups (older than 30 days)
DELETE FROM backups
WHERE date < datetime('now', '-30 days');

-- Delete servers with no backups
DELETE FROM servers
WHERE id NOT IN (SELECT DISTINCT server_id FROM backups);

Mappage JSON vers Base de Données​

Mappage du Corps de Requête API aux Colonnes de Base de Données​

Quand Duplicati envoie les données de sauvegarde via HTTP POST, la structure JSON est mappée aux colonnes de la base de données :

{
"Data": {
"ExaminedFiles": 15399, // → examined_files
"OpenedFiles": 1861, // → opened_files
"AddedFiles": 1861, // → added_files
"SizeOfExaminedFiles": 11086692615, // → size_of_examined_files
"SizeOfOpenedFiles": 13450481, // → size_of_opened_files
"SizeOfAddedFiles": 13450481, // → size_of_added_files
"SizeOfModifiedFiles": 0, // → size_of_modified_files
"ParsedResult": "Success", // → status
"BeginTime": "2025-04-21T23:45:46.9712217Z", // → begin_time and date
"Duration": "00:00:51.3856057", // → duration_seconds (calculated)
"WarningsActualLength": 0, // → warnings_actual_length
"ErrorsActualLength": 0 // → errors_actual_length
},
"Extra": {
"machine-id": "66f5ffc7ff474a73a3c9cba4ac7bfb65", // → server_id
"machine-name": "WSJ-SER5", // → server name
"backup-name": "WSJ-SER5 Local files", // → backup_name
"backup-id": "DB-2" // → backup_id
}
}

Note : Le champ size dans la table des sauvegardes stocke SizeOfExaminedFiles et uploaded_size stocke la taille réelle téléchargée/transférée à partir de l'opération de sauvegarde.