Saltar al contenido principal

Historial de precios de una gasolinera

Implementa: api, web, app
Consume: api
Estado: borrador
Última revisión: 2026-05-21T19:38:35Z

# Implementa: api, web, app
# Consume: api
# Estado: borrador
# Última revisión: 2026-05-21T19:38:35Z
# Position: 3

Feature: Historial de precios de una gasolinera

El historial de precios muestra la evolución del precio de uno o varios
combustibles a lo largo del tiempo para una gasolinera concreta.

Los datos provienen del feed oficial del gobierno (MINETUR), que se actualiza
aproximadamente cada 30 minutos. Solo se registra un punto cuando el precio
cambia; si el precio se mantiene igual, no se escribe ningún registro. Por eso
los puntos representan eventos de cambio, no muestras periódicas.

El endpoint es GET /v2/stations/{id}/price-history.

Query parameters: solo `period`. No existe parámetro `fuel` — la respuesta
siempre incluye todos los combustibles con cambios en el periodo.

Ejemplo de respuesta:

```json
// GET /v2/stations/{id}/price-history?period=1W
{
"period": "1W",
"histories": {
"diesel": {
"change_eur": -0.020,
"points": [
{ "timestamp": "2026-05-14T16:38:00+00:00", "price": 1.789 },
{ "timestamp": "2026-05-17T08:12:00+00:00", "price": 1.769 }
]
},
"sp95": {
"change_eur": null,
"points": [
{ "timestamp": "2026-05-14T16:38:00+00:00", "price": 1.615 }
]
}
}
}
```

# ---------------------------------------------------------------------------
# Parámetro de periodo
# ---------------------------------------------------------------------------

Scenario Outline: El parámetro period selecciona la ventana temporal correcta
When se solicita el historial con period=<period>
Then la respuesta incluye puntos dentro de los <ventana> anteriores a ahora
And no incluye puntos anteriores a ese límite

Examples:
| period | ventana |
| 1W | 7 días |
| 1M | 1 mes |
| 3M | 3 meses |
| 6M | 6 meses |
| 1Y | 1 año |
| 5Y | 5 años |
| ALL | todo el histórico disponible |

Scenario: El periodo por defecto es 1W cuando no se especifica el parámetro
When se solicita el historial sin el parámetro period
Then la respuesta equivale a haber enviado period=1W

Scenario: El parámetro fuel no existe y es ignorado si se envía
When se solicita el historial con un parámetro fuel=diesel en la query
Then la respuesta incluye todos los combustibles con cambios en el periodo
And no filtra por ningún combustible concreto

Scenario: La API devuelve 404 si la gasolinera no tiene cambios en el periodo
Given una gasolinera sin ningún cambio de precio en el periodo solicitado
When se solicita el historial
Then la API responde con 404

# ---------------------------------------------------------------------------
# Modelo de datos — respuesta
# ---------------------------------------------------------------------------

Scenario: Solo aparecen combustibles que tuvieron al menos un cambio en el periodo
Given una gasolinera con SP95 y Diésel
And SP95 cambió de precio dos veces en la última semana
And Diésel no cambió de precio en la última semana
When se solicita el historial con period=1W
Then la respuesta incluye SP95 con sus puntos de cambio
And la respuesta no incluye Diésel

Scenario: Los puntos de cada combustible están ordenados del más antiguo al más reciente
Given SP95 tuvo cambios de precio en varios momentos distintos
When se solicita el historial
Then la lista points del SP95 está ordenada cronológicamente de forma ascendente

Scenario: change_eur refleja la diferencia entre el precio más reciente y el más antiguo del periodo
Given SP95 tenía un precio de 1,650 €/L al inicio del periodo
And SP95 tiene un precio de 1,589 €/L al final del periodo
When se solicita el historial
Then change_eur del SP95 es -0,061

Scenario: change_eur es nulo cuando hay menos de dos puntos en el periodo
Given SP95 tuvo exactamente un cambio de precio en el periodo
When se solicita el historial
Then change_eur del SP95 es nulo

# ---------------------------------------------------------------------------
# Modelo de datos — registro de cambios
# ---------------------------------------------------------------------------

Scenario: No se escribe un registro histórico si el precio no cambió
Given SP95 tiene precio 1,650 €/L guardado
When se procesa una actualización del feed y SP95 sigue a 1,650 €/L
Then no se añade ningún punto nuevo al historial de SP95

Scenario: Se escribe un registro histórico cuando el precio cambia
Given SP95 tiene precio 1,650 €/L guardado
When se procesa una actualización del feed y SP95 aparece a 1,630 €/L
Then se añade un punto al historial de SP95 con precio 1,630 €/L y la fecha exacta del cambio

# ---------------------------------------------------------------------------
# Visualización — gráfica
# ---------------------------------------------------------------------------

Scenario: La gráfica se dibuja como línea suavizada
Given el historial tiene varios puntos de cambio de precio
Then la gráfica muestra una línea curva suavizada entre los puntos
And cada punto de cambio real queda marcado visualmente sobre la curva

