Mejoras de sesion: estabilizacion, IA, Nexus Yonke y marketplace B2B
- F0 blindaje: Redis/Celery, pg_hba sin trust LAN, secretos a env 600, backups, webhook auth, jobs muertos - F1 caja: bugs POS, reembolsos al corte, apartados, CFDI, topes de descuento en cotizacion/apartado - F2/F7 IA de catalogo: autocategorizacion, dedup de SKUs con embeddings, OCR de facturas, descripciones, claves SAT, limpieza de fitment - F3 IA en el flujo: vision Yonke, preguntas MeLi, venta cruzada, anomalias, sinonimos, busqueda semantica (rerank/embeddings) - F4/F8 escala y cartera: /metrics+Prometheus+Grafana, pool, score de credito, churn, metricas multi-tenant - Nexus Yonke (M1-M6): modelo de datos 1-de-1, alta por donador, vitrina publica, MeLi usado, consignacion, garantia por dias, reportes, etiquetas - Marketplace B2B entre yonkes (catalogo + pedidos cross-tenant) - Seguridad: auth en /api/admin/* (35 endpoints), alertas por tenant - Migraciones v4.27/v4.28; timers expire-demos y rollup-metrics
This commit is contained in:
@@ -25,9 +25,10 @@ fatal() { err "$*"; exit 1; }
|
||||
|
||||
# ─── Configuration ─────────────────────────────────────────────────────────
|
||||
BACKUP_DIR="${BACKUP_DIR:-${PROJECT_DIR}/backups}"
|
||||
RETENTION_DAYS="${RETENTION_DAYS:-30}"
|
||||
RETENTION_DAYS="${RETENTION_DAYS:-21}"
|
||||
MASTER_DB="${MASTER_DB:-nexus_autoparts}"
|
||||
DB_USER="${DB_USER:-nexus}"
|
||||
AWS_CLI="${PROJECT_DIR}/tools/bin/aws"
|
||||
|
||||
# Load .env if exists
|
||||
if [[ -f "${PROJECT_DIR}/.env" ]]; then
|
||||
@@ -128,8 +129,15 @@ backup_master_data() {
|
||||
rm -f "$tables_file"
|
||||
}
|
||||
|
||||
# ─── Backup vehicle_parts schema only ──────────────────────────────────────
|
||||
# ─── Backup vehicle_parts schema only (if table exists) ────────────────────
|
||||
backup_vehicle_parts_schema() {
|
||||
local exists=$(sudo -u postgres psql "$MASTER_DB" -Atc \
|
||||
"SELECT 1 FROM pg_tables WHERE schemaname='public' AND tablename='vehicle_parts'" 2>/dev/null)
|
||||
if [[ "$exists" != "1" ]]; then
|
||||
info "vehicle_parts table does not exist — skipping (legacy step)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
info "Backing up vehicle_parts schema only (structure, no data)..."
|
||||
|
||||
local output="${BACKUP_PATH}/03_vehicle_parts_schema.sql"
|
||||
@@ -146,6 +154,34 @@ backup_vehicle_parts_schema() {
|
||||
}
|
||||
|
||||
# ─── Backup all tenant databases ───────────────────────────────────────────
|
||||
# ─── Backup WA CRM (Supabase self-hosted, docker) ─────────────────────────
|
||||
backup_wacrm() {
|
||||
local container="supabase-db"
|
||||
if ! docker ps --format '{{.Names}}' 2>/dev/null | grep -qx "$container"; then
|
||||
info "WA CRM (supabase-db) no está corriendo — se omite"
|
||||
return 0
|
||||
fi
|
||||
local output="${BACKUP_PATH}/wacrm_supabase.sql"
|
||||
info "Backing up WA CRM (Supabase postgres)..."
|
||||
if docker exec "$container" pg_dump -U postgres -d postgres --clean --if-exists > "$output" 2>/dev/null; then
|
||||
gzip -f "$output"
|
||||
ok "WA CRM: $(du -h "${output}.gz" | cut -f1)"
|
||||
else
|
||||
warn "WA CRM: pg_dump falló (se omite)"
|
||||
rm -f "$output"
|
||||
fi
|
||||
|
||||
# Volumen de storage (archivos multimedia de los chats) — solo si existe
|
||||
local media_tar="${BACKUP_PATH}/wacrm_storage.tar.gz"
|
||||
if docker volume inspect supabase_storage >/dev/null 2>&1; then
|
||||
if docker run --rm -v supabase_storage:/data:ro -v "${BACKUP_PATH}":/backup alpine \
|
||||
tar czf /backup/wacrm_storage.tar.gz -C /data . >/dev/null 2>&1; then
|
||||
ok "WA CRM storage: $(du -h "$media_tar" 2>/dev/null | cut -f1)"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
backup_tenants() {
|
||||
info "Discovering tenant databases..."
|
||||
|
||||
@@ -205,6 +241,8 @@ CONTENTS:
|
||||
02_master_data.sql.gz — Data for all tables EXCEPT vehicle_parts
|
||||
03_vehicle_parts_schema.sql — Structure of vehicle_parts only (no data)
|
||||
tenant_*.sql.gz — Full backup of each active tenant database
|
||||
wacrm_supabase.sql.gz — Base de datos de WA CRM (Supabase self-hosted)
|
||||
wacrm_storage.tar.gz — Archivos multimedia de los chats de WA CRM (si existe)
|
||||
|
||||
RESTORE INSTRUCTIONS:
|
||||
---------------------
|
||||
@@ -263,9 +301,12 @@ cleanup_old_backups() {
|
||||
local deleted=0
|
||||
while IFS= read -r file; do
|
||||
rm -f "$file"
|
||||
((deleted++))
|
||||
deleted=$((deleted + 1))
|
||||
done < <(find "$BACKUP_DIR" -name "nexus_backup_*.tar.gz" -mtime +$RETENTION_DAYS)
|
||||
|
||||
# Remove empty leftovers from failed runs
|
||||
find "$BACKUP_DIR" -maxdepth 1 -name "nexus_backup_*" -type f -empty -delete
|
||||
|
||||
if [[ "$deleted" -gt 0 ]]; then
|
||||
ok "Deleted ${deleted} old backup(s)"
|
||||
else
|
||||
@@ -273,6 +314,38 @@ cleanup_old_backups() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ─── Verify archive integrity ──────────────────────────────────────────────
|
||||
verify_archive() {
|
||||
local archive="${BACKUP_DIR}/${BACKUP_NAME}.tar.gz"
|
||||
info "Verifying archive integrity..."
|
||||
if ! gzip -t "$archive"; then
|
||||
fatal "Archive failed integrity check: ${archive}"
|
||||
fi
|
||||
if [[ $(stat -c%s "$archive") -lt 1000000 ]]; then
|
||||
fatal "Archive suspiciously small (<1MB): ${archive}"
|
||||
fi
|
||||
ok "Archive integrity verified"
|
||||
}
|
||||
|
||||
# ─── Upload offsite (optional, needs BACKUP_S3_BUCKET) ─────────────────────
|
||||
upload_offsite() {
|
||||
local archive="${BACKUP_DIR}/${BACKUP_NAME}.tar.gz"
|
||||
if [[ -z "${BACKUP_S3_BUCKET:-}" ]]; then
|
||||
info "BACKUP_S3_BUCKET not set. Skipping offsite upload (backups are local-only)."
|
||||
return 0
|
||||
fi
|
||||
if [[ ! -x "$AWS_CLI" ]]; then
|
||||
warn "AWS CLI not found at ${AWS_CLI}. Skipping offsite upload."
|
||||
return 0
|
||||
fi
|
||||
info "Uploading to s3://${BACKUP_S3_BUCKET}/nexus-backups/ ..."
|
||||
if "$AWS_CLI" s3 cp "$archive" "s3://${BACKUP_S3_BUCKET}/nexus-backups/" --storage-class STANDARD_IA; then
|
||||
ok "Offsite upload complete"
|
||||
else
|
||||
warn "Offsite upload failed (local backup is still valid)"
|
||||
fi
|
||||
}
|
||||
|
||||
# ─── Main ──────────────────────────────────────────────────────────────────
|
||||
main() {
|
||||
echo ""
|
||||
@@ -283,14 +356,20 @@ main() {
|
||||
echo -e "${NC}"
|
||||
echo ""
|
||||
|
||||
# Cleanup FIRST so a nearly-full disk cannot turn one failed backup
|
||||
# into permanent retention (the backup.sh vicious cycle).
|
||||
cleanup_old_backups
|
||||
|
||||
check_prerequisites
|
||||
backup_master_schema
|
||||
backup_master_data
|
||||
backup_vehicle_parts_schema
|
||||
backup_tenants
|
||||
backup_wacrm
|
||||
create_manifest
|
||||
create_archive
|
||||
cleanup_old_backups
|
||||
verify_archive
|
||||
upload_offsite
|
||||
|
||||
echo -e "${BOLD}${GREEN}"
|
||||
echo " Backup completed successfully!"
|
||||
|
||||
Reference in New Issue
Block a user