Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ricardomb-tech/surqo/llms.txt

Use this file to discover all available pages before exploring further.

Surqo is built as a layered, event-driven platform that moves data from low-cost sensor hardware in Colombian farm fields all the way to AI-generated agronomic recommendations — with no significant cold-start latency at any layer. The physical layer consists of ESP32 nodes publishing sensor readings over MQTT TLS to HiveMQ Cloud. A FastAPI backend running on Fly.io (Dallas dfw) subscribes to those messages, processes them asynchronously, and fans out results to PostgreSQL for persistence, Upstash Redis for caching and alert cooldowns, and connected WebSocket clients for real-time dashboard updates. AI analysis is handled by a multi-provider LLM service (Groq primary, Anthropic fallback) that fuses sensor history with Open-Meteo weather forecasts and a YAML crop knowledge base before returning structured recommendations. The Next.js 16 frontend at surqo.online serves the complete user interface over Vercel’s Edge network.

Architecture Diagram

┌─────────────────────────────────────────────────────────┐
│                     CAMPO / FINCA                       │
│  ESP32 Node → MQTT TLS (8883) → HiveMQ Cloud           │
└─────────────────────────────────────┬───────────────────┘


┌─────────────────────────────────────────────────────────┐
│              FastAPI Backend (Fly.io — dfw)             │
│  MQTT Consumer · LLM Service · Alert Service           │
│  KPI Engine · WebSocket Manager                        │
└──────┬──────────────┬──────────────┬────────────────────┘
       │              │              │
  Supabase      Upstash Redis   Groq/Anthropic
  PostgreSQL    (Cache/TTL)     (LLM Analysis)

  WebSocket + REST API

┌──────▼──────────────────────────────────────────────────┐
│         Next.js 16 Frontend (Vercel — surqo.online)     │
│  Dashboard · Sensores · Análisis IA · Alertas          │
└─────────────────────────────────────────────────────────┘

Production Infrastructure

The entire production stack runs on free-tier services and sustains approximately 500 concurrent users at a cost of $0–35 USD per month.
ServiceProviderRegionTier
Backend (FastAPI)Fly.ioDallas dfwshared-cpu-1x 512MB
Frontend (Next.js)VercelEdge globalHobby
DatabaseSupabase PostgreSQLus-east-1Free (500MB)
CacheUpstash Redisus-east-1Free (10K req/day)
MQTT BrokerHiveMQ CloudEUFree (100 connections)
EmailResendFree (3K emails/month)
LLM PrimaryGroqFree (14.4K req/day)
WeatherOpen-MeteoUnlimited free

Design Decisions

The following decisions shaped the architecture and are worth understanding before making changes to any layer.
The backend previously ran on Render’s free tier. Render hibernates the machine after 15 minutes of inactivity, meaning the first request after a quiet period could take up to 60 seconds to respond — unacceptable for a platform where farmers check alerts at unpredictable hours.Fly.io with auto_stop_machines = false and min_machines_running = 1 in fly.toml keeps at least one VM running at all times. There are no cold starts. Every request gets an immediate response, and the MQTT consumer thread stays alive to receive sensor readings 24/7.
The ESP32 nodes spend most of their time in deep sleep (~10µA draw) and only wake every 15 minutes to take readings. MQTT with QoS 1 guarantees exactly-once delivery even if the backend briefly restarts during a firmware publish cycle — the broker will buffer the message and re-deliver it.HTTP is still available as a fallback. The firmware attempts MQTT first and falls back to a direct POST /api/v1/sensors/readings if the broker is unreachable, so no reading is ever silently dropped. This dual-path design also lets the IoT simulator send readings via HTTP during development without needing a live HiveMQ account.
llm_service.py selects a provider at startup via the LLM_PROVIDER environment variable and exposes a uniform LLMProvider protocol so all three implementations are interchangeable:
  • Groq (primary) — Llama 3.3 70B, free up to 14,400 requests/day, latency under 1 second. Used for all production analyses.
  • Anthropic (fallback) — Claude Haiku 4.x, approximately $0.0003 per analysis. Activated when Groq quota is exhausted or for premium accuracy.
  • Ollama (local dev) — any locally-served model, zero cost, zero network dependency. Used during development so engineers do not consume production quotas.
LLM prompts are stored as versioned YAML files (farm_analysis_v1.0.yaml, alert_triage_v1.0.yaml, daily_summary_v1.0.yaml) so prompt changes can be reviewed in git, A/B tested, and rolled back without touching Python code.
Two caching patterns run through Upstash Redis:Weather cache: Each call to Open-Meteo takes ~800ms. Results are cached for 1 hour under a key derived from the farm’s coordinates. A cache hit costs ~5ms — a 160× reduction in latency for the most common path through the AI analysis pipeline.Alert cooldown: When the backend detects a threshold violation it checks for a Redis key alert_email_cooldown:{farm_id}. If the key exists the violation is still written to the alerts table but no email is sent. If the key is absent an email is dispatched and the key is set with a 30-minute TTL. This prevents alert-spam during sustained sensor exceedances (e.g., an all-day drought event) while still providing an auditable record of every violation.

Security Model

Swagger UI (/docs), ReDoc (/redoc), and the OpenAPI schema (/openapi.json) are disabled in production. They are only accessible at http://localhost:8000/docs during local development.
Surqo enforces security at every layer:
  • Authentication: JWTs issued by Supabase Auth using ES256 (P-256 elliptic curve). The backend constructs the EC public key once at startup using @lru_cache and validates every protected request without a network call.
  • Database: Row Level Security policies in PostgreSQL ensure users can only read and write their own farms, sensor readings, and analyses — even if the application layer is bypassed.
  • Transport: HTTPS is enforced at the Fly.io layer (force_https = true). MQTT traffic to HiveMQ Cloud uses TLS on port 8883. Security headers (X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Strict-Transport-Security) are applied to every HTTP response by a middleware in main.py.
  • Rate limiting: slowapi applies per-IP rate limits on critical endpoints to prevent abuse.

Build docs developers (and LLMs) love