Scenario Outline: El selector de periodo actualiza la gráfica
When el usuario selecciona el periodo <period>
Then la gráfica muestra los datos de los <ventana> anteriores
And el selector marca <period> como periodo activo

Examples:
| period | ventana |
| 1W | 7 días |
| 1M | 1 mes |
| 3M | 3 meses |
| 6M | 6 meses |
| 1Y | 1 año |
| 5Y | 5 años |
| ALL | todo el histórico disponible |

Scenario: El periodo por defecto al abrir el detalle es 1W
When el usuario abre la pantalla de detalle de una gasolinera
Then el selector de periodo muestra 1W seleccionado

# ---------------------------------------------------------------------------
# Selección de combustible — filas de la lista
# ---------------------------------------------------------------------------

# El gráfico muestra un solo combustible a la vez. La selección se hace
# pulsando la fila de combustible en la lista de precios del detalle de la
# estación. No hay chips ni leyenda sobre el gráfico.

Scenario: Al abrir el detalle el gráfico muestra el combustible de la búsqueda
Given el usuario buscó gasolineras baratas para "SP95"
When abre el detalle de una gasolinera
Then la fila "SP95" aparece resaltada en la lista de precios
And la gráfica muestra la curva histórica del SP95

Scenario: Pulsar una fila cambia el combustible del gráfico
Given la fila "SP95" está resaltada y el gráfico muestra el historial del SP95
When el usuario pulsa la fila "Diésel"
Then la fila "Diésel" pasa a estar resaltada
And la fila "SP95" deja de estar resaltada
And la gráfica muestra la curva histórica del Diésel

Scenario: El indicador de variación corresponde siempre al combustible seleccionado
Given el usuario ha seleccionado "Diésel" en la lista
Then el indicador de variación muestra el change_eur del Diésel
And no muestra datos de ningún otro combustible

# ---------------------------------------------------------------------------
# Visualización — scrubbing táctil
# ---------------------------------------------------------------------------

Scenario: Deslizar sobre la gráfica muestra el precio y fecha exactos en ese punto
Given la gráfica tiene datos de SP95
When el usuario desliza el dedo sobre la gráfica
Then se muestra un tooltip con el precio en €/L y la fecha exacta del punto más cercano
And el tooltip sigue la posición del dedo

Scenario: El tooltip desaparece al soltar el dedo
Given el usuario está deslizando el dedo y el tooltip está visible
When el usuario levanta el dedo
Then el tooltip desaparece

# ---------------------------------------------------------------------------
# Visualización — indicador de variación
# ---------------------------------------------------------------------------

Scenario: El indicador muestra euros y porcentaje cuando el precio bajó
Given SP95 bajó 0,003 €/L respecto al inicio del periodo (de 1,592 a 1,589), un 0,2%
Then el indicador muestra "▼ 0,003 € (0,2%)"

Scenario: El indicador muestra euros y porcentaje cuando el precio subió
Given SP95 subió 0,010 €/L respecto al inicio del periodo (de 1,579 a 1,589), un 0,6%
Then el indicador muestra "▲ 0,010 € (0,6%)"

Scenario: El indicador no se muestra cuando change_eur es nulo
Given el periodo activo tiene exactamente un punto para SP95
Then el indicador de variación no se renderiza

# ---------------------------------------------------------------------------
# Fechas — localización
# ---------------------------------------------------------------------------

Scenario: Los labels de fecha del eje X usan el locale del dispositivo
Given el dispositivo tiene el locale configurado en "en-US"
Then los meses en el eje X se muestran en inglés
And el formato de fecha sigue las convenciones del locale "en-US"

# ---------------------------------------------------------------------------
# Estado de error
# ---------------------------------------------------------------------------

Scenario: Si la llamada a price-history falla, el gráfico no se muestra
Given la petición GET /v2/stations/{id}/price-history devuelve un error
Then el componente de gráfico no se renderiza
And el resto de la pantalla de detalle permanece funcional

# ---------------------------------------------------------------------------
# Casos límite y estados vacíos
# ---------------------------------------------------------------------------

Scenario: No se muestra gráfica si no hay puntos en el periodo seleccionado
Given el combustible activo no tuvo cambios de precio en el periodo seleccionado
Then la gráfica muestra un estado vacío
And el indicador de variación no se muestra

Scenario: Si la gasolinera no apareció en el feed durante un intervalo, ese tramo no tiene datos
Given la gasolinera estuvo ausente del feed oficial entre el día 3 y el día 7
Then el historial no tiene puntos en ese intervalo
And la gráfica refleja la ausencia de datos en ese tramo

# ---------------------------------------------------------------------------
# Limitaciones conocidas
# ---------------------------------------------------------------------------

# El historial solo existe desde que se desplegó esta versión de la API.
# No hay datos retroactivos anteriores a esa fecha.

# La frecuencia mínima de detección de cambios es ~30 minutos, limitada por
# la cadencia del feed oficial del MINETUR.

# Si la gasolinera no aparece en el feed durante un periodo (por baja temporal
# u otros motivos), no habrá datos históricos para ese intervalo.