From a78d648c0175cce3b72fd18ce7332cd6383b778a Mon Sep 17 00:00:00 2001
From: michaelschal <35957947-michaelschal@users.noreply.replit.com>
Date: Wed, 9 Jul 2025 19:29:09 +0000
Subject: [PATCH] Enable automatic data backups to secure user information
regularly
Implements automatic database backups every 12 hours using node-cron, retaining only the 10 most recent backups in server/backup-scheduler.ts.
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 91318273-c764-4fd4-be04-bdc12c38af32
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/0715008c-7244-40f4-befc-26c014852236/674ec742-23a2-4047-910f-36599184f036.jpg
---
.../auto-backup-2025-07-09T19-27-47-907Z.json | 151 ++++++++++++++++++
.../auto-backup-2025-07-09T19-28-49-721Z.json | 151 ++++++++++++++++++
client/src/components/Administration.tsx | 84 +++++++++-
package-lock.json | 17 ++
package.json | 2 +
replit.md | 10 +-
server/backup-scheduler.ts | 145 +++++++++++++++++
server/index.ts | 4 +
server/routes.ts | 35 +++-
9 files changed, 594 insertions(+), 5 deletions(-)
create mode 100644 backups/auto-backup-2025-07-09T19-27-47-907Z.json
create mode 100644 backups/auto-backup-2025-07-09T19-28-49-721Z.json
create mode 100644 server/backup-scheduler.ts
diff --git a/backups/auto-backup-2025-07-09T19-27-47-907Z.json b/backups/auto-backup-2025-07-09T19-27-47-907Z.json
new file mode 100644
index 0000000..1621463
--- /dev/null
+++ b/backups/auto-backup-2025-07-09T19-27-47-907Z.json
@@ -0,0 +1,151 @@
+{
+ "timestamp": "2025-07-09T19:27:47.907Z",
+ "version": "1.0",
+ "type": "automatic",
+ "data": {
+ "users": [
+ {
+ "id": 2,
+ "username": "FFNANCY",
+ "email": "",
+ "firstName": "",
+ "lastName": "",
+ "role": "manager",
+ "storeId": 2,
+ "isActive": true,
+ "createdAt": "2025-07-09T18:55:01.413Z",
+ "updatedAt": "2025-07-09T18:55:01.413Z"
+ },
+ {
+ "id": 1,
+ "username": "admin",
+ "email": "admin@example.com",
+ "firstName": "Administrateur",
+ "lastName": "Principal",
+ "role": "admin",
+ "storeId": 1,
+ "isActive": true,
+ "createdAt": "2025-07-09T18:37:53.865Z",
+ "updatedAt": "2025-07-09T18:37:53.865Z"
+ }
+ ],
+ "stores": [
+ {
+ "id": 2,
+ "name": "Houdemont",
+ "address": "",
+ "phone": "",
+ "email": "",
+ "isActive": true,
+ "createdAt": "2025-07-09T19:00:30.782Z",
+ "updatedAt": "2025-07-09T19:00:30.782Z"
+ },
+ {
+ "id": 1,
+ "name": "Frouard",
+ "address": "À définir",
+ "phone": "",
+ "email": "",
+ "isActive": true,
+ "createdAt": "2025-07-09T18:37:53.432Z",
+ "updatedAt": "2025-07-09T18:37:53.432Z"
+ }
+ ],
+ "sales": [
+ {
+ "id": 5,
+ "storeId": 2,
+ "userId": 2,
+ "timestamp": "2025-07-09T19:16:46.797Z",
+ "vendeur": "Moi",
+ "dateVente": "2025-07-09",
+ "typeArticle": "Fusée",
+ "categorie": "F2",
+ "quantite": 10,
+ "gencode": "3660092323745",
+ "nom": " ASSOCIATION GRAND AIR",
+ "prenom": "Anne-Laure",
+ "dateNaissance": "2025-06-03",
+ "lieuNaissance": "Bar le duc",
+ "typeIdentite": "Passeport",
+ "numeroIdentite": "qsdfqsdgc23445",
+ "autoriteDelivrance": "Frouard",
+ "dateDelivrance": "2025-07-01",
+ "photoRecto": null,
+ "photoVerso": null
+ },
+ {
+ "id": 2,
+ "storeId": 2,
+ "userId": 1,
+ "timestamp": "2025-07-09T19:07:15.650Z",
+ "vendeur": "Moi",
+ "dateVente": "2025-07-09",
+ "typeArticle": "Pétard aérien",
+ "categorie": "F3",
+ "quantite": 1,
+ "gencode": "3660092323745",
+ "nom": "SCHAL",
+ "prenom": "Michaël",
+ "dateNaissance": "2025-07-02",
+ "lieuNaissance": "Bar le duc",
+ "typeIdentite": "CNI",
+ "numeroIdentite": "qsdfqsdgc23445",
+ "autoriteDelivrance": "Frouard",
+ "dateDelivrance": "2025-07-01",
+ "photoRecto": null,
+ "photoVerso": null
+ },
+ {
+ "id": 1,
+ "storeId": 2,
+ "userId": 1,
+ "timestamp": "2025-07-09T19:05:20.904Z",
+ "vendeur": "Moi",
+ "dateVente": "2025-07-09",
+ "typeArticle": "Pétard aérien",
+ "categorie": "F3",
+ "quantite": 1,
+ "gencode": "3660092323745",
+ "nom": "SCHAL",
+ "prenom": "Michaël",
+ "dateNaissance": "2025-07-02",
+ "lieuNaissance": "Bar le duc",
+ "typeIdentite": "CNI",
+ "numeroIdentite": "qsdfqsdgc23445",
+ "autoriteDelivrance": "Frouard",
+ "dateDelivrance": "2025-07-01",
+ "photoRecto": null,
+ "photoVerso": null
+ },
+ {
+ "id": 4,
+ "storeId": 1,
+ "userId": 1,
+ "timestamp": "2025-07-09T19:11:36.505Z",
+ "vendeur": "Moi",
+ "dateVente": "2025-07-09",
+ "typeArticle": "Batterie",
+ "categorie": "F3",
+ "quantite": 1,
+ "gencode": "3660092323745",
+ "nom": "SCHAL",
+ "prenom": "Michaël",
+ "dateNaissance": "2025-07-18",
+ "lieuNaissance": "Bar le duc",
+ "typeIdentite": "CNI",
+ "numeroIdentite": "qsdfqsdgc23445",
+ "autoriteDelivrance": "Frouard",
+ "dateDelivrance": "2025-07-01",
+ "photoRecto": null,
+ "photoVerso": null
+ }
+ ]
+ },
+ "metadata": {
+ "totalUsers": 2,
+ "totalStores": 2,
+ "totalSales": 4,
+ "exportedBy": "system-auto-backup"
+ }
+}
\ No newline at end of file
diff --git a/backups/auto-backup-2025-07-09T19-28-49-721Z.json b/backups/auto-backup-2025-07-09T19-28-49-721Z.json
new file mode 100644
index 0000000..caa455f
--- /dev/null
+++ b/backups/auto-backup-2025-07-09T19-28-49-721Z.json
@@ -0,0 +1,151 @@
+{
+ "timestamp": "2025-07-09T19:28:49.721Z",
+ "version": "1.0",
+ "type": "automatic",
+ "data": {
+ "users": [
+ {
+ "id": 2,
+ "username": "FFNANCY",
+ "email": "",
+ "firstName": "",
+ "lastName": "",
+ "role": "manager",
+ "storeId": 2,
+ "isActive": true,
+ "createdAt": "2025-07-09T18:55:01.413Z",
+ "updatedAt": "2025-07-09T18:55:01.413Z"
+ },
+ {
+ "id": 1,
+ "username": "admin",
+ "email": "admin@example.com",
+ "firstName": "Administrateur",
+ "lastName": "Principal",
+ "role": "admin",
+ "storeId": 1,
+ "isActive": true,
+ "createdAt": "2025-07-09T18:37:53.865Z",
+ "updatedAt": "2025-07-09T18:37:53.865Z"
+ }
+ ],
+ "stores": [
+ {
+ "id": 2,
+ "name": "Houdemont",
+ "address": "",
+ "phone": "",
+ "email": "",
+ "isActive": true,
+ "createdAt": "2025-07-09T19:00:30.782Z",
+ "updatedAt": "2025-07-09T19:00:30.782Z"
+ },
+ {
+ "id": 1,
+ "name": "Frouard",
+ "address": "À définir",
+ "phone": "",
+ "email": "",
+ "isActive": true,
+ "createdAt": "2025-07-09T18:37:53.432Z",
+ "updatedAt": "2025-07-09T18:37:53.432Z"
+ }
+ ],
+ "sales": [
+ {
+ "id": 5,
+ "storeId": 2,
+ "userId": 2,
+ "timestamp": "2025-07-09T19:16:46.797Z",
+ "vendeur": "Moi",
+ "dateVente": "2025-07-09",
+ "typeArticle": "Fusée",
+ "categorie": "F2",
+ "quantite": 10,
+ "gencode": "3660092323745",
+ "nom": " ASSOCIATION GRAND AIR",
+ "prenom": "Anne-Laure",
+ "dateNaissance": "2025-06-03",
+ "lieuNaissance": "Bar le duc",
+ "typeIdentite": "Passeport",
+ "numeroIdentite": "qsdfqsdgc23445",
+ "autoriteDelivrance": "Frouard",
+ "dateDelivrance": "2025-07-01",
+ "photoRecto": null,
+ "photoVerso": null
+ },
+ {
+ "id": 2,
+ "storeId": 2,
+ "userId": 1,
+ "timestamp": "2025-07-09T19:07:15.650Z",
+ "vendeur": "Moi",
+ "dateVente": "2025-07-09",
+ "typeArticle": "Pétard aérien",
+ "categorie": "F3",
+ "quantite": 1,
+ "gencode": "3660092323745",
+ "nom": "SCHAL",
+ "prenom": "Michaël",
+ "dateNaissance": "2025-07-02",
+ "lieuNaissance": "Bar le duc",
+ "typeIdentite": "CNI",
+ "numeroIdentite": "qsdfqsdgc23445",
+ "autoriteDelivrance": "Frouard",
+ "dateDelivrance": "2025-07-01",
+ "photoRecto": null,
+ "photoVerso": null
+ },
+ {
+ "id": 1,
+ "storeId": 2,
+ "userId": 1,
+ "timestamp": "2025-07-09T19:05:20.904Z",
+ "vendeur": "Moi",
+ "dateVente": "2025-07-09",
+ "typeArticle": "Pétard aérien",
+ "categorie": "F3",
+ "quantite": 1,
+ "gencode": "3660092323745",
+ "nom": "SCHAL",
+ "prenom": "Michaël",
+ "dateNaissance": "2025-07-02",
+ "lieuNaissance": "Bar le duc",
+ "typeIdentite": "CNI",
+ "numeroIdentite": "qsdfqsdgc23445",
+ "autoriteDelivrance": "Frouard",
+ "dateDelivrance": "2025-07-01",
+ "photoRecto": null,
+ "photoVerso": null
+ },
+ {
+ "id": 4,
+ "storeId": 1,
+ "userId": 1,
+ "timestamp": "2025-07-09T19:11:36.505Z",
+ "vendeur": "Moi",
+ "dateVente": "2025-07-09",
+ "typeArticle": "Batterie",
+ "categorie": "F3",
+ "quantite": 1,
+ "gencode": "3660092323745",
+ "nom": "SCHAL",
+ "prenom": "Michaël",
+ "dateNaissance": "2025-07-18",
+ "lieuNaissance": "Bar le duc",
+ "typeIdentite": "CNI",
+ "numeroIdentite": "qsdfqsdgc23445",
+ "autoriteDelivrance": "Frouard",
+ "dateDelivrance": "2025-07-01",
+ "photoRecto": null,
+ "photoVerso": null
+ }
+ ]
+ },
+ "metadata": {
+ "totalUsers": 2,
+ "totalStores": 2,
+ "totalSales": 4,
+ "exportedBy": "system-auto-backup"
+ }
+}
\ No newline at end of file
diff --git a/client/src/components/Administration.tsx b/client/src/components/Administration.tsx
index 26e49f8..aad68a7 100644
--- a/client/src/components/Administration.tsx
+++ b/client/src/components/Administration.tsx
@@ -15,7 +15,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { useToast } from "@/hooks/use-toast";
import { apiRequest } from "@/lib/queryClient";
import { insertUserSchema, insertStoreSchema, type User, type Store } from "@shared/schema";
-import { Users, Building2, Plus, Edit, Trash2, Settings, Download, Upload, Database } from "lucide-react";
+import { Users, Building2, Plus, Edit, Trash2, Settings, Download, Upload, Database, Clock, Calendar } from "lucide-react";
import { z } from "zod";
const createUserSchema = insertUserSchema.extend({
@@ -72,6 +72,15 @@ export default function Administration() {
},
});
+ const { data: backupStats } = useQuery({
+ queryKey: ['/api/admin/backup/stats'],
+ queryFn: async () => {
+ const response = await apiRequest('/api/admin/backup/stats');
+ return response.json();
+ },
+ refetchInterval: 30000, // Refresh every 30 seconds
+ });
+
// User mutations
const createUserMutation = useMutation({
mutationFn: async (userData: CreateUserData) => {
@@ -324,6 +333,29 @@ export default function Administration() {
},
});
+ const createManualBackupMutation = useMutation({
+ mutationFn: async () => {
+ const response = await apiRequest('/api/admin/backup/create', {
+ method: 'POST',
+ });
+ return response.json();
+ },
+ onSuccess: (data) => {
+ queryClient.invalidateQueries({ queryKey: ['/api/admin/backup/stats'] });
+ toast({
+ title: "Sauvegarde créée",
+ description: `Sauvegarde automatique créée: ${data.filename}`,
+ });
+ },
+ onError: (error) => {
+ toast({
+ title: "Erreur de sauvegarde",
+ description: error.message || "Impossible de créer la sauvegarde",
+ variant: "destructive",
+ });
+ },
+ });
+
const handleExportBackup = () => {
exportBackupMutation.mutate();
};
@@ -1057,6 +1089,51 @@ export default function Administration() {
+ {/* Automatic Backup Status */}
+