#!/bin/bash # ═══════════════════════════════════════════════════════════════════════ # Nexus Autoparts — Instance Setup Script # Target: Raspberry Pi OS / Debian / Ubuntu # Usage: sudo bash setup_instance.sh "Refaccionaria El Toro" "refac-eltoro" # ═══════════════════════════════════════════════════════════════════════ set -e BUSINESS_NAME="${1:-Refaccionaria Demo}" INSTANCE_ID="${2:-refac-$(date +%s)}" DB_PASSWORD="nexus_autoparts_2026" DB_USER="nexus" MASTER_DB="nexus_autoparts" OWNER_PIN="${3:-1234}" INSTALL_DIR="/home/Autopartes" echo "╔══════════════════════════════════════════════╗" echo "║ Nexus Autoparts — Instance Setup ║" echo "║ Business: $BUSINESS_NAME" echo "║ ID: $INSTANCE_ID" echo "╚══════════════════════════════════════════════╝" echo "" # ─── 1. System deps ─────────────────────────────────────────────────── echo "→ Installing system dependencies..." apt-get update -qq apt-get install -y -qq \ postgresql postgresql-client \ python3 python3-pip python3-venv python3-dev \ nodejs npm \ ffmpeg espeak-ng \ git curl wget \ libpq-dev gcc \ 2>/dev/null echo " ✓ System deps installed" # ─── 2. Python deps ────────────────────────────────────────────────── echo "→ Installing Python packages..." # Try system packages first (faster, no compilation needed) apt-get install -y -qq \ python3-flask python3-psycopg2 python3-sqlalchemy \ python3-jwt python3-bcrypt python3-requests \ gunicorn 2>/dev/null || true # Install remaining packages with --break-system-packages (safe for a dedicated server) pip3 install --break-system-packages --quiet \ flask psycopg2-binary sqlalchemy pyjwt bcrypt requests \ gunicorn faster-whisper \ 2>/dev/null || \ pip3 install --break-system-packages --force-reinstall --quiet \ flask psycopg2-binary sqlalchemy PyJWT bcrypt requests \ gunicorn \ 2>/dev/null || true echo " ✓ Python packages installed" # ─── 3. Node.js deps (WhatsApp bridge) ─────────────────────────────── if [ -d "/opt/whatsapp-bridge" ]; then echo "→ Installing WhatsApp bridge deps..." cd /opt/whatsapp-bridge && npm install --silent 2>/dev/null echo " ✓ WhatsApp bridge ready" else echo " ⚠ WhatsApp bridge not found at /opt/whatsapp-bridge — skipping" fi # ─── 4. PostgreSQL setup ───────────────────────────────────────────── echo "→ Configuring PostgreSQL..." systemctl enable postgresql systemctl start postgresql # Create user if doesn't exist su - postgres -c "psql -tc \"SELECT 1 FROM pg_roles WHERE rolname='$DB_USER'\" | grep -q 1" \ || su - postgres -c "createuser -s $DB_USER" # Set password su - postgres -c "psql -c \"ALTER USER $DB_USER WITH PASSWORD '$DB_PASSWORD';\"" # Create master DB if doesn't exist su - postgres -c "psql -tc \"SELECT 1 FROM pg_database WHERE datname='$MASTER_DB'\" | grep -q 1" \ || su - postgres -c "createdb -O $DB_USER $MASTER_DB" echo " ✓ PostgreSQL configured" # ─── 5. Import schema (master + tenant template) ───────────────────── echo "→ Importing database schema..." if [ -f "$INSTALL_DIR/vehicle_database/sql/schema.sql" ]; then PGPASSWORD=$DB_PASSWORD psql -U $DB_USER -h localhost -d $MASTER_DB \ -f "$INSTALL_DIR/vehicle_database/sql/schema.sql" 2>/dev/null || true fi if [ -f "$INSTALL_DIR/sql/marketplace_schema.sql" ]; then PGPASSWORD=$DB_PASSWORD psql -U $DB_USER -h localhost -d $MASTER_DB \ -f "$INSTALL_DIR/sql/marketplace_schema.sql" 2>/dev/null || true fi echo " ✓ Schema imported" # ─── 6. Create tenant for this refaccionaria ───────────────────────── echo "→ Creating tenant database for '$BUSINESS_NAME'..." TENANT_DB="tenant_${INSTANCE_ID//-/_}" su - postgres -c "psql -tc \"SELECT 1 FROM pg_database WHERE datname='$TENANT_DB'\" | grep -q 1" && { echo " ⚠ Tenant DB '$TENANT_DB' already exists — skipping creation" } || { # Create from template if available, else create fresh if su - postgres -c "psql -tc \"SELECT 1 FROM pg_database WHERE datname='tenant_template'\" | grep -q 1"; then su - postgres -c "createdb -O $DB_USER -T tenant_template $TENANT_DB" echo " ✓ Created from tenant_template" else su - postgres -c "createdb -O $DB_USER $TENANT_DB" echo " ✓ Created fresh (no template available)" fi } # Apply marketplace migration to tenant if [ -f "$INSTALL_DIR/sql/marketplace_tenant_users.sql" ]; then PGPASSWORD=$DB_PASSWORD psql -U $DB_USER -h localhost -d "$TENANT_DB" \ -f "$INSTALL_DIR/sql/marketplace_tenant_users.sql" 2>/dev/null || true fi # Apply plate_vehicles migration if [ -f "$INSTALL_DIR/pos/migrations/v1.7_plates.sql" ]; then PGPASSWORD=$DB_PASSWORD psql -U $DB_USER -h localhost -d "$TENANT_DB" \ -f "$INSTALL_DIR/pos/migrations/v1.7_plates.sql" 2>/dev/null || true fi echo " ✓ Tenant DB ready: $TENANT_DB" # ─── 7. Register tenant in master ──────────────────────────────────── echo "→ Registering tenant in master DB..." PGPASSWORD=$DB_PASSWORD psql -U $DB_USER -h localhost -d $MASTER_DB -c " INSERT INTO tenants (name, db_name, is_active, subdomain) VALUES ('$BUSINESS_NAME', '$TENANT_DB', true, '$INSTANCE_ID') ON CONFLICT DO NOTHING; " 2>/dev/null || true # Get tenant ID TENANT_ID=$(PGPASSWORD=$DB_PASSWORD psql -U $DB_USER -h localhost -d $MASTER_DB -t -c " SELECT id FROM tenants WHERE db_name = '$TENANT_DB' LIMIT 1; " 2>/dev/null | tr -d ' ') echo " ✓ Tenant registered: ID=$TENANT_ID" # ─── 8. Create owner employee ──────────────────────────────────────── echo "→ Creating owner employee..." PIN_HASH=$(python3 -c "import bcrypt; print(bcrypt.hashpw('$OWNER_PIN'.encode(), bcrypt.gensalt()).decode())") PGPASSWORD=$DB_PASSWORD psql -U $DB_USER -h localhost -d "$TENANT_DB" -c " INSERT INTO employees (name, role, pin, password_hash, is_active, marketplace_role) VALUES ('Administrador', 'owner', '$PIN_HASH', '$PIN_HASH', true, 'buyer') ON CONFLICT DO NOTHING; INSERT INTO branches (name, address, phone, is_active) VALUES ('Principal', '', '', true) ON CONFLICT DO NOTHING; " 2>/dev/null || true echo " ✓ Owner employee created (PIN: $OWNER_PIN)" # ─── 9. Configure peers.json ───────────────────────────────────────── echo "→ Configuring peers.json..." # Get this machine's IP LOCAL_IP=$(hostname -I | awk '{print $1}') cat > "$INSTALL_DIR/pos/peers.json" << EOJSON { "instance_name": "$BUSINESS_NAME", "instance_id": "$INSTANCE_ID", "tenant_id": $TENANT_ID, "peers": [], "peer_timeout_seconds": 3, "notes": "Add peer instances here: {\"name\": \"Refac B\", \"url\": \"http://192.168.X.Y:5001\", \"enabled\": true}" } EOJSON echo " ✓ peers.json configured (local IP: $LOCAL_IP)" # ─── 10. Create Gunicorn systemd service ───────────────────────────── echo "→ Setting up Gunicorn service..." cat > /etc/systemd/system/nexus-pos.service << EOSERVICE [Unit] Description=Nexus Autoparts POS After=network.target postgresql.service [Service] User=root WorkingDirectory=$INSTALL_DIR/pos Environment="PATH=/usr/local/bin:/usr/bin" ExecStart=/usr/local/bin/gunicorn -w 2 -b 0.0.0.0:5001 --timeout 120 app:app Restart=always RestartSec=5 [Install] WantedBy=multi-user.target EOSERVICE systemctl daemon-reload systemctl enable nexus-pos # Don't start yet — let user verify config first echo " ✓ Gunicorn service created (nexus-pos)" # ─── Done ───────────────────────────────────────────────────────────── echo "" echo "╔══════════════════════════════════════════════╗" echo "║ SETUP COMPLETE ║" echo "╚══════════════════════════════════════════════╝" echo "" echo "Instance: $BUSINESS_NAME" echo "Tenant DB: $TENANT_DB (ID: $TENANT_ID)" echo "Owner PIN: $OWNER_PIN" echo "Local IP: $LOCAL_IP" echo "" echo "To start the POS:" echo " systemctl start nexus-pos" echo " # or manually: cd $INSTALL_DIR/pos && gunicorn -w 2 -b 0.0.0.0:5001 app:app" echo "" echo "To add peers, edit: $INSTALL_DIR/pos/peers.json" echo "To import inventory: python3 $INSTALL_DIR/scripts/import_inventory.py --tenant=$TENANT_ID --csv=inventario.csv" echo "" echo "Access: http://$LOCAL_IP:5001/pos/login"