Deployment Guide

Complete guide to deploying Gridova backend, mobile app, and ESP32 firmware to production

Backend Deployment

Deploy to Vercel

Vercel is perfect for Next.js applications with serverless API routes.

1. Install Vercel CLI

terminalbash
npm install -g vercel

2. Login to Vercel

terminalbash
vercel login

3. Deploy

terminalbash
# Deploy to preview
vercel

# Deploy to production
vercel --prod

4. Configure Environment Variables

terminalbash
# Via CLI
vercel env add DATABASE_URL
vercel env add JWT_SECRET

# Or via Vercel Dashboard:
# Project Settings → Environment Variables

5. vercel.json Configuration

vercel.jsonjson
{
  "version": 2,
  "builds": [
    {
      "src": "package.json",
      "use": "@vercel/next"
    }
  ],
  "regions": ["sin1"],
  "env": {
    "NODE_ENV": "production"
  },
  "functions": {
    "api/**/*.js": {
      "memory": 1024,
      "maxDuration": 10
    }
  }
}

Vercel Limitations

Serverless functions have 10s timeout on Hobby plan, 60s on Pro. For long-running tasks (like WebSocket), consider using Vercel Edge Functions or external service.

Mobile App Deployment

Build and Publish to Google Play

1. Generate Keystore

terminalbash
keytool -genkey -v -keystore gridova-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias gridova

# Save the keystore file securely!
# Note the keystore password and key password

2. Configure android/key.properties

android/key.propertiesproperties
storePassword=your_keystore_password
keyPassword=your_key_password
keyAlias=gridova
storeFile=../gridova-key.jks

3. Update android/app/build.gradle

android/app/build.gradlegradle
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}

android {
    compileSdkVersion 34
    
    defaultConfig {
        applicationId "com.gridova.app"
        minSdkVersion 21
        targetSdkVersion 34
        versionCode 1
        versionName "1.0.0"
    }
    
    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
            storePassword keystoreProperties['storePassword']
        }
    }
    
    buildTypes {
        release {
            signingConfig signingConfigs.release
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

4. Build Release APK/AAB

terminalbash
# Build APK
flutter build apk --release

# Or build App Bundle (recommended for Play Store)
flutter build appbundle --release

# Output files:
# APK: build/app/outputs/flutter-apk/app-release.apk
# AAB: build/app/outputs/bundle/release/app-release.aab

5. Upload to Google Play Console

  • Go to Google Play Console
  • Create new app → Enter app details
  • Production → Create new release
  • Upload app-release.aab
  • Fill in release notes and publish

Testing Before Release

Use Internal Testing or Closed Testing tracks to test with limited users before publishing to production.

ESP32 OTA Updates

Over-The-Air (OTA) updates allow you to update ESP32 firmware remotely without physical access.

ESP32 OTA Implementation

1. Enable OTA in Code

esp32_ota.inocpp
#include <WiFi.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

void setup() {
  Serial.begin(115200);
  
  // Connect to WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
  
  // Setup OTA
  ArduinoOTA.setHostname("Gridova-ESP32-001");
  ArduinoOTA.setPassword("admin");  // Change this!
  
  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH) {
      type = "sketch";
    } else {
      type = "filesystem";
    }
    Serial.println("Start updating " + type);
  });
  
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) {
      Serial.println("Auth Failed");
    } else if (error == OTA_BEGIN_ERROR) {
      Serial.println("Begin Failed");
    } else if (error == OTA_CONNECT_ERROR) {
      Serial.println("Connect Failed");
    } else if (error == OTA_RECEIVE_ERROR) {
      Serial.println("Receive Failed");
    } else if (error == OTA_END_ERROR) {
      Serial.println("End Failed");
    }
  });
  
  ArduinoOTA.begin();
  Serial.println("OTA Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  ArduinoOTA.handle();  // Handle OTA updates
  
  // Your code here
}

2. Upload Firmware via OTA

terminalbash
# Find ESP32 devices
# Arduino IDE → Tools → Port → Network ports

# Or use espota.py
python espota.py -i 192.168.1.100 -p 3232 -f firmware.bin

# Or upload via Arduino IDE
# Select network port and click Upload

3. HTTP OTA Update

http_ota.inocpp
#include <HTTPUpdate.h>

const char* firmwareUrl = "https://api.gridova.com/firmware/latest.bin";

void checkForUpdate() {
  WiFiClientSecure client;
  client.setInsecure();  // Skip certificate validation
  
  httpUpdate.setLedPin(LED_BUILTIN, LOW);
  
  t_httpUpdate_return ret = httpUpdate.update(client, firmwareUrl);
  
  switch (ret) {
    case HTTP_UPDATE_FAILED:
      Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", 
                    httpUpdate.getLastError(), 
                    httpUpdate.getLastErrorString().c_str());
      break;
      
    case HTTP_UPDATE_NO_UPDATES:
      Serial.println("HTTP_UPDATE_NO_UPDATES");
      break;
      
    case HTTP_UPDATE_OK:
      Serial.println("HTTP_UPDATE_OK");
      break;
  }
}

void loop() {
  // Check for updates daily
  static unsigned long lastCheck = 0;
  if (millis() - lastCheck > 86400000) {  // 24 hours
    checkForUpdate();
    lastCheck = millis();
  }
}

OTA Safety Tips

  • Always test firmware locally before OTA deployment
  • Implement rollback mechanism in case of failed update
  • Use strong password for OTA
  • Verify firmware integrity (checksum/signature)
  • Never interrupt power during OTA update

CI/CD Pipeline

GitHub Actions Workflow
.github/workflows/deploy.ymlyaml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy-backend:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '20'
          
      - name: Install dependencies
        run: npm ci
        
      - name: Run tests
        run: npm test
        
      - name: Build
        run: npm run build
        
      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.ORG_ID }}
          vercel-project-id: ${{ secrets.PROJECT_ID }}
          vercel-args: '--prod'
  
  deploy-mobile:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Flutter
        uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.22.0'
          
      - name: Install dependencies
        run: flutter pub get
        
      - name: Run tests
        run: flutter test
        
      - name: Build APK
        run: flutter build apk --release
        
      - name: Upload to Play Store
        uses: r0adkll/upload-google-play@v1
        with:
          serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }}
          packageName: com.gridova.app
          releaseFiles: build/app/outputs/bundle/release/app-release.aab
          track: production

Production Checklist

Monitoring & Maintenance

Application Monitoring
  • Sentry - Error tracking and performance monitoring
  • New Relic - APM and infrastructure monitoring
  • DataDog - Full-stack observability platform
  • Prometheus + Grafana - Metrics and visualization
Uptime Monitoring
  • UptimeRobot - Free uptime monitoring (5-minute checks)
  • Pingdom - Website performance and uptime monitoring
  • StatusPage - Public status page for users
Regular Maintenance Tasks
  • Update dependencies weekly (security patches)
  • Review and rotate API keys monthly
  • Check database size and optimize queries
  • Review error logs and fix recurring issues
  • Test backup restoration quarterly
  • Update SSL certificates before expiry

Support & Resources

Need Help?

Contact our support team:

  • Email: support@gridova.com
  • Documentation: docs.gridova.com
  • Community Forum: community.gridova.com