Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/elenacarino-max/mas-climapp/llms.txt

Use this file to discover all available pages before exploring further.

ClimApp handles two distinct data paths: an automatic real-time path driven by the user’s GPS coordinates and a manual path where users submit their own measurements. Both paths converge at the same normalization and persistence layer, ensuring that every record stored in the system shares a consistent schema regardless of its origin.
1

Browser reads GPS coordinates

The browser loads index.html. JavaScript immediately calls navigator.geolocation.getCurrentPosition(), prompting the user to allow location access. No data is fetched until the browser has confirmed coordinates.
2

Browser sends coordinates to the API

Once latitude and longitude are available, a JavaScript fetch call fires:
GET /api/clima?lat=40.4168&lon=-3.7038
The page does not reload — the UI updates in place once the response arrives.
3

api_controller receives and validates the request

api_controller.py reads the lat and lon query parameters. If either is missing it returns a 400 error immediately. Otherwise it forwards both values to the service layer:
api_controller.py
raw_data = obtener_clima_por_coordenadas(lat, lon)
4

WeatherAPIService sends the first request to AEMET

WeatherAPIService._obtener_datos_crudos() sends a GET request to AEMET’s observation endpoint with the API key in the headers:
https://opendata.aemet.es/opendata/api/observacion/convencional/todas
AEMET responds with a metadata JSON containing a datos field — a short-lived temporary URL where the actual observation payload is stored.
5

Second request downloads the observation payload

A second GET is sent immediately to the temporary URL from the previous step. This two-step handshake is how AEMET’s API works; both requests are wrapped in a RetryService session that retries up to three times with exponential back-off on HTTP 429, 500, 502, 503, and 504 errors.
6

Haversine algorithm finds the nearest station

WeatherAPIService.obtener_clima_por_coordenadas() iterates over every observation returned by AEMET. For each station it calls calcular_distancia() from utils/helpers.py, which implements the Haversine formula to compute great-circle distance in kilometres between the user’s coordinates and the station’s coordinates. The observation with the smallest distance is selected.
7

normalizer_service maps raw fields to the standard schema

normalizar_datos_aemet() translates AEMET’s abbreviated field names into the application’s canonical keys:
AEMET fieldStandard keyNotes
ubiciudad / estacionStation name
fintfechaObservation timestamp
tatemperaturaAir temperature, °C
hrhumedadRelative humidity, %
vvvientoWind speed, km/h
prespresionAtmospheric pressure, hPa
preclluviaPrecipitation, mm ("Ip"0.0)
The most recent entry in the list is used when AEMET returns multiple observations.
8

alert_service evaluates thresholds

The normalised dict is passed directly to AlertService.evaluar_alertas(). The method checks each meteorological variable against its configured thresholds and appends the matching alert codes to a list. The list is then added to the dict under the alertas key. See Alert System for the full threshold table.
9

Record saved to JSONRepository

Back in api_controller.py, the source tag is added and the record is persisted:
api_controller.py
data['fuente'] = 'aemet'
guardar_registro(data)
JSONRepository.guardar() appends the dict to data/registros_climaticos.json, creating the file if it does not already exist.
10

JSON response returned to the browser

The controller returns the normalised dict — including alerts — as a JSON HTTP response. JavaScript on the page reads the fields (ciudad, temperatura, humedad, viento, presion, lluvia, alertas) and updates the DOM without triggering a page reload.

Build docs developers (and LLMs) love