#!/usr/bin/env bash # ============================================================================== # Sovereign Map Platform - Full Autonomous Restoration System # منصة الخرائط السيادية - نظام الاستعادة الشامل وإعادة التشغيل على سيرفر جديد # ============================================================================== # Architect: Hamza Ayed - Founding Tech Architect & Sovereign Mobility Strategist # ============================================================================== set -euo pipefail # ANSI Color Codes GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[1;33m' RED='\033[0;31m' CYAN='\033[0;36m' NC='\033[0m' ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" echo -e "${CYAN}==================================================================${NC}" echo -e "${CYAN} 🛡️ منصة خرائط سيرو السيادية | معالج استعادة النظام والسيرفر${NC}" echo -e "${CYAN}==================================================================${NC}" if [ $# -lt 1 ]; then echo -e "${RED}❌ خطأ: يرجى تحديد مسار ملف النسخة الاحتياطية (.tar.gz) أو مجلد النسخة.${NC}" echo -e "الاستخدام: $0 " echo -e "مثال: $0 /home/hamzadoctor/backups/sovereign_map_full_backup_20260926_120000.tar.gz" exit 1 fi INPUT_PATH="$1" TEMP_RESTORE_DIR="" # Determine whether input is a tarball or a directory if [ -f "$INPUT_PATH" ] && [[ "$INPUT_PATH" == *.tar.gz ]]; then echo -e "📦 تم التعرف على ملف أرشيف مضغوط: ${YELLOW}$INPUT_PATH${NC}" TEMP_RESTORE_DIR=$(mktemp -d /tmp/sovereign_restore_XXXXXX) echo -e "⏳ جاري فك ضغط الأرشيف إلى: ${CYAN}$TEMP_RESTORE_DIR${NC}..." tar -xzf "$INPUT_PATH" -C "$TEMP_RESTORE_DIR" # Find the unpacked inner folder RESTORE_SRC=$(find "$TEMP_RESTORE_DIR" -maxdepth 1 -mindepth 1 -type d | head -n 1) if [ -z "$RESTORE_SRC" ]; then RESTORE_SRC="$TEMP_RESTORE_DIR" fi elif [ -d "$INPUT_PATH" ]; then echo -e "📁 تم التعرف على مجلد نسخة احتياطية: ${YELLOW}$INPUT_PATH${NC}" RESTORE_SRC="$INPUT_PATH" else echo -e "${RED}❌ المسار المحدد غير صالح: $INPUT_PATH${NC}" exit 1 fi echo -e "🔍 فحص مكونات النسخة الاحتياطية في: ${GREEN}$RESTORE_SRC${NC}" # Check for database dump DUMP_FILE="$RESTORE_SRC/database/mapdb_custom.dump" SQL_FILE="$RESTORE_SRC/database/mapdb_schema.sql" if [ ! -f "$DUMP_FILE" ] && [ ! -f "$SQL_FILE" ]; then echo -e "${RED}❌ لم يتم العثور على ملفات قاعدة البيانات (mapdb_custom.dump أو mapdb_schema.sql)${NC}" exit 1 fi # Step 1: Ensure Docker is active echo -e "\n${BLUE}[1/6] 🐳 فحص بيئة Docker و Docker Compose...${NC}" if ! command -v docker &> /dev/null; then echo -e "${RED}❌ Docker غير مثبت على هذا السيرفر! يرجى تثبيته أولاً.${NC}" exit 1 fi DOCKER_COMPOSE_CMD="" if docker compose version &> /dev/null; then DOCKER_COMPOSE_CMD="docker compose" elif command -v docker-compose &> /dev/null; then DOCKER_COMPOSE_CMD="docker-compose" else echo -e "${RED}❌ docker compose غير متاح!${NC}" exit 1 fi echo -e " ✅ محرك الحاويات جاهز: ${GREEN}$($DOCKER_COMPOSE_CMD version --short)${NC}" # Step 2: Check & prepare .env file echo -e "\n${BLUE}[2/6] ⚙️ تهيئة متغيرات البيئة (.env)...${NC}" cd "$ROOT_DIR" if [ ! -f "$ROOT_DIR/.env" ] && [ -f "$RESTORE_SRC/configs/.env.backup" ]; then echo -e " 📥 استعادة ملف .env من النسخة الاحتياطية..." cp "$RESTORE_SRC/configs/.env.backup" "$ROOT_DIR/.env" elif [ -f "$ROOT_DIR/.env" ]; then echo -e " ✅ ملف .env موجود مسبقاً في مسار المشروع." else echo -e " ${YELLOW}⚠️ لم يوجد .env! يرجى إنشاء ملف .env بالاعتماد على .env.example${NC}" fi # Step 3: Restore offline MBTiles & OSM packages echo -e "\n${BLUE}[3/6] 🗺️ استعادة المربعات السيادية وحزم التوجيه (Offline Datasets)...${NC}" if [ -d "$RESTORE_SRC/geodata/mbtiles" ]; then mkdir -p "$ROOT_DIR/data/mbtiles" echo -e " 📥 استعادة ملفات الارتفاع والأقمار الصناعية (MBTiles)..." cp -rf "$RESTORE_SRC/geodata/mbtiles/"* "$ROOT_DIR/data/mbtiles/" 2>/dev/null || true fi if [ -f "$RESTORE_SRC/geodata/jordan-latest.osm.pbf" ]; then mkdir -p "$ROOT_DIR/infrastructure/osm-data" echo -e " 📥 استعادة ملف خريطة الأردن الخام (OSM PBF)..." cp -f "$RESTORE_SRC/geodata/jordan-latest.osm.pbf" "$ROOT_DIR/infrastructure/osm-data/" fi if [ -d "$RESTORE_SRC/geodata/routing-packages" ]; then mkdir -p "$ROOT_DIR/infrastructure/osm-data/routing-packages" echo -e " 📥 استعادة حزم التوجيه المحلية (Valhalla routing)..." cp -rf "$RESTORE_SRC/geodata/routing-packages/"* "$ROOT_DIR/infrastructure/osm-data/routing-packages/" 2>/dev/null || true fi # Step 4: Boot Database & Redis Containers echo -e "\n${BLUE}[4/6] 🐘 تشغيل حاويات الداتابيز والكاش والتأكد من جاهزيتها...${NC}" $DOCKER_COMPOSE_CMD up -d db redis echo -e " ⏳ في انتظار جاهزية PostgreSQL و PostGIS..." for i in {1..30}; do if docker exec map-db pg_isready -U mapuser -d mapdb &>/dev/null; then echo -e " ✅ قاعدة البيانات PostGIS جاهزة للحقن!" break fi sleep 2 if [ $i -eq 30 ]; then echo -e "${RED}❌ فشل انتظار جاهزية قاعدة البيانات! تفقد سجلات docker logs map-db${NC}" exit 1 fi done # Step 5: Inject PostGIS Database echo -e "\n${BLUE}[5/6] 📥 استعادة وحقن البيانات المكانية في PostGIS...${NC}" if [ -f "$DUMP_FILE" ]; then echo -e " ⏳ جاري الاستعادة من ملف الـ Custom Dump المسرّع..." # Ensure postgis extension exists docker exec -i map-db psql -U mapuser -d mapdb -c "CREATE EXTENSION IF NOT EXISTS postgis;" docker exec -i map-db psql -U mapuser -d mapdb -c "CREATE EXTENSION IF NOT EXISTS postgis_topology;" # Restore dump (ignore non-fatal warnings for clean recreation) docker exec -i map-db pg_restore -U mapuser -d mapdb --clean --if-exists --no-owner --no-acl < "$DUMP_FILE" || true # Run VACUUM ANALYZE to optimize geometry indices echo -e " ⚡ تحسين الفهارس المكانية (VACUUM ANALYZE)..." docker exec -i map-db psql -U mapuser -d mapdb -c "VACUUM ANALYZE;" echo -e " ✅ تم استعادة قاعدة البيانات وتحديث الفهارس بنجاح!" fi # Step 6: Start Full Application Stack & Healthcheck echo -e "\n${BLUE}[6/6] 🚀 بناء وتشغيل كافة خدمات المنصة السيادية...${NC}" $DOCKER_COMPOSE_CMD up -d --build api martin web dashboard routing echo -e "\n⏳ فحص صحة الخدمات (Health Checks)..." sleep 5 check_service() { local name="$1" local url="$2" if curl -s -f -m 5 "$url" > /dev/null 2>&1; then echo -e " ✅ خدمة ${GREEN}$name${NC} تعمل بنجاح: $url" else echo -e " ℹ️ خدمة ${YELLOW}$name${NC} في طور الإقلاع أو تتطلب ثوانٍ إضافية: $url" fi } check_service "Backend API (NestJS)" "http://localhost:3200/api/health" check_service "Martin Vector Tiles" "http://localhost:3202/health" check_service "GraphHopper Routing" "http://localhost:8989/health" check_service "Web Tactical Portal" "http://localhost:3201" check_service "Developer Dashboard" "http://localhost:3204" # Cleanup temp unpack dir if created if [ -n "$TEMP_RESTORE_DIR" ] && [ -d "$TEMP_RESTORE_DIR" ]; then rm -rf "$TEMP_RESTORE_DIR" fi echo -e "\n${GREEN}==================================================================${NC}" echo -e "${GREEN} 🎉 اكتملت عملية الاستعادة بنجاح والمنصة تعمل بكامل طاقتها!${NC}" echo -e "${GREEN}==================================================================${NC}" echo -e "🌐 البوابة التكتيكية والمناورة: http://localhost:3201/#maneuver" echo -e "📡 خادم الخرائط السيادي (Martin): http://localhost:3202" echo -e "⚡ محرك التوجيه (GraphHopper): http://localhost:8989" echo -e "💼 لوحة المطورين والإدارة: http://localhost:3204" echo -e "------------------------------------------------------------------"