764 lines
20 KiB
Markdown
764 lines
20 KiB
Markdown
# RF-ADM-005: Backups Automáticos y Disaster Recovery
|
|
|
|
**ID:** RF-ADM-005
|
|
**Módulo:** MAI-013 - Administración & Seguridad
|
|
**Tipo:** Requerimiento Funcional
|
|
**Prioridad:** P0 (Crítica)
|
|
**Fecha de creación:** 2025-11-20
|
|
**Versión:** 1.0
|
|
|
|
---
|
|
|
|
## 📋 Descripción
|
|
|
|
El sistema debe proporcionar **backups automáticos** y un plan de **Disaster Recovery (DR)** que garantice:
|
|
|
|
- **Backups automáticos** programados sin intervención manual
|
|
- **Estrategia 3-2-1:** 3 copias, 2 medios diferentes, 1 copia offsite
|
|
- **Restauración rápida:** RTO < 4 horas, RPO < 1 hora
|
|
- **Verificación de integridad:** Checksums MD5/SHA-256
|
|
- **Pruebas mensuales** de restauración
|
|
- **Alertas** de backups fallidos
|
|
|
|
La estrategia de backups es fundamental para garantizar **continuidad del negocio** ante desastres (fallas de hardware, ataques ransomware, errores humanos).
|
|
|
|
---
|
|
|
|
## 🎯 Objetivos
|
|
|
|
### Objetivos de Negocio
|
|
|
|
1. **Protección de datos:** Cero pérdida de datos críticos
|
|
2. **Continuidad del negocio:** Recuperación rápida ante desastres
|
|
3. **Cumplimiento normativo:** ISO 27001, SOC 2, GDPR
|
|
4. **Confianza del cliente:** Datos siempre disponibles y seguros
|
|
5. **Reducción de riesgos:** Mitigación de ransomware, fallas, errores
|
|
|
|
### Objetivos Técnicos
|
|
|
|
1. **RTO (Recovery Time Objective):** < 4 horas
|
|
2. **RPO (Recovery Point Objective):** < 1 hora
|
|
3. **Automatización:** 100% de backups sin intervención manual
|
|
4. **Retención:** Según criticidad (7 días, 30 días, 1 año)
|
|
5. **Performance:** Backups no afectan operación del sistema
|
|
|
|
---
|
|
|
|
## 📊 Estrategia 3-2-1 de Backups
|
|
|
|
### Regla 3-2-1
|
|
|
|
**3 copias** de los datos:
|
|
- 1 copia en producción (activa)
|
|
- 2 copias de respaldo (backups)
|
|
|
|
**2 medios diferentes:**
|
|
- Local: NAS/SAN en oficina
|
|
- Cloud: AWS S3 / Azure Blob Storage
|
|
|
|
**1 copia offsite:**
|
|
- Geográficamente separada (otra ciudad/país)
|
|
- Protección contra desastres físicos (incendio, inundación)
|
|
|
|
### Implementación
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ ESTRATEGIA 3-2-1 │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ COPIA 1: Producción (Activa) │
|
|
│ └─> Servidor DB Principal (PostgreSQL) │
|
|
│ Ubicación: Culiacán, Sinaloa │
|
|
│ │
|
|
│ COPIA 2: Backup Local (Medio 1) │
|
|
│ └─> NAS/SAN en oficina │
|
|
│ Ubicación: Culiacán, Sinaloa │
|
|
│ Retención: 7 días │
|
|
│ │
|
|
│ COPIA 3: Backup Cloud (Medio 2 + Offsite) │
|
|
│ └─> AWS S3 / Azure Blob │
|
|
│ Ubicación: us-west-2 (Oregon, USA) │
|
|
│ Retención: 30 días (rolling) │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 🗂️ Tipos de Backup
|
|
|
|
### 1. Full Backup (Completo)
|
|
|
|
**Frecuencia:** Diario (3:00 AM)
|
|
**Duración:** 2-4 horas (según tamaño)
|
|
**Retención:** 7 días
|
|
|
|
**Contenido:**
|
|
- Base de datos completa (PostgreSQL dump)
|
|
- Archivos subidos (documentos, evidencias, planos)
|
|
- Configuraciones del sistema
|
|
- Variables de entorno (secrets)
|
|
- Logs de aplicación (últimos 7 días)
|
|
|
|
**Comando (PostgreSQL):**
|
|
```bash
|
|
pg_dump -h localhost -U postgres -F c \
|
|
-f /backups/full/backup-$(date +%Y-%m-%d).dump \
|
|
erp_construccion
|
|
```
|
|
|
|
**Tamaño estimado:**
|
|
- DB pequeña (< 1 año): 5-10 GB
|
|
- DB mediana (1-3 años): 20-50 GB
|
|
- DB grande (> 3 años): 100-200 GB
|
|
|
|
**Ventajas:**
|
|
- ✅ Restauración más rápida (un solo archivo)
|
|
- ✅ Autónomo (no depende de backups anteriores)
|
|
|
|
**Desventajas:**
|
|
- ❌ Consume más espacio
|
|
- ❌ Más lento que incremental
|
|
|
|
---
|
|
|
|
### 2. Incremental Backup
|
|
|
|
**Frecuencia:** Cada 6 horas (00:00, 06:00, 12:00, 18:00)
|
|
**Duración:** 15-30 minutos
|
|
**Retención:** 48 horas
|
|
|
|
**Contenido:**
|
|
- Solo cambios desde el último backup (full o incremental)
|
|
- Archivos modificados/creados en últimas 6 horas
|
|
- Logs de aplicación nuevos
|
|
|
|
**Herramienta:** `rsync` o `pg_basebackup` con WAL archiving
|
|
|
|
**Comando (rsync):**
|
|
```bash
|
|
rsync -av --delete --link-dest=/backups/previous \
|
|
/var/lib/postgresql/data \
|
|
/backups/incremental/backup-$(date +%Y-%m-%d_%H-%M)
|
|
```
|
|
|
|
**Ventajas:**
|
|
- ✅ Rápido (solo cambios)
|
|
- ✅ Consume menos espacio
|
|
|
|
**Desventajas:**
|
|
- ❌ Restauración más lenta (requiere full + todos los incrementales)
|
|
|
|
---
|
|
|
|
### 3. Backup de Archivos Críticos
|
|
|
|
**Frecuencia:** Cada hora (top of the hour)
|
|
**Duración:** 5-10 minutos
|
|
**Retención:** 24 horas
|
|
|
|
**Contenido:**
|
|
- Documentos subidos (contratos, minutas)
|
|
- Evidencias fotográficas de obra
|
|
- Planos y documentación técnica
|
|
- Archivos CFDI (facturas electrónicas)
|
|
|
|
**Ubicaciones:**
|
|
```
|
|
/storage/documents/
|
|
/storage/photos/
|
|
/storage/plans/
|
|
/storage/invoices/
|
|
```
|
|
|
|
**Método:**
|
|
- Sincronización en tiempo real a AWS S3
|
|
- Versionado activado (conservar versiones anteriores)
|
|
|
|
**Ventajas:**
|
|
- ✅ RPO < 1 hora (baja pérdida de datos)
|
|
- ✅ Archivos versionados (recuperar versiones antiguas)
|
|
|
|
---
|
|
|
|
### 4. Snapshots de Base de Datos (PITR)
|
|
|
|
**Frecuencia:** Cada 30 minutos
|
|
**Duración:** Instantáneo
|
|
**Retención:** 6 horas
|
|
|
|
**Contenido:**
|
|
- Snapshot del filesystem de PostgreSQL
|
|
- WAL (Write-Ahead Logging) archiving
|
|
- Permite Point-In-Time Recovery
|
|
|
|
**Configuración PostgreSQL:**
|
|
```ini
|
|
# postgresql.conf
|
|
wal_level = replica
|
|
archive_mode = on
|
|
archive_command = 'rsync %p /backups/wal/%f'
|
|
```
|
|
|
|
**Ventajas:**
|
|
- ✅ RPO mínimo (< 1 hora)
|
|
- ✅ Recuperación a cualquier punto en el tiempo
|
|
|
|
**Desventajas:**
|
|
- ❌ Requiere configuración avanzada
|
|
|
|
---
|
|
|
|
## 📅 Calendario de Backups
|
|
|
|
### Calendario Semanal
|
|
|
|
```
|
|
┌──────────┬────────┬────────────┬──────────┬──────────┐
|
|
│ Hora │ Lun-Dom│ Tipo │ Ubicación│ Retención│
|
|
├──────────┼────────┼────────────┼──────────┼──────────┤
|
|
│ 03:00 AM │ Diario │ Full │ Local+S3 │ 7 días │
|
|
│ 00:00 │ Diario │ Incremental│ Local │ 48 hrs │
|
|
│ 06:00 │ Diario │ Incremental│ Local │ 48 hrs │
|
|
│ 12:00 │ Diario │ Incremental│ Local │ 48 hrs │
|
|
│ 18:00 │ Diario │ Incremental│ Local │ 48 hrs │
|
|
│ Hourly │ Diario │ Archivos │ S3 │ 24 hrs │
|
|
│ :00/:30 │ Diario │ Snapshot │ Local │ 6 hrs │
|
|
└──────────┴────────┴────────────┴──────────┴──────────┘
|
|
```
|
|
|
|
### Calendario Mensual
|
|
|
|
**Primer domingo de cada mes:**
|
|
- Backup full completo con retención de **1 año**
|
|
- Prueba de restauración completa
|
|
- Reporte de integridad de backups
|
|
|
|
**Ejemplo:**
|
|
- Backup del 2025-12-01 se conserva hasta 2026-12-01
|
|
- Total: 12 backups mensuales por año
|
|
|
|
---
|
|
|
|
## 🔄 Proceso de Restauración
|
|
|
|
### Escenarios de Recuperación
|
|
|
|
#### Escenario 1: Recuperación de Archivo Individual
|
|
|
|
**Caso:** Usuario borró por error un contrato PDF
|
|
|
|
**RTO:** 15 minutos
|
|
**RPO:** < 1 hora
|
|
|
|
**Procedimiento:**
|
|
1. Usuario reporta: "Borré contrato-123.pdf por error"
|
|
2. Admin accede a AWS S3 console
|
|
3. Busca archivo en versiones anteriores
|
|
4. Descarga versión más reciente
|
|
5. Sube archivo nuevamente al sistema
|
|
6. Valida con usuario
|
|
|
|
**Herramienta:** AWS S3 Versioning
|
|
|
|
---
|
|
|
|
#### Escenario 2: Recuperación de Base de Datos a Punto Específico
|
|
|
|
**Caso:** Error en script SQL borró 500 registros a las 14:30
|
|
|
|
**RTO:** 1-2 horas
|
|
**RPO:** < 30 minutos
|
|
|
|
**Procedimiento:**
|
|
1. Identificar timestamp exacto del error: 2025-11-20 14:30
|
|
2. Detener aplicación (modo mantenimiento)
|
|
3. Crear backup de estado actual (por si acaso)
|
|
4. Restaurar base de datos a 2025-11-20 14:25 (5 min antes):
|
|
```bash
|
|
pg_restore -h localhost -U postgres \
|
|
--clean --if-exists \
|
|
/backups/full/backup-2025-11-20.dump
|
|
```
|
|
5. Aplicar WAL logs hasta 14:25:
|
|
```bash
|
|
pg_wal_replay --target-time='2025-11-20 14:25:00'
|
|
```
|
|
6. Verificar integridad de datos
|
|
7. Reiniciar aplicación
|
|
8. Validar con usuarios clave
|
|
|
|
**Resultado:** Recuperados 500 registros, pérdida de datos: 5 minutos.
|
|
|
|
---
|
|
|
|
#### Escenario 3: Disaster Recovery (Servidor Completo)
|
|
|
|
**Caso:** Servidor físico destruido por incendio
|
|
|
|
**RTO:** 4-8 horas
|
|
**RPO:** < 1 hora
|
|
|
|
**Procedimiento:**
|
|
|
|
**Fase 1: Provisionamiento (2 horas)**
|
|
1. Provisionar nueva infraestructura:
|
|
- Servidor cloud (AWS EC2 / Azure VM)
|
|
- Disco de 500 GB SSD
|
|
- Configuración de red (VPC, Security Groups)
|
|
2. Instalar sistema operativo (Ubuntu 22.04 LTS)
|
|
3. Instalar PostgreSQL 15
|
|
4. Instalar Node.js 20, npm, pm2
|
|
|
|
**Fase 2: Restauración de Datos (2 horas)**
|
|
5. Descargar último full backup desde AWS S3:
|
|
```bash
|
|
aws s3 cp s3://backups-empresa/backup-2025-11-20.dump .
|
|
```
|
|
6. Restaurar base de datos:
|
|
```bash
|
|
pg_restore -h localhost -U postgres \
|
|
--clean --create \
|
|
backup-2025-11-20.dump
|
|
```
|
|
7. Sincronizar archivos desde S3:
|
|
```bash
|
|
aws s3 sync s3://storage-empresa/documents /storage/documents
|
|
aws s3 sync s3://storage-empresa/photos /storage/photos
|
|
```
|
|
8. Restaurar configuraciones:
|
|
```bash
|
|
aws s3 cp s3://backups-empresa/configs/env .env
|
|
```
|
|
|
|
**Fase 3: Validación y Reinicio (1 hora)**
|
|
9. Validar integridad de datos:
|
|
```sql
|
|
SELECT COUNT(*) FROM projects; -- Debe coincidir con último reporte
|
|
SELECT COUNT(*) FROM users;
|
|
```
|
|
10. Ejecutar smoke tests:
|
|
- Login funciona
|
|
- Proyectos se listan correctamente
|
|
- Crear registro de prueba
|
|
11. Reconfigurar DNS:
|
|
```
|
|
app.ejemplo.com → Nueva IP: 54.123.45.67
|
|
```
|
|
12. Reiniciar aplicación:
|
|
```bash
|
|
pm2 start ecosystem.config.js
|
|
pm2 logs --lines 100
|
|
```
|
|
13. Notificar a usuarios: "Sistema restaurado, funcionando normalmente"
|
|
|
|
**Fase 4: Post-Mortem (1 hora)**
|
|
14. Reunión de equipo para analizar incidente
|
|
15. Documentar lecciones aprendidas
|
|
16. Actualizar plan de DR si es necesario
|
|
|
|
**Resultado:** Sistema en línea en 4-8 horas, pérdida de datos < 1 hora.
|
|
|
|
---
|
|
|
|
## 🔒 Seguridad de Backups
|
|
|
|
### Encriptación
|
|
|
|
**En tránsito (upload a S3):**
|
|
```bash
|
|
aws s3 cp backup.dump s3://backups/ \
|
|
--sse AES256 \
|
|
--storage-class STANDARD_IA
|
|
```
|
|
|
|
**En reposo (S3):**
|
|
- Server-Side Encryption (SSE-S3 o SSE-KMS)
|
|
- Archivos cifrados con AES-256
|
|
|
|
**Backups locales:**
|
|
```bash
|
|
# Cifrar backup antes de almacenar
|
|
gpg --symmetric --cipher-algo AES256 backup.dump
|
|
```
|
|
|
|
### Control de Acceso
|
|
|
|
**AWS S3 Bucket Policy:**
|
|
```json
|
|
{
|
|
"Version": "2012-10-17",
|
|
"Statement": [
|
|
{
|
|
"Effect": "Deny",
|
|
"Principal": "*",
|
|
"Action": "s3:DeleteObject",
|
|
"Resource": "arn:aws:s3:::backups-empresa/*"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Resultado:** Backups no se pueden eliminar, solo agregar nuevos.
|
|
|
|
**Acceso:**
|
|
- Solo Admin de TI tiene credenciales de S3
|
|
- MFA requerido para acceder a S3 console
|
|
- Logs de acceso activados (CloudTrail)
|
|
|
|
---
|
|
|
|
## ✅ Verificación de Integridad
|
|
|
|
### Checksums MD5/SHA-256
|
|
|
|
**Al crear backup:**
|
|
```bash
|
|
# Crear backup
|
|
pg_dump -F c -f backup.dump erp_construccion
|
|
|
|
# Calcular checksum
|
|
sha256sum backup.dump > backup.dump.sha256
|
|
```
|
|
|
|
**Al restaurar:**
|
|
```bash
|
|
# Verificar checksum antes de restaurar
|
|
sha256sum -c backup.dump.sha256
|
|
|
|
# Si OK, proceder con restauración
|
|
```
|
|
|
|
### Validación de Contenido
|
|
|
|
**Tests automáticos post-backup:**
|
|
```bash
|
|
#!/bin/bash
|
|
# validate-backup.sh
|
|
|
|
# Restaurar en DB temporal
|
|
createdb backup_test
|
|
pg_restore -d backup_test backup.dump
|
|
|
|
# Ejecutar queries de validación
|
|
psql -d backup_test -c "SELECT COUNT(*) FROM users;" > users_count.txt
|
|
psql -d backup_test -c "SELECT COUNT(*) FROM projects;" > projects_count.txt
|
|
|
|
# Comparar con producción
|
|
diff users_count.txt /backups/validation/users_count_prod.txt
|
|
|
|
# Si diff vacío, backup OK
|
|
if [ $? -eq 0 ]; then
|
|
echo "✅ Backup válido"
|
|
else
|
|
echo "❌ Backup corrupto, enviar alerta"
|
|
fi
|
|
|
|
# Limpiar
|
|
dropdb backup_test
|
|
```
|
|
|
|
---
|
|
|
|
## 📋 Modelo de Datos de Backup
|
|
|
|
```typescript
|
|
interface BackupRecord {
|
|
// Identificación
|
|
id: string; // UUID
|
|
timestamp: Date;
|
|
backupType: BackupType; // full | incremental | files | snapshot
|
|
|
|
// Ubicación
|
|
storagePath: string; // "/backups/full/backup-2025-11-20.dump"
|
|
s3Url?: string; // "s3://backups-empresa/backup-2025-11-20.dump"
|
|
storageTier: 'local' | 's3_standard' | 's3_glacier';
|
|
|
|
// Tamaño y compresión
|
|
sizeBytes: number;
|
|
sizeCompressed?: number;
|
|
compressionRatio?: number; // %
|
|
|
|
// Integridad
|
|
checksum: string; // SHA-256
|
|
checksumAlgorithm: 'md5' | 'sha256';
|
|
isVerified: boolean;
|
|
verifiedAt?: Date;
|
|
|
|
// Metadata
|
|
databaseVersion: string; // "PostgreSQL 15.3"
|
|
schemaVersion: string; // "v2.5.0"
|
|
recordCount?: {
|
|
users: number;
|
|
projects: number;
|
|
budgets: number;
|
|
// ...
|
|
};
|
|
|
|
// Estado
|
|
status: BackupStatus; // pending | in_progress | completed | failed | verified
|
|
startedAt: Date;
|
|
completedAt?: Date;
|
|
duration?: number; // Segundos
|
|
|
|
// Retención
|
|
retentionDays: number; // 7, 30, 365
|
|
expiresAt: Date;
|
|
isDeleted: boolean;
|
|
|
|
// Errores
|
|
errorMessage?: string;
|
|
errorDetails?: string;
|
|
|
|
// Restauración
|
|
lastRestoreTest?: Date;
|
|
restoreTestSuccess?: boolean;
|
|
}
|
|
|
|
enum BackupType {
|
|
FULL = 'full',
|
|
INCREMENTAL = 'incremental',
|
|
FILES = 'files',
|
|
SNAPSHOT = 'snapshot'
|
|
}
|
|
|
|
enum BackupStatus {
|
|
PENDING = 'pending',
|
|
IN_PROGRESS = 'in_progress',
|
|
COMPLETED = 'completed',
|
|
FAILED = 'failed',
|
|
VERIFIED = 'verified'
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🚨 Alertas de Backups
|
|
|
|
### Configuración de Alertas
|
|
|
|
| Condición | Severidad | Destinatarios | Canal |
|
|
|-----------|-----------|---------------|-------|
|
|
| **Backup fallido** | Critical | Admin TI + Director | Email + SMS |
|
|
| **Backup > 2 horas** | High | Admin TI | Email |
|
|
| **Checksum inválido** | Critical | Admin TI | Email + SMS |
|
|
| **Disco > 80% lleno** | High | Admin TI | Email |
|
|
| **Prueba restauración fallida** | Critical | Admin TI + Director | Email + SMS |
|
|
| **Backup no ejecutado** | Critical | Admin TI | Email + SMS |
|
|
|
|
### Ejemplo de Alerta
|
|
|
|
**Asunto:** 🚨 CRÍTICO: Backup Full Fallido
|
|
|
|
```
|
|
Estimado Administrador,
|
|
|
|
El backup full programado para hoy falló:
|
|
|
|
Tipo: Full Backup
|
|
Fecha/Hora: 2025-11-20 03:00 AM
|
|
Duración: 35 minutos (abortado)
|
|
Error: "Disk quota exceeded"
|
|
|
|
Detalles del error:
|
|
- Disco /backups al 98% de capacidad
|
|
- Backup abortado tras escribir 45 GB de 50 GB
|
|
|
|
Acciones recomendadas:
|
|
1. Liberar espacio en disco /backups
|
|
2. Ejecutar backup manualmente
|
|
3. Verificar integridad del último backup exitoso (2025-11-19)
|
|
|
|
Último backup exitoso: 2025-11-19 03:00 AM (24 horas atrás)
|
|
|
|
⚠️ Acción inmediata requerida
|
|
|
|
---
|
|
Sistema de Backups Automáticos
|
|
Constructora ABC
|
|
```
|
|
|
|
---
|
|
|
|
## 📋 Casos de Uso
|
|
|
|
### Caso 1: Prueba Mensual de Restauración
|
|
|
|
**Actor:** Admin de TI (automatizado)
|
|
|
|
**Flujo:**
|
|
1. Primer domingo del mes a las 02:00 AM
|
|
2. Cron job ejecuta script: `monthly-restore-test.sh`
|
|
3. Script:
|
|
- Descarga último full backup desde S3
|
|
- Verifica checksum
|
|
- Crea base de datos temporal `erp_restore_test`
|
|
- Restaura backup completo
|
|
- Ejecuta 20 queries de validación
|
|
- Compara resultados con producción
|
|
- Genera reporte HTML
|
|
4. Si exitoso:
|
|
- Marca backup como `verified`
|
|
- Envía reporte a Admin TI y Director
|
|
5. Si falla:
|
|
- Alerta crítica por email + SMS
|
|
- Reporte de error detallado
|
|
|
|
**Resultado:** Confianza mensual de que backups funcionan.
|
|
|
|
---
|
|
|
|
### Caso 2: Ataque Ransomware
|
|
|
|
**Contexto:** Ransomware cifra toda la base de datos de producción
|
|
|
|
**Flujo:**
|
|
1. 08:30 AM - Usuarios reportan: "Sistema no funciona, pide pago de $50K BTC"
|
|
2. Admin identifica ransomware
|
|
3. **Decisión: No pagar, restaurar desde backup**
|
|
4. Admin:
|
|
- Aísla servidor infectado (desconecta red)
|
|
- Provisiona nuevo servidor limpio
|
|
- Descarga último backup (ayer 03:00 AM)
|
|
- Restaura base de datos
|
|
- Restaura archivos desde S3
|
|
5. 12:00 PM - Sistema en línea
|
|
6. Pérdida de datos: 5.5 horas (desde 03:00 AM backup hasta 08:30 AM ataque)
|
|
7. Post-mortem:
|
|
- Identificar vector de ataque
|
|
- Actualizar firewall rules
|
|
- Capacitar usuarios en phishing
|
|
|
|
**Resultado:** Ataque mitigado sin pagar rescate, pérdida < 6 horas.
|
|
|
|
---
|
|
|
|
## ✅ Criterios de Aceptación
|
|
|
|
### AC1: Backups Automáticos sin Falla
|
|
|
|
**DADO** el sistema configurado correctamente
|
|
**CUANDO** se ejecuta cron job de backup full a las 03:00 AM
|
|
**ENTONCES**
|
|
- ✅ Backup se ejecuta automáticamente (sin intervención)
|
|
- ✅ Backup se completa exitosamente en < 4 horas
|
|
- ✅ Archivo generado con checksum SHA-256
|
|
- ✅ Backup subido a S3 con encriptación
|
|
- ✅ Backup local guardado en NAS
|
|
- ✅ Registro creado en tabla `backup_records`
|
|
- ✅ Si falla, alerta enviada inmediatamente
|
|
|
|
### AC2: Estrategia 3-2-1 Implementada
|
|
|
|
**DADO** un backup full exitoso
|
|
**CUANDO** se valida la estrategia
|
|
**ENTONCES**
|
|
- ✅ 3 copias existen:
|
|
- Producción (activa)
|
|
- Backup local (NAS)
|
|
- Backup cloud (S3)
|
|
- ✅ 2 medios diferentes:
|
|
- Local (NAS)
|
|
- Cloud (S3)
|
|
- ✅ 1 copia offsite:
|
|
- S3 en región diferente (us-west-2)
|
|
|
|
### AC3: Restauración < RTO
|
|
|
|
**DADO** un desastre que requiere restauración completa
|
|
**CUANDO** se ejecuta plan de DR
|
|
**ENTONCES**
|
|
- ✅ Sistema completamente restaurado en < 4 horas (RTO)
|
|
- ✅ Pérdida de datos < 1 hora (RPO)
|
|
- ✅ Integridad de datos validada (checksums OK)
|
|
- ✅ Aplicación funcional y accesible
|
|
|
|
### AC4: Pruebas Mensuales Exitosas
|
|
|
|
**DADO** el primer domingo del mes
|
|
**CUANDO** se ejecuta prueba de restauración
|
|
**ENTONCES**
|
|
- ✅ Backup se restaura en DB temporal exitosamente
|
|
- ✅ Queries de validación retornan resultados esperados
|
|
- ✅ Reporte HTML generado automáticamente
|
|
- ✅ Email enviado a Admin y Director
|
|
- ✅ Si falla, alerta crítica enviada
|
|
|
|
### AC5: Retención Automática
|
|
|
|
**DADO** backups con diferentes retenciones
|
|
**CUANDO** pasa el periodo de retención
|
|
**ENTONCES**
|
|
- ✅ Backups diarios eliminados tras 7 días
|
|
- ✅ Backups incrementales eliminados tras 48 horas
|
|
- ✅ Backups mensuales conservados 1 año
|
|
- ✅ Proceso de limpieza ejecuta automáticamente
|
|
|
|
---
|
|
|
|
## 🧪 Escenarios de Prueba
|
|
|
|
### Test 1: Backup Full Exitoso
|
|
|
|
```typescript
|
|
describe('RF-ADM-005: Full Backup', () => {
|
|
it('should create full backup successfully', async () => {
|
|
const backupService = new BackupService();
|
|
|
|
const result = await backupService.createFullBackup();
|
|
|
|
expect(result.status).toBe('completed');
|
|
expect(result.sizeBytes).toBeGreaterThan(0);
|
|
expect(result.checksum).toBeDefined();
|
|
expect(result.isVerified).toBe(true);
|
|
expect(result.s3Url).toContain('s3://backups-empresa');
|
|
|
|
// Verificar archivo existe
|
|
const fileExists = await fs.pathExists(result.storagePath);
|
|
expect(fileExists).toBe(true);
|
|
});
|
|
});
|
|
```
|
|
|
|
### Test 2: Restauración Point-in-Time
|
|
|
|
```typescript
|
|
describe('RF-ADM-005: Point-in-Time Recovery', () => {
|
|
it('should restore database to specific timestamp', async () => {
|
|
// Crear datos iniciales
|
|
await createProject({ name: 'Proyecto 1' });
|
|
|
|
const snapshot1 = new Date();
|
|
await sleep(1000);
|
|
|
|
// Crear más datos
|
|
await createProject({ name: 'Proyecto 2' });
|
|
|
|
// Restaurar a snapshot1 (antes de Proyecto 2)
|
|
await restoreToPointInTime(snapshot1);
|
|
|
|
// Validar
|
|
const projects = await db.query('SELECT * FROM projects');
|
|
expect(projects.rows).toHaveLength(1);
|
|
expect(projects.rows[0].name).toBe('Proyecto 1');
|
|
});
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 🔗 Referencias
|
|
|
|
- **Especificación técnica:** [ET-ADM-004](../especificaciones/ET-ADM-004-backups-dr.md)
|
|
- **Historia de usuario:** [US-ADM-005](../historias-usuario/US-ADM-005-backups-automaticos.md), [US-ADM-006](../historias-usuario/US-ADM-006-restaurar-backup.md)
|
|
- **RF relacionado:** [RF-ADM-004](./RF-ADM-004-auditoria.md)
|
|
- **Módulo:** [README.md](../README.md)
|
|
|
|
---
|
|
|
|
**Generado:** 2025-11-20
|
|
**Versión:** 1.0
|
|
**Autor:** Sistema de Documentación Técnica
|
|
**Estado:** ✅ Completo
|