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
- Create
app/static/grass_runner/js/my-tool.js— exporthandleToolbarClick(),collectState(),restoreState(state) - Add a toolbar button in
grass_runner.html - Add a panel section
<section id="section-my-tool" …>ingrass_runner.html - Import and wire the module in
main.js - Add state shape to
session-state.jscollectSessionState/restoreSessionState
Adding a new API route
- Create
app/api/routes/my_feature.pywith anAPIRouter(prefix="/my-feature") - Include it in
app/api/routes/grass.pyunder the/grassaggregate router - Write tests in
tests/test_my_feature.py - Document endpoints in
docs-site/docs/reference/api-reference.md