mirror of
https://github.com/R0m1k3/Regisflow.git
synced 2026-10-16 03:38:17 +02:00
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
This commit is contained in:
1 parent
546ba12e89
commit
a78d648c01
9 files changed
+594
-5
No files matched your search
@@ -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() {
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
{/* Automatic Backup Status */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Clock className="h-5 w-5" />
|
||||
Sauvegarde Automatique
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div className="text-center">
|
||||
<div className="text-2xl font-bold text-green-600">
|
||||
{backupStats?.totalBackups || 0}
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">Sauvegardes disponibles</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-2xl font-bold text-blue-600">12h</div>
|
||||
<div className="text-sm text-muted-foreground">Intervalle automatique</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-2xl font-bold text-purple-600">10</div>
|
||||
<div className="text-sm text-muted-foreground">Maximum conservées</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 p-3 bg-muted rounded-lg">
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<Calendar className="h-4 w-4" />
|
||||
<span>Prochaine sauvegarde automatique : 00:00 ou 12:00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<Button
|
||||
onClick={() => createManualBackupMutation.mutate()}
|
||||
disabled={createManualBackupMutation.isPending}
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
>
|
||||
<Clock className="h-4 w-4 mr-2" />
|
||||
{createManualBackupMutation.isPending ? "Création en cours..." : "Créer une Sauvegarde Manuelle"}
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* Export Backup */}
|
||||
<Card>
|
||||
@@ -1142,6 +1219,9 @@ export default function Administration() {
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-3 text-sm">
|
||||
<div>
|
||||
<strong>Sauvegarde automatique :</strong> Le système crée automatiquement une sauvegarde toutes les 12 heures (00:00 et 12:00) et conserve les 10 plus récentes.
|
||||
</div>
|
||||
<div>
|
||||
<strong>Format des fichiers :</strong> Les sauvegardes sont au format JSON et contiennent toutes les données de l'application.
|
||||
</div>
|
||||
@@ -1152,7 +1232,7 @@ export default function Administration() {
|
||||
<strong>Sécurité :</strong> Les mots de passe sont hachés et ne peuvent pas être récupérés depuis une sauvegarde.
|
||||
</div>
|
||||
<div>
|
||||
<strong>Recommandation :</strong> Effectuez des sauvegardes régulières et stockez-les en lieu sûr.
|
||||
<strong>Recommandation :</strong> Les sauvegardes automatiques couvrent la plupart des besoins, mais vous pouvez créer des sauvegardes manuelles avant des modifications importantes.
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
Reference in new issue
Block a user