Skip to main content

Local Development

Repository layout

FastGIS/
├── app/
│ ├── api/routes/ # FastAPI route modules (one file per domain)
│ ├── db/ # PostGIS / SQLite helpers (routes, POI, migrate)
│ ├── services/ # Business logic (env_registry, routing, curvature …)
│ ├── auth/ # API key and web-session auth
│ ├── static/
│ │ └── grass_runner/
│ │ └── js/ # ES module browser frontend (no build step)
│ └── templates/ # Jinja2 HTML templates
├── mobile-app/ # Expo / React Native mobile client
│ ├── app/ # Expo Router file-based screens
│ └── src/
│ ├── stores/ # Zustand state (connection, env, field-capture, tiles …)
│ ├── modules/ # Feature modules (field-capture, map, navigation …)
│ └── lib/ # Shared utilities (fastgis-client, tileGrid …)
├── scripts/ # Build and data-pipeline scripts
│ ├── fetch_region_data.py
│ ├── ingest_curvature_kmz.py
│ ├── enrich_population_density.py
│ ├── build_poi_tiles.py
│ └── build_curvature_tiles.py
├── support_data/ # Downloaded KMZ + WorldPop CSVs (gitignored)
├── tests/ # pytest test suite
├── docs-site/ # This Docusaurus site
├── regions.yml # Enabled countries for routing + curvature
├── fastgis.yml # Docker Swarm stack file
├── requirements.txt
└── update_service.sh # Production deploy helper

Backend (Python / FastAPI)

Install

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements-dev.txt

Run with hot-reload

uvicorn app.main:app --reload --port 8000

JavaScript modules are plain ES modules loaded directly by the browser — no build step is needed during development.

Import smoke check

DATA_ROOT="$PWD/.local-data" \
GRASS_BIN="/Applications/GRASS-8.5.app/Contents/MacOS/grass.sh" \
.venv/bin/python -c "from app.main import app; print('imports OK')"

Run tests

# Full suite
pytest

# Focused regression suite
GRASS_COMPAT=1 pytest tests/test_deploy_config.py tests/test_routes.py tests/test_services.py --tb=short

# DB Manager + WFS
pytest tests/test_db_manager.py tests/test_wfs.py tests/test_vector_style_frontend.py --tb=short

Lint

ruff check app/

Mobile app (React Native / Expo)

Prerequisites

  • Node.js ≥ 18
  • Expo CLI: npm install -g expo-cli
  • For iOS: macOS + Xcode (or use EAS Build in the cloud)

Install

cd mobile-app
npm install

TypeScript check

npm run mobile:typecheck
# or from mobile-app/:
npx tsc --noEmit

Start (local network)

# From repo root
npm run mobile:start:lan

# From mobile-app/
npm run start:lan

Start (tunnel — for remote or cross-subnet testing)

npm run start:tunnel

iOS development build (EAS)

Local dev builds require native modules (MapLibre, Skia). Use EAS for the first install:

cd mobile-app
eas build --platform ios --profile development

After install, refresh JS only with:

npm run start:dev-client:lan -- --clear

:::caution Native modules npm run start:lan alone only refreshes the JS bundle. After adding native packages (MapLibre, Skia, etc.) or changing app.json plugins, rebuild and reinstall the dev client before testing. :::

Regenerate build info banner

npm --prefix mobile-app run generate:build-info

Docs site

cd docs-site
npm start # dev server at http://localhost:3000 (hot-reload)
npm run build # production build → docs-site/build/

Deploying to production

sh update_service.sh fastgis your-domain.com

See Deployment for the full pipeline including data packs and Valhalla tiles.

Adding a new GRASS tool panel

  1. Create app/static/grass_runner/js/my-tool.js — export handleToolbarClick(), collectState(), restoreState(state)
  2. Add a toolbar button in grass_runner.html
  3. Add a panel section <section id="section-my-tool" …> in grass_runner.html
  4. Import and wire the module in main.js
  5. Add state shape to session-state.js collectSessionState / restoreSessionState

Adding a new API route

  1. Create app/api/routes/my_feature.py with an APIRouter(prefix="/my-feature")
  2. Include it in app/api/routes/grass.py under the /grass aggregate router
  3. Write tests in tests/test_my_feature.py
  4. Document endpoints in docs-site/docs/reference/api-reference.md