← Back to Home

Government Project 1

Geospatial Platform Backend

The backend of a regional government plantation-management platform: a spatial API that maps every plantation parcel, tracks commodities and farmer groups, ingests field pest reports, and publishes interactive map layers — backed by PostGIS, served as GeoJSON and Mapbox Vector Tiles, and paired with a Hasura GraphQL data layer, JWT/Google auth, and object storage. (Built as a government client project; my role was backend engineering.)

#Geospatial / GIS#PostGIS#Mapbox Vector Tiles (MVT)#GeoJSON#FastAPI#Async PostgreSQL#GraphQL (Hasura)#JWT / OAuth#Object Storage (MinIO)#Backend API

// Overview

What it does (backend). The platform helps a regional plantation authority see and manage its crops spatially. The backend exposes the data and geometry behind that: it serves map-ready geospatial layers of plantation parcels (crop type, yield, planting method), accepts and stores field pest reports with their locations, manages commodity price data, and handles public-facing inputs (suggestions / comments) plus the various sub-apps the authority runs (Service Portal, Info Portal). Spatial data is delivered both as GeoJSON feature collections (for detail/overlay) and as Mapbox Vector Tiles generated directly in the database (for fast, zoomable maps).

Background

A plantation authority's data is inherently spatial and operational, and off-the-shelf tooling didn't fit:

  • Maps need two delivery shapes. Detail views want rich GeoJSON; smooth pan/zoom over many parcels wants lightweight vector tiles — both had to come from one source of truth.
  • Field reporting was disconnected. Pest outbreaks reported from the field needed to be captured with location and tied back to commodity and parcel data.
  • Mixed access patterns. Some consumers wanted plain relational CRUD (well served by GraphQL); others needed spatial queries, auth flows, file handling, and email that a generic GraphQL layer can't do cleanly.
  • Multiple sub-apps, one backend. Several authority programs (price info, the Service Portal and Info Portal apps, public suggestions) needed to share one data layer and one auth system.
  • Public + internal users. Citizen-facing inputs and internal management both had to be served securely from the same API.

Solution

  1. Async spatial API. A FastAPI app over an asyncpg pool exposes the platform's data, with PostGIS doing the heavy geometric lifting in the database.
  2. GeoJSON layers. Parcel and pest-report geometries are returned as FeatureCollections via ST_AsGeoJSON + json_build_object/json_agg, filterable by village/commodity/pest so the frontend can overlay exactly what it needs.
  3. On-the-fly vector tiles. A reusable MVT builder renders z/x/y tiles straight from PostGIS (ST_AsMVT + ST_AsMVTGeom + ST_TileEnvelope, with SRID auto-detected via Find_SRID and reprojection to 3857) for fast, scalable web maps.
  4. Domain endpoints. Routers for prices (harga), homepage aggregates, pest reports (laporan hama), suggestions/comments (saran/komentar), and the Service Portal / Info Portal sub-apps, each backed by parameterized SQL.
  5. Auth. JWT issuance with hashed-password login/signup plus Google OAuth sign-in, role switching for app users, and protected routes.
  6. Files & email. MinIO object storage for photos/exports with presigned-URL access, and an async SMTP mailer for notifications.
  7. Hasura alongside. A Hasura GraphQL layer on the same Postgres serves relational CRUD, tracked tables, allow-lists, and cron triggers — leaving the FastAPI service to own spatial, auth, storage, and email.

Impact

  • One source, two map formats. GeoJSON for detail and database-generated vector tiles for speed, both from the same PostGIS tables — no pre-baked tile pipeline to maintain.
  • Field data captured spatially. Pest reports land with geometry attached, queryable by commodity and pest type for outbreak mapping.
  • Right tool per access pattern. Hasura handles plain CRUD productively while the custom API owns the spatial/auth/file/email work GraphQL can't.
  • Shared backbone for many apps. Prices, sub-apps, and public inputs all run on one Postgres and one auth system.
  • Secure mixed access. JWT + Google OAuth serve internal and public users from the same surface, with files gated behind presigned URLs.

// Tech Stack

LayerTechnologies
APIFastAPI, Uvicorn, Pydantic, CORS
DatabasePostgreSQL + PostGIS, asyncpg async pool
GeospatialST_AsGeoJSON, ST_AsMVT / ST_AsMVTGeom / ST_TileEnvelope, Find_SRID, reprojection (3857)
GraphQLHasura (tracked tables, allow-list, query collections, cron triggers, actions)
AuthJWT (PyJWT), passlib password hashing, Google OAuth (Authlib)
Storage / filesMinIO object storage, presigned URLs, aiofiles, multipart uploads
Emailaiosmtplib async SMTP mailer
InfraDocker / docker-compose, GitHub Actions CI/CD, Poetry

// Architecture & Diagrams

1 / 3System Architecture — Simple (high level)

The backend in one glance: PostGIS is the source of truth; FastAPI serves spatial + app data and Hasura serves relational CRUD to the maps and apps.

rendering…

Disclaimer: sample visuals may contain anonymized, simulated, or non-production values for presentation purposes.

// Demo

No demo configured yet.