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 an end-to-end IoT and AI platform built entirely from free-tier cloud services, an async Python backend, a React server-components frontend, and a $15 hardware node. Every technology choice was made to minimise cost at the target scale of ~500 users while keeping the codebase fully typed, observable, and testable. The sections below describe each layer in detail, from the ESP32 firmware running in a Colombian field to the Vercel Edge deployment serving the dashboard.

Backend Stack

The backend is a fully async Python 3.11 application built on FastAPI and deployed as a single-process Uvicorn server on Fly.io. All database I/O uses SQLAlchemy 2.0 async sessions with the asyncpg driver, so the event loop is never blocked by a database query.
TechnologyVersionRole
Python3.11Runtime
FastAPI0.115+HTTP + WebSocket framework
uv (Astral)latestPackage manager (10–100× faster than pip)
SQLAlchemy2.0 asyncORM
asyncpglatestAsync PostgreSQL driver
Pydantic v2latestValidation + Settings
paho-mqttlatestMQTT client for HiveMQ
httpx0.27+Async HTTP (Open-Meteo, LLM APIs)
redislatestCache + alert cooldowns
resendlatestEmail SDK
anthropiclatestClaude SDK
slowapilatestRate limiting per-IP
logfire0.50+Structured observability
pytest + pytest-asynciolatest86+ tests with SQLite in-memory
The test suite uses SQLite in-memory databases via pytest fixtures in conftest.py, so no external Supabase connection is needed to run uv run pytest tests/ -v. All 86+ tests pass on a clean checkout with only the dev dependencies installed.

Frontend Stack

The frontend is a Next.js 16 application using the App Router with React Server Components for data-heavy pages and client components for real-time WebSocket feeds. Authentication state is managed server-side using @supabase/ssr with HTTP-only cookies, so protected routes are enforced before any JavaScript is sent to the browser.
TechnologyVersionRole
Next.js16.xApp Router, SSR, Edge
React19.0+UI
TypeScript5.xType safety
Tailwind CSS3.4+Styles
@supabase/ssr0.10+Auth SSR (HTTP-only cookies)
Framer Motion11.0+Animations
Recharts2.xSVG charts
Lucide React0.400+Icons

Hardware

Each sensor node costs approximately $15 USD assembled and delivers roughly two weeks of autonomy on a pair of 18650 Li-Ion cells. The deep sleep current draw is ~10µA — the ESP32 is effectively off between readings.
ComponentSpecCost
ESP32 WROOM-32Dual-core 240MHz, WiFi$4 USD
DHT22Temp ±0.5°C, Humidity ±2%$2 USD
DS18B20 waterproofSoil temp −55/125°C, OneWire$2 USD
Capacitive soil sensor v2.00–100% moisture, no corrosion$1.5 USD
ML8511UV index 0–11+$2 USD
2× 18650 Li-Ion2,000mAh, ~2 week autonomy$4 USD
Total node cost~$15 USD
Use the DHT22 (AM2302), not the DHT11. The DHT11 has ±2°C accuracy — far too coarse for accurate VPD calculation. VPD errors of this magnitude produce incorrect irrigation recommendations.

External Services

All services in the production stack have free tiers that are adequate for approximately 500 active users. The estimated monthly infrastructure cost is $0–35 USD depending on email volume.

Supabase

PostgreSQL database and Auth. Provides Row Level Security policies, JWT issuance with ES256 keys, and a managed connection pooler. The JWKS endpoint exposes the P-256 public key used by the backend to verify tokens without a network call on each request.

HiveMQ Cloud

Managed MQTT broker. The free tier supports 100 simultaneous connections, which is sufficient for hundreds of sensor nodes sending one message every 15 minutes. TLS on port 8883 encrypts all firmware-to-cloud traffic.

Upstash Redis

Serverless Redis with pay-per-request pricing. Used for two purposes: caching Open-Meteo API responses for 1 hour, and enforcing the 30-minute alert email cooldown per farm. The free tier provides 10,000 requests per day.

Resend

Transactional email API with high deliverability. The backend sends HTML alert emails with sensor readings and recommended actions. The free tier provides 3,000 emails per month.

LLM Provider Comparison

llm_service.py selects a provider at startup based on the LLM_PROVIDER environment variable. All three implementations satisfy the same LLMProvider protocol, so switching providers requires only a configuration change — no code change.
ProviderModelCostUse Case
GroqLlama 3.3 70B (llama-3.3-70b-versatile)$0 (14.4K req/day)Primary — all production analyses
AnthropicClaude Haiku 4.x (claude-haiku-4-5-20251001)~$0.0003/analysisFallback — premium accuracy
OllamaLocal model (configurable)$0Local development — no network or quota needed
The GroqProvider class in llm_service.py calls the Groq OpenAI-compatible chat completions endpoint with temperature: 0.2 for analysis and temperature: 0.4 for conversational chat. When json_mode=True is set, the request includes "response_format": {"type": "json_object"} to prevent malformed JSON from reasoning-style responses.For image-based crop diagnosis (chat with photo), the provider automatically switches to meta-llama/llama-4-scout-17b-16e-instruct and injects the base64-encoded image as a multimodal message content block.
# From llm_service.py — GroqProvider.complete()
payload = {
    "model": self.model,           # llama-3.3-70b-versatile
    "messages": [...],
    "max_tokens": max_tokens,
    "temperature": 0.2,
    "response_format": {"type": "json_object"},  # when json_mode=True
}

Build docs developers (and LLMs) love