Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/danizd/urbanviable/llms.txt

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

GET /api/status is not a dynamic API endpoint backed by application code. It is a static JSON file (last_update.json) written by the ETL pipeline and served directly by Nginx from a volume-mounted path. There is no server-side computation, no database query, and no authentication. The file is written once per ETL run and remains static until the next run. This design mirrors the broader UrbanViable architecture: data freshness is a property of the deployed artifacts, not of a running service. The equivalent in GeoViable is GET /api/v1/layers/status, which queries a layer_update_log table — UrbanViable achieves the same observability result with a flat file.

Endpoint

GET /api/status
PropertyValue
Response typeapplication/json
Cache-Controlpublic, max-age=3600 (1 hour, set by Nginx)
AuthenticationNone
Dynamic computationNone — static file

Response Schema

updated_at
string
required
ISO 8601 timestamp of when the ETL pipeline (process_data.py) last completed successfully and wrote this file. Timezone-aware (UTC, denoted by Z or +00:00 offset). Example: "2026-04-26T11:06:05.485510+00:00".The DataStatus component compares this value against the current date to determine whether to show a freshness warning.
sections_count
integer
required
Number of census section features present in the current galicia_scouting.mbtiles file. Written from the len(gdf_output) value at the end of the ETL run. Useful for quickly verifying that a deployment is using the correct MBTiles build. Example: 2134.
year_data
string
required
The INE reference year of the income data incorporated in this ETL run. This is the most recent year available in the renta.csv file at time of processing. Example: "2023". This value may differ from the calendar year of the ETL run, because INE publishes Atlas de Renta data with approximately a one-year lag.
sources
object
required
An object with one key per data source incorporated in this ETL run. Keys are fixed identifiers; values are human-readable strings describing the source and reference year. The presence of a key indicates that the source was processed; absence indicates it was skipped (e.g., in an MVP run without OSM or Catastro).
sources.geometries
string
Census section geometry source. Example: "CNIG secciones censales".
sources.renta
string
INE income data source, including reference year. Example: "INE Atlas de Renta (año 2023)".
sources.osm
string
OpenStreetMap extract source. Example: "OpenStreetMap Galicia (Geofabrik)".
sources.catastro
string
Catastro building data source. Example: "Sede Electronica del Catastro".
variables
array of strings
required
List of _norm column names that were computed and included in the tile schema for this ETL run. The frontend can use this array to determine which variables have actual non-zero data. In a full run this will contain all seven scoring variables; in an MVP run without OSM or Catastro data, actividad_norm, uso_comercial_norm, and antiguedad_norm may be absent or present with all-zero values.

Example Response

{
  "updated_at": "2026-04-26T11:06:05.485510+00:00",
  "sections_count": 2134,
  "year_data": "2023",
  "sources": {
    "geometries": "CNIG secciones censales",
    "renta": "INE Atlas de Renta (año 2023)",
    "osm": "OpenStreetMap Galicia (Geofabrik)",
    "catastro": "Sede Electronica del Catastro"
  },
  "variables": [
    "renta_norm", "densidad_norm", "jovenes_norm", "mayores_norm",
    "actividad_norm", "uso_comercial_norm", "antiguedad_norm"
  ]
}

DataStatus Component Behavior

The DataStatus component (src/components/DataStatus.jsx) fetches this endpoint on mount and renders a status badge in the application header. Badge states:
ConditionBadgeStyle
updated_at is less than 400 days agoDatos: DD/MM/YYYYDefault (green or neutral)
updated_at is more than 400 days ago⚠️ Datos: DD/MM/YYYYYellow warning
Fetch error (network, 404, parse failure)(badge hidden)No notification — app continues normally
The 400-day threshold accounts for the INE’s ~1 year publication lag: data updated within the past 13 months is considered current. Data older than that warrants a user-visible warning that the income figures may be from an earlier reference year than expected. Fetch behavior:
  • Called once on component mount via fetch('/api/status')
  • No polling or refresh — the badge reflects the data at page load time
  • On any error (network failure, malformed JSON, missing updated_at field): the component sets its state to null and renders nothing, rather than showing an error state that would distract from the map

Updating the Status File

last_update.json is generated automatically at the end of each ETL run by process_data.py:
last_update = {
    "updated_at": datetime.now(timezone.utc).isoformat(),
    "sections_count": int(len(output)),
    "year_data": renta_year,
    "sources": {
        "geometries": "CNIG secciones censales",
        "renta": f"INE Atlas de Renta (año {renta_year})",
        "osm": "OpenStreetMap Galicia (Geofabrik)",
        "catastro": "Sede Electronica del Catastro",
    },
    "variables": [c for c in cols_output if c.endswith("_norm")],
}

with open(PROCESSED_DIR / "last_update.json", "w", encoding="utf-8") as file:
    json.dump(last_update, file, indent=2, ensure_ascii=False)
Deployment: After the ETL run completes and the new .mbtiles file has been verified, copy last_update.json to the server alongside the tile file:
scp etl/data/processed/last_update.json \
    usuario@servidor:~/urbanviable/tiles_data/last_update.json
Nginx volume mapping: The tiles_data/ directory is mounted into the urbanviable-web container at /data (read-only). Nginx maps the /api/status URL to that file via an alias directive:
Host filesystem:       ./tiles_data/last_update.json
Container mount:       /data/last_update.json  (./tiles_data:/data:ro)
Nginx location:        /api/status  →  alias /data/last_update.json
External URL:          https://urbanviable.example.com/api/status
No container restart is required after updating the file — Nginx serves the new content on the next request once the file is in place.

Build docs developers (and LLMs) love