Skip to main content

Best practices

Best Practices - Trekking and Mountaineering

Technical guidelines for developers building AI/RAG/agent applications in the outdoor domain. Each practice includes rationale and concrete do/don't examples.

> Informational note: The safety practices described are for educational purposes and as reference for developing information systems. They do not replace specialized training or the judgment of mountain professionals.

Use WGS84 as the reference datum for all coordinates

Rationale: WGS84 (EPSG:4326) is the global datum used by all GPS/GNSS systems and major geographic APIs. Historical Italian data (pre-1990 IGM maps) uses the Monte Mario / Rome 40 datum, which differs from WGS84 by 1–5 m in coordinates. Using mixed datums causes systematic positioning errors.

Do: Always convert input/output coordinates to WGS84 at the system boundary. Document the datum of each data source. Use proj4js/pyproj for transformations. Store coordinates as DECIMAL(9,6) (6 decimals = ±0.1 m precision) with separate lat/lon columns + PostGIS geometry(POINT, 4326) for spatial queries.

Don't: Don't mix coordinates from different sources without verifying the datum. Don't truncate coordinates to fewer than 5 decimal places (you lose metre-level precision). Don't use float32 for coordinates - single precision introduces metric errors at alpine latitudes.

Include elevation in all georeferenced entities

Rationale: In mountains, elevation is the critical third parameter after latitude and longitude. Planar distances underestimate real distances on steep terrain (a 45° slope introduces a 41% error). Walking time calculation (Naismith/Tobler formula) depends on elevation gain.

Do: Store elevation_m INTEGER for every geographic entity (huts, waypoints, start/end points). Calculate D+ and D– from GPX tracks with a smoothing algorithm to reduce GPS elevation noise (typically ±15–30 m). Validate elevation against a reference DEM (EU-DEM ≤25 m error for the Alps) before inserting into the database.

Don't: Don't omit elevation from GPX exports assuming the recipient can derive it. Don't sum elevation gains from unfiltered GPS points - cumulative noise overestimates D+ by 20–40%.

Normalize difficulty grades to a controlled vocabulary

Rationale: Difficulty scales are multiple and partially overlapping: CAI (T/E/EE/EEA), SAC (T1–T6), Hüsler for via ferratas (F/PD/MD/D/TD/ED), UIAA for rock (I–XII). A RAG system comparing "EE" with "T3" without normalization returns inconsistent results.

Do: Define an internal canonical vocabulary with mapping from each external scale: {grade_system: "CAI", grade_raw: "EE", grade_normalized: "intermediate", grade_numeric: 3}. Always include grade_system and grade_raw for traceability. Document the mapping in the dataset README.

Don't: Don't store only the raw grade without the originating classification system. Don't automatically equate "EE" CAI with "T4" SAC without checking the official definitions.

Validate GPX files against the XSD schema before ingestion

Rationale: GPX files produced by different devices and apps frequently contain proprietary extensions, non-conforming tags, or out-of-range coordinates. A malformed GPX file can cause silent errors during parsing (0,0 coordinates for unread points, anomalous elevation gains).

Do: Validate every ingested GPX against the official GPX 1.1 XSD schema (topografix.com/GPX/1/1). Verify that lat is in [-90, 90] and lon is in [-180, 180]. Check that ele is in a realistic range for the Alps (-500 m, 5,000 m). Log and isolate invalid files instead of partially importing them.

Don't: Don't assume that GPX files from well-known platforms conform to the schema. Don't ignore parsing warnings - a GPX with 100 points of which 20 are malformed produces incorrect statistics.

Respect rate limits on open geographic APIs

Rationale: OpenStreetMap Nominatim, Overpass API, and public tile APIs have strict rate limits (Nominatim: 1 req/s; Overpass: 180s timeout, max 1 req/min for heavy queries). Exceeding rate limits causes temporary IP bans (24–48h) and violates OSM terms of use.

Do: Implement an AsyncLimiter (≤1 req/s) for Nominatim calls. For Overpass, use well-optimized queries with tight bounding boxes and filters. For routing and tiles, use self-hosted instances (osrm-backend, MapTiler/Mapbox free tier) in production. Cache results in Redis with TTL 24h for POI and 1h for routing.

Don't: Don't call Nominatim in a loop without throttling. Don't run Overpass queries with area=Italy without a bounding box. Don't use official OSM tiles in high-traffic production.

Structure weather data for alpine elevations

Rationale: Weather conditions in mountains vary dramatically with elevation (thermal lapse rate: –6.5°C per 1,000 m; wind increases with altitude; localized convective precipitation). A standard weather API providing valley-floor data is unusable for a hut at 2,800 m without altitudinal interpolation.

Do: Use weather APIs supporting elevation as a parameter (Open-Meteo elevation parameter, MeteoAM with high-resolution Alpine models). Calculate the thermal lapse rate for vertical interpolation. Store weather forecasts as a time array with elevation, temperature, wind, precipitation for each alpine point of interest.

Don't: Don't use the weather forecast for the nearest valley municipality for a high-altitude hut. Don't ignore wind - at 2,000 m average wind is 30–50% stronger than at 500 m.

Implement GPX track caching at the hash level

Rationale: GPX tracks are immutable once recorded. Calculating statistics (D+, D–, distance, elevation profile) is computationally expensive and idempotent: the same GPX always produces the same statistics. Recalculating on every request wastes resources.

Do: Calculate a SHA-256 hash of the GPX file at ingestion. Store calculated statistics with the hash as key in a cache (Redis or PostgreSQL materialized view). If the hash is already present, return cached data. Invalidate the cache only on formula update (not on source file update).

Don't: Don't recalculate elevation profiles on every request. Don't use file name or modification timestamp as cache key - they are mutable.

Separate absolute location data from route-relative data

Rationale: A trekking data system mixes two types of data with different semantics: absolute location data (point coordinates, elevation, datum) which are invariant, and route-relative data (cumulative distance, partial D+, estimated time) which depend on the route chosen by the user. Mixing them in the same table complicates queries and causes redundancy.

Do: Schema with separation: waypoints table (id, lat, lon, elevation, name, type) and route_waypoints table (route_id, waypoint_id, sequence, cumulative_distance_m, cumulative_elevation_gain_m). Route statistics are calculated from the relation, not stored in the waypoint.

Don't: Don't store cumulative distance as a waypoint attribute. Don't duplicate elevation in route_waypoints - always read it from waypoints.elevation.

Include informational safety notes in risk-adjacent content

Rationale: Applications providing mountain safety guidance (weather assessment, route selection, equipment advice) operate in a context of physical risk. Even at an informational level, omitting the safety context increases the risk of misunderstanding.

Do: Add an optional (but recommended) safety_note field in route and POI data for high-difficulty ratings. In LLM prompts for route recommendation, include in the system prompt the instruction to add an informational disclaimer for EEA/UIAA IV+ routes. Make the disclaimer visible in the UI (not hidden in a footer).

Don't: Don't present avalanche risk assessments or weather conditions as operational guidance without citing the source (AINEVA bulletin). Don't omit estimated difficulty from AI-generated route recommendations.

Use GeoJSON as the output format for REST APIs

Rationale: GeoJSON (RFC 7946) is the standard for geographic REST APIs. It is readable by browsers (Leaflet, MapLibre, Mapbox), QGIS, and libraries like Turf.js. GPX format is preferable for file import/export but not for APIs - it is verbose XML without native support for domain extensions.

Do: Expose REST APIs with Content-Type: application/geo+json. Use Feature for single objects and FeatureCollection for arrays. Include domain properties (difficulty, elevation, etc.) in the properties object. Support GeoJSON as input on POST endpoints for route import.

Don't: Don't expose raw GPX as a primary API response - it is a file format, not an API format. Don't invent a proprietary JSON format when GeoJSON covers the use case.

Version route datasets with semantic versioning

Rationale: Trail datasets change over time (new trails, diversions, seasonal closures). A RAG system trained on a January dataset can give incorrect advice in June if trails have been modified. Without versioning, it is impossible to trace which dataset version produced a specific result.

Do: Assign a MAJOR.MINOR.PATCH version tag to each dataset snapshot. Increment MINOR for updates to existing routes, MAJOR for schema changes. Store the version tag in the RAG corpus manifest (corpus_version, generated_at). Document breaking changes in dataset changelogs.

Don't: Don't overwrite the dataset without creating a previous version. Don't use dates as the version (ambiguous for multiple releases on the same day).

Include emergency plans in every automatically generated itinerary

Rationale: An AI system that plans multi-stage itineraries must always include a Plan B for each stage, because alpine conditions change rapidly. An app that provides only the main route without escape options can be dangerous if used in the field by inexperienced hikers.

Do: For each generated stage, add at least one early return option (escape route) with GPS coordinates, distance and time. Include the emergency number 112 and the nearest mountain hut coordinates in the itinerary output. Indicate reliable weather windows for each stage (e.g. Open-Meteo forecast for the next 3 days). Add disclaimer: "This itinerary is for informational purposes. Evaluate actual conditions on site before proceeding."

Don't: Don't generate itineraries without specifying each stage difficulty or without mentioning seasonal hut availability. Don't present the plan as final - it is a proposal subject to verification before departure.