Bloomverd Backend

AI-Powered Precision Agriculture for Africa

Node.js NestJS GraphQL TypeScript License


Overview

Bloomverd is a full-stack agritech backend that gives African farmers access to agronomist-level intelligence through their smartphones. It combines IoT sensor networks, computer vision disease and yield predictions, and LLM-driven farm health analysis into a single, unified API.

The system monitors farms autonomously — collecting telemetry, running AI health assessments every few hours, triggering irrigation or image capture automatically when conditions require it, and surfacing actionable alerts so farmers can intervene before losses occur.

See ai/docs/ for deeper technical and business documentation.


Key Features

  • Automated AI Health Monitoring — scheduled pipeline collects IoT telemetry and asks an LLM to score soil, crop, disease risk, and weather stress; results stored and alerted automatically
  • Agentic IoT Control — the LLM can autonomously trigger irrigation, image capture, and sensor activation based on field conditions
  • Conversational AI Assistant — multi-turn chat with 5 farm tools (health, predictions, devices, details, IoT commands), streamed token by token to the client
  • Disease & Yield Predictions — external computer vision service analyzes geotagged field photos and returns risk levels (LOW / MODERATE / HIGH)
  • IoT Device Management — AWS IoT Core integration for provisioning sensors, weather stations, drones, irrigation controllers with full X.509 certificate lifecycle; each device stores optional GPS coordinates (lat/lon) used by the prediction pipeline
  • Subscription Tiers — Free / Popular / Premium plans enforced server-side, paid via Paystack
  • Real-time Streaming — Server-Sent Events (SSE) for live IoT events and AI chat token streams
  • Cloud File Storage — Cloudflare R2 (S3-compatible) with presigned upload URLs and CDN delivery
  • Multi-Channel Notifications — prediction alerts delivered via in-app SSE stream, email, and SMS (Twilio); each channel toggled per-farmer in settings

Architecture Overview

┌──────────────┐
│   Client App  │  (mobile / web)
└──────┬───────┘
       │ GraphQL (Apollo Server v5)
       │ REST (auth, IoT webhooks, SSE)
┌──────▼────────────────────────────────┐
│           NestJS Application           │
│  Auth · Farmer · Farm · Health         │
│  Predictions · Chat · Payment          │
│  Email · FarmData · Upload             │
│  Notifications · SMS                   │
└──────┬────────────────────────────────┘
       │ BullMQ Jobs
┌──────▼──────────────────────────────────────────┐
│                  Workers                         │
│  HealthConsumer  PredictionConsumer              │
│  ChatConsumer    EmailProcessor                  │
│  FarmDataConsumer                                │
└──────┬──────────────────────────────────────────┘
       │
┌──────▼──────────────────────────────────────────┐
│               Infrastructure                     │
│  PostgreSQL 17   Redis    DynamoDB               │
│  AWS IoT Core    Cloudflare R2                   │
│  Ollama / LLM    Prediction ML Service           │
│  Twilio (SMS)                                    │
└─────────────────────────────────────────────────┘

Prerequisites

RequirementVersion / Notes
Node.js≥ 22
npm≥ 10
Docker & Docker ComposeAny recent version
PostgreSQL17 (can use Docker)
RedisLatest (can use Docker)
AWS accountIoT Core + DynamoDB
Cloudflare R2Or any S3-compatible storage
Paystack accountFor payment processing
OllamaLocal LLM runtime (or set OLLAMA_BASE_URL to a hosted endpoint)
Gmail App PasswordFor transactional email

Quick Start (Docker)

The fastest way to run the full stack locally:

# 1. Clone and enter the repo
git clone <repo-url>
cd bloomverd-backend

# 2. Copy environment template and fill in your secrets
cp .env.example .env

# 3. Start PostgreSQL + Redis + the application
docker-compose up -d

# 4. (Optional) Start a local Ollama LLM service
docker-compose -f docker-compose.ollama.yml up -d

The API will be available at http://localhost:4000/graphql.


Manual Local Setup

If you prefer to run the app directly (requires Postgres and Redis already running):

# 1. Install dependencies
npm install

# 2. Copy and configure environment variables
cp .env.example .env
# Edit .env with your values (see table below)

# 3. Start supporting services (skip if already running)
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres:17
docker run -d -p 6379:6379 redis:latest

# 4. Run database migrations
npm run migration:run

# 5. Start in development mode (hot reload)
npm run start:dev

Environment Variables

Copy .env.example to .env and supply values for your environment.

Server

VariableDefaultDescription
PORT4000HTTP port the server listens on
STAGEdevelopment or production
FRONTEND_URLhttp://localhost:3000Allowed CORS origin
CORS_ORIGINAdditional CORS origin (optional)

Database

VariableDefaultDescription
DATABASE_URLFull PostgreSQL connection string
DB_USERNAMEpostgresDatabase username
DB_PASSWORDpostgresDatabase password
DB_HOSTlocalhostDatabase host
DB_PORT5432Database port
DB_NAMEbloomverd-dbDatabase name
DB_NAME_TESTbloomverd-test-dbTest database name

Redis

VariableDescription
REDIS_URLRedis connection string, e.g. redis://default:password@localhost:6379

Auth / JWT

VariableDescription
JWT_SECRETSecret used to sign JWT access tokens

Google OAuth

VariableDescription
GOOGLE_CLIENT_IDGoogle OAuth client ID
GOOGLE_SECRETGoogle OAuth client secret
GOOGLE_CALLBACK_URLOAuth redirect URI (e.g. http://localhost:4000/v1/auth/google/callback)

Cloudflare R2 (file storage)

VariableDescription
S3_REGIONauto for Cloudflare R2
S3_ENDPOINTR2 endpoint, e.g. https://<account-id>.r2.cloudflarestorage.com
S3_ACCESS_KEY_IDR2 access key
S3_SECRET_ACCESS_KEYR2 secret key
S3_BUCKET_PUBLICPublic bucket name (images served via CDN)
S3_BUCKET_PRIVATEPrivate bucket name (documents, certs)
S3_CDN_URLCDN base URL, e.g. https://<public-id>.r2.dev

AWS IoT Core

VariableDescription
IOT_REGIONAWS region for IoT Core, e.g. us-east-1
IOT_ACCESS_KEY_IDAWS access key with IoT permissions
IOT_SECRET_ACCESS_KEYAWS secret key

AWS DynamoDB (telemetry)

VariableDescription
DYNAMODB_REGIONAWS region for DynamoDB
DYNAMODB_ACCESS_KEY_IDAWS access key with DynamoDB permissions
DYNAMODB_SECRET_ACCESS_KEYAWS secret key

Email

VariableDescription
GMAIL_USERGmail address for sending transactional email
GMAIL_APP_PASSWORDGmail app password (not your account password)
EMAIL_FROMFrom address shown to recipients
EMAIL_HOSTSMTP host (smtp.gmail.com in production, smtp.ethereal.email in dev)

SMS (Twilio)

VariableDescription
TWILIO_ACCOUNT_SIDTwilio account SID (ACxxx…)
TWILIO_AUTH_TOKENTwilio auth token
TWILIO_FROM_NUMBERTwilio phone number to send from (E.164 format, e.g. +1234567890)

All three are optional — if omitted, SMS notifications are silently skipped.

Ollama / LLM

VariableDefaultDescription
OLLAMA_BASE_URLhttp://localhost:11434Ollama or OpenAI-compatible LLM endpoint
OLLAMA_API_KEYollamaAPI key (use ollama for local Ollama)
OLLAMA_MODELllama3.2Model name to use
OLLAMA_VERSIONlatestDocker image tag for the Ollama service
OLLAMA_KEEP_ALIVE24hHow long Ollama keeps the model loaded
OLLAMA_MAX_LOADED_MODELS1Maximum concurrently loaded models

Prediction Service

VariableDefaultDescription
PREDICTION_BASE_URLhttp://localhost:8000URL of the external Python ML prediction service

Paystack

VariableDescription
PAYSTACK_SECRET_KEYPaystack secret key (sk_test_... or sk_live_...)

Available Scripts

ScriptDescription
npm run start:devDevelopment mode with hot reload
npm run start:debugDebug mode with hot reload
npm run start:prodRun compiled production build
npm run buildCompile TypeScript to dist/
npm run lintRun ESLint with auto-fix
npm run formatRun Prettier formatter
npm run testRun unit tests
npm run test:watchUnit tests in watch mode
npm run test:covUnit tests with coverage report
npm run test:e2eEnd-to-end tests
npm run migration:generateGenerate a new migration from entity changes
npm run migration:runApply pending migrations
npm run migration:revertRevert the most recent migration
npm run migration:showList migrations and their status

Database Migrations

The project uses TypeORM migrations. Migrations run automatically on application startup (migrationsRun: true). For manual control:

# Apply all pending migrations
npm run migration:run

# Generate a new migration after changing entities
npm run migration:generate --name=DescriptiveName

# Undo the last applied migration
npm run migration:revert

Migration files live in src/database/migrations/.


Infrastructure as Code

The iac/ directory contains a Terraform configuration that provisions the full AWS deployment stack:

ResourceDetails
VPCPublic + private subnets, NAT gateway, internet gateway
App EC2 (t3.medium)Runs the backend via Docker Compose; public subnet
Ollama EC2 (g4dn.xlarge)GPU instance (NVIDIA T4) in private subnet for LLM inference
DynamoDBfarm_telemetry table with TTL for IoT telemetry
AWS IoT CoreTopic rule routing farms/+/+/telemetry → Lambda
LambdaPython 3.12 function writing IoT events to DynamoDB
SSM Parameter StoreStores the full .env file; fetched by EC2 at boot
GitHub SecretsAuto-updates EC2_IP and OLLAMA_IP after apply

Deploy

cd iac
terraform init
terraform apply \
  -var="public_key=$(cat ~/.ssh/id_rsa.pub)" \
  -var="env_file_content=$(cat ../.env)" \
  -var="github_repo=bloomverd/bloomverd-backend"

Terraform state is stored in S3 (bloomverd-bucket). Requires Terraform ≥ 1.6.0 and AWS CLI credentials with IoT Core, EC2, DynamoDB, Lambda, SSM, and IAM permissions.


Testing

# Unit tests
npm run test

# Unit tests (watch mode)
npm run test:watch

# Coverage report
npm run test:cov

# End-to-end tests
npm run test:e2e

Further Documentation

DocumentDescription
ai/docs/architecture.mdSystem architecture, module breakdown, data flows, database schema
ai/docs/ai-integration.mdAI/LLM integration details, health pipeline, chat tools, predictions
ai/docs/business-potential.mdAfrican market opportunity, revenue model, growth strategy
ai/docs/iot-aws-setup-cli.mdAWS IoT Core setup via CLI
ai/docs/iot-aws-setup-console.mdAWS IoT Core setup via AWS Console