Skip to the content.

ADR 004 — Geolocation: JSONField over PostGIS (Interim Strategy)

Date: March 2026 Status: Accepted — scheduled for revision at Phase 4 Author: Ezinna (Founder)


Context

AgriOps requires farm geolocation data to support EUDR (EU Deforestation Regulation) compliance. The regulation mandates that operators trading in specific commodities (including soy) must provide geolocation data for the plots of land where the commodity was produced. This means storing farm boundary polygons — not just a single point — and associating them with supply chain records.

The question is how to store this geolocation data in the database.


Decision Drivers


Options Considered

Option 1 — PostGIS + PointField / PolygonField (django.contrib.gis)

Django’s GeoDjango framework with PostGIS extension provides native GIS field types.

Pros:

Cons:

Option 2 — JSONField storing GeoJSON ✅ Chosen (interim)

Store farm geolocation as a JSONField containing a GeoJSON-format object.

Pros:

Cons:

Option 3 — Separate lat/long fields (FloatField x2)

Store only a centroid point as two float fields.

Pros: Simplest possible implementation.

Cons: Does not meet EUDR requirements — the regulation requires the actual plot boundary, not a point. Confirmed by internal company process: “you will have to measure the perimeter of the farm and document the GPS.” Rejected outright.


Decision

Use JSONField storing GeoJSON-format data as the interim geolocation storage strategy for Phase 2 and Phase 3. Migrate to PostGIS PolygonField in Phase 4 when deploying to a managed cloud PostgreSQL instance with PostGIS support.


GeoJSON Storage Format

All farm geolocation data is stored in the following standard GeoJSON structure:

{
  "type": "Polygon",
  "coordinates": [
    [
      [8.8583, 9.8965],
      [8.8601, 9.8965],
      [8.8601, 9.8982],
      [8.8583, 9.8982],
      [8.8583, 9.8965]
    ]
  ],
  "properties": {
    "area_hectares": 12.4,
    "mapped_by": "field_agent_name",
    "mapped_date": "2026-03-11",
    "source_app": "SW Maps",
    "accuracy_metres": 3
  }
}

This format is:


Field Implementation

class Farm(models.Model):
    geolocation = models.JSONField(
        null=True,
        blank=True,
        help_text="GeoJSON Polygon. Exported from SW Maps or NCAN Farm Mapper."
    )

Phase 4 Migration Path

Phase 2-3: JSONField (GeoJSON stored as JSONB)
Phase 4:   Add PostGIS extension to managed PostgreSQL
           Add PolygonField alongside JSONField
           Data migration: parse JSONField → populate PolygonField
           Remove JSONField after validation

No data loss during migration — GeoJSON in JSONField maps directly to PostGIS Polygon geometry.


Consequences