chore: update backup configurations and directory structure
- Modified `.gitignore` to exclude all files in the `/data/` directory. - Enhanced `BACKUP.md` with customization options for backup storage paths and updated database path configurations. - Updated `docker-compose.yml` to reflect new paths for database and backup storage. - Adjusted `Dockerfile` to create a dedicated backups directory. - Refactored `BackupService` to utilize environment variables for backup paths, improving flexibility and reliability. - Deleted `dev.db` as it is no longer needed in the repository.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -43,4 +43,4 @@ next-env.d.ts
|
||||
/src/generated/prisma
|
||||
/prisma/dev.db
|
||||
|
||||
backups/
|
||||
/data/*
|
||||
|
||||
43
BACKUP.md
43
BACKUP.md
@@ -52,6 +52,19 @@ tsx scripts/backup-manager.ts config-set maxBackups=10
|
||||
tsx scripts/backup-manager.ts config-set compression=true
|
||||
```
|
||||
|
||||
### Personnalisation du dossier de sauvegarde
|
||||
|
||||
```bash
|
||||
# Via variable d'environnement permanente (.env)
|
||||
BACKUP_STORAGE_PATH="./custom-backups"
|
||||
|
||||
# Via variable temporaire (une seule fois)
|
||||
BACKUP_STORAGE_PATH="./my-backups" npm run backup:create
|
||||
|
||||
# Exemple avec un chemin absolu
|
||||
BACKUP_STORAGE_PATH="/var/backups/towercontrol" npm run backup:create
|
||||
```
|
||||
|
||||
## Utilisation
|
||||
|
||||
### Interface graphique
|
||||
@@ -272,8 +285,34 @@ export const prisma = globalThis.__prisma || new PrismaClient({
|
||||
### Variables d'environnement
|
||||
|
||||
```bash
|
||||
# Optionnel : personnaliser le chemin de la base
|
||||
DATABASE_URL="file:./custom/path/dev.db"
|
||||
# Configuration des chemins de base de données
|
||||
DATABASE_URL="file:./prisma/dev.db" # Pour Prisma
|
||||
BACKUP_DATABASE_PATH="./prisma/dev.db" # Base à sauvegarder (optionnel)
|
||||
BACKUP_STORAGE_PATH="./backups" # Dossier des sauvegardes (optionnel)
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
En environnement Docker, tout est centralisé dans le dossier `data/` :
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
environment:
|
||||
DATABASE_URL: "file:./data/prod.db" # Base de données Prisma
|
||||
BACKUP_DATABASE_PATH: "./data/prod.db" # Base à sauvegarder
|
||||
BACKUP_STORAGE_PATH: "./data/backups" # Dossier des sauvegardes
|
||||
volumes:
|
||||
- ./data:/app/data # Bind mount vers dossier local
|
||||
```
|
||||
|
||||
**Structure des dossiers :**
|
||||
```
|
||||
./data/ # Dossier local mappé
|
||||
├── prod.db # Base de données production
|
||||
├── dev.db # Base de données développement
|
||||
└── backups/ # Sauvegardes (créé automatiquement)
|
||||
├── towercontrol_*.db.gz
|
||||
└── ...
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
201
DOCKER.md
Normal file
201
DOCKER.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# 🐳 Docker - TowerControl
|
||||
|
||||
Guide d'utilisation de TowerControl avec Docker.
|
||||
|
||||
## 🚀 Démarrage rapide
|
||||
|
||||
### Production
|
||||
```bash
|
||||
# Démarrer le service de production
|
||||
docker-compose up -d towercontrol
|
||||
|
||||
# Accéder à l'application
|
||||
open http://localhost:3006
|
||||
```
|
||||
|
||||
### Développement
|
||||
```bash
|
||||
# Démarrer le service de développement avec live reload
|
||||
docker-compose --profile dev up towercontrol-dev
|
||||
|
||||
# Accéder à l'application
|
||||
open http://localhost:3005
|
||||
```
|
||||
|
||||
## 📋 Services disponibles
|
||||
|
||||
### 🚀 `towercontrol` (Production)
|
||||
- **Port** : 3006
|
||||
- **Base de données** : `./data/prod.db`
|
||||
- **Sauvegardes** : `./data/backups/`
|
||||
- **Mode** : Optimisé, standalone
|
||||
- **Restart** : Automatique
|
||||
|
||||
### 🛠️ `towercontrol-dev` (Développement)
|
||||
- **Port** : 3005
|
||||
- **Base de données** : `./data/dev.db`
|
||||
- **Sauvegardes** : `./data/backups/` (partagées)
|
||||
- **Mode** : Live reload, debug
|
||||
- **Profile** : `dev`
|
||||
|
||||
## 📁 Structure des données
|
||||
|
||||
```
|
||||
./data/ # Mappé vers /app/data dans les conteneurs
|
||||
├── README.md # Documentation du dossier data
|
||||
├── prod.db # Base SQLite production
|
||||
├── dev.db # Base SQLite développement
|
||||
└── backups/ # Sauvegardes automatiques
|
||||
├── towercontrol_2025-01-15T10-30-00-000Z.db.gz
|
||||
└── ...
|
||||
```
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Variables d'environnement
|
||||
|
||||
| Variable | Production | Développement | Description |
|
||||
|----------|------------|---------------|-------------|
|
||||
| `NODE_ENV` | `production` | `development` | Mode d'exécution |
|
||||
| `DATABASE_URL` | `file:./data/prod.db` | `file:./data/dev.db` | Base Prisma |
|
||||
| `BACKUP_DATABASE_PATH` | `./data/prod.db` | `./data/dev.db` | Source backup |
|
||||
| `BACKUP_STORAGE_PATH` | `./data/backups` | `./data/backups` | Dossier backup |
|
||||
| `TZ` | `Europe/Paris` | `Europe/Paris` | Fuseau horaire |
|
||||
|
||||
### Ports
|
||||
|
||||
- **Production** : `3006:3000`
|
||||
- **Développement** : `3005:3000`
|
||||
|
||||
## 📚 Commandes utiles
|
||||
|
||||
### Gestion des conteneurs
|
||||
```bash
|
||||
# Voir les logs
|
||||
docker-compose logs -f towercontrol
|
||||
docker-compose logs -f towercontrol-dev
|
||||
|
||||
# Arrêter les services
|
||||
docker-compose down
|
||||
|
||||
# Reconstruire les images
|
||||
docker-compose build
|
||||
|
||||
# Nettoyer tout
|
||||
docker-compose down -v --rmi all
|
||||
```
|
||||
|
||||
### Gestion des données
|
||||
```bash
|
||||
# Sauvegarder les données
|
||||
docker-compose exec towercontrol npm run backup:create
|
||||
|
||||
# Lister les sauvegardes
|
||||
docker-compose exec towercontrol npm run backup:list
|
||||
|
||||
# Accéder au shell du conteneur
|
||||
docker-compose exec towercontrol sh
|
||||
```
|
||||
|
||||
### Base de données
|
||||
```bash
|
||||
# Migrations Prisma
|
||||
docker-compose exec towercontrol npx prisma migrate deploy
|
||||
|
||||
# Reset de la base (dev uniquement)
|
||||
docker-compose exec towercontrol-dev npx prisma migrate reset
|
||||
|
||||
# Studio Prisma (dev)
|
||||
docker-compose exec towercontrol-dev npx prisma studio
|
||||
```
|
||||
|
||||
## 🔍 Debugging
|
||||
|
||||
### Vérifier la santé
|
||||
```bash
|
||||
# Health check
|
||||
curl http://localhost:3006/api/health
|
||||
curl http://localhost:3005/api/health
|
||||
|
||||
# Vérifier les variables d'env
|
||||
docker-compose exec towercontrol env | grep -E "(DATABASE|BACKUP|NODE_ENV)"
|
||||
```
|
||||
|
||||
### Logs détaillés
|
||||
```bash
|
||||
# Logs avec timestamps
|
||||
docker-compose logs -f -t towercontrol
|
||||
|
||||
# Logs des 100 dernières lignes
|
||||
docker-compose logs --tail=100 towercontrol
|
||||
```
|
||||
|
||||
## 🚨 Dépannage
|
||||
|
||||
### Problèmes courants
|
||||
|
||||
**Port déjà utilisé**
|
||||
```bash
|
||||
# Trouver le processus qui utilise le port
|
||||
lsof -i :3006
|
||||
kill -9 <PID>
|
||||
```
|
||||
|
||||
**Base de données corrompue**
|
||||
```bash
|
||||
# Restaurer depuis une sauvegarde
|
||||
docker-compose exec towercontrol npm run backup:restore filename.db.gz
|
||||
```
|
||||
|
||||
**Permissions**
|
||||
```bash
|
||||
# Corriger les permissions du dossier data
|
||||
sudo chown -R $USER:$USER ./data
|
||||
```
|
||||
|
||||
## 📊 Monitoring
|
||||
|
||||
### Espace disque
|
||||
```bash
|
||||
# Taille du dossier data
|
||||
du -sh ./data
|
||||
|
||||
# Espace libre
|
||||
df -h .
|
||||
```
|
||||
|
||||
### Performance
|
||||
```bash
|
||||
# Stats des conteneurs
|
||||
docker stats
|
||||
|
||||
# Utilisation mémoire
|
||||
docker-compose exec towercontrol free -h
|
||||
```
|
||||
|
||||
## 🔒 Production
|
||||
|
||||
### Recommandations
|
||||
- Utiliser un reverse proxy (nginx, traefik)
|
||||
- Configurer HTTPS
|
||||
- Sauvegarder régulièrement `./data/`
|
||||
- Monitorer l'espace disque
|
||||
- Logs centralisés
|
||||
|
||||
### Exemple nginx
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name towercontrol.example.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:3006;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
📚 **Voir aussi** : [BACKUP.md](./BACKUP.md) | [data/README.md](./data/README.md)
|
||||
@@ -35,8 +35,8 @@ RUN npm run build
|
||||
# Production image, copy all the files and run next
|
||||
FROM base AS runner
|
||||
|
||||
# Set timezone to Europe/Paris
|
||||
RUN apk add --no-cache tzdata
|
||||
# Set timezone to Europe/Paris and install sqlite3 for backups
|
||||
RUN apk add --no-cache tzdata sqlite
|
||||
RUN ln -snf /usr/share/zoneinfo/Europe/Paris /etc/localtime && echo Europe/Paris > /etc/timezone
|
||||
|
||||
WORKDIR /app
|
||||
@@ -64,8 +64,8 @@ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
COPY --from=builder /app/prisma ./prisma
|
||||
COPY --from=builder /app/node_modules/.prisma ./node_modules/.prisma
|
||||
|
||||
# Create data directory for SQLite
|
||||
RUN mkdir -p /app/data && chown nextjs:nodejs /app/data
|
||||
# Create data directory for SQLite and backups
|
||||
RUN mkdir -p /app/data/backups && chown -R nextjs:nodejs /app/data
|
||||
|
||||
# Set all ENV vars before switching user
|
||||
ENV PORT=3000
|
||||
|
||||
@@ -1,31 +1,27 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
towercontrol:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
target: runner
|
||||
ports:
|
||||
- "3006:3000"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- DATABASE_URL=file:/app/data/prod.db
|
||||
- TZ=Europe/Paris
|
||||
NODE_ENV: production
|
||||
DATABASE_URL: "file:../data/prod.db" # Prisma
|
||||
BACKUP_DATABASE_PATH: "./data/prod.db" # Base de données à sauvegarder
|
||||
BACKUP_STORAGE_PATH: "./data/backups" # Dossier des sauvegardes
|
||||
TZ: Europe/Paris
|
||||
volumes:
|
||||
# Volume persistant pour la base SQLite
|
||||
- sqlite_data:/app/data
|
||||
# Monter ta DB locale (décommente pour utiliser tes données locales)
|
||||
- ./prisma/dev.db:/app/data/prod.db
|
||||
- ./backups:/app/backups
|
||||
- ./data:/app/data # Dossier local data/ vers /app/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health || exit 1"]
|
||||
test: ["CMD", "wget", "-qO-", "http://localhost:3000/api/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
# Service de développement (optionnel)
|
||||
towercontrol-dev:
|
||||
build:
|
||||
context: .
|
||||
@@ -34,20 +30,29 @@ services:
|
||||
ports:
|
||||
- "3005:3000"
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- DATABASE_URL=file:/app/data/dev.db
|
||||
NODE_ENV: development
|
||||
DATABASE_URL: "file:../data/dev.db" # Prisma
|
||||
BACKUP_DATABASE_PATH: "./data/dev.db" # Base de données à sauvegarder
|
||||
BACKUP_STORAGE_PATH: "./data/backups" # Dossier des sauvegardes
|
||||
TZ: Europe/Paris
|
||||
volumes:
|
||||
- .:/app
|
||||
- /app/node_modules
|
||||
- .:/app # code en live
|
||||
- /app/node_modules # vol anonyme pour ne pas écraser ceux du conteneur
|
||||
- /app/.next
|
||||
- sqlite_data_dev:/app/data
|
||||
command: sh -c "npm install && npx prisma generate && npx prisma migrate deploy && npm run dev"
|
||||
- ./data:/app/data # Dossier local data/ vers /app/data
|
||||
command: >
|
||||
sh -c "npm install &&
|
||||
npx prisma generate &&
|
||||
npx prisma migrate deploy &&
|
||||
npm run dev"
|
||||
profiles:
|
||||
- dev
|
||||
|
||||
volumes:
|
||||
sqlite_data:
|
||||
driver: local
|
||||
sqlite_data_dev:
|
||||
driver: local
|
||||
|
||||
# 📁 Structure des données :
|
||||
# ./data/ -> /app/data (bind mount)
|
||||
# ├── prod.db -> Base de données production
|
||||
# ├── dev.db -> Base de données développement
|
||||
# └── backups/ -> Sauvegardes automatiques
|
||||
#
|
||||
# 🔧 Configuration via .env.docker
|
||||
# 📚 Documentation : ./data/README.md
|
||||
10
env.example
10
env.example
@@ -1,5 +1,13 @@
|
||||
# Base de données (requis)
|
||||
DATABASE_URL="file:./dev.db"
|
||||
DATABASE_URL="file:../data/dev.db"
|
||||
|
||||
# Chemin de la base de données pour les backups (optionnel)
|
||||
# Si non défini, utilise DATABASE_URL ou le chemin par défaut
|
||||
BACKUP_DATABASE_PATH="./data/dev.db"
|
||||
|
||||
# Dossier de stockage des sauvegardes (optionnel)
|
||||
# Par défaut: ./backups en local, ./data/backups en production
|
||||
BACKUP_STORAGE_PATH="./backups"
|
||||
|
||||
# Intégration Jira (optionnel)
|
||||
JIRA_BASE_URL="" # https://votre-domaine.atlassian.net
|
||||
|
||||
@@ -31,11 +31,23 @@ export class BackupService {
|
||||
enabled: true,
|
||||
interval: 'hourly',
|
||||
maxBackups: 5,
|
||||
backupPath: path.join(process.cwd(), 'backups'),
|
||||
backupPath: this.getDefaultBackupPath(),
|
||||
includeUploads: true,
|
||||
compression: true,
|
||||
};
|
||||
|
||||
private getDefaultBackupPath(): string {
|
||||
// 1. Variable d'environnement explicite
|
||||
if (process.env.BACKUP_STORAGE_PATH) {
|
||||
return path.resolve(process.cwd(), process.env.BACKUP_STORAGE_PATH);
|
||||
}
|
||||
|
||||
// 2. Chemin par défaut selon l'environnement
|
||||
return process.env.NODE_ENV === 'production'
|
||||
? path.join(process.cwd(), 'data', 'backups') // Docker: /app/data/backups
|
||||
: path.join(process.cwd(), 'backups'); // Local: ./backups
|
||||
}
|
||||
|
||||
private config: BackupConfig;
|
||||
|
||||
constructor(config?: Partial<BackupConfig>) {
|
||||
@@ -106,10 +118,7 @@ export class BackupService {
|
||||
// Créer le dossier de backup si nécessaire
|
||||
await this.ensureBackupDirectory();
|
||||
|
||||
// Vérifier l'état de la base de données
|
||||
await this.verifyDatabaseHealth();
|
||||
|
||||
// Créer la sauvegarde SQLite
|
||||
// Créer la sauvegarde SQLite (sans vérification de santé pour éviter les conflits)
|
||||
await this.createSQLiteBackup(backupPath);
|
||||
|
||||
// Compresser si activé
|
||||
@@ -156,7 +165,26 @@ export class BackupService {
|
||||
* Crée une sauvegarde SQLite en utilisant la commande .backup
|
||||
*/
|
||||
private async createSQLiteBackup(backupPath: string): Promise<void> {
|
||||
const dbPath = path.resolve(process.env.DATABASE_URL?.replace('file:', '') || './prisma/dev.db');
|
||||
// Résoudre le chemin de la base de données
|
||||
let dbPath: string;
|
||||
if (process.env.BACKUP_DATABASE_PATH) {
|
||||
// Utiliser la variable spécifique aux backups
|
||||
dbPath = path.resolve(process.cwd(), process.env.BACKUP_DATABASE_PATH);
|
||||
} else if (process.env.DATABASE_URL) {
|
||||
// Fallback sur DATABASE_URL si BACKUP_DATABASE_PATH n'est pas défini
|
||||
dbPath = path.resolve(process.env.DATABASE_URL.replace('file:', ''));
|
||||
} else {
|
||||
// Chemin par défaut vers prisma/dev.db
|
||||
dbPath = path.resolve(process.cwd(), 'prisma', 'dev.db');
|
||||
}
|
||||
|
||||
// Vérifier que le fichier source existe
|
||||
try {
|
||||
await fs.stat(dbPath);
|
||||
} catch (error) {
|
||||
console.error(`❌ Source database not found: ${dbPath}`, error);
|
||||
throw new Error(`Source database not found: ${dbPath}`);
|
||||
}
|
||||
|
||||
// Méthode 1: Utiliser sqlite3 CLI (plus fiable)
|
||||
try {
|
||||
@@ -199,7 +227,19 @@ export class BackupService {
|
||||
*/
|
||||
async restoreBackup(filename: string): Promise<void> {
|
||||
const backupPath = path.join(this.config.backupPath, filename);
|
||||
const dbPath = path.resolve(process.env.DATABASE_URL?.replace('file:', '') || './prisma/dev.db');
|
||||
|
||||
// Résoudre le chemin de la base de données
|
||||
let dbPath: string;
|
||||
if (process.env.BACKUP_DATABASE_PATH) {
|
||||
// Utiliser la variable spécifique aux backups
|
||||
dbPath = path.resolve(process.cwd(), process.env.BACKUP_DATABASE_PATH);
|
||||
} else if (process.env.DATABASE_URL) {
|
||||
// Fallback sur DATABASE_URL si BACKUP_DATABASE_PATH n'est pas défini
|
||||
dbPath = path.resolve(process.env.DATABASE_URL.replace('file:', ''));
|
||||
} else {
|
||||
// Chemin par défaut vers prisma/dev.db
|
||||
dbPath = path.resolve(process.cwd(), 'prisma', 'dev.db');
|
||||
}
|
||||
|
||||
console.log(`🔄 Restore paths - backup: ${backupPath}, target: ${dbPath}`);
|
||||
|
||||
|
||||
94
src/app/api/backups/[filename]/route.ts
Normal file
94
src/app/api/backups/[filename]/route.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { backupService } from '@/services/backup';
|
||||
|
||||
interface RouteParams {
|
||||
params: Promise<{
|
||||
filename: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export async function DELETE(
|
||||
request: NextRequest,
|
||||
{ params }: RouteParams
|
||||
) {
|
||||
try {
|
||||
const { filename } = await params;
|
||||
|
||||
// Vérification de sécurité - s'assurer que c'est bien un fichier de backup
|
||||
if (!filename.startsWith('towercontrol_') ||
|
||||
(!filename.endsWith('.db') && !filename.endsWith('.db.gz'))) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Invalid backup filename' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
await backupService.deleteBackup(filename);
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: `Backup ${filename} deleted successfully`
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error deleting backup:', error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to delete backup'
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(
|
||||
request: NextRequest,
|
||||
{ params }: RouteParams
|
||||
) {
|
||||
try {
|
||||
const { filename } = await params;
|
||||
const body = await request.json();
|
||||
const { action } = body;
|
||||
|
||||
if (action === 'restore') {
|
||||
// Vérification de sécurité
|
||||
if (!filename.startsWith('towercontrol_') ||
|
||||
(!filename.endsWith('.db') && !filename.endsWith('.db.gz'))) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Invalid backup filename' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Protection environnement de production
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Restore not allowed in production via API' },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
await backupService.restoreBackup(filename);
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: `Database restored from ${filename}`
|
||||
});
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Invalid action' },
|
||||
{ status: 400 }
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error in backup operation:', error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Operation failed'
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
103
src/app/api/backups/route.ts
Normal file
103
src/app/api/backups/route.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { backupService } from '@/services/backup';
|
||||
import { backupScheduler } from '@/services/backup-scheduler';
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
console.log('🔄 API GET /api/backups called');
|
||||
|
||||
// Test de la configuration d'abord
|
||||
const config = backupService.getConfig();
|
||||
console.log('✅ Config loaded:', config);
|
||||
|
||||
// Test du scheduler
|
||||
const schedulerStatus = backupScheduler.getStatus();
|
||||
console.log('✅ Scheduler status:', schedulerStatus);
|
||||
|
||||
// Test de la liste des backups
|
||||
const backups = await backupService.listBackups();
|
||||
console.log('✅ Backups loaded:', backups.length);
|
||||
|
||||
const response = {
|
||||
success: true,
|
||||
data: {
|
||||
backups,
|
||||
scheduler: schedulerStatus,
|
||||
config,
|
||||
}
|
||||
};
|
||||
|
||||
console.log('✅ API response ready');
|
||||
return NextResponse.json(response);
|
||||
} catch (error) {
|
||||
console.error('❌ Error fetching backups:', error);
|
||||
console.error('Error stack:', error instanceof Error ? error.stack : 'Unknown');
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to fetch backups',
|
||||
details: error instanceof Error ? error.stack : undefined
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { action, ...params } = body;
|
||||
|
||||
switch (action) {
|
||||
case 'create':
|
||||
const backup = await backupService.createBackup('manual');
|
||||
return NextResponse.json({ success: true, data: backup });
|
||||
|
||||
case 'verify':
|
||||
await backupService.verifyDatabaseHealth();
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Database health check passed'
|
||||
});
|
||||
|
||||
case 'config':
|
||||
await backupService.updateConfig(params.config);
|
||||
// Redémarrer le scheduler si la config a changé
|
||||
if (params.config.enabled !== undefined || params.config.interval !== undefined) {
|
||||
backupScheduler.restart();
|
||||
}
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Configuration updated',
|
||||
data: backupService.getConfig()
|
||||
});
|
||||
|
||||
case 'scheduler':
|
||||
if (params.enabled) {
|
||||
backupScheduler.start();
|
||||
} else {
|
||||
backupScheduler.stop();
|
||||
}
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: backupScheduler.getStatus()
|
||||
});
|
||||
|
||||
default:
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Invalid action' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error in backup operation:', error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user