Teyk0o/biotrack

Open-source biodiversity monitoring tool powered by satellite imagery and open data.

★ 1Forks 0PythonGitHub ↗Compare

README

BioTrack

Open-source biodiversity monitoring tool powered by satellite imagery and open data.

BioTrack Screenshot


BioTrack aggregates free data sources (Sentinel-2, iNaturalist, GBIF, OpenStreetMap) to provide ecological health assessments for any user-defined zone. The interface is designed to be accessible to everyone, including children.

Features

  • Interactive map — Full-screen MapLibre GL map with OpenFreeMap tiles
  • Tile grid selection — Click on 10×10 km tiles (max 4) to define analysis zones, latitude-adjusted grid visible at zoom >= 9
  • Location search — Geocoding via Nominatim (OpenStreetMap)
  • Zone management — Save, list, view, and delete zones via REST API
  • Vegetation index (NDVI) — Monthly NDVI analysis from Sentinel-2 satellite imagery with temporal slider, raster overlay, and animated GIF export
  • Species diversity — Parallel aggregation of observations from iNaturalist and GBIF, with colored map markers, species cards, expandable taxonomy details, and category filters
  • French UI — Fully localized interface with vulgarized labels accessible to all audiences

Tech Stack

Component Technology
Frontend Next.js 16, React 19, TypeScript, Tailwind CSS 4
Maps MapLibre GL JS, Turf.js (area, bbox, union)
Icons Lucide React
Backend FastAPI, Python 3.12
Database PostgreSQL + PostGIS
ORM SQLAlchemy 2 + GeoAlchemy2
Migrations Alembic
Satellite Copernicus CDSE (Sentinel-2 L2A), Rasterio, NumPy
Imaging Pillow (GIF generation)
HTTP httpx (external API calls)
Data sources Sentinel-2, iNaturalist, GBIF, OpenStreetMap

Installation

Prerequisites

Tool Version Notes
Node.js >= 20 JavaScript runtime
pnpm >= 10 Package manager for the frontend
Python >= 3.12 Backend runtime
PostgreSQL >= 14 Database with PostGIS extension

1. Clone the repository

git clone https://github.com/Teyk0o/biotrack.git
cd biotrack

2. Database setup

Linux

Install PostgreSQL and PostGIS:

# Ubuntu / Debian
sudo apt update
sudo apt install postgresql postgresql-contrib postgis

# Start the service
sudo systemctl start postgresql
sudo systemctl enable postgresql

Connect as the postgres superuser and create the database:

sudo -u postgres psql
CREATE USER biotrack WITH PASSWORD 'biotrack';
CREATE DATABASE biotrack OWNER biotrack;
\c biotrack
CREATE EXTENSION IF NOT EXISTS postgis;

For tests, create a separate database:

CREATE DATABASE biotrack_test OWNER biotrack;
\c biotrack_test
CREATE EXTENSION IF NOT EXISTS postgis;
\q

Windows

  1. Download and install PostgreSQL (includes pgAdmin)
  2. During installation, note the superuser password you set
  3. Install PostGIS via the Stack Builder included with PostgreSQL, or download it from postgis.net
  4. Open pgAdmin or SQL Shell (psql) and run:
CREATE USER biotrack WITH PASSWORD 'biotrack';
CREATE DATABASE biotrack OWNER biotrack;
\c biotrack
CREATE EXTENSION IF NOT EXISTS postgis;

For tests:

CREATE DATABASE biotrack_test OWNER biotrack;
\c biotrack_test
CREATE EXTENSION IF NOT EXISTS postgis;
\q

3. Backend setup

Linux / macOS

cd backend
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

Windows (PowerShell)

cd backend
python -m venv .venv
.venv\Scripts\activate
pip install -e ".[dev]"

Windows note: If you encounter a UnicodeDecodeError with psycopg2, install psycopg v3 instead:

pip install "psycopg[binary]>=3.1.0"

Then use this driver in your .env:

DATABASE_URL=postgresql+psycopg://biotrack:biotrack@localhost:5432/biotrack

Configure environment variables

Create a backend/.env file:

DATABASE_URL=postgresql://biotrack:biotrack@localhost:5432/biotrack
COPERNICUS_CLIENT_ID=your_client_id
COPERNICUS_CLIENT_SECRET=your_client_secret

Copernicus credentials are required for NDVI analysis. Create a free account at dataspace.copernicus.eu and register an OAuth client.

Run migrations and start the server

alembic upgrade head
uvicorn app.main:app --reload

The API is now available at http://localhost:8000. Interactive docs at http://localhost:8000/docs.

4. Frontend setup

Linux / macOS

cd app
pnpm install

Windows (PowerShell)

cd app
pnpm install

Windows note: If you encounter ERR_PNPM_VIRTUAL_STORE_DIR_MAX_LENGTH_DIFF:

Remove-Item -Recurse -Force node_modules
$env:CI = "true"
pnpm install

Configure environment variables

Copy the example file and adjust if needed:

cp .env.local.example .env.local

Default values:

NEXT_PUBLIC_API_URL=http://localhost:8000
NEXT_PUBLIC_MAP_STYLE=https://tiles.openfreemap.org/styles/liberty

Start the development server

pnpm dev

Open http://localhost:3000.

5. Verify everything works

  1. Open http://localhost:3000 — you should see the full-screen map
  2. Zoom in (level 9+) to see the tile grid appear
  3. Select 1 to 4 tiles and click Enregistrer to create a zone
  4. Click a zone in the sidebar — the NDVI panel appears at the bottom, the biodiversity panel on the right

Running Tests

Backend

cd backend
pytest

Requires a running PostgreSQL instance with a biotrack_test database. Set TEST_DATABASE_URL to override the default connection string.

Frontend

cd app
pnpm lint
pnpm build

API Endpoints

Health

Method Path Description
GET /health Health check

Zones

Method Path Description
POST /api/zones Create a zone (GeoJSON Polygon/MultiPolygon)
GET /api/zones List zones (paginated: skip, limit)
GET /api/zones/{id} Get a zone by ID
PUT /api/zones/{id} Update a zone
DELETE /api/zones/{id} Delete a zone

NDVI (Vegetation Index)

Method Path Description
POST /api/zones/{id}/ndvi Trigger NDVI analysis (start_date, end_date, interval)
GET /api/zones/{id}/ndvi Get cached NDVI results (optional date range)
GET /api/zones/{id}/ndvi/tile?date=YYYY-MM-DD Get NDVI PNG tile
POST /api/zones/{id}/ndvi/preload Preload 12 months (Server-Sent Events progress)
GET /api/zones/{id}/ndvi/animation?speed=500 Generate animated GIF
DELETE /api/zones/{id}/ndvi Delete cached NDVI results

Biodiversity

Method Path Description
GET /api/zones/{id}/biodiversity Fetch species observations (source, limit, category)

Project Structure

biotrack/
├── app/                              # Next.js frontend
│   ├── app/                          # Pages and layouts
│   ├── components/map/               # Map UI components
│   │   ├── map-view.tsx              # MapLibre GL initialization
│   │   ├── map-context.tsx           # React Context (map state)
│   │   ├── tile-grid-selector.tsx    # Tile grid overlay + selection
│   │   ├── ndvi-panel.tsx            # NDVI temporal slider
│   │   ├── biodiversity-panel.tsx    # Species list + map markers
│   │   ├── zone-list.tsx             # Sidebar zone management
│   │   ├── zone-save-dialog.tsx      # Zone creation dialog
│   │   └── location-search.tsx       # Geocoding search bar
│   ├── hooks/                        # Custom React hooks
│   │   ├── use-tile-grid.ts          # Grid display + selection logic
│   │   └── use-debounce.ts           # Debounce utility
│   ├── lib/                          # API client and services
│   │   ├── api.ts                    # Generic fetch wrapper
│   │   ├── zones.ts                  # Zone CRUD
│   │   ├── ndvi.ts                   # NDVI data + tile URLs
│   │   ├── biodiversity.ts           # Biodiversity API calls
│   │   └── grid.ts                   # Tile grid math
│   └── types/                        # TypeScript interfaces
│       ├── zone.ts                   # Zone types
│       ├── ndvi.ts                   # NDVI types
│       └── biodiversity.ts           # Species + taxonomy types
│
├── backend/                          # FastAPI backend
│   ├── alembic/                      # Database migrations
│   ├── app/
│   │   ├── api/routes/               # API endpoints
│   │   │   ├── health.py             # Health check
│   │   │   ├── zones.py              # Zone CRUD (5 endpoints)
│   │   │   ├── ndvi.py               # NDVI analysis (6 endpoints)
│   │   │   └── biodiversity.py       # Biodiversity fetch
│   │   ├── core/                     # Config + database engine
│   │   ├── models/                   # SQLAlchemy ORM models
│   │   │   ├── zone.py               # Zone model
│   │   │   ├── ndvi_result.py        # NDVI statistics
│   │   │   └── ndvi_tile_cache.py    # Cached PNG tiles (BLOB)
│   │   ├── schemas/                  # Pydantic validation schemas
│   │   ├── services/                 # Business logic
│   │   │   ├── zone_service.py       # Zone operations
│   │   │   ├── ndvi_service.py       # NDVI analysis + caching
│   │   │   ├── biodiversity_service.py # iNaturalist + GBIF (parallel)
│   │   │   ├── sentinel_hub_service.py # Sentinel Hub API
│   │   │   ├── copernicus_auth_service.py # OAuth token management
│   │   │   ├── gif_service.py        # Animated GIF generation
│   │   │   └── exceptions.py         # Custom exceptions
│   │   └── utils/                    # Shared utilities
│   │       └── geometry.py           # Geometry bbox helper
│   └── tests/                        # pytest test suite
│
├── assets/                           # Logo and screenshots
├── CONTRIBUTING.md                   # Contribution guidelines
└── LICENSE                           # MIT License

Troubleshooting

Windows: psycopg2 UnicodeDecodeError

If you encounter UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 when connecting to PostgreSQL on Windows, install psycopg v3:

pip install "psycopg[binary]>=3.1.0"

Then update backend/.env:

DATABASE_URL=postgresql+psycopg://biotrack:biotrack@localhost:5432/biotrack

Windows: Alembic migration fails with DuplicateTable

If tables were created manually, Alembic doesn't know about them. Stamp the current state:

alembic stamp head

pnpm install: ERR_PNPM_VIRTUAL_STORE_DIR_MAX_LENGTH_DIFF

Delete node_modules and reinstall:

Linux / macOS:

rm -rf node_modules
CI=true pnpm install

Windows (PowerShell):

Remove-Item -Recurse -Force node_modules
$env:CI = "true"
pnpm install

Contributing

See CONTRIBUTING.md for guidelines.

License

MIT

Issues