Vision: A world where every farm, from smallholders to enterprises, can access transparent, trustworthy, and affordable digital farming intelligence.
Mission: Build and maintain an open, reproducible crop intelligence platform that turns satellite, weather, sensor and field data into actionable insights, with modular workflows for scouting, operations, and analytics — deployable anywhere (self-hosted or hosted).
- Self-hostable stack with clear service boundaries (Next.js ↔ FastAPI ↔ TiTiler ↔ MinIO ↔ PostGIS)
- Reproducible NDVI pipeline with provenance (Element84 STAC → COG → TiTiler tiles)
- Tenant isolation via
X-Org-Id+ JWT; RBAC (owner/admin/member/viewer) - MapLibre + PMTiles (no Mapbox token needed), ECharts for time series
- Open, permissive BSD-3-Clause license
- Docker + Docker Compose v2
- Node.js 20+ and npm 10+ (for local web development)
- Python 3.11+ and pip (for local API development)
- Google OAuth credentials (
GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET)
apps/web/ → Next.js 14 + NextAuth (Google OAuth) + Tailwind + shadcn/ui + MapLibre + ECharts
services/api/ → FastAPI + SQLAlchemy 2.0 (async) + Alembic + Celery tasks (NDVI)
services/tiler/ → TiTiler COG tile server (shared JWT auth)
docker-compose.yml → Postgres/PostGIS, Redis, MinIO, API, Celery worker, TiTiler, Web
Critical rule: Next.js talks to Postgres only for user upsert during NextAuth auth callback (apps/web/src/lib/db.ts). All other data flows through the FastAPI API via apps/web/src/lib/api.ts.
cp .env.example .env
# Fill GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET
# Generate secrets:
# NEXTAUTH_SECRET: openssl rand -base64 32
# OPENFARM_JWT_SECRET: openssl rand -base64 64
docker compose -f docker-compose.yml -f docker-compose.dev.yml up --buildServices:
| Service | URL | Purpose |
|---|---|---|
| Web (Next.js) | http://localhost:3000 | Frontend UI |
| API (FastAPI) | http://localhost:8000 | Backend API |
| API Docs | http://localhost:8000/docs | Swagger UI |
| TiTiler | http://localhost:8080 | COG tiles |
| MinIO Console | http://localhost:9001 | Object storage admin |
Health checks:
curl http://localhost:8000/healthz # API
curl http://localhost:8080/healthz # TiTiler
curl http://localhost:3000/api/health # Webcd apps/web
npm install
npm run dev # start dev server
npm run lint # ESLint
npm run type-check # TypeScript (no emit)
npm run build # production buildcd services/api
pip install -e ".[dev]" # includes ruff
alembic upgrade head
uvicorn app.main:app --reload --port 8000
ruff check . # lint
ruff format --check . # format checkcd services/api
alembic revision --autogenerate -m "describe change"
alembic upgrade head
Run these before opening a PR:
# Web
cd apps/web
npm run lint
npm run type-check
npm run build
# API
cd ../../services/api
ruff check .
ruff format --check .- All endpoints prefixed with
/v1 - Org-scoped endpoints require
X-Org-Idheader and JWT - Pagination envelope:
{ items, total, limit, offset } - Soft delete via
deleted_atcolumn - Geometry stored as
MultiPolygon(4326); polygons auto-wrapped - Audit events on key actions (e.g., field_created)
- Auth: Google OAuth via NextAuth → JWT bridge (
/api/auth/token) - Orgs & RBAC: owner/admin/member/viewer
- Farms & Fields: draw/upload GeoJSON/KML, area calc, soft delete
- NDVI Monitoring: STAC search → NDVI COG → TiTiler tiles → time-series stats
- Alerts: ndvi_drop / ndvi_threshold
- Scouting: geotagged notes, optional photo
- Sharing: read-only field health report via share links
- GitHub Actions: lint + type-check (
.github/workflows/ci.yml) - Frontend:
npm run lint,npm run type-check - Backend:
ruff check,ruff format --check - No tests yet — contributions welcome
See DEPLOYMENT.md for a step-by-step guide to deploy on a free Oracle Cloud VM (or any VPS) with Docker Compose + Caddy auto-SSL.
See ROADMAP.md for the full development plan — what's done, what's in progress, and where contributors can help most.
- See CONTRIBUTING.md for setup, style, and PR process
- See CODE_OF_CONDUCT.md for community standards
- See SECURITY.md to report vulnerabilities (hello@openfarm.earth)
BSD-3-Clause — see LICENSE